diff --git a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
index 85daf0053a42667e7286022b39473bbbfd617af4..f2530acd689777f783563072496a66e3ca7966cd 100644
--- a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
+++ b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
@@ -50,8 +50,11 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
 		Cipher frameCipher = crypto.getFrameCipher();
 		OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out,
 				capacity, tagCipher, frameCipher, tagKey, frameKey, false);
+		// No error correction
+		OutgoingErrorCorrectionLayer correcter =
+			new NullOutgoingErrorCorrectionLayer(encrypter);
 		// Create the writer
 		Mac mac = crypto.getMac();
-		return new ConnectionWriterImpl(encrypter, mac, macKey);
+		return new ConnectionWriterImpl(correcter, mac, macKey);
 	}
 }
diff --git a/components/net/sf/briar/transport/ConnectionWriterImpl.java b/components/net/sf/briar/transport/ConnectionWriterImpl.java
index 017572791679b905ab2484273dac6af93130486b..9a7ad2efca1ddd919ac03bc28424d1b5c1ab185c 100644
--- a/components/net/sf/briar/transport/ConnectionWriterImpl.java
+++ b/components/net/sf/briar/transport/ConnectionWriterImpl.java
@@ -23,16 +23,16 @@ import net.sf.briar.api.transport.ConnectionWriter;
  */
 class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 
-	private final OutgoingEncryptionLayer encrypter;
+	private final OutgoingErrorCorrectionLayer out;
 	private final Mac mac;
-	private final byte[] buf;
+	private final Frame frame;
 
-	private int length = FRAME_HEADER_LENGTH;
-	private long frame = 0L;
+	private int offset = FRAME_HEADER_LENGTH;
+	private long frameNumber = 0L;
 
-	ConnectionWriterImpl(OutgoingEncryptionLayer encrypter, Mac mac,
+	ConnectionWriterImpl(OutgoingErrorCorrectionLayer out, Mac mac,
 			ErasableKey macKey) {
-		this.encrypter = encrypter;
+		this.out = out;
 		this.mac = mac;
 		// Initialise the MAC
 		try {
@@ -43,7 +43,7 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 		macKey.erase();
 		if(mac.getMacLength() != MAC_LENGTH)
 			throw new IllegalArgumentException();
-		buf = new byte[MAX_FRAME_LENGTH];
+		frame = new Frame();
 	}
 
 	public OutputStream getOutputStream() {
@@ -51,10 +51,10 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 	}
 
 	public long getRemainingCapacity() {
-		long capacity = encrypter.getRemainingCapacity();
+		long capacity = out.getRemainingCapacity();
 		// If there's any data buffered, subtract it and its overhead
-		if(length > FRAME_HEADER_LENGTH)
-			capacity -= length + MAC_LENGTH;
+		if(offset > FRAME_HEADER_LENGTH)
+			capacity -= offset + MAC_LENGTH;
 		// Subtract the overhead from the remaining capacity
 		long frames = (long) Math.ceil((double) capacity / MAX_FRAME_LENGTH);
 		int overheadPerFrame = FRAME_HEADER_LENGTH + MAC_LENGTH;
@@ -63,14 +63,14 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 
 	@Override
 	public void flush() throws IOException {
-		if(length > FRAME_HEADER_LENGTH) writeFrame();
-		encrypter.flush();
+		if(offset > FRAME_HEADER_LENGTH) writeFrame();
+		out.flush();
 	}
 
 	@Override
 	public void write(int b) throws IOException {
-		buf[length++] = (byte) b;
-		if(length + MAC_LENGTH == MAX_FRAME_LENGTH) writeFrame();
+		frame.getBuffer()[offset++] = (byte) b;
+		if(offset + MAC_LENGTH == MAX_FRAME_LENGTH) writeFrame();
 	}
 
 	@Override
@@ -80,32 +80,35 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 
 	@Override
 	public void write(byte[] b, int off, int len) throws IOException {
-		int available = MAX_FRAME_LENGTH - length - MAC_LENGTH;
+		byte[] buf = frame.getBuffer();
+		int available = MAX_FRAME_LENGTH - offset - MAC_LENGTH;
 		while(available <= len) {
-			System.arraycopy(b, off, buf, length, available);
-			length += available;
+			System.arraycopy(b, off, buf, offset, available);
+			offset += available;
 			writeFrame();
 			off += available;
 			len -= available;
-			available = MAX_FRAME_LENGTH - length - MAC_LENGTH;
+			available = MAX_FRAME_LENGTH - offset - MAC_LENGTH;
 		}
-		System.arraycopy(b, off, buf, length, len);
-		length += len;
+		System.arraycopy(b, off, buf, offset, len);
+		offset += len;
 	}
 
 	private void writeFrame() throws IOException {
-		if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
-		int payloadLength = length - FRAME_HEADER_LENGTH;
+		if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
+		byte[] buf = frame.getBuffer();
+		int payloadLength = offset - FRAME_HEADER_LENGTH;
 		assert payloadLength > 0;
-		HeaderEncoder.encodeHeader(buf, frame, payloadLength, 0);
-		mac.update(buf, 0, length);
+		HeaderEncoder.encodeHeader(buf, frameNumber, payloadLength, 0);
+		mac.update(buf, 0, offset);
 		try {
-			mac.doFinal(buf, length);
+			mac.doFinal(buf, offset);
 		} catch(ShortBufferException badMac) {
 			throw new RuntimeException(badMac);
 		}
-		encrypter.writeFrame(buf, length + MAC_LENGTH);
-		length = FRAME_HEADER_LENGTH;
-		frame++;
+		frame.setLength(offset + MAC_LENGTH);
+		out.writeFrame(frame);
+		offset = FRAME_HEADER_LENGTH;
+		frameNumber++;
 	}
 }
diff --git a/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java b/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java
index cdfd11e99526281e2b9b46df6c13d90b13a8cd46..447656ab66aa1b5b9bcb2b13365b636252ceb058 100644
--- a/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java
+++ b/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java
@@ -42,7 +42,7 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
 		blockSize = frameCipher.getBlockSize();
 		if(blockSize < FRAME_HEADER_LENGTH)
 			throw new IllegalArgumentException();
-		iv = IvEncoder.encodeIv(0, blockSize);
+		iv = IvEncoder.encodeIv(0L, blockSize);
 		ciphertext = new byte[MAX_SEGMENT_LENGTH];
 	}
 
diff --git a/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java b/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java
index 00652bd49ebb15a6e27955f24857968bac90b282..21caee2ce62e915b11bcc53ad437947660840b82 100644
--- a/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java
+++ b/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java
@@ -41,7 +41,7 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
 		blockSize = frameCipher.getBlockSize();
 		if(blockSize < FRAME_HEADER_LENGTH)
 			throw new IllegalArgumentException();
-		iv = IvEncoder.encodeIv(0, blockSize);
+		iv = IvEncoder.encodeIv(0L, blockSize);
 		segment = new SegmentImpl();
 	}
 
diff --git a/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java b/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bf37eac5253a85a8d649128e7907c2ebb55fd57
--- /dev/null
+++ b/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java
@@ -0,0 +1,39 @@
+package net.sf.briar.transport;
+
+import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
+
+import java.io.IOException;
+
+import net.sf.briar.api.plugins.Segment;
+
+class NullOutgoingErrorCorrectionLayer implements OutgoingErrorCorrectionLayer {
+
+	private final OutgoingEncryptionLayer out;
+	private final Segment segment;
+
+	private long segmentNumber = 0L;
+
+	public NullOutgoingErrorCorrectionLayer(OutgoingEncryptionLayer out) {
+		this.out = out;
+		segment = new SegmentImpl();
+	}
+
+	public void writeFrame(Frame f) throws IOException {
+		if(segmentNumber > MAX_32_BIT_UNSIGNED)
+			throw new IllegalStateException();
+		int length = f.getLength();
+		// FIXME: Unnecessary copy
+		System.arraycopy(f.getBuffer(), 0, segment.getBuffer(), 0, length);
+		segment.setLength(length);
+		segment.setSegmentNumber(segmentNumber++);
+		out.writeSegment(segment);
+	}
+
+	public void flush() throws IOException {
+		out.flush();
+	}
+
+	public long getRemainingCapacity() {
+		return out.getRemainingCapacity();
+	}
+}
diff --git a/components/net/sf/briar/transport/OutgoingEncryptionLayer.java b/components/net/sf/briar/transport/OutgoingEncryptionLayer.java
index bd902736a2e23db7b857461cc75512e96d4386cc..fecc03d286118d8f86ef08b4b0fc99f7a8649d20 100644
--- a/components/net/sf/briar/transport/OutgoingEncryptionLayer.java
+++ b/components/net/sf/briar/transport/OutgoingEncryptionLayer.java
@@ -2,13 +2,14 @@ package net.sf.briar.transport;
 
 import java.io.IOException;
 
-/** Encrypts authenticated data to be sent over a connection. */
+import net.sf.briar.api.plugins.Segment;
+
 interface OutgoingEncryptionLayer {
 
-	/** Writes the given frame. */
-	void writeFrame(byte[] b, int len) throws IOException;
+	/** Writes the given segment. */
+	void writeSegment(Segment s) throws IOException;
 
-	/** Flushes the output stream. */
+	/** Flushes the stack. */
 	void flush() throws IOException;
 
 	/** Returns the maximum number of bytes that can be written. */
diff --git a/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java b/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java
index 33cb929435b8c46d5ca894d18ad0902ad98e5f08..5a3ff9d0927b9148fd5d153a068cb7bb3641eeaf 100644
--- a/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java
+++ b/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java
@@ -1,7 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
-import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -11,6 +11,7 @@ import javax.crypto.Cipher;
 import javax.crypto.spec.IvParameterSpec;
 
 import net.sf.briar.api.crypto.ErasableKey;
+import net.sf.briar.api.plugins.Segment;
 
 class OutgoingEncryptionLayerImpl implements OutgoingEncryptionLayer {
 
@@ -18,13 +19,13 @@ class OutgoingEncryptionLayerImpl implements OutgoingEncryptionLayer {
 	private final Cipher tagCipher, frameCipher;
 	private final ErasableKey tagKey, frameKey;
 	private final boolean tagEverySegment;
-	private final byte[] iv, tag;
+	private final byte[] iv, ciphertext;
 
-	private long capacity, frame = 0L;
+	private long capacity;
 
-	OutgoingEncryptionLayerImpl(OutputStream out, long capacity, Cipher tagCipher,
-			Cipher frameCipher, ErasableKey tagKey, ErasableKey frameKey,
-			boolean tagEverySegment) {
+	OutgoingEncryptionLayerImpl(OutputStream out, long capacity,
+			Cipher tagCipher, Cipher frameCipher, ErasableKey tagKey,
+			ErasableKey frameKey, boolean tagEverySegment) {
 		this.out = out;
 		this.capacity = capacity;
 		this.tagCipher = tagCipher;
@@ -32,35 +33,37 @@ class OutgoingEncryptionLayerImpl implements OutgoingEncryptionLayer {
 		this.tagKey = tagKey;
 		this.frameKey = frameKey;
 		this.tagEverySegment = tagEverySegment;
-		iv = IvEncoder.encodeIv(0, frameCipher.getBlockSize());
-		tag = new byte[TAG_LENGTH];
+		iv = IvEncoder.encodeIv(0L, frameCipher.getBlockSize());
+		ciphertext = new byte[MAX_SEGMENT_LENGTH];
 	}
 
-	public void writeFrame(byte[] b, int len) throws IOException {
-		if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
+	public void writeSegment(Segment s) throws IOException {
+		byte[] plaintext = s.getBuffer();
+		int length = s.getLength();
+		long segmentNumber = s.getSegmentNumber();
+		int offset = 0;
+		if(tagEverySegment || segmentNumber == 0) {
+			TagEncoder.encodeTag(ciphertext, segmentNumber, tagCipher, tagKey);
+			offset = TAG_LENGTH;
+		}
+		IvEncoder.updateIv(iv, segmentNumber);
+		IvParameterSpec ivSpec = new IvParameterSpec(iv);
+		try {
+			frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
+			int encrypted = frameCipher.doFinal(plaintext, 0, length,
+					ciphertext, offset);
+			if(encrypted != length) throw new RuntimeException();
+		} catch(GeneralSecurityException badCipher) {
+			throw new RuntimeException(badCipher);
+		}
 		try {
-			if(tagEverySegment || frame == 0) {
-				TagEncoder.encodeTag(tag, frame, tagCipher, tagKey);
-				out.write(tag);
-				capacity -= tag.length;
-			}
-			IvEncoder.updateIv(iv, frame);
-			IvParameterSpec ivSpec = new IvParameterSpec(iv);
-			try {
-				frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
-				int encrypted = frameCipher.doFinal(b, 0, len, b);
-				if(encrypted != len) throw new RuntimeException();
-			} catch(GeneralSecurityException badCipher) {
-				throw new RuntimeException(badCipher);
-			}
-			out.write(b, 0, len);
-			capacity -= len;
-			frame++;
+			out.write(ciphertext, 0, offset + length);
 		} catch(IOException e) {
 			frameKey.erase();
 			tagKey.erase();
 			throw e;
 		}
+		capacity -= offset + length;
 	}
 
 	public void flush() throws IOException {
diff --git a/components/net/sf/briar/transport/OutgoingErrorCorrectionLayer.java b/components/net/sf/briar/transport/OutgoingErrorCorrectionLayer.java
new file mode 100644
index 0000000000000000000000000000000000000000..206a594df3e0e9704e85e3e24b586ec38a8843c2
--- /dev/null
+++ b/components/net/sf/briar/transport/OutgoingErrorCorrectionLayer.java
@@ -0,0 +1,15 @@
+package net.sf.briar.transport;
+
+import java.io.IOException;
+
+interface OutgoingErrorCorrectionLayer {
+
+	/** Writes the given frame. */
+	void writeFrame(Frame f) throws IOException;
+
+	/** Flushes the stack. */
+	void flush() throws IOException;
+
+	/** Returns the maximum number of bytes that can be written. */
+	long getRemainingCapacity();
+}
diff --git a/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java b/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java
index 8d7708aaa2e88f3ff13b793883ab1539a24c0c80..2bf1864454a209019cd261376ff3c8f4d80482d3 100644
--- a/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java
+++ b/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java
@@ -1,7 +1,6 @@
 package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
-import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 
 import java.io.IOException;
 import java.security.GeneralSecurityException;
@@ -22,7 +21,7 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer {
 	private final byte[] iv;
 	private final Segment segment;
 
-	private long capacity, frame = 0L;
+	private long capacity;
 
 	OutgoingSegmentedEncryptionLayer(SegmentSink out, long capacity,
 			Cipher tagCipher, Cipher frameCipher, ErasableKey tagKey,
@@ -34,29 +33,30 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer {
 		this.tagKey = tagKey;
 		this.frameKey = frameKey;
 		this.tagEverySegment = tagEverySegment;
-		iv = IvEncoder.encodeIv(0, frameCipher.getBlockSize());
+		iv = IvEncoder.encodeIv(0L, frameCipher.getBlockSize());
 		segment = new SegmentImpl();
 	}
 
-	public void writeFrame(byte[] b, int len) throws IOException {
-		if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
+	public void writeSegment(Segment s) throws IOException {
+		byte[] plaintext = s.getBuffer(), ciphertext = segment.getBuffer();
+		int length = s.getLength();
+		long segmentNumber = s.getSegmentNumber();
 		int offset = 0;
-		if(tagEverySegment || frame == 0) {
-			TagEncoder.encodeTag(segment.getBuffer(), frame, tagCipher, tagKey);
+		if(tagEverySegment || segmentNumber == 0) {
+			TagEncoder.encodeTag(ciphertext, segmentNumber, tagCipher, tagKey);
 			offset = TAG_LENGTH;
-			capacity -= TAG_LENGTH;
 		}
-		IvEncoder.updateIv(iv, frame);
+		IvEncoder.updateIv(iv, segmentNumber);
 		IvParameterSpec ivSpec = new IvParameterSpec(iv);
 		try {
 			frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
-			int encrypted = frameCipher.doFinal(b, 0, len, segment.getBuffer(),
-					offset);
-			if(encrypted != len) throw new RuntimeException();
+			int encrypted = frameCipher.doFinal(plaintext, 0, length,
+					ciphertext, offset);
+			if(encrypted != length) throw new RuntimeException();
 		} catch(GeneralSecurityException badCipher) {
 			throw new RuntimeException(badCipher);
 		}
-		segment.setLength(offset + len);
+		segment.setLength(offset + length);
 		try {
 			out.writeSegment(segment);
 		} catch(IOException e) {
@@ -64,8 +64,7 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer {
 			tagKey.erase();
 			throw e;
 		}
-		capacity -= len;
-		frame++;
+		capacity -= offset + length;
 	}
 
 	public void flush() throws IOException {}
diff --git a/components/net/sf/briar/transport/TagEncoder.java b/components/net/sf/briar/transport/TagEncoder.java
index 3ca17ea6208b8fb93771c3d117568a2a3bcdd0cd..e7a223f2a3cee537515e093c8e7dc5400b56d9f7 100644
--- a/components/net/sf/briar/transport/TagEncoder.java
+++ b/components/net/sf/briar/transport/TagEncoder.java
@@ -17,6 +17,8 @@ class TagEncoder {
 		if(tag.length < TAG_LENGTH) throw new IllegalArgumentException();
 		if(segmentNumber < 0 || segmentNumber > MAX_32_BIT_UNSIGNED)
 			throw new IllegalArgumentException();
+		// Clear the tag
+		for(int i = 0; i < TAG_LENGTH; i++) tag[i] = 0;
 		// Encode the segment number as a uint32 at the end of the tag
 		ByteUtils.writeUint32(segmentNumber, tag, TAG_LENGTH - 4);
 		try {
diff --git a/test/net/sf/briar/transport/ConnectionWriterImplTest.java b/test/net/sf/briar/transport/ConnectionWriterImplTest.java
index 030fa28d19fa64e65757199e03058d4787f74d7a..4259d717b5c524045e7517784f32b0e31c98ab65 100644
--- a/test/net/sf/briar/transport/ConnectionWriterImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionWriterImplTest.java
@@ -21,8 +21,11 @@ public class ConnectionWriterImplTest extends TransportTest {
 	@Test
 	public void testFlushWithoutWriteProducesNothing() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
-		ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
+		OutgoingEncryptionLayer encrypter =
+			new NullOutgoingEncryptionLayer(out);
+		OutgoingErrorCorrectionLayer correcter =
+			new NullOutgoingErrorCorrectionLayer(encrypter);
+		ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey);
 		w.getOutputStream().flush();
 		w.getOutputStream().flush();
 		w.getOutputStream().flush();
@@ -41,8 +44,11 @@ public class ConnectionWriterImplTest extends TransportTest {
 		mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength);
 		// Check that the ConnectionWriter gets the same results
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
-		ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
+		OutgoingEncryptionLayer encrypter =
+			new NullOutgoingEncryptionLayer(out);
+		OutgoingErrorCorrectionLayer correcter =
+			new NullOutgoingErrorCorrectionLayer(encrypter);
+		ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey);
 		w.getOutputStream().write(0);
 		w.getOutputStream().flush();
 		assertArrayEquals(frame, out.toByteArray());
@@ -51,8 +57,11 @@ public class ConnectionWriterImplTest extends TransportTest {
 	@Test
 	public void testWriteByteToMaxLengthWritesFrame() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
-		ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
+		OutgoingEncryptionLayer encrypter =
+			new NullOutgoingEncryptionLayer(out);
+		OutgoingErrorCorrectionLayer correcter =
+			new NullOutgoingErrorCorrectionLayer(encrypter);
+		ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey);
 		OutputStream out1 = w.getOutputStream();
 		// The first maxPayloadLength - 1 bytes should be buffered
 		for(int i = 0; i < MAX_PAYLOAD_LENGTH - 1; i++) out1.write(0);
@@ -65,8 +74,11 @@ public class ConnectionWriterImplTest extends TransportTest {
 	@Test
 	public void testWriteArrayToMaxLengthWritesFrame() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
-		ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
+		OutgoingEncryptionLayer encrypter =
+			new NullOutgoingEncryptionLayer(out);
+		OutgoingErrorCorrectionLayer correcter =
+			new NullOutgoingErrorCorrectionLayer(encrypter);
+		ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey);
 		OutputStream out1 = w.getOutputStream();
 		// The first maxPayloadLength - 1 bytes should be buffered
 		out1.write(new byte[MAX_PAYLOAD_LENGTH - 1]);
@@ -100,8 +112,11 @@ public class ConnectionWriterImplTest extends TransportTest {
 		byte[] expected = out.toByteArray();
 		// Check that the ConnectionWriter gets the same results
 		out.reset();
-		OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
-		ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
+		OutgoingEncryptionLayer encrypter =
+			new NullOutgoingEncryptionLayer(out);
+		OutgoingErrorCorrectionLayer correcter =
+			new NullOutgoingErrorCorrectionLayer(encrypter);
+		ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey);
 		w.getOutputStream().write(new byte[123]);
 		w.getOutputStream().flush();
 		w.getOutputStream().write(new byte[1234]);
diff --git a/test/net/sf/briar/transport/FrameReadWriteTest.java b/test/net/sf/briar/transport/FrameReadWriteTest.java
index 4699597f901a96b5aaff5fc151ed066853bdc078..465e85e3ebcf87ef4ac97e2618af0774cacc913c 100644
--- a/test/net/sf/briar/transport/FrameReadWriteTest.java
+++ b/test/net/sf/briar/transport/FrameReadWriteTest.java
@@ -77,7 +77,9 @@ public class FrameReadWriteTest extends BriarTestCase {
 		OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out,
 				Long.MAX_VALUE, tagCipher, frameCipher, tagCopy, frameCopy,
 				false);
-		ConnectionWriter writer = new ConnectionWriterImpl(encrypter, mac,
+		OutgoingErrorCorrectionLayer correcter =
+			new NullOutgoingErrorCorrectionLayer(encrypter);
+		ConnectionWriter writer = new ConnectionWriterImpl(correcter, mac,
 				macCopy);
 		OutputStream out1 = writer.getOutputStream();
 		out1.write(frame);
@@ -93,9 +95,9 @@ public class FrameReadWriteTest extends BriarTestCase {
 		// Read the frames back
 		IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in,
 				tagCipher, frameCipher, tagKey, frameKey, false);
-		IncomingErrorCorrectionLayer correcter =
+		IncomingErrorCorrectionLayer correcter1 =
 			new NullIncomingErrorCorrectionLayer(decrypter);
-		ConnectionReader reader = new ConnectionReaderImpl(correcter, mac,
+		ConnectionReader reader = new ConnectionReaderImpl(correcter1, mac,
 				macKey);
 		InputStream in1 = reader.getInputStream();
 		byte[] recovered = new byte[frame.length];
diff --git a/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java b/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java
index 8d2448433aec570b489a6ade7524b1141f01ad7e..ed8ff5d55956654d62973fb027ba9b4ae7de3aa5 100644
--- a/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java
+++ b/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java
@@ -3,6 +3,8 @@ package net.sf.briar.transport;
 import java.io.IOException;
 import java.io.OutputStream;
 
+import net.sf.briar.api.plugins.Segment;
+
 /** An encryption layer that performs no encryption. */
 class NullOutgoingEncryptionLayer implements OutgoingEncryptionLayer {
 
@@ -20,9 +22,9 @@ class NullOutgoingEncryptionLayer implements OutgoingEncryptionLayer {
 		this.capacity = capacity;
 	}
 
-	public void writeFrame(byte[] b, int len) throws IOException {
-		out.write(b, 0, len);
-		capacity -= len;
+	public void writeSegment(Segment s) throws IOException {
+		out.write(s.getBuffer(), 0, s.getLength());
+		capacity -= s.getLength();
 	}
 
 	public void flush() throws IOException {
diff --git a/test/net/sf/briar/transport/OutgoingEncryptionLayerImplTest.java b/test/net/sf/briar/transport/OutgoingEncryptionLayerImplTest.java
index 6e16d1aa7245e92424550d978b347e1b80c9b112..bd1246e965560f5434b5bf48cf7284e3097712bc 100644
--- a/test/net/sf/briar/transport/OutgoingEncryptionLayerImplTest.java
+++ b/test/net/sf/briar/transport/OutgoingEncryptionLayerImplTest.java
@@ -11,6 +11,7 @@ import javax.crypto.spec.IvParameterSpec;
 import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.ErasableKey;
+import net.sf.briar.api.plugins.Segment;
 import net.sf.briar.crypto.CryptoModule;
 
 import org.junit.Test;
@@ -63,8 +64,15 @@ public class OutgoingEncryptionLayerImplTest extends BriarTestCase {
 		OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out,
 				Long.MAX_VALUE, tagCipher, frameCipher, tagKey, frameKey,
 				false);
-		encrypter.writeFrame(plaintext, plaintext.length);
-		encrypter.writeFrame(plaintext1, plaintext1.length);
+		Segment s = new SegmentImpl();
+		System.arraycopy(plaintext, 0, s.getBuffer(), 0, plaintext.length);
+		s.setLength(plaintext.length);
+		s.setSegmentNumber(0L);
+		encrypter.writeSegment(s);
+		System.arraycopy(plaintext1, 0, s.getBuffer(), 0, plaintext1.length);
+		s.setLength(plaintext1.length);
+		s.setSegmentNumber(1L);
+		encrypter.writeSegment(s);
 		byte[] actual = out.toByteArray();
 		// Check that the actual ciphertext matches the expected ciphertext
 		assertArrayEquals(expected, actual);
@@ -103,8 +111,15 @@ public class OutgoingEncryptionLayerImplTest extends BriarTestCase {
 		out.reset();
 		OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out,
 				Long.MAX_VALUE, tagCipher, frameCipher, tagKey, frameKey, true);
-		encrypter.writeFrame(plaintext, plaintext.length);
-		encrypter.writeFrame(plaintext1, plaintext1.length);
+		Segment s = new SegmentImpl();
+		System.arraycopy(plaintext, 0, s.getBuffer(), 0, plaintext.length);
+		s.setLength(plaintext.length);
+		s.setSegmentNumber(0L);
+		encrypter.writeSegment(s);
+		System.arraycopy(plaintext1, 0, s.getBuffer(), 0, plaintext1.length);
+		s.setLength(plaintext1.length);
+		s.setSegmentNumber(1L);
+		encrypter.writeSegment(s);
 		byte[] actual = out.toByteArray();
 		// Check that the actual ciphertext matches the expected ciphertext
 		assertArrayEquals(expected, actual);
diff --git a/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java b/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java
index 0fa64f2c0cc711c3ef8471ecd10eaaf7623354a3..42668013602ebd52c02c1bab33d215fbfd19b261 100644
--- a/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java
+++ b/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java
@@ -66,9 +66,15 @@ public class OutgoingSegmentedEncryptionLayerTest extends BriarTestCase {
 		OutgoingEncryptionLayer encrypter =
 			new OutgoingSegmentedEncryptionLayer(sink, Long.MAX_VALUE,
 					tagCipher, frameCipher, tagKey, frameKey, false);
-		// The first frame's buffer must have enough space for the tag
-		encrypter.writeFrame(plaintext, plaintext.length);
-		encrypter.writeFrame(plaintext1, plaintext1.length);
+		Segment s = new SegmentImpl();
+		System.arraycopy(plaintext, 0, s.getBuffer(), 0, plaintext.length);
+		s.setLength(plaintext.length);
+		s.setSegmentNumber(0L);
+		encrypter.writeSegment(s);
+		System.arraycopy(plaintext1, 0, s.getBuffer(), 0, plaintext1.length);
+		s.setLength(plaintext1.length);
+		s.setSegmentNumber(1L);
+		encrypter.writeSegment(s);
 		byte[] actual = out.toByteArray();
 		// Check that the actual ciphertext matches the expected ciphertext
 		assertArrayEquals(expected, actual);
@@ -108,8 +114,15 @@ public class OutgoingSegmentedEncryptionLayerTest extends BriarTestCase {
 		OutgoingEncryptionLayer encrypter =
 			new OutgoingSegmentedEncryptionLayer(sink, Long.MAX_VALUE,
 					tagCipher, frameCipher, tagKey, frameKey, true);
-		encrypter.writeFrame(plaintext, plaintext.length);
-		encrypter.writeFrame(plaintext1, plaintext1.length);
+		Segment s = new SegmentImpl();
+		System.arraycopy(plaintext, 0, s.getBuffer(), 0, plaintext.length);
+		s.setLength(plaintext.length);
+		s.setSegmentNumber(0L);
+		encrypter.writeSegment(s);
+		System.arraycopy(plaintext1, 0, s.getBuffer(), 0, plaintext1.length);
+		s.setLength(plaintext1.length);
+		s.setSegmentNumber(1L);
+		encrypter.writeSegment(s);
 		byte[] actual = out.toByteArray();
 		// Check that the actual ciphertext matches the expected ciphertext
 		assertArrayEquals(expected, actual);