diff --git a/api/net/sf/briar/api/plugins/Segment.java b/api/net/sf/briar/api/plugins/Segment.java
index 47ed6147732e9b629101c6256fac6573edf84f38..61c0a3ed2dec6ae98f63b90948db7c0f55868af5 100644
--- a/api/net/sf/briar/api/plugins/Segment.java
+++ b/api/net/sf/briar/api/plugins/Segment.java
@@ -8,9 +8,9 @@ public interface Segment {
 
 	int getLength();
 
-	long getTransmissionNumber();
+	long getSegmentNumber();
 
 	void setLength(int length);
 
-	void setTransmissionNumber(int transmission);
+	void setSegmentNumber(long segmentNumber);
 }
diff --git a/api/net/sf/briar/api/transport/TransportConstants.java b/api/net/sf/briar/api/transport/TransportConstants.java
index dd1c71f9af2117e857d142aadbf27c88a843fb2b..cd62a65b1324248cc51d3b4debcfbc17d62af32d 100644
--- a/api/net/sf/briar/api/transport/TransportConstants.java
+++ b/api/net/sf/briar/api/transport/TransportConstants.java
@@ -2,19 +2,20 @@ package net.sf.briar.api.transport;
 
 public interface TransportConstants {
 
-	/**
-	 * The maximum length of a frame in bytes, including the header and footer.
-	 */
-	static final int MAX_FRAME_LENGTH = 65536; // 2^16, 64 KiB
+	/** The maximum length of a segment in bytes, including the tag. */
+	static final int MAX_SEGMENT_LENGTH = 65536; // 2^16, 64 KiB
+
+	/** The length of the segment tag in bytes. */
+	static final int TAG_LENGTH = 16;
+
+	/** The maximum length of a frame in bytes, including the header and MAC. */
+	static final int MAX_FRAME_LENGTH = MAX_SEGMENT_LENGTH - TAG_LENGTH;
 
 	/** The length of the frame header in bytes. */
 	static final int FRAME_HEADER_LENGTH = 8;
 
-	/**
-	 * The length in bytes of the pseudo-random tag that uniquely identifies a
-	 * connection.
-	 */
-	static final int TAG_LENGTH = 16;
+	/** The length of the MAC in bytes. */
+	static final int MAC_LENGTH = 32;
 
 	/**
 	 * The minimum connection length in bytes that all transport plugins must
diff --git a/components/net/sf/briar/protocol/ProtocolWriterImpl.java b/components/net/sf/briar/protocol/ProtocolWriterImpl.java
index ba8aebfaa872e3ffa7dc8ab0fd720ca76814b3a3..51e42998bd2b776eb1cae8c67470b14ad85d174f 100644
--- a/components/net/sf/briar/protocol/ProtocolWriterImpl.java
+++ b/components/net/sf/briar/protocol/ProtocolWriterImpl.java
@@ -1,5 +1,7 @@
 package net.sf.briar.protocol;
 
+import static net.sf.briar.api.protocol.ProtocolConstants.MAX_PACKET_LENGTH;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.BitSet;
@@ -10,7 +12,6 @@ import net.sf.briar.api.protocol.BatchId;
 import net.sf.briar.api.protocol.Group;
 import net.sf.briar.api.protocol.MessageId;
 import net.sf.briar.api.protocol.Offer;
-import static net.sf.briar.api.protocol.ProtocolConstants.MAX_PACKET_LENGTH;
 import net.sf.briar.api.protocol.ProtocolWriter;
 import net.sf.briar.api.protocol.RawBatch;
 import net.sf.briar.api.protocol.Request;
diff --git a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java
index 1a82bd8359cd65329db9198543c91f1035c54fb3..350eef73a34deebd53c606cae5ca95feb367a919 100644
--- a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java
+++ b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java
@@ -49,8 +49,8 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
 		Cipher tagCipher = crypto.getTagCipher();
 		Cipher frameCipher = crypto.getFrameCipher();
 		Mac mac = crypto.getMac();
-		IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, tagCipher,
-				frameCipher, tagKey, frameKey, mac.getMacLength(), false);
+		IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in,
+				tagCipher, frameCipher, tagKey, frameKey, false);
 		// Create the reader
 		return new ConnectionReaderImpl(decrypter, mac, macKey);
 	}
diff --git a/components/net/sf/briar/transport/ConnectionReaderImpl.java b/components/net/sf/briar/transport/ConnectionReaderImpl.java
index 9ee8b7180be6dbebc2acbc5df304498d1d3f6f3b..1afa4ab3780fc26fa0815b849318192bc121c548 100644
--- a/components/net/sf/briar/transport/ConnectionReaderImpl.java
+++ b/components/net/sf/briar/transport/ConnectionReaderImpl.java
@@ -1,6 +1,7 @@
 package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 
@@ -18,13 +19,13 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader {
 
 	private final IncomingEncryptionLayer decrypter;
 	private final Mac mac;
-	private final int macLength;
 	private final byte[] buf;
 
 	private long frame = 0L;
-	private int bufOffset = 0, bufLength = 0;
+	private int offset = 0, length = 0;
 
-	ConnectionReaderImpl(IncomingEncryptionLayer decrypter, Mac mac, ErasableKey macKey) {
+	ConnectionReaderImpl(IncomingEncryptionLayer decrypter, Mac mac,
+			ErasableKey macKey) {
 		this.decrypter = decrypter;
 		this.mac = mac;
 		// Initialise the MAC
@@ -34,7 +35,8 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader {
 			throw new IllegalArgumentException(e);
 		}
 		macKey.erase();
-		macLength = mac.getMacLength();
+		if(mac.getMacLength() != MAC_LENGTH)
+			throw new IllegalArgumentException();
 		buf = new byte[MAX_FRAME_LENGTH];
 	}
 
@@ -44,10 +46,10 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader {
 
 	@Override
 	public int read() throws IOException {
-		while(bufLength == 0) if(!readFrame()) return -1;
-		int b = buf[bufOffset] & 0xff;
-		bufOffset++;
-		bufLength--;
+		while(length == 0) if(!readFrame()) return -1;
+		int b = buf[offset] & 0xff;
+		offset++;
+		length--;
 		return b;
 	}
 
@@ -58,28 +60,27 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader {
 
 	@Override
 	public int read(byte[] b, int off, int len) throws IOException {
-		while(bufLength == 0) if(!readFrame()) return -1;
-		len = Math.min(len, bufLength);
-		System.arraycopy(buf, bufOffset, b, off, len);
-		bufOffset += len;
-		bufLength -= len;
+		while(length == 0) if(!readFrame()) return -1;
+		len = Math.min(len, length);
+		System.arraycopy(buf, offset, b, off, len);
+		offset += len;
+		length -= len;
 		return len;
 	}
 
 	private boolean readFrame() throws IOException {
-		assert bufLength == 0;
+		assert length == 0;
 		// Don't allow more than 2^32 frames to be read
 		if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
 		// Read a frame
-		int length = decrypter.readFrame(buf);
-		if(length == -1) return false;
+		int frameLength = decrypter.readFrame(buf);
+		if(frameLength == -1) return false;
 		// Check that the frame number is correct and the length is legal
-		int max = MAX_FRAME_LENGTH - FRAME_HEADER_LENGTH - macLength;
-		if(!HeaderEncoder.validateHeader(buf, frame, max))
+		if(!HeaderEncoder.validateHeader(buf, frame))
 			throw new FormatException();
 		int payload = HeaderEncoder.getPayloadLength(buf);
 		int padding = HeaderEncoder.getPaddingLength(buf);
-		if(length != FRAME_HEADER_LENGTH + payload + padding + macLength)
+		if(frameLength != FRAME_HEADER_LENGTH + payload + padding + MAC_LENGTH)
 			throw new FormatException();
 		// Check that the padding is all zeroes
 		int paddingStart = FRAME_HEADER_LENGTH + payload;
@@ -90,11 +91,11 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader {
 		int macStart = FRAME_HEADER_LENGTH + payload + padding;
 		mac.update(buf, 0, macStart);
 		byte[] expectedMac = mac.doFinal();
-		for(int i = 0; i < macLength; i++) {
+		for(int i = 0; i < expectedMac.length; i++) {
 			if(expectedMac[i] != buf[macStart + i]) throw new FormatException();
 		}
-		bufOffset = FRAME_HEADER_LENGTH;
-		bufLength = payload;
+		offset = FRAME_HEADER_LENGTH;
+		length = payload;
 		frame++;
 		return true;
 	}
diff --git a/components/net/sf/briar/transport/ConnectionWriterImpl.java b/components/net/sf/briar/transport/ConnectionWriterImpl.java
index 87e7089f9f1074a041bb77cf8673c7898f7cd7e9..017572791679b905ab2484273dac6af93130486b 100644
--- a/components/net/sf/briar/transport/ConnectionWriterImpl.java
+++ b/components/net/sf/briar/transport/ConnectionWriterImpl.java
@@ -1,6 +1,7 @@
 package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 
@@ -26,7 +27,7 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 	private final Mac mac;
 	private final byte[] buf;
 
-	private int bufLength = FRAME_HEADER_LENGTH;
+	private int length = FRAME_HEADER_LENGTH;
 	private long frame = 0L;
 
 	ConnectionWriterImpl(OutgoingEncryptionLayer encrypter, Mac mac,
@@ -40,6 +41,8 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 			throw new IllegalArgumentException(badKey);
 		}
 		macKey.erase();
+		if(mac.getMacLength() != MAC_LENGTH)
+			throw new IllegalArgumentException();
 		buf = new byte[MAX_FRAME_LENGTH];
 	}
 
@@ -49,25 +52,25 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 
 	public long getRemainingCapacity() {
 		long capacity = encrypter.getRemainingCapacity();
-		// If there's any data buffered, subtract it and its auth overhead
-		if(bufLength > FRAME_HEADER_LENGTH)
-			capacity -= bufLength + mac.getMacLength();
-		// Subtract the auth overhead from the remaining capacity
+		// If there's any data buffered, subtract it and its overhead
+		if(length > FRAME_HEADER_LENGTH)
+			capacity -= length + 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.getMacLength();
+		int overheadPerFrame = FRAME_HEADER_LENGTH + MAC_LENGTH;
 		return Math.max(0L, capacity - frames * overheadPerFrame);
 	}
 
 	@Override
 	public void flush() throws IOException {
-		if(bufLength > FRAME_HEADER_LENGTH) writeFrame();
+		if(length > FRAME_HEADER_LENGTH) writeFrame();
 		encrypter.flush();
 	}
 
 	@Override
 	public void write(int b) throws IOException {
-		buf[bufLength++] = (byte) b;
-		if(bufLength + mac.getMacLength() == MAX_FRAME_LENGTH) writeFrame();
+		buf[length++] = (byte) b;
+		if(length + MAC_LENGTH == MAX_FRAME_LENGTH) writeFrame();
 	}
 
 	@Override
@@ -77,32 +80,32 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 
 	@Override
 	public void write(byte[] b, int off, int len) throws IOException {
-		int available = MAX_FRAME_LENGTH - bufLength - mac.getMacLength();
+		int available = MAX_FRAME_LENGTH - length - MAC_LENGTH;
 		while(available <= len) {
-			System.arraycopy(b, off, buf, bufLength, available);
-			bufLength += available;
+			System.arraycopy(b, off, buf, length, available);
+			length += available;
 			writeFrame();
 			off += available;
 			len -= available;
-			available = MAX_FRAME_LENGTH - bufLength - mac.getMacLength();
+			available = MAX_FRAME_LENGTH - length - MAC_LENGTH;
 		}
-		System.arraycopy(b, off, buf, bufLength, len);
-		bufLength += len;
+		System.arraycopy(b, off, buf, length, len);
+		length += len;
 	}
 
 	private void writeFrame() throws IOException {
 		if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
-		int payloadLength = bufLength - FRAME_HEADER_LENGTH;
+		int payloadLength = length - FRAME_HEADER_LENGTH;
 		assert payloadLength > 0;
 		HeaderEncoder.encodeHeader(buf, frame, payloadLength, 0);
-		mac.update(buf, 0, bufLength);
+		mac.update(buf, 0, length);
 		try {
-			mac.doFinal(buf, bufLength);
+			mac.doFinal(buf, length);
 		} catch(ShortBufferException badMac) {
 			throw new RuntimeException(badMac);
 		}
-		encrypter.writeFrame(buf, bufLength + mac.getMacLength());
-		bufLength = FRAME_HEADER_LENGTH;
+		encrypter.writeFrame(buf, length + MAC_LENGTH);
+		length = FRAME_HEADER_LENGTH;
 		frame++;
 	}
 }
diff --git a/components/net/sf/briar/transport/HeaderEncoder.java b/components/net/sf/briar/transport/HeaderEncoder.java
index 58bf41da1e3f454aa03bbbc6461c6ce49593ec23..b1d47a6c1b5bed306dc2b8db82751b02ba80d76b 100644
--- a/components/net/sf/briar/transport/HeaderEncoder.java
+++ b/components/net/sf/briar/transport/HeaderEncoder.java
@@ -1,34 +1,43 @@
 package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 import net.sf.briar.util.ByteUtils;
 
 class HeaderEncoder {
 
-	static void encodeHeader(byte[] header, long frame, int payload,
+	static void encodeHeader(byte[] header, long frameNumber, int payload,
 			int padding) {
 		if(header.length < FRAME_HEADER_LENGTH)
 			throw new IllegalArgumentException();
-		if(frame < 0 || frame > ByteUtils.MAX_32_BIT_UNSIGNED)
+		if(frameNumber < 0 || frameNumber > ByteUtils.MAX_32_BIT_UNSIGNED)
 			throw new IllegalArgumentException();
 		if(payload < 0 || payload > ByteUtils.MAX_16_BIT_UNSIGNED)
 			throw new IllegalArgumentException();
 		if(padding < 0 || padding > ByteUtils.MAX_16_BIT_UNSIGNED)
 			throw new IllegalArgumentException();
-		ByteUtils.writeUint32(frame, header, 0);
+		ByteUtils.writeUint32(frameNumber, header, 0);
 		ByteUtils.writeUint16(payload, header, 4);
 		ByteUtils.writeUint16(padding, header, 6);
 	}
 
-	static boolean validateHeader(byte[] header, long frame, int max) {
+	static boolean validateHeader(byte[] header, long frameNumber) {
 		if(header.length < FRAME_HEADER_LENGTH) return false;
-		if(ByteUtils.readUint32(header, 0) != frame) return false;
+		if(ByteUtils.readUint32(header, 0) != frameNumber) return false;
 		int payload = ByteUtils.readUint16(header, 4);
 		int padding = ByteUtils.readUint16(header, 6);
-		if(payload + padding > max) return false;
+		int frameLength = FRAME_HEADER_LENGTH + payload + padding + MAC_LENGTH;
+		if(frameLength > MAX_FRAME_LENGTH) return false;
 		return true;
 	}
 
+	static long getFrameNumber(byte[] header) {
+		if(header.length < FRAME_HEADER_LENGTH)
+			throw new IllegalArgumentException();
+		return ByteUtils.readUint32(header, 0);
+	}
+
 	static int getPayloadLength(byte[] header) {
 		if(header.length < FRAME_HEADER_LENGTH)
 			throw new IllegalArgumentException();
diff --git a/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java b/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java
index b8f684d0aa6785580e8756fc9f1b776ac2fe8ea1..21d64a3744ee7629aa851e519b5d08200176d96b 100644
--- a/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java
+++ b/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java
@@ -1,7 +1,7 @@
 package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
-import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
 import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 
@@ -21,7 +21,7 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
 	private final InputStream in;
 	private final Cipher tagCipher, frameCipher;
 	private final ErasableKey tagKey, frameKey;
-	private final int macLength, blockSize;
+	private final int blockSize;
 	private final byte[] iv;
 	private final boolean tagEverySegment;
 
@@ -29,13 +29,12 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
 
 	IncomingEncryptionLayerImpl(InputStream in, Cipher tagCipher,
 			Cipher frameCipher, ErasableKey tagKey, ErasableKey frameKey,
-			int macLength, boolean tagEverySegment) {
+			boolean tagEverySegment) {
 		this.in = in;
 		this.tagCipher = tagCipher;
 		this.frameCipher = frameCipher;
 		this.tagKey = tagKey;
 		this.frameKey = frameKey;
-		this.macLength = macLength;
 		this.tagEverySegment = tagEverySegment;
 		blockSize = frameCipher.getBlockSize();
 		if(blockSize < FRAME_HEADER_LENGTH)
@@ -44,7 +43,6 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
 	}
 
 	public int readFrame(byte[] b) throws IOException {
-		if(b.length < MAX_FRAME_LENGTH) throw new IllegalArgumentException();
 		if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
 		boolean tag = tagEverySegment && frame > 0;
 		// Clear the buffer before exposing it to the transport plugin
@@ -85,13 +83,11 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
 				throw new RuntimeException(badCipher);
 			}
 			// Validate and parse the header
-			int max = MAX_FRAME_LENGTH - FRAME_HEADER_LENGTH - macLength;
-			if(!HeaderEncoder.validateHeader(b, frame, max))
+			if(!HeaderEncoder.validateHeader(b, frame))
 				throw new FormatException();
 			int payload = HeaderEncoder.getPayloadLength(b);
 			int padding = HeaderEncoder.getPaddingLength(b);
-			int length = FRAME_HEADER_LENGTH + payload + padding + macLength;
-			if(length > MAX_FRAME_LENGTH) throw new FormatException();
+			int length = FRAME_HEADER_LENGTH + payload + padding + MAC_LENGTH;
 			// Read the remainder of the frame
 			while(offset < length) {
 				int read = in.read(b, offset, length - offset);
diff --git a/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java b/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java
index dfa063c93be39bcbd552cb8de831fed8b0e0c191..61af30b988eed27bc9a97dc7c3ca1a4c54db6b3d 100644
--- a/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java
+++ b/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java
@@ -1,7 +1,8 @@
 package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
-import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
+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;
 
@@ -21,7 +22,7 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
 	private final SegmentSource in;
 	private final Cipher tagCipher, frameCipher;
 	private final ErasableKey tagKey, frameKey;
-	private final int macLength, blockSize;
+	private final int blockSize;
 	private final byte[] iv;
 	private final Segment segment;
 	private final boolean tagEverySegment;
@@ -30,13 +31,12 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
 
 	IncomingSegmentedEncryptionLayer(SegmentSource in, Cipher tagCipher,
 			Cipher frameCipher, ErasableKey tagKey, ErasableKey frameKey,
-			int macLength, boolean tagEverySegment) {
+			boolean tagEverySegment) {
 		this.in = in;
 		this.tagCipher = tagCipher;
 		this.frameCipher = frameCipher;
 		this.tagKey = tagKey;
 		this.frameKey = frameKey;
-		this.macLength = macLength;
 		this.tagEverySegment = tagEverySegment;
 		blockSize = frameCipher.getBlockSize();
 		if(blockSize < FRAME_HEADER_LENGTH)
@@ -46,7 +46,6 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
 	}
 
 	public int readFrame(byte[] b) throws IOException {
-		if(b.length < MAX_FRAME_LENGTH) throw new IllegalArgumentException();
 		if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
 		boolean tag = tagEverySegment && frame > 0;
 		// Clear the buffer before exposing it to the transport plugin
@@ -55,8 +54,8 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
 			// Read the segment
 			if(!in.readSegment(segment)) return -1;
 			int offset = tag ? TAG_LENGTH : 0, length = segment.getLength();
-			if(length > MAX_FRAME_LENGTH) throw new FormatException();
-			if(length < offset + FRAME_HEADER_LENGTH + macLength)
+			if(length > MAX_SEGMENT_LENGTH) throw new FormatException();
+			if(length < offset + FRAME_HEADER_LENGTH + MAC_LENGTH)
 				throw new FormatException();
 			// If a tag is expected, decrypt and validate it
 			if(tag && !TagEncoder.validateTag(segment.getBuffer(), frame,
@@ -73,13 +72,12 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
 				throw new RuntimeException(badCipher);
 			}
 			// Validate and parse the header
-			int max = MAX_FRAME_LENGTH - FRAME_HEADER_LENGTH - macLength;
-			if(!HeaderEncoder.validateHeader(b, frame, max))
+			if(!HeaderEncoder.validateHeader(b, frame))
 				throw new FormatException();
 			int payload = HeaderEncoder.getPayloadLength(b);
 			int padding = HeaderEncoder.getPaddingLength(b);
 			if(length != offset + FRAME_HEADER_LENGTH + payload + padding
-					+ macLength) throw new FormatException();
+					+ MAC_LENGTH) throw new FormatException();
 			frame++;
 			return length - offset;
 		} catch(IOException e) {
diff --git a/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java b/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java
index 99ce32f90d5bd56401bcb2e3ca2f123343c46196..8d7708aaa2e88f3ff13b793883ab1539a24c0c80 100644
--- a/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java
+++ b/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java
@@ -1,6 +1,5 @@
 package net.sf.briar.transport;
 
-import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
 import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 
@@ -43,8 +42,6 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer {
 		if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
 		int offset = 0;
 		if(tagEverySegment || frame == 0) {
-			if(len + TAG_LENGTH > MAX_FRAME_LENGTH)
-				throw new IllegalArgumentException();
 			TagEncoder.encodeTag(segment.getBuffer(), frame, tagCipher, tagKey);
 			offset = TAG_LENGTH;
 			capacity -= TAG_LENGTH;
diff --git a/components/net/sf/briar/transport/SegmentImpl.java b/components/net/sf/briar/transport/SegmentImpl.java
index b7cb6398e4265572ea4e1235e5b1f3cfe3019ed2..0ad809bdc0838e86bf82c0b89d3ba9e5ce4a4642 100644
--- a/components/net/sf/briar/transport/SegmentImpl.java
+++ b/components/net/sf/briar/transport/SegmentImpl.java
@@ -1,20 +1,20 @@
 package net.sf.briar.transport;
 
-import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH;
 import net.sf.briar.api.plugins.Segment;
 import net.sf.briar.util.ByteUtils;
 
 class SegmentImpl implements Segment {
 
-	private final byte[] buf = new byte[MAX_FRAME_LENGTH];
+	private final byte[] buf = new byte[MAX_SEGMENT_LENGTH];
 
 	private int length = -1;
-	private long transmission = -1;
+	private long segmentNumber = -1;
 
 	public void clear() {
 		for(int i = 0; i < buf.length; i++) buf[i] = 0;
 		length = -1;
-		transmission = -1;
+		segmentNumber = -1;
 	}
 
 	public byte[] getBuffer() {
@@ -26,9 +26,9 @@ class SegmentImpl implements Segment {
 		return length;
 	}
 
-	public long getTransmissionNumber() {
-		if(transmission == -1) throw new IllegalStateException();
-		return transmission;
+	public long getSegmentNumber() {
+		if(segmentNumber == -1) throw new IllegalStateException();
+		return segmentNumber;
 	}
 
 	public void setLength(int length) {
@@ -37,9 +37,9 @@ class SegmentImpl implements Segment {
 		this.length = length;
 	}
 
-	public void setTransmissionNumber(int transmission) {
-		if(transmission < 0 || transmission > ByteUtils.MAX_32_BIT_UNSIGNED)
+	public void setSegmentNumber(long segmentNumber) {
+		if(segmentNumber < 0 || segmentNumber > ByteUtils.MAX_32_BIT_UNSIGNED)
 			throw new IllegalArgumentException();
-		this.transmission = transmission;
+		this.segmentNumber = segmentNumber;
 	}
 }
diff --git a/components/net/sf/briar/transport/TransportModule.java b/components/net/sf/briar/transport/TransportModule.java
index 9ebc40e8d5ac90bac892e67b575addc4aee040bd..89db1a259b7455e298f7202456a253928e339cb6 100644
--- a/components/net/sf/briar/transport/TransportModule.java
+++ b/components/net/sf/briar/transport/TransportModule.java
@@ -7,10 +7,10 @@ import net.sf.briar.api.transport.ConnectionContextFactory;
 import net.sf.briar.api.transport.ConnectionDispatcher;
 import net.sf.briar.api.transport.ConnectionReaderFactory;
 import net.sf.briar.api.transport.ConnectionRecogniser;
-import net.sf.briar.api.transport.IncomingConnectionExecutor;
 import net.sf.briar.api.transport.ConnectionRegistry;
 import net.sf.briar.api.transport.ConnectionWindowFactory;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
+import net.sf.briar.api.transport.IncomingConnectionExecutor;
 
 import com.google.inject.AbstractModule;
 
diff --git a/test/net/sf/briar/plugins/socket/LanSocketClientTest.java b/test/net/sf/briar/plugins/socket/LanSocketClientTest.java
index 72be342cb2d6329404d13ba49c7b2c02c882dd27..8070b9191f309a49e0269f52a9a09308c1583b7e 100644
--- a/test/net/sf/briar/plugins/socket/LanSocketClientTest.java
+++ b/test/net/sf/briar/plugins/socket/LanSocketClientTest.java
@@ -2,9 +2,9 @@ package net.sf.briar.plugins.socket;
 
 import java.util.Collections;
 import java.util.Map;
+import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.Executor;
 
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportConfig;
diff --git a/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java b/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java
index 10cfe900b479f0534f508e02caa9b074b999b07b..8b7c473e63933b85e2db3d50e345d8e86a9e8faf 100644
--- a/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java
+++ b/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java
@@ -7,8 +7,8 @@ import java.net.Socket;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executors;
 import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
diff --git a/test/net/sf/briar/protocol/simplex/OutgoingSimplexConnectionTest.java b/test/net/sf/briar/protocol/simplex/OutgoingSimplexConnectionTest.java
index d469c60ab438d7b717914a5fdb27230a5d7bb3fc..41646ea651ea5de8958c463f2d00334c8414a41b 100644
--- a/test/net/sf/briar/protocol/simplex/OutgoingSimplexConnectionTest.java
+++ b/test/net/sf/briar/protocol/simplex/OutgoingSimplexConnectionTest.java
@@ -25,7 +25,6 @@ import net.sf.briar.api.transport.TransportConstants;
 import net.sf.briar.crypto.CryptoModule;
 import net.sf.briar.protocol.ProtocolModule;
 import net.sf.briar.protocol.duplex.DuplexProtocolModule;
-import net.sf.briar.protocol.simplex.SimplexProtocolModule;
 import net.sf.briar.serial.SerialModule;
 import net.sf.briar.transport.TransportModule;
 
diff --git a/test/net/sf/briar/protocol/simplex/SimplexConnectionReadWriteTest.java b/test/net/sf/briar/protocol/simplex/SimplexConnectionReadWriteTest.java
index dd7c14ca128a36b79034a8b98523d26406db257b..7c551d09b5b97cca8249239ed0b56c78189c34a4 100644
--- a/test/net/sf/briar/protocol/simplex/SimplexConnectionReadWriteTest.java
+++ b/test/net/sf/briar/protocol/simplex/SimplexConnectionReadWriteTest.java
@@ -36,7 +36,6 @@ import net.sf.briar.lifecycle.LifecycleModule;
 import net.sf.briar.plugins.ImmediateExecutor;
 import net.sf.briar.protocol.ProtocolModule;
 import net.sf.briar.protocol.duplex.DuplexProtocolModule;
-import net.sf.briar.protocol.simplex.SimplexProtocolModule;
 import net.sf.briar.serial.SerialModule;
 import net.sf.briar.transport.TransportModule;
 
diff --git a/test/net/sf/briar/transport/ConnectionReaderImplTest.java b/test/net/sf/briar/transport/ConnectionReaderImplTest.java
index bb385b9192c81c76f7198de68cf133aa5f0bba81..2eda0dc36597ae0d3c8eec7c82ed0348844a506e 100644
--- a/test/net/sf/briar/transport/ConnectionReaderImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionReaderImplTest.java
@@ -1,6 +1,7 @@
 package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 import static org.junit.Assert.assertArrayEquals;
 
@@ -23,7 +24,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 	public void testLengthZero() throws Exception {
 		int payloadLength = 0;
 		byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
-		                        + macLength];
+		                        + MAC_LENGTH];
 		HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
 		// Calculate the MAC
 		mac.init(macKey);
@@ -31,8 +32,8 @@ public class ConnectionReaderImplTest extends TransportTest {
 		mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength);
 		// Read the frame
 		ByteArrayInputStream in = new ByteArrayInputStream(frame);
-		IncomingEncryptionLayer d = new NullConnectionDecrypter(in, macLength);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
+		IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in);
+		ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey);
 		// There should be no bytes available before EOF
 		assertEquals(-1, r.getInputStream().read());
 	}
@@ -41,7 +42,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 	public void testLengthOne() throws Exception {
 		int payloadLength = 1;
 		byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
-		                        + macLength];
+		                        + MAC_LENGTH];
 		HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
 		// Calculate the MAC
 		mac.init(macKey);
@@ -49,8 +50,8 @@ public class ConnectionReaderImplTest extends TransportTest {
 		mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength);
 		// Read the frame
 		ByteArrayInputStream in = new ByteArrayInputStream(frame);
-		IncomingEncryptionLayer d = new NullConnectionDecrypter(in, macLength);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
+		IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in);
+		ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey);
 		// There should be one byte available before EOF
 		assertEquals(0, r.getInputStream().read());
 		assertEquals(-1, r.getInputStream().read());
@@ -60,27 +61,27 @@ public class ConnectionReaderImplTest extends TransportTest {
 	public void testMaxLength() throws Exception {
 		// First frame: max payload length
 		byte[] frame = new byte[MAX_FRAME_LENGTH];
-		HeaderEncoder.encodeHeader(frame, 0, maxPayloadLength, 0);
+		HeaderEncoder.encodeHeader(frame, 0, MAX_PAYLOAD_LENGTH, 0);
 		mac.init(macKey);
-		mac.update(frame, 0, FRAME_HEADER_LENGTH + maxPayloadLength);
-		mac.doFinal(frame, FRAME_HEADER_LENGTH + maxPayloadLength);
+		mac.update(frame, 0, FRAME_HEADER_LENGTH + MAX_PAYLOAD_LENGTH);
+		mac.doFinal(frame, FRAME_HEADER_LENGTH + MAX_PAYLOAD_LENGTH);
 		// Second frame: max payload length plus one
 		byte[] frame1 = new byte[MAX_FRAME_LENGTH + 1];
-		HeaderEncoder.encodeHeader(frame1, 1, maxPayloadLength + 1, 0);
-		mac.update(frame1, 0, FRAME_HEADER_LENGTH + maxPayloadLength + 1);
-		mac.doFinal(frame1, FRAME_HEADER_LENGTH + maxPayloadLength + 1);
+		HeaderEncoder.encodeHeader(frame1, 1, MAX_PAYLOAD_LENGTH + 1, 0);
+		mac.update(frame1, 0, FRAME_HEADER_LENGTH + MAX_PAYLOAD_LENGTH + 1);
+		mac.doFinal(frame1, FRAME_HEADER_LENGTH + MAX_PAYLOAD_LENGTH + 1);
 		// Concatenate the frames
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		out.write(frame);
 		out.write(frame1);
 		// Read the first frame
 		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
-		IncomingEncryptionLayer d = new NullConnectionDecrypter(in, macLength);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
-		byte[] read = new byte[maxPayloadLength];
+		IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in);
+		ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey);
+		byte[] read = new byte[MAX_PAYLOAD_LENGTH];
 		TestUtils.readFully(r.getInputStream(), read);
 		// Try to read the second frame
-		byte[] read1 = new byte[maxPayloadLength + 1];
+		byte[] read1 = new byte[MAX_PAYLOAD_LENGTH + 1];
 		try {
 			TestUtils.readFully(r.getInputStream(), read1);
 			fail();
@@ -92,29 +93,29 @@ public class ConnectionReaderImplTest extends TransportTest {
 		int paddingLength = 10;
 		// First frame: max payload length, including padding
 		byte[] frame = new byte[MAX_FRAME_LENGTH];
-		HeaderEncoder.encodeHeader(frame, 0, maxPayloadLength - paddingLength,
+		HeaderEncoder.encodeHeader(frame, 0, MAX_PAYLOAD_LENGTH - paddingLength,
 				paddingLength);
 		mac.init(macKey);
-		mac.update(frame, 0, FRAME_HEADER_LENGTH + maxPayloadLength);
-		mac.doFinal(frame, FRAME_HEADER_LENGTH + maxPayloadLength);
+		mac.update(frame, 0, FRAME_HEADER_LENGTH + MAX_PAYLOAD_LENGTH);
+		mac.doFinal(frame, FRAME_HEADER_LENGTH + MAX_PAYLOAD_LENGTH);
 		// Second frame: max payload length plus one, including padding
 		byte[] frame1 = new byte[MAX_FRAME_LENGTH + 1];
 		HeaderEncoder.encodeHeader(frame1, 1,
-				maxPayloadLength + 1 - paddingLength, paddingLength);
-		mac.update(frame1, 0, FRAME_HEADER_LENGTH + maxPayloadLength + 1);
-		mac.doFinal(frame1, FRAME_HEADER_LENGTH + maxPayloadLength + 1);
+				MAX_PAYLOAD_LENGTH + 1 - paddingLength, paddingLength);
+		mac.update(frame1, 0, FRAME_HEADER_LENGTH + MAX_PAYLOAD_LENGTH + 1);
+		mac.doFinal(frame1, FRAME_HEADER_LENGTH + MAX_PAYLOAD_LENGTH + 1);
 		// Concatenate the frames
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		out.write(frame);
 		out.write(frame1);
 		// Read the first frame
 		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
-		IncomingEncryptionLayer d = new NullConnectionDecrypter(in, macLength);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
-		byte[] read = new byte[maxPayloadLength - paddingLength];
+		IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in);
+		ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey);
+		byte[] read = new byte[MAX_PAYLOAD_LENGTH - paddingLength];
 		TestUtils.readFully(r.getInputStream(), read);
 		// Try to read the second frame
-		byte[] read1 = new byte[maxPayloadLength + 1 - paddingLength];
+		byte[] read1 = new byte[MAX_PAYLOAD_LENGTH + 1 - paddingLength];
 		try {
 			TestUtils.readFully(r.getInputStream(), read1);
 			fail();
@@ -125,7 +126,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 	public void testNonZeroPadding() throws Exception {
 		int payloadLength = 10, paddingLength = 10;
 		byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
-		                        + paddingLength + macLength];
+		                        + paddingLength + MAC_LENGTH];
 		HeaderEncoder.encodeHeader(frame, 0, payloadLength, paddingLength);
 		// Set a byte of the padding to a non-zero value
 		frame[FRAME_HEADER_LENGTH + payloadLength] = 1;
@@ -135,8 +136,8 @@ public class ConnectionReaderImplTest extends TransportTest {
 		mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength + paddingLength);
 		// Read the frame
 		ByteArrayInputStream in = new ByteArrayInputStream(frame);
-		IncomingEncryptionLayer d = new NullConnectionDecrypter(in, macLength);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
+		IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in);
+		ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey);
 		// The non-zero padding should be rejected
 		try {
 			r.getInputStream().read();
@@ -149,7 +150,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 		// First frame: 123-byte payload
 		int payloadLength = 123;
 		byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
-		                        + macLength];
+		                        + MAC_LENGTH];
 		HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
 		mac.init(macKey);
 		mac.update(frame, 0, FRAME_HEADER_LENGTH + payloadLength);
@@ -157,7 +158,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 		// Second frame: 1234-byte payload
 		int payloadLength1 = 1234;
 		byte[] frame1 = new byte[FRAME_HEADER_LENGTH + payloadLength1
-		                         + macLength];
+		                         + MAC_LENGTH];
 		HeaderEncoder.encodeHeader(frame1, 1, payloadLength1, 0);
 		mac.update(frame1, 0, FRAME_HEADER_LENGTH + payloadLength1);
 		mac.doFinal(frame1, FRAME_HEADER_LENGTH + payloadLength1);
@@ -167,8 +168,8 @@ public class ConnectionReaderImplTest extends TransportTest {
 		out.write(frame1);
 		// Read the frames
 		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
-		IncomingEncryptionLayer d = new NullConnectionDecrypter(in, macLength);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
+		IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in);
+		ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey);
 		byte[] read = new byte[payloadLength];
 		TestUtils.readFully(r.getInputStream(), read);
 		assertArrayEquals(new byte[payloadLength], read);
@@ -181,7 +182,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 	public void testCorruptPayload() throws Exception {
 		int payloadLength = 8;
 		byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
-		                        + macLength];
+		                        + MAC_LENGTH];
 		HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
 		// Calculate the MAC
 		mac.init(macKey);
@@ -191,8 +192,8 @@ public class ConnectionReaderImplTest extends TransportTest {
 		frame[12] ^= 1;
 		// Try to read the frame - not a single byte should be read
 		ByteArrayInputStream in = new ByteArrayInputStream(frame);
-		IncomingEncryptionLayer d = new NullConnectionDecrypter(in, macLength);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
+		IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in);
+		ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey);
 		try {
 			r.getInputStream().read();
 			fail();
@@ -203,7 +204,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 	public void testCorruptMac() throws Exception {
 		int payloadLength = 8;
 		byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
-		                        + macLength];
+		                        + MAC_LENGTH];
 		HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
 		// Calculate the MAC
 		mac.init(macKey);
@@ -213,8 +214,8 @@ public class ConnectionReaderImplTest extends TransportTest {
 		frame[17] ^= 1;
 		// Try to read the frame - not a single byte should be read
 		ByteArrayInputStream in = new ByteArrayInputStream(frame);
-		IncomingEncryptionLayer d = new NullConnectionDecrypter(in, macLength);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
+		IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in);
+		ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey);
 		try {
 			r.getInputStream().read();
 			fail();
diff --git a/test/net/sf/briar/transport/ConnectionWriterImplTest.java b/test/net/sf/briar/transport/ConnectionWriterImplTest.java
index 43f6cf47cbd260cd6581952bd24e66577f9598d5..030fa28d19fa64e65757199e03058d4787f74d7a 100644
--- a/test/net/sf/briar/transport/ConnectionWriterImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionWriterImplTest.java
@@ -1,6 +1,7 @@
 package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 import static org.junit.Assert.assertArrayEquals;
 
@@ -20,8 +21,8 @@ public class ConnectionWriterImplTest extends TransportTest {
 	@Test
 	public void testFlushWithoutWriteProducesNothing() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		OutgoingEncryptionLayer e = new NullConnectionEncrypter(out);
-		ConnectionWriter w = new ConnectionWriterImpl(e, mac, macKey);
+		OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
+		ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
 		w.getOutputStream().flush();
 		w.getOutputStream().flush();
 		w.getOutputStream().flush();
@@ -32,7 +33,7 @@ public class ConnectionWriterImplTest extends TransportTest {
 	public void testSingleByteFrame() throws Exception {
 		int payloadLength = 1;
 		byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
-		                        + macLength];
+		                        + MAC_LENGTH];
 		HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
 		// Calculate the MAC
 		mac.init(macKey);
@@ -40,8 +41,8 @@ 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 e = new NullConnectionEncrypter(out);
-		ConnectionWriter w = new ConnectionWriterImpl(e, mac, macKey);
+		OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
+		ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
 		w.getOutputStream().write(0);
 		w.getOutputStream().flush();
 		assertArrayEquals(frame, out.toByteArray());
@@ -50,11 +51,11 @@ public class ConnectionWriterImplTest extends TransportTest {
 	@Test
 	public void testWriteByteToMaxLengthWritesFrame() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		OutgoingEncryptionLayer e = new NullConnectionEncrypter(out);
-		ConnectionWriter w = new ConnectionWriterImpl(e, mac, macKey);
+		OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
+		ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
 		OutputStream out1 = w.getOutputStream();
 		// The first maxPayloadLength - 1 bytes should be buffered
-		for(int i = 0; i < maxPayloadLength - 1; i++) out1.write(0);
+		for(int i = 0; i < MAX_PAYLOAD_LENGTH - 1; i++) out1.write(0);
 		assertEquals(0, out.size());
 		// The next byte should trigger the writing of a frame
 		out1.write(0);
@@ -64,14 +65,14 @@ public class ConnectionWriterImplTest extends TransportTest {
 	@Test
 	public void testWriteArrayToMaxLengthWritesFrame() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		OutgoingEncryptionLayer e = new NullConnectionEncrypter(out);
-		ConnectionWriter w = new ConnectionWriterImpl(e, mac, macKey);
+		OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
+		ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
 		OutputStream out1 = w.getOutputStream();
 		// The first maxPayloadLength - 1 bytes should be buffered
-		out1.write(new byte[maxPayloadLength - 1]);
+		out1.write(new byte[MAX_PAYLOAD_LENGTH - 1]);
 		assertEquals(0, out.size());
 		// The next maxPayloadLength + 1 bytes should trigger two frames
-		out1.write(new byte[maxPayloadLength + 1]);
+		out1.write(new byte[MAX_PAYLOAD_LENGTH + 1]);
 		assertEquals(MAX_FRAME_LENGTH * 2, out.size());
 	}
 
@@ -80,7 +81,7 @@ public class ConnectionWriterImplTest extends TransportTest {
 		// First frame: 123-byte payload
 		int payloadLength = 123;
 		byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
-		                        + macLength];
+		                        + MAC_LENGTH];
 		HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
 		mac.init(macKey);
 		mac.update(frame, 0, FRAME_HEADER_LENGTH + payloadLength);
@@ -88,7 +89,7 @@ public class ConnectionWriterImplTest extends TransportTest {
 		// Second frame: 1234-byte payload
 		int payloadLength1 = 1234;
 		byte[] frame1 = new byte[FRAME_HEADER_LENGTH + payloadLength1
-		                         + macLength];
+		                         + MAC_LENGTH];
 		HeaderEncoder.encodeHeader(frame1, 1, payloadLength1, 0);
 		mac.update(frame1, 0, FRAME_HEADER_LENGTH + 1234);
 		mac.doFinal(frame1, FRAME_HEADER_LENGTH + 1234);
@@ -99,8 +100,8 @@ public class ConnectionWriterImplTest extends TransportTest {
 		byte[] expected = out.toByteArray();
 		// Check that the ConnectionWriter gets the same results
 		out.reset();
-		OutgoingEncryptionLayer e = new NullConnectionEncrypter(out);
-		ConnectionWriter w = new ConnectionWriterImpl(e, mac, macKey);
+		OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
+		ConnectionWriter w = new ConnectionWriterImpl(encrypter, 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 53b4a8f1cf8889a33abfddd1e897ad2dcb21d0dc..1646c8c36034d8dbb08e252d1b26a6e8d92cdcff 100644
--- a/test/net/sf/briar/transport/FrameReadWriteTest.java
+++ b/test/net/sf/briar/transport/FrameReadWriteTest.java
@@ -91,8 +91,8 @@ public class FrameReadWriteTest extends BriarTestCase {
 		assertArrayEquals(tag, recoveredTag);
 		assertTrue(TagEncoder.validateTag(tag, 0, tagCipher, tagKey));
 		// Read the frames back
-		IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, tagCipher,
-				frameCipher, tagKey, frameKey, mac.getMacLength(), false);
+		IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in,
+				tagCipher, frameCipher, tagKey, frameKey, false);
 		ConnectionReader reader = new ConnectionReaderImpl(decrypter, mac,
 				macKey);
 		InputStream in1 = reader.getInputStream();
diff --git a/test/net/sf/briar/transport/IncomingEncryptionLayerImplTest.java b/test/net/sf/briar/transport/IncomingEncryptionLayerImplTest.java
index 6ac04ef08a7790b47915dcf8c6ad99766956a17e..62724afbb8c3e604c27365d5640de8cdb62ac140 100644
--- a/test/net/sf/briar/transport/IncomingEncryptionLayerImplTest.java
+++ b/test/net/sf/briar/transport/IncomingEncryptionLayerImplTest.java
@@ -1,6 +1,7 @@
 package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
 
@@ -22,8 +23,6 @@ import com.google.inject.Injector;
 
 public class IncomingEncryptionLayerImplTest extends BriarTestCase {
 
-	private static final int MAC_LENGTH = 32;
-
 	private final Cipher tagCipher, frameCipher;
 	private final ErasableKey tagKey, frameKey;
 
@@ -61,7 +60,7 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase {
 		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
 		// Use the encryption layer to decrypt the ciphertext
 		IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in,
-				tagCipher, frameCipher, tagKey, frameKey, MAC_LENGTH, false);
+				tagCipher, frameCipher, tagKey, frameKey, false);
 		// First frame
 		byte[] decrypted = new byte[MAX_FRAME_LENGTH];
 		assertEquals(plaintext.length, decrypter.readFrame(decrypted));
@@ -101,7 +100,7 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase {
 		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
 		// Use the encryption layer to decrypt the ciphertext
 		IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in,
-				tagCipher, frameCipher, tagKey, frameKey, MAC_LENGTH, true);
+				tagCipher, frameCipher, tagKey, frameKey, true);
 		// First frame
 		byte[] decrypted = new byte[MAX_FRAME_LENGTH];
 		assertEquals(plaintext.length, decrypter.readFrame(decrypted));
diff --git a/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java b/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java
index d3e580ff5afef479f92c8fedebdc7f0080e12040..f5c70be4d84074365a588f88588170fd366cf79c 100644
--- a/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java
+++ b/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java
@@ -1,6 +1,7 @@
 package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
 
@@ -23,8 +24,6 @@ import com.google.inject.Injector;
 
 public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase {
 
-	private static final int MAC_LENGTH = 32;
-
 	private final Cipher tagCipher, frameCipher;
 	private final ErasableKey tagKey, frameKey;
 
@@ -60,7 +59,7 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase {
 		SegmentSource in = new ByteArraySegmentSource(frames);
 		IncomingEncryptionLayer decrypter =
 			new IncomingSegmentedEncryptionLayer(in, tagCipher, frameCipher,
-					tagKey, frameKey, MAC_LENGTH, false);
+					tagKey, frameKey, false);
 		// First frame
 		byte[] decrypted = new byte[MAX_FRAME_LENGTH];
 		assertEquals(plaintext.length, decrypter.readFrame(decrypted));
@@ -98,7 +97,7 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase {
 		SegmentSource in = new ByteArraySegmentSource(frames);
 		IncomingEncryptionLayer decrypter =
 			new IncomingSegmentedEncryptionLayer(in, tagCipher, frameCipher,
-					tagKey, frameKey, MAC_LENGTH, true);
+					tagKey, frameKey, true);
 		// First frame
 		byte[] decrypted = new byte[MAX_FRAME_LENGTH];
 		assertEquals(plaintext.length, decrypter.readFrame(decrypted));
diff --git a/test/net/sf/briar/transport/NullConnectionDecrypter.java b/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java
similarity index 74%
rename from test/net/sf/briar/transport/NullConnectionDecrypter.java
rename to test/net/sf/briar/transport/NullIncomingEncryptionLayer.java
index ac1a59ddc24c6dcbbb36f45d9994b99fddb41b6f..03892bdaf6d00900e73b8c655e418805f1f1c3ee 100644
--- a/test/net/sf/briar/transport/NullConnectionDecrypter.java
+++ b/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java
@@ -1,6 +1,7 @@
 package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 
 import java.io.EOFException;
@@ -9,19 +10,16 @@ import java.io.InputStream;
 
 import net.sf.briar.api.FormatException;
 
-/** A connection decrypter that performs no decryption. */
-class NullConnectionDecrypter implements IncomingEncryptionLayer {
+/** An encryption layer that performs no encryption. */
+class NullIncomingEncryptionLayer implements IncomingEncryptionLayer {
 
 	private final InputStream in;
-	private final int macLength;
 
-	NullConnectionDecrypter(InputStream in, int macLength) {
+	NullIncomingEncryptionLayer(InputStream in) {
 		this.in = in;
-		this.macLength = macLength;
 	}
 
 	public int readFrame(byte[] b) throws IOException {
-		if(b.length < MAX_FRAME_LENGTH) throw new IllegalArgumentException();
 		// Read the header to determine the frame length
 		int offset = 0, length = FRAME_HEADER_LENGTH;
 		while(offset < length) {
@@ -35,7 +33,7 @@ class NullConnectionDecrypter implements IncomingEncryptionLayer {
 		// Parse the header
 		int payload = HeaderEncoder.getPayloadLength(b);
 		int padding = HeaderEncoder.getPaddingLength(b);
-		length = FRAME_HEADER_LENGTH + payload + padding + macLength;
+		length = FRAME_HEADER_LENGTH + payload + padding + MAC_LENGTH;
 		if(length > MAX_FRAME_LENGTH) throw new FormatException();
 		// Read the remainder of the frame
 		while(offset < length) {
diff --git a/test/net/sf/briar/transport/NullConnectionEncrypter.java b/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java
similarity index 66%
rename from test/net/sf/briar/transport/NullConnectionEncrypter.java
rename to test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java
index 182f612ca0f82ee7209e30886b79b1a38b48a545..8d2448433aec570b489a6ade7524b1141f01ad7e 100644
--- a/test/net/sf/briar/transport/NullConnectionEncrypter.java
+++ b/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java
@@ -3,19 +3,19 @@ package net.sf.briar.transport;
 import java.io.IOException;
 import java.io.OutputStream;
 
-/** A ConnectionEncrypter that performs no encryption. */
-class NullConnectionEncrypter implements OutgoingEncryptionLayer {
+/** An encryption layer that performs no encryption. */
+class NullOutgoingEncryptionLayer implements OutgoingEncryptionLayer {
 
 	private final OutputStream out;
 
 	private long capacity;
 
-	NullConnectionEncrypter(OutputStream out) {
+	NullOutgoingEncryptionLayer(OutputStream out) {
 		this.out = out;
 		capacity = Long.MAX_VALUE;
 	}
 
-	NullConnectionEncrypter(OutputStream out, long capacity) {
+	NullOutgoingEncryptionLayer(OutputStream out, long capacity) {
 		this.out = out;
 		this.capacity = capacity;
 	}
diff --git a/test/net/sf/briar/transport/TransportTest.java b/test/net/sf/briar/transport/TransportTest.java
index a4f81d10c00ba6315927420286276a2ba51c9ea2..3db6a202fdbbabc4fb144d1d0a9aad53d1c59ecd 100644
--- a/test/net/sf/briar/transport/TransportTest.java
+++ b/test/net/sf/briar/transport/TransportTest.java
@@ -1,6 +1,7 @@
 package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 
 import javax.crypto.Mac;
@@ -15,9 +16,11 @@ import com.google.inject.Injector;
 
 public abstract class TransportTest extends BriarTestCase {
 
+	static final int MAX_PAYLOAD_LENGTH
+	= MAX_FRAME_LENGTH - FRAME_HEADER_LENGTH - MAC_LENGTH;
+
 	protected final Mac mac;
 	protected final ErasableKey macKey;
-	protected final int macLength, maxPayloadLength;
 
 	public TransportTest() throws Exception {
 		super();
@@ -25,7 +28,5 @@ public abstract class TransportTest extends BriarTestCase {
 		CryptoComponent crypto = i.getInstance(CryptoComponent.class);
 		mac = crypto.getMac();
 		macKey = crypto.generateTestKey();
-		macLength = mac.getMacLength();
-		maxPayloadLength = MAX_FRAME_LENGTH - FRAME_HEADER_LENGTH - macLength;
 	}
 }