diff --git a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java
index 2b4288a445075284431aac79b83ec1394b3e2958..fc951da24a9ab393516db85b478e25a1bf0f9e32 100644
--- a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java
+++ b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java
@@ -26,15 +26,26 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
 
 	public ConnectionReader createConnectionReader(InputStream in,
 			byte[] secret, boolean initiator) {
-		// Derive the keys and erase the secret
-		ErasableKey tagKey = crypto.deriveTagKey(secret, initiator);
-		ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
-		ByteUtils.erase(secret);
-		// Create the reader
-		Cipher tagCipher = crypto.getTagCipher();
-		AuthenticatedCipher frameCipher = crypto.getFrameCipher();
-		FrameReader encryption = new IncomingEncryptionLayer(in, tagCipher,
-				frameCipher, tagKey, frameKey, !initiator, MAX_FRAME_LENGTH);
-		return new ConnectionReaderImpl(encryption, MAX_FRAME_LENGTH);
+		if(initiator) {
+			// Derive the frame key and erase the secret
+			ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
+			ByteUtils.erase(secret);
+			// Create a reader for the responder's side of the connection
+			AuthenticatedCipher frameCipher = crypto.getFrameCipher();
+			FrameReader encryption = new IncomingEncryptionLayer(in,
+					frameCipher, frameKey, MAX_FRAME_LENGTH);
+			return new ConnectionReaderImpl(encryption, MAX_FRAME_LENGTH);
+		} else {
+			// Derive the tag and frame keys and erase the secret
+			ErasableKey tagKey = crypto.deriveTagKey(secret, initiator);
+			ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
+			ByteUtils.erase(secret);
+			// Create a reader for the initiator's side of the connection
+			Cipher tagCipher = crypto.getTagCipher();
+			AuthenticatedCipher frameCipher = crypto.getFrameCipher();
+			FrameReader encryption = new IncomingEncryptionLayer(in, tagCipher,
+					frameCipher, tagKey, frameKey, MAX_FRAME_LENGTH);
+			return new ConnectionReaderImpl(encryption, MAX_FRAME_LENGTH);
+		}
 	}
 }
diff --git a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
index e719edd3114daa0a5e6fcb331112eae08d54d08d..415eb2fdf74ece8fa3f2be2f1cfc1309b50c854f 100644
--- a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
+++ b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
@@ -26,16 +26,26 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
 
 	public ConnectionWriter createConnectionWriter(OutputStream out,
 			long capacity, byte[] secret, boolean initiator) {
-		// Derive the keys and erase the secret
-		ErasableKey tagKey = crypto.deriveTagKey(secret, initiator);
-		ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
-		ByteUtils.erase(secret);
-		// Create the writer
-		Cipher tagCipher = crypto.getTagCipher();
-		AuthenticatedCipher frameCipher = crypto.getFrameCipher();
-		FrameWriter encryption = new OutgoingEncryptionLayer(out, capacity,
-				tagCipher, frameCipher, tagKey, frameKey, initiator,
-				MAX_FRAME_LENGTH);
-		return new ConnectionWriterImpl(encryption, MAX_FRAME_LENGTH);
+		if(initiator) {
+			// Derive the tag and frame keys and erase the secret
+			ErasableKey tagKey = crypto.deriveTagKey(secret, initiator);
+			ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
+			ByteUtils.erase(secret);
+			// Create a writer for the initiator's side of the connection
+			Cipher tagCipher = crypto.getTagCipher();
+			AuthenticatedCipher frameCipher = crypto.getFrameCipher();
+			FrameWriter encryption = new OutgoingEncryptionLayer(out, capacity,
+					tagCipher, frameCipher, tagKey, frameKey, MAX_FRAME_LENGTH);
+			return new ConnectionWriterImpl(encryption, MAX_FRAME_LENGTH);
+		} else {
+			// Derive the frame key and erase the secret
+			ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
+			ByteUtils.erase(secret);
+			// Create a writer for the responder's side of the connection
+			AuthenticatedCipher frameCipher = crypto.getFrameCipher();
+			FrameWriter encryption = new OutgoingEncryptionLayer(out, capacity,
+					frameCipher, frameKey, MAX_FRAME_LENGTH);
+			return new ConnectionWriterImpl(encryption, MAX_FRAME_LENGTH);
+		}
 	}
-}
+}
\ No newline at end of file
diff --git a/components/net/sf/briar/transport/IncomingEncryptionLayer.java b/components/net/sf/briar/transport/IncomingEncryptionLayer.java
index 084b5f5d72e8c6be7a481bfca5261786ae18f393..4e9bb09c2936d7b52485544c1c2029b70d9dcc24 100644
--- a/components/net/sf/briar/transport/IncomingEncryptionLayer.java
+++ b/components/net/sf/briar/transport/IncomingEncryptionLayer.java
@@ -25,26 +25,44 @@ class IncomingEncryptionLayer implements FrameReader {
 	private final AuthenticatedCipher frameCipher;
 	private final ErasableKey tagKey, frameKey;
 	private final byte[] iv, aad, ciphertext;
-	private final int maxFrameLength;
+	private final int frameLength;
 
-	private boolean readTag, lastFrame;
 	private long frameNumber;
+	private boolean readTag, lastFrame;
 
+	/** Constructor for the initiator's side of a connection. */
 	IncomingEncryptionLayer(InputStream in, Cipher tagCipher,
 			AuthenticatedCipher frameCipher, ErasableKey tagKey,
-			ErasableKey frameKey, boolean readTag, int maxFrameLength) {
+			ErasableKey frameKey, int frameLength) {
 		this.in = in;
 		this.tagCipher = tagCipher;
 		this.frameCipher = frameCipher;
 		this.tagKey = tagKey;
 		this.frameKey = frameKey;
-		this.readTag = readTag;
-		this.maxFrameLength = maxFrameLength;
+		this.frameLength = frameLength;
+		iv = new byte[IV_LENGTH];
+		aad = new byte[AAD_LENGTH];
+		ciphertext = new byte[frameLength];
+		frameNumber = 0L;
+		readTag = true;
 		lastFrame = false;
+	}
+
+	/** Constructor for the responder's side of a connection. */
+	IncomingEncryptionLayer(InputStream in, AuthenticatedCipher frameCipher,
+			ErasableKey frameKey, int frameLength) {
+		this.in = in;
+		this.frameCipher = frameCipher;
+		this.frameKey = frameKey;
+		this.frameLength = frameLength;
+		tagCipher = null;
+		tagKey = null;
 		iv = new byte[IV_LENGTH];
 		aad = new byte[AAD_LENGTH];
-		ciphertext = new byte[maxFrameLength];
+		ciphertext = new byte[frameLength];
 		frameNumber = 0L;
+		readTag = false;
+		lastFrame = false;
 	}
 
 	public int readFrame(byte[] frame) throws IOException {
@@ -70,9 +88,9 @@ class IncomingEncryptionLayer implements FrameReader {
 		// Read the frame
 		int ciphertextLength = 0;
 		try {
-			while(ciphertextLength < maxFrameLength) {
+			while(ciphertextLength < frameLength) {
 				int read = in.read(ciphertext, ciphertextLength,
-						maxFrameLength - ciphertextLength);
+						frameLength - ciphertextLength);
 				if(read == -1) break; // We'll check the length later
 				ciphertextLength += read;
 			}
@@ -96,7 +114,7 @@ class IncomingEncryptionLayer implements FrameReader {
 		}
 		// Decode and validate the header
 		lastFrame = FrameEncoder.isLastFrame(frame);
-		if(!lastFrame && ciphertextLength < maxFrameLength)
+		if(!lastFrame && ciphertextLength < frameLength)
 			throw new EOFException();
 		int payloadLength = FrameEncoder.getPayloadLength(frame);
 		if(payloadLength > plaintextLength - HEADER_LENGTH)
diff --git a/components/net/sf/briar/transport/OutgoingEncryptionLayer.java b/components/net/sf/briar/transport/OutgoingEncryptionLayer.java
index f3cebfd1e9a93bed17503c3507c15e2dab2fc63a..c9080a6c5e95ec010abc51c9ed00ad83b92a843c 100644
--- a/components/net/sf/briar/transport/OutgoingEncryptionLayer.java
+++ b/components/net/sf/briar/transport/OutgoingEncryptionLayer.java
@@ -23,35 +23,54 @@ class OutgoingEncryptionLayer implements FrameWriter {
 	private final AuthenticatedCipher frameCipher;
 	private final ErasableKey tagKey, frameKey;
 	private final byte[] iv, aad, ciphertext;
-	private final int maxFrameLength;
+	private final int frameLength;
 
-	private boolean writeTag;
 	private long capacity, frameNumber;
+	private boolean writeTag;
 
+	/** Constructor for the initiator's side of a connection. */
 	OutgoingEncryptionLayer(OutputStream out, long capacity, Cipher tagCipher,
 			AuthenticatedCipher frameCipher, ErasableKey tagKey,
-			ErasableKey frameKey, boolean writeTag, int maxFrameLength) {
+			ErasableKey frameKey, int frameLength) {
 		this.out = out;
-		this.capacity = writeTag ? capacity - TAG_LENGTH : capacity;
+		this.capacity = capacity - TAG_LENGTH;
 		this.tagCipher = tagCipher;
 		this.frameCipher = frameCipher;
 		this.tagKey = tagKey;
 		this.frameKey = frameKey;
-		this.writeTag = writeTag;
-		this.maxFrameLength = maxFrameLength;
+		this.frameLength = frameLength;
+		iv = new byte[IV_LENGTH];
+		aad = new byte[AAD_LENGTH];
+		ciphertext = new byte[frameLength];
+		frameNumber = 0L;
+		writeTag = true;
+	}
+
+	/** Constructor for the responder's side of a connection. */
+	OutgoingEncryptionLayer(OutputStream out, long capacity,
+			AuthenticatedCipher frameCipher, ErasableKey frameKey,
+			int frameLength) {
+		this.out = out;
+		this.capacity = capacity;
+		this.frameCipher = frameCipher;
+		this.frameKey = frameKey;
+		this.frameLength = frameLength;
+		tagCipher = null;
+		tagKey = null;
 		iv = new byte[IV_LENGTH];
 		aad = new byte[AAD_LENGTH];
-		ciphertext = new byte[maxFrameLength];
+		ciphertext = new byte[frameLength];
 		frameNumber = 0L;
+		writeTag = false;
 	}
 
 	public void writeFrame(byte[] frame, int payloadLength, int paddingLength,
 			boolean lastFrame) throws IOException {
 		int plaintextLength = HEADER_LENGTH + payloadLength + paddingLength;
 		int ciphertextLength = plaintextLength + MAC_LENGTH;
-		if(ciphertextLength > maxFrameLength)
+		if(ciphertextLength > frameLength)
 			throw new IllegalArgumentException();
-		if(!lastFrame && ciphertextLength < maxFrameLength)
+		if(!lastFrame && ciphertextLength < frameLength)
 			throw new IllegalArgumentException();
 		// If the initiator's side of the connection is closed without writing
 		// any payload or padding, don't write a tag or an empty frame
diff --git a/test/net/sf/briar/transport/FrameReadWriteTest.java b/test/net/sf/briar/transport/FrameReadWriteTest.java
index 620a63f6780045be6d7f5b5a05d068220ef6b185..a9b7361e75604551ac9257e2cc65de8c7c94bf26 100644
--- a/test/net/sf/briar/transport/FrameReadWriteTest.java
+++ b/test/net/sf/briar/transport/FrameReadWriteTest.java
@@ -75,7 +75,7 @@ public class FrameReadWriteTest extends BriarTestCase {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		FrameWriter encryptionOut = new OutgoingEncryptionLayer(out,
 				Long.MAX_VALUE, tagCipher, frameCipher, tagCopy, frameCopy,
-				true, FRAME_LENGTH);
+				FRAME_LENGTH);
 		ConnectionWriter writer = new ConnectionWriterImpl(encryptionOut,
 				FRAME_LENGTH);
 		OutputStream out1 = writer.getOutputStream();
@@ -88,7 +88,7 @@ public class FrameReadWriteTest extends BriarTestCase {
 		// Read the tag and the frames back
 		ByteArrayInputStream in = new ByteArrayInputStream(output);
 		FrameReader encryptionIn = new IncomingEncryptionLayer(in, tagCipher,
-				frameCipher, tagKey, frameKey, true, FRAME_LENGTH);
+				frameCipher, tagKey, frameKey, FRAME_LENGTH);
 		ConnectionReader reader = new ConnectionReaderImpl(encryptionIn,
 				FRAME_LENGTH);
 		InputStream in1 = reader.getInputStream();