diff --git a/api/net/sf/briar/api/protocol/Ack.java b/api/net/sf/briar/api/protocol/Ack.java
index c8822c2d5dad9f573e3b6c33ffcb8b86a02bf207..8be9162b23ff254918ff4be6a78d4ed618410851 100644
--- a/api/net/sf/briar/api/protocol/Ack.java
+++ b/api/net/sf/briar/api/protocol/Ack.java
@@ -5,12 +5,6 @@ import java.util.Collection;
 /** A packet acknowledging receipt of one or more batches. */
 public interface Ack {
 
-	/**
-	 * The maximum size of a serialised ack, excluding encryption and
-	 * authentication.
-	 */
-	static final int MAX_SIZE = (1024 * 1024) - 100;
-
 	/** Returns the IDs of the acknowledged batches. */
 	Collection<BatchId> getBatchIds();
 }
diff --git a/api/net/sf/briar/api/protocol/Author.java b/api/net/sf/briar/api/protocol/Author.java
index 690e4c69aa1bf7582e6ab4d2ab00879d71a0cee7..a3a76a3751abae4aa6e653a5cd9f4b2bfe24ac1c 100644
--- a/api/net/sf/briar/api/protocol/Author.java
+++ b/api/net/sf/briar/api/protocol/Author.java
@@ -5,12 +5,15 @@ import net.sf.briar.api.serial.Writable;
 /** A pseudonymous author of messages. */
 public interface Author extends Writable {
 
-	/** The maximum length of an author's name, in UTF-8 bytes. */
+	/** The maximum length of an author's name in UTF-8 bytes. */
 	static final int MAX_NAME_LENGTH = 50;
 
-	/** The maximum length of an author's public key, in bytes. */
+	/** The maximum length of an author's public key in bytes. */
 	static final int MAX_PUBLIC_KEY_LENGTH = 100;
 
+	/** The maximum length of a serialised author in bytes. */
+	static final int MAX_LENGTH = MAX_NAME_LENGTH + MAX_PUBLIC_KEY_LENGTH + 5;
+
 	/** Returns the author's unique identifier. */
 	AuthorId getId();
 
diff --git a/api/net/sf/briar/api/protocol/Batch.java b/api/net/sf/briar/api/protocol/Batch.java
index 8097fb1fc738254dc97510f23f5b986d75e478ac..eb46a8f7de53cd771955936bc4415b38626e009c 100644
--- a/api/net/sf/briar/api/protocol/Batch.java
+++ b/api/net/sf/briar/api/protocol/Batch.java
@@ -5,12 +5,6 @@ import java.util.Collection;
 /** A packet containing messages. */
 public interface Batch {
 
-	/**
-	 * The maximum size of a serialised batch, excluding encryption and
-	 * authentication.
-	 */
-	static final int MAX_SIZE = (1024 * 1024) - 100;
-
 	/** Returns the batch's unique identifier. */
 	BatchId getId();
 
diff --git a/api/net/sf/briar/api/protocol/Group.java b/api/net/sf/briar/api/protocol/Group.java
index a552cb17e20c0939154efb9da99be19e05b57f8d..29e99d818c0b73f80cafd3a81c9e6d8c6f5d81cf 100644
--- a/api/net/sf/briar/api/protocol/Group.java
+++ b/api/net/sf/briar/api/protocol/Group.java
@@ -5,12 +5,15 @@ import net.sf.briar.api.serial.Writable;
 /** A group to which users may subscribe. */
 public interface Group extends Writable {
 
-	/** The maximum length of a group's name, in UTF-8 bytes. */
+	/** The maximum length of a group's name in UTF-8 bytes. */
 	static final int MAX_NAME_LENGTH = 50;
 
-	/** The maximum length of a group's public key, in bytes. */
+	/** The maximum length of a group's public key in bytes. */
 	static final int MAX_PUBLIC_KEY_LENGTH = 100;
 
+	/** The maximum length of a serialised group in bytes. */
+	static final int MAX_LENGTH = MAX_NAME_LENGTH + MAX_PUBLIC_KEY_LENGTH + 5;
+
 	/** Returns the group's unique identifier. */
 	GroupId getId();
 
diff --git a/api/net/sf/briar/api/protocol/Message.java b/api/net/sf/briar/api/protocol/Message.java
index bbc418214f47afe0f856736ad229e55c690494d6..7438ecf0e8316dc408d279ed66bdbfb8efe2d89f 100644
--- a/api/net/sf/briar/api/protocol/Message.java
+++ b/api/net/sf/briar/api/protocol/Message.java
@@ -2,12 +2,23 @@ package net.sf.briar.api.protocol;
 
 public interface Message {
 
-	/** The maximum size of a serialised message, in bytes. */
-	static final int MAX_SIZE = (1024 * 1024) - 200;
+	/**
+	 * The maximum length of a serialised message in bytes. To allow for future
+	 * changes in the batch format, this is smaller than the amount of data
+	 * that can fit in a batch using the current format.
+	 */
+	static final int MAX_LENGTH = ProtocolConstants.MAX_PACKET_LENGTH - 1024;
 
-	/** The maximum size of a signature, in bytes. */
+	/** The maximum length of a signature in bytes. */
 	static final int MAX_SIGNATURE_LENGTH = 100;
 
+	/**
+	 * The maximum length of a message body in bytes. To allow for future
+	 * changes in the message format, this is smaller than the amount of data
+	 * that can fit in a message using the current format.
+	 */
+	static final int MAX_BODY_LENGTH = MAX_LENGTH - 1024;
+
 	/** Returns the message's unique identifier. */
 	MessageId getId();
 
diff --git a/api/net/sf/briar/api/protocol/Offer.java b/api/net/sf/briar/api/protocol/Offer.java
index fbeda85080afe92ed2667dcd94cc89da3d208fea..3f6a5ebac939d14b47f6f9858a4d7bd434643ce3 100644
--- a/api/net/sf/briar/api/protocol/Offer.java
+++ b/api/net/sf/briar/api/protocol/Offer.java
@@ -5,12 +5,6 @@ import java.util.Collection;
 /** A packet offering the recipient some messages. */
 public interface Offer {
 
-	/**
-	 * The maximum size of a serialised offer, excluding encryption and
-	 * authentication.
-	 */
-	static final int MAX_SIZE = (1024 * 1024) - 100;
-
 	/** Returns the offer's unique identifier. */
 	OfferId getId();
 
diff --git a/api/net/sf/briar/api/protocol/ProtocolConstants.java b/api/net/sf/briar/api/protocol/ProtocolConstants.java
new file mode 100644
index 0000000000000000000000000000000000000000..506aceab326c481a491bcffb3253405139777778
--- /dev/null
+++ b/api/net/sf/briar/api/protocol/ProtocolConstants.java
@@ -0,0 +1,14 @@
+package net.sf.briar.api.protocol;
+
+import net.sf.briar.api.transport.TransportConstants;
+
+public interface ProtocolConstants {
+
+	/**
+	 * The maximum length of a serialised packet in bytes. To allow for future
+	 * changes in the frame format, this is smaller than the amount of data
+	 * that can fit in a frame using the current format.
+	 */
+	static final int MAX_PACKET_LENGTH =
+		TransportConstants.MAX_FRAME_LENGTH - 1024;
+}
diff --git a/api/net/sf/briar/api/protocol/Request.java b/api/net/sf/briar/api/protocol/Request.java
index bc21df77ccb26b1b87e6ea68db54e042e67655cc..9cc8dce438c818e5b989aa8888ecddb8e85676a9 100644
--- a/api/net/sf/briar/api/protocol/Request.java
+++ b/api/net/sf/briar/api/protocol/Request.java
@@ -5,12 +5,6 @@ import java.util.BitSet;
 /** A packet requesting some or all of the messages from an offer. */
 public interface Request {
 
-	/**
-	 * The maximum size of a serialised request, exlcuding encryption and
-	 * authentication.
-	 */
-	static final int MAX_SIZE = (1024 * 1024) - 100;
-
 	/**
 	 * Returns the unique identifier of the offer to which this request
 	 * responds.
diff --git a/api/net/sf/briar/api/protocol/SubscriptionUpdate.java b/api/net/sf/briar/api/protocol/SubscriptionUpdate.java
index 4e6d025ad429cf776baf87ad6a020ec50ad08a09..05a17ed54ad1385071da215ed3fdd30c2e99ba3c 100644
--- a/api/net/sf/briar/api/protocol/SubscriptionUpdate.java
+++ b/api/net/sf/briar/api/protocol/SubscriptionUpdate.java
@@ -5,12 +5,6 @@ import java.util.Map;
 /** A packet updating the sender's subscriptions. */
 public interface SubscriptionUpdate {
 
-	/**
-	 * The maximum size of a serialized subscription update, excluding
-	 * encryption and authentication.
-	 */
-	static final int MAX_SIZE = (1024 * 1024) - 100;
-
 	/** Returns the subscriptions contained in the update. */
 	Map<Group, Long> getSubscriptions();
 
diff --git a/api/net/sf/briar/api/protocol/TransportUpdate.java b/api/net/sf/briar/api/protocol/TransportUpdate.java
index 742ddaad2dee6b613ae24be981c18dbd17552918..8855fea3d6f2ef74b1db996d0e439f0f5bb745be 100644
--- a/api/net/sf/briar/api/protocol/TransportUpdate.java
+++ b/api/net/sf/briar/api/protocol/TransportUpdate.java
@@ -5,12 +5,6 @@ import java.util.Map;
 /** A packet updating the sender's transport properties. */
 public interface TransportUpdate {
 
-	/**
-	 * The maximum size of a serialised transport update, excluding
-	 * encryption and authentication.
-	 */
-	static final int MAX_SIZE = (1024 * 1024) - 100;
-
 	/** Returns the transport properties contained in the update. */
 	Map<String, Map<String, String>> getTransports();
 
diff --git a/api/net/sf/briar/api/protocol/UniqueId.java b/api/net/sf/briar/api/protocol/UniqueId.java
index 0cbccb5ff52f5ed9ef0438c232ed581e1a54b305..cb379b89a5a0065a84c06231cfafd4667b3c60b1 100644
--- a/api/net/sf/briar/api/protocol/UniqueId.java
+++ b/api/net/sf/briar/api/protocol/UniqueId.java
@@ -6,8 +6,8 @@ import net.sf.briar.api.serial.Writable;
 
 public abstract class UniqueId implements Writable {
 
+	/** The length of a unique identifier in bytes. */
 	public static final int LENGTH = 32;
-	public static final int SERIALISED_LENGTH = LENGTH + 3;
 
 	protected final byte[] id;
 
diff --git a/api/net/sf/briar/api/transport/TransportConstants.java b/api/net/sf/briar/api/transport/TransportConstants.java
new file mode 100644
index 0000000000000000000000000000000000000000..3b8503f5663d63d6721ce3a381e79451db5b28ae
--- /dev/null
+++ b/api/net/sf/briar/api/transport/TransportConstants.java
@@ -0,0 +1,22 @@
+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
+
+	/** The length in bytes of the tag that uniquely identifies a connection. */
+	static final int TAG_LENGTH = 16;
+
+	/**
+	 * The maximum value that can be represented as an unsigned 16-bit integer.
+	 */
+	static final int MAX_16_BIT_UNSIGNED = 65535; // 2^16 - 1
+
+	/**
+	 * The maximum value that can be represented as an unsigned 32-bit integer.
+	 */
+	static final long MAX_32_BIT_UNSIGNED = 4294967295L; // 2^32 - 1
+}
diff --git a/components/net/sf/briar/protocol/AckReader.java b/components/net/sf/briar/protocol/AckReader.java
index 96c74d70db08fd6d1b5d5ece38ea575d7f47eb90..3817115cf34ca0eb226eb7b8497271173f03348a 100644
--- a/components/net/sf/briar/protocol/AckReader.java
+++ b/components/net/sf/briar/protocol/AckReader.java
@@ -5,6 +5,7 @@ import java.util.Collection;
 
 import net.sf.briar.api.protocol.Ack;
 import net.sf.briar.api.protocol.BatchId;
+import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.Tags;
 import net.sf.briar.api.serial.Consumer;
 import net.sf.briar.api.serial.ObjectReader;
@@ -22,7 +23,8 @@ class AckReader implements ObjectReader<Ack> {
 
 	public Ack readObject(Reader r) throws IOException {
 		// Initialise the consumer
-		Consumer counting = new CountingConsumer(Ack.MAX_SIZE);
+		Consumer counting =
+			new CountingConsumer(ProtocolConstants.MAX_PACKET_LENGTH);
 		// Read and digest the data
 		r.addConsumer(counting);
 		r.readUserDefinedTag(Tags.ACK);
diff --git a/components/net/sf/briar/protocol/BatchReader.java b/components/net/sf/briar/protocol/BatchReader.java
index bc41e694e8e7284ded8d25661a53c1e1cfa4b002..5f3bce3283c72ca85c0cd36245af3f2cc697e536 100644
--- a/components/net/sf/briar/protocol/BatchReader.java
+++ b/components/net/sf/briar/protocol/BatchReader.java
@@ -8,6 +8,7 @@ import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.protocol.Batch;
 import net.sf.briar.api.protocol.BatchId;
 import net.sf.briar.api.protocol.Message;
+import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.Tags;
 import net.sf.briar.api.serial.Consumer;
 import net.sf.briar.api.serial.ObjectReader;
@@ -28,7 +29,8 @@ class BatchReader implements ObjectReader<Batch> {
 
 	public Batch readObject(Reader r) throws IOException {
 		// Initialise the consumers
-		Consumer counting = new CountingConsumer(Batch.MAX_SIZE);
+		Consumer counting =
+			new CountingConsumer(ProtocolConstants.MAX_PACKET_LENGTH);
 		DigestingConsumer digesting = new DigestingConsumer(messageDigest);
 		messageDigest.reset();
 		// Read and digest the data
diff --git a/components/net/sf/briar/protocol/MessageReader.java b/components/net/sf/briar/protocol/MessageReader.java
index 5319c11710b781d641950ad5592e142df07038f7..e4c24078a67392612966d0d7d0530a55cf20a370 100644
--- a/components/net/sf/briar/protocol/MessageReader.java
+++ b/components/net/sf/briar/protocol/MessageReader.java
@@ -41,7 +41,7 @@ class MessageReader implements ObjectReader<Message> {
 
 	public Message readObject(Reader r) throws IOException {
 		CopyingConsumer copying = new CopyingConsumer();
-		CountingConsumer counting = new CountingConsumer(Message.MAX_SIZE);
+		CountingConsumer counting = new CountingConsumer(Message.MAX_LENGTH);
 		r.addConsumer(copying);
 		r.addConsumer(counting);
 		// Read the initial tag
@@ -64,7 +64,7 @@ class MessageReader implements ObjectReader<Message> {
 		long timestamp = r.readInt64();
 		if(timestamp < 0L) throw new FormatException();
 		// Skip the message body
-		r.readBytes(Message.MAX_SIZE);
+		r.readBytes(Message.MAX_LENGTH);
 		// Record the length of the data covered by the author's signature
 		int signedByAuthor = (int) counting.getCount();
 		// Read the author's signature, if there is one
diff --git a/components/net/sf/briar/protocol/OfferReader.java b/components/net/sf/briar/protocol/OfferReader.java
index e269e865a6048bc768cc8a2a15c9277ab0add702..7152189ce7e14510883670a27bf7ba16303b64aa 100644
--- a/components/net/sf/briar/protocol/OfferReader.java
+++ b/components/net/sf/briar/protocol/OfferReader.java
@@ -8,6 +8,7 @@ import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.protocol.MessageId;
 import net.sf.briar.api.protocol.Offer;
 import net.sf.briar.api.protocol.OfferId;
+import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.Tags;
 import net.sf.briar.api.serial.Consumer;
 import net.sf.briar.api.serial.ObjectReader;
@@ -28,7 +29,8 @@ class OfferReader implements ObjectReader<Offer> {
 
 	public Offer readObject(Reader r) throws IOException {
 		// Initialise the consumers
-		Consumer counting = new CountingConsumer(Offer.MAX_SIZE);
+		Consumer counting =
+			new CountingConsumer(ProtocolConstants.MAX_PACKET_LENGTH);
 		DigestingConsumer digesting = new DigestingConsumer(messageDigest);
 		messageDigest.reset();
 		// Read the data
diff --git a/components/net/sf/briar/protocol/RequestReader.java b/components/net/sf/briar/protocol/RequestReader.java
index 901a557564f04c107510c9d875bbb368ac0e02a0..77594c650922d73c92ef7bbf3feaa5c25048137e 100644
--- a/components/net/sf/briar/protocol/RequestReader.java
+++ b/components/net/sf/briar/protocol/RequestReader.java
@@ -4,6 +4,7 @@ import java.io.IOException;
 import java.util.BitSet;
 
 import net.sf.briar.api.protocol.OfferId;
+import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.Request;
 import net.sf.briar.api.protocol.Tags;
 import net.sf.briar.api.serial.Consumer;
@@ -23,13 +24,14 @@ class RequestReader implements ObjectReader<Request> {
 
 	public Request readObject(Reader r) throws IOException {
 		// Initialise the consumer
-		Consumer counting = new CountingConsumer(Request.MAX_SIZE);
+		Consumer counting =
+			new CountingConsumer(ProtocolConstants.MAX_PACKET_LENGTH);
 		// Read the data
 		r.addConsumer(counting);
 		r.readUserDefinedTag(Tags.REQUEST);
 		r.addObjectReader(Tags.OFFER_ID, offerIdReader);
 		OfferId offerId = r.readUserDefined(Tags.OFFER_ID, OfferId.class);
-		byte[] bitmap = r.readBytes(Request.MAX_SIZE);
+		byte[] bitmap = r.readBytes(ProtocolConstants.MAX_PACKET_LENGTH);
 		r.removeConsumer(counting);
 		// Convert the bitmap into a BitSet
 		BitSet b = new BitSet(bitmap.length * 8);
diff --git a/components/net/sf/briar/protocol/SubscriptionReader.java b/components/net/sf/briar/protocol/SubscriptionReader.java
index 7ea4cacb356e1ecb3c398f128054c89fec22c99a..7c13d6ffa6a0abfba5618b33b638d844a72b45b7 100644
--- a/components/net/sf/briar/protocol/SubscriptionReader.java
+++ b/components/net/sf/briar/protocol/SubscriptionReader.java
@@ -4,6 +4,7 @@ import java.io.IOException;
 import java.util.Map;
 
 import net.sf.briar.api.protocol.Group;
+import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.SubscriptionUpdate;
 import net.sf.briar.api.protocol.Tags;
 import net.sf.briar.api.serial.Consumer;
@@ -23,7 +24,8 @@ class SubscriptionReader implements ObjectReader<SubscriptionUpdate> {
 
 	public SubscriptionUpdate readObject(Reader r) throws IOException {
 		// Initialise the consumer
-		Consumer counting = new CountingConsumer(SubscriptionUpdate.MAX_SIZE);
+		Consumer counting =
+			new CountingConsumer(ProtocolConstants.MAX_PACKET_LENGTH);
 		// Read the data
 		r.addConsumer(counting);
 		r.readUserDefinedTag(Tags.SUBSCRIPTION_UPDATE);
diff --git a/components/net/sf/briar/protocol/TransportReader.java b/components/net/sf/briar/protocol/TransportReader.java
index fe729f3f0ddcefbe24422fe9f93c7baf8df0bea1..bf4f251c708931724388e54934ebf996db05f201 100644
--- a/components/net/sf/briar/protocol/TransportReader.java
+++ b/components/net/sf/briar/protocol/TransportReader.java
@@ -5,6 +5,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
+import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.Tags;
 import net.sf.briar.api.protocol.TransportUpdate;
 import net.sf.briar.api.serial.Consumer;
@@ -23,12 +24,13 @@ class TransportReader implements ObjectReader<TransportUpdate> {
 
 	public TransportUpdate readObject(Reader r) throws IOException {
 		// Initialise the consumer
-		Consumer counting = new CountingConsumer(TransportUpdate.MAX_SIZE);
+		Consumer counting =
+			new CountingConsumer(ProtocolConstants.MAX_PACKET_LENGTH);
 		// Read the data
 		r.addConsumer(counting);
 		r.readUserDefinedTag(Tags.TRANSPORT_UPDATE);
 		r.addObjectReader(Tags.TRANSPORT_PROPERTIES, propertiesReader);
-		r.setMaxStringLength(TransportUpdate.MAX_SIZE);
+		r.setMaxStringLength(ProtocolConstants.MAX_PACKET_LENGTH);
 		List<TransportProperties> l = r.readList(TransportProperties.class);
 		r.resetMaxStringLength();
 		r.removeObjectReader(Tags.TRANSPORT_PROPERTIES);
diff --git a/components/net/sf/briar/protocol/writers/AckWriterImpl.java b/components/net/sf/briar/protocol/writers/AckWriterImpl.java
index 6d3648c214a4f692aeb5cb01d82b7f33f483b6d1..cb7516655eb2d5e836a64343a902089e43b934a2 100644
--- a/components/net/sf/briar/protocol/writers/AckWriterImpl.java
+++ b/components/net/sf/briar/protocol/writers/AckWriterImpl.java
@@ -3,8 +3,8 @@ package net.sf.briar.protocol.writers;
 import java.io.IOException;
 import java.io.OutputStream;
 
-import net.sf.briar.api.protocol.Ack;
 import net.sf.briar.api.protocol.BatchId;
+import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.Tags;
 import net.sf.briar.api.protocol.writers.AckWriter;
 import net.sf.briar.api.serial.Writer;
@@ -28,8 +28,11 @@ class AckWriterImpl implements AckWriter {
 			w.writeListStart();
 			started = true;
 		}
-		int capacity = Ack.MAX_SIZE - (int) w.getBytesWritten() - 1;
-		if(capacity < BatchId.SERIALISED_LENGTH) return false;
+		int capacity = ProtocolConstants.MAX_PACKET_LENGTH
+		- (int) w.getBytesWritten() - 1;
+		// Allow one byte for the BATCH_ID tag, one byte for the BYTES tag and
+		// one byte for the length as a uint7
+		if(capacity < BatchId.LENGTH + 3) return false;
 		b.writeTo(w);
 		return true;
 	}
diff --git a/components/net/sf/briar/protocol/writers/BatchWriterImpl.java b/components/net/sf/briar/protocol/writers/BatchWriterImpl.java
index e0c518642062210a8dd5b87e2c519c2180f4354d..95863a9d0751c32560fc036a314d9c7841e76add 100644
--- a/components/net/sf/briar/protocol/writers/BatchWriterImpl.java
+++ b/components/net/sf/briar/protocol/writers/BatchWriterImpl.java
@@ -5,8 +5,8 @@ import java.io.OutputStream;
 import java.security.DigestOutputStream;
 import java.security.MessageDigest;
 
-import net.sf.briar.api.protocol.Batch;
 import net.sf.briar.api.protocol.BatchId;
+import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.Tags;
 import net.sf.briar.api.protocol.writers.BatchWriter;
 import net.sf.briar.api.serial.Writer;
@@ -28,7 +28,9 @@ class BatchWriterImpl implements BatchWriter {
 	}
 
 	public int getCapacity() {
-		return Batch.MAX_SIZE - 3;
+		// Allow one byte for the batch tag, one for the list start tag and
+		// one for the list end tag
+		return ProtocolConstants.MAX_PACKET_LENGTH - 3;
 	}
 
 	public boolean writeMessage(byte[] message) throws IOException {
@@ -38,7 +40,8 @@ class BatchWriterImpl implements BatchWriter {
 			w.writeListStart();
 			started = true;
 		}
-		int capacity = Batch.MAX_SIZE - (int) w.getBytesWritten() - 1;
+		int capacity = ProtocolConstants.MAX_PACKET_LENGTH
+		- (int) w.getBytesWritten() - 1;
 		if(capacity < message.length) return false;
 		// Bypass the writer and write each raw message directly
 		out.write(message);
diff --git a/components/net/sf/briar/protocol/writers/OfferWriterImpl.java b/components/net/sf/briar/protocol/writers/OfferWriterImpl.java
index 7bbac598dfa6f1135954a7d54aa4f7bb9a948160..0a310ac6b3e7fa0ff85cdbb3dad173b9bd2bd9c1 100644
--- a/components/net/sf/briar/protocol/writers/OfferWriterImpl.java
+++ b/components/net/sf/briar/protocol/writers/OfferWriterImpl.java
@@ -6,8 +6,8 @@ import java.security.DigestOutputStream;
 import java.security.MessageDigest;
 
 import net.sf.briar.api.protocol.MessageId;
-import net.sf.briar.api.protocol.Offer;
 import net.sf.briar.api.protocol.OfferId;
+import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.Tags;
 import net.sf.briar.api.protocol.writers.OfferWriter;
 import net.sf.briar.api.serial.Writer;
@@ -35,8 +35,11 @@ class OfferWriterImpl implements OfferWriter {
 			w.writeListStart();
 			started = true;
 		}
-		int capacity = Offer.MAX_SIZE - (int) w.getBytesWritten() - 1;
-		if(capacity < MessageId.SERIALISED_LENGTH) return false;
+		int capacity = ProtocolConstants.MAX_PACKET_LENGTH
+		- (int) w.getBytesWritten() - 1;
+		// Allow one byte for the MESSAGE_ID tag, one byte for the BYTES tag
+		// and one byte for the length as a uint7
+		if(capacity < MessageId.LENGTH + 3) return false;
 		m.writeTo(w);
 		return true;
 	}
diff --git a/components/net/sf/briar/transport/ConnectionRecogniserImpl.java b/components/net/sf/briar/transport/ConnectionRecogniserImpl.java
index 77865ddfc11b4ae838cb2ab448de18178d269674..f9f0f9a63654a101254d8ec7c78d9ec1aeeb99e0 100644
--- a/components/net/sf/briar/transport/ConnectionRecogniserImpl.java
+++ b/components/net/sf/briar/transport/ConnectionRecogniserImpl.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+
 import java.security.InvalidKeyException;
 import java.util.HashMap;
 import java.util.Map;
@@ -92,7 +94,7 @@ DatabaseListener {
 
 	public synchronized ContactId acceptConnection(byte[] tag)
 	throws DbException {
-		if(tag.length != Constants.TAG_BYTES)
+		if(tag.length != TAG_LENGTH)
 			throw new IllegalArgumentException();
 		if(!initialised) initialise();
 		Bytes b = new Bytes(tag);
diff --git a/components/net/sf/briar/transport/ConnectionWindowImpl.java b/components/net/sf/briar/transport/ConnectionWindowImpl.java
index 6db2b6c41a6aefb8ddc3e61744a4081c16e6a47b..5ce228e7d3faaac267e8b64c4681b7d78222b258 100644
--- a/components/net/sf/briar/transport/ConnectionWindowImpl.java
+++ b/components/net/sf/briar/transport/ConnectionWindowImpl.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.MAX_32_BIT_UNSIGNED;
+
 import java.util.ArrayList;
 import java.util.Collection;
 
@@ -31,7 +33,7 @@ class ConnectionWindowImpl implements ConnectionWindow {
 
 	private int getOffset(long connection) {
 		if(connection < 0L) throw new IllegalArgumentException();
-		if(connection > Constants.MAX_32_BIT_UNSIGNED)
+		if(connection > MAX_32_BIT_UNSIGNED)
 			throw new IllegalArgumentException();
 		int offset = (int) (connection - centre) + 16;
 		if(offset < 0 || offset > 31) throw new IllegalArgumentException();
@@ -56,11 +58,12 @@ class ConnectionWindowImpl implements ConnectionWindow {
 			int mask = 0x80000000 >>> i;
 			if((bitmap & mask) == 0) {
 				long c = centre - 16 + i;
-				if(c >= 0L && c <= Constants.MAX_32_BIT_UNSIGNED) unseen.add(c);
+				if(c >= 0L && c <= MAX_32_BIT_UNSIGNED) unseen.add(c);
 			}
 		}
-		assert unseen.contains(centre)
-		|| centre == Constants.MAX_32_BIT_UNSIGNED + 1;
+		// The centre of the window should be an unseen value unless the
+		// maximum possible value has been seen
+		assert unseen.contains(centre) || centre == MAX_32_BIT_UNSIGNED + 1;
 		return unseen;
 	}
 }
diff --git a/components/net/sf/briar/transport/Constants.java b/components/net/sf/briar/transport/Constants.java
deleted file mode 100644
index 07d8a1fd2320460e33efc1dfc7d3445de864c350..0000000000000000000000000000000000000000
--- a/components/net/sf/briar/transport/Constants.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package net.sf.briar.transport;
-
-interface Constants {
-
-	static final int TAG_BYTES = 16;
-	static final int MAX_16_BIT_UNSIGNED = 65535; // 2^16 - 1
-	static final long MAX_32_BIT_UNSIGNED = 4294967295L; // 2^32 - 1
-}
diff --git a/components/net/sf/briar/transport/PacketDecrypterImpl.java b/components/net/sf/briar/transport/PacketDecrypterImpl.java
index 3fe5adb5c6840f92bf52db92aa53017b34f97463..b1ed14790443856e867258a073334082dc6daec8 100644
--- a/components/net/sf/briar/transport/PacketDecrypterImpl.java
+++ b/components/net/sf/briar/transport/PacketDecrypterImpl.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+
 import java.io.EOFException;
 import java.io.FilterInputStream;
 import java.io.IOException;
@@ -21,16 +23,16 @@ class PacketDecrypterImpl extends FilterInputStream implements PacketDecrypter {
 	private final SecretKey packetKey;
 
 	private byte[] cipherBuf, plainBuf;
-	private int bufOff = 0, bufLen = Constants.TAG_BYTES;
+	private int bufOff = 0, bufLen = TAG_LENGTH;
 	private boolean betweenPackets = true;
 
 	PacketDecrypterImpl(byte[] firstTag, InputStream in, Cipher tagCipher,
 			Cipher packetCipher, SecretKey tagKey, SecretKey packetKey) {
 		super(in);
-		if(firstTag.length != Constants.TAG_BYTES)
+		if(firstTag.length != TAG_LENGTH)
 			throw new IllegalArgumentException();
 		cipherBuf = Arrays.copyOf(firstTag, firstTag.length);
-		plainBuf = new byte[Constants.TAG_BYTES];
+		plainBuf = new byte[TAG_LENGTH];
 		this.tagCipher = tagCipher;
 		this.packetCipher = packetCipher;
 		this.packetKey = packetKey;
@@ -39,7 +41,7 @@ class PacketDecrypterImpl extends FilterInputStream implements PacketDecrypter {
 		} catch(InvalidKeyException e) {
 			throw new IllegalArgumentException(e);
 		}
-		if(tagCipher.getOutputSize(Constants.TAG_BYTES) != Constants.TAG_BYTES)
+		if(tagCipher.getOutputSize(TAG_LENGTH) != TAG_LENGTH)
 			throw new IllegalArgumentException();
 	}
 
@@ -48,7 +50,7 @@ class PacketDecrypterImpl extends FilterInputStream implements PacketDecrypter {
 	}
 
 	public byte[] readTag() throws IOException {
-		byte[] tag = new byte[Constants.TAG_BYTES];
+		byte[] tag = new byte[TAG_LENGTH];
 		System.arraycopy(cipherBuf, bufOff, tag, 0, bufLen);
 		int offset = bufLen;
 		bufOff = bufLen = 0;
diff --git a/components/net/sf/briar/transport/PacketEncrypterImpl.java b/components/net/sf/briar/transport/PacketEncrypterImpl.java
index 69ca0c9ca3aa60d608f4caaa4ce1d0af22c3ab16..bd9b5e5a766165e6330e4eb45fd476de7486ae99 100644
--- a/components/net/sf/briar/transport/PacketEncrypterImpl.java
+++ b/components/net/sf/briar/transport/PacketEncrypterImpl.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+
 import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -29,7 +31,7 @@ implements PacketEncrypter {
 		} catch(InvalidKeyException e) {
 			throw new IllegalArgumentException(e);
 		}
-		if(tagCipher.getOutputSize(Constants.TAG_BYTES) != Constants.TAG_BYTES)
+		if(tagCipher.getOutputSize(TAG_LENGTH) != TAG_LENGTH)
 			throw new IllegalArgumentException();
 	}
 
@@ -38,8 +40,7 @@ implements PacketEncrypter {
 	}
 
 	public void writeTag(byte[] tag) throws IOException {
-		if(tag.length != Constants.TAG_BYTES)
-			throw new IllegalArgumentException();
+		if(tag.length != TAG_LENGTH) throw new IllegalArgumentException();
 		IvParameterSpec iv = new IvParameterSpec(tag);
 		try {
 			out.write(tagCipher.doFinal(tag));
diff --git a/components/net/sf/briar/transport/PacketReaderImpl.java b/components/net/sf/briar/transport/PacketReaderImpl.java
index 0e6372a0c6d8c4577629ed73bd11666e3c6c8f43..2db8bafefe53750316b113e56d058971a72eab8c 100644
--- a/components/net/sf/briar/transport/PacketReaderImpl.java
+++ b/components/net/sf/briar/transport/PacketReaderImpl.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.MAX_32_BIT_UNSIGNED;
+
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -78,8 +80,7 @@ class PacketReaderImpl extends FilterInputStream implements PacketReader {
 
 	private void readTag() throws IOException {
 		assert betweenPackets;
-		if(packet > Constants.MAX_32_BIT_UNSIGNED)
-			throw new IllegalStateException();
+		if(packet > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
 		byte[] tag = decrypter.readTag();
 		if(tag == null) return; // EOF
 		if(!TagDecoder.decodeTag(tag, transportId, connection, packet))
diff --git a/components/net/sf/briar/transport/PacketWriterImpl.java b/components/net/sf/briar/transport/PacketWriterImpl.java
index 943e3d95f6e4a17dd4c929713596b0b71e05fdf4..7ca9f9289d223c8a6c94c1704d4fdddfffc87058 100644
--- a/components/net/sf/briar/transport/PacketWriterImpl.java
+++ b/components/net/sf/briar/transport/PacketWriterImpl.java
@@ -1,5 +1,8 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.MAX_16_BIT_UNSIGNED;
+import static net.sf.briar.api.transport.TransportConstants.MAX_32_BIT_UNSIGNED;
+
 import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -24,11 +27,11 @@ class PacketWriterImpl extends FilterOutputStream implements PacketWriter {
 		this.encrypter = encrypter;
 		this.mac = mac;
 		if(transportId < 0) throw new IllegalArgumentException();
-		if(transportId > Constants.MAX_16_BIT_UNSIGNED)
+		if(transportId > MAX_16_BIT_UNSIGNED)
 			throw new IllegalArgumentException();
 		this.transportId = transportId;
 		if(connection < 0L) throw new IllegalArgumentException();
-		if(connection > Constants.MAX_32_BIT_UNSIGNED)
+		if(connection > MAX_32_BIT_UNSIGNED)
 			throw new IllegalArgumentException();
 		this.connection = connection;
 	}
@@ -68,8 +71,7 @@ class PacketWriterImpl extends FilterOutputStream implements PacketWriter {
 
 	private void writeTag() throws IOException {
 		assert betweenPackets;
-		if(packet > Constants.MAX_32_BIT_UNSIGNED)
-			throw new IllegalStateException();
+		if(packet > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
 		byte[] tag = TagEncoder.encodeTag(transportId, connection,
 				packet);
 		// Write the tag to the encrypter and start calculating the MAC
diff --git a/components/net/sf/briar/transport/TagDecoder.java b/components/net/sf/briar/transport/TagDecoder.java
index 01b59b61918248cd3424daadeca72175aeaca237..169f1ad15175372aaff44c011454dddd54b2ba8b 100644
--- a/components/net/sf/briar/transport/TagDecoder.java
+++ b/components/net/sf/briar/transport/TagDecoder.java
@@ -1,10 +1,12 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+
 class TagDecoder {
 
 	static boolean decodeTag(byte[] tag, int transportId, long connection,
 			long packet) {
-		if(tag.length != Constants.TAG_BYTES) return false;
+		if(tag.length != TAG_LENGTH) return false;
 		// First 16 bits must be zero
 		if(readUint16(tag, 0) != 0) return false;
 		// Transport identifier is encoded as an unsigned 16-bit integer
diff --git a/components/net/sf/briar/transport/TagEncoder.java b/components/net/sf/briar/transport/TagEncoder.java
index 8160f76212212d15847faba407e2c70e6c3ef14c..1660c437120e5f110943e27f809b693a9e9dbbfd 100644
--- a/components/net/sf/briar/transport/TagEncoder.java
+++ b/components/net/sf/briar/transport/TagEncoder.java
@@ -1,10 +1,14 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAX_16_BIT_UNSIGNED;
+import static net.sf.briar.api.transport.TransportConstants.MAX_32_BIT_UNSIGNED;
+
 class TagEncoder {
 
 	static byte[] encodeTag(int transportId, long connection,
 			long packet) {
-		byte[] tag = new byte[Constants.TAG_BYTES];
+		byte[] tag = new byte[TAG_LENGTH];
 		// Encode the transport identifier as an unsigned 16-bit integer
 		writeUint16(transportId, tag, 2);
 		// Encode the connection number as an unsigned 32-bit integer
@@ -17,7 +21,7 @@ class TagEncoder {
 	// Package access for testing
 	static void writeUint16(int i, byte[] b, int offset) {
 		assert i >= 0;
-		assert i <= Constants.MAX_16_BIT_UNSIGNED;
+		assert i <= MAX_16_BIT_UNSIGNED;
 		assert b.length >= offset + 2;
 		b[offset] = (byte) (i >> 8);
 		b[offset + 1] = (byte) (i & 0xFF);
@@ -26,7 +30,7 @@ class TagEncoder {
 	// Package access for testing
 	static void writeUint32(long i, byte[] b, int offset) {
 		assert i >= 0L;
-		assert i <= Constants.MAX_32_BIT_UNSIGNED;
+		assert i <= MAX_32_BIT_UNSIGNED;
 		assert b.length >= offset + 4;
 		b[offset] = (byte) (i >> 24);
 		b[offset + 1] = (byte) (i >> 16 & 0xFF);
diff --git a/test/net/sf/briar/protocol/AckReaderTest.java b/test/net/sf/briar/protocol/AckReaderTest.java
index dd189d99c761b9cb3f565eedcbbeaccd60dfc089..67f08091e979d5cd2902b3fd22165816eaaf8a4d 100644
--- a/test/net/sf/briar/protocol/AckReaderTest.java
+++ b/test/net/sf/briar/protocol/AckReaderTest.java
@@ -9,6 +9,7 @@ import java.util.Random;
 import junit.framework.TestCase;
 import net.sf.briar.api.protocol.Ack;
 import net.sf.briar.api.protocol.BatchId;
+import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.Tags;
 import net.sf.briar.api.protocol.UniqueId;
 import net.sf.briar.api.serial.FormatException;
@@ -103,7 +104,8 @@ public class AckReaderTest extends TestCase {
 		w.writeListStart();
 		byte[] b = new byte[UniqueId.LENGTH];
 		Random random = new Random();
-		while(out.size() < Ack.MAX_SIZE - BatchId.SERIALISED_LENGTH) {
+		while(out.size() + BatchId.LENGTH + 3
+				< ProtocolConstants.MAX_PACKET_LENGTH) {
 			w.writeUserDefinedTag(Tags.BATCH_ID);
 			random.nextBytes(b);
 			w.writeBytes(b);
@@ -114,7 +116,7 @@ public class AckReaderTest extends TestCase {
 			w.writeBytes(b);
 		}
 		w.writeListEnd();
-		assertEquals(tooBig, out.size() > Ack.MAX_SIZE);
+		assertEquals(tooBig, out.size() > ProtocolConstants.MAX_PACKET_LENGTH);
 		return out.toByteArray();
 	}
 
diff --git a/test/net/sf/briar/protocol/BatchReaderTest.java b/test/net/sf/briar/protocol/BatchReaderTest.java
index fa487c5495a197f9442208b8bbf5e4bbcfa0040d..9c7407dbbaebdae5f17f4f0b8af1a9f8beac2792 100644
--- a/test/net/sf/briar/protocol/BatchReaderTest.java
+++ b/test/net/sf/briar/protocol/BatchReaderTest.java
@@ -11,6 +11,7 @@ import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.protocol.Batch;
 import net.sf.briar.api.protocol.BatchId;
 import net.sf.briar.api.protocol.Message;
+import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.Tags;
 import net.sf.briar.api.serial.FormatException;
 import net.sf.briar.api.serial.ObjectReader;
@@ -54,7 +55,7 @@ public class BatchReaderTest extends TestCase {
 		BatchReader batchReader = new BatchReader(crypto, messageReader,
 				batchFactory);
 
-		byte[] b = createBatch(Batch.MAX_SIZE + 1);
+		byte[] b = createBatch(ProtocolConstants.MAX_PACKET_LENGTH + 1);
 		ByteArrayInputStream in = new ByteArrayInputStream(b);
 		Reader reader = readerFactory.createReader(in);
 		reader.addObjectReader(Tags.BATCH, batchReader);
@@ -79,7 +80,7 @@ public class BatchReaderTest extends TestCase {
 			will(returnValue(batch));
 		}});
 
-		byte[] b = createBatch(Batch.MAX_SIZE);
+		byte[] b = createBatch(ProtocolConstants.MAX_PACKET_LENGTH);
 		ByteArrayInputStream in = new ByteArrayInputStream(b);
 		Reader reader = readerFactory.createReader(in);
 		reader.addObjectReader(Tags.BATCH, batchReader);
@@ -90,7 +91,7 @@ public class BatchReaderTest extends TestCase {
 
 	@Test
 	public void testBatchId() throws Exception {
-		byte[] b = createBatch(Batch.MAX_SIZE);
+		byte[] b = createBatch(ProtocolConstants.MAX_PACKET_LENGTH);
 		// Calculate the expected batch ID
 		MessageDigest messageDigest = crypto.getMessageDigest();
 		messageDigest.reset();
diff --git a/test/net/sf/briar/protocol/RequestReaderTest.java b/test/net/sf/briar/protocol/RequestReaderTest.java
index b9c2be3ef866801ac3907a4cf6bdcd4491a8ccf3..5b10e496488f01a7796080b43d607494bd4ac442 100644
--- a/test/net/sf/briar/protocol/RequestReaderTest.java
+++ b/test/net/sf/briar/protocol/RequestReaderTest.java
@@ -6,6 +6,7 @@ import java.util.BitSet;
 
 import junit.framework.TestCase;
 import net.sf.briar.api.protocol.OfferId;
+import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.Request;
 import net.sf.briar.api.protocol.Tags;
 import net.sf.briar.api.protocol.UniqueId;
@@ -127,9 +128,10 @@ public class RequestReaderTest extends TestCase {
 		// UniqueID.LENGTH bytes for the offer ID, one byte for the BYTES tag,
 		// and five bytes for the length as an int32
 		int overhead = UniqueId.LENGTH + 10;
-		if(tooBig) w.writeBytes(new byte[Request.MAX_SIZE - overhead + 1]);
-		else w.writeBytes(new byte[Request.MAX_SIZE - overhead]);
-		assertEquals(tooBig, out.size() > Request.MAX_SIZE);
+		int size = ProtocolConstants.MAX_PACKET_LENGTH - overhead;
+		if(tooBig) size++;
+		w.writeBytes(new byte[size]);
+		assertEquals(tooBig, out.size() > ProtocolConstants.MAX_PACKET_LENGTH);
 		return out.toByteArray();
 	}
 
diff --git a/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java b/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java
index c5009db87de80dffeaeb594e821ce13798993955..52ed9148b5b6db6760ba0976404e9c390c77fd65 100644
--- a/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+
 import java.util.Collection;
 import java.util.Collections;
 
@@ -53,7 +55,7 @@ public class ConnectionRecogniserImplTest extends TestCase {
 		}});
 		final ConnectionRecogniserImpl c =
 			new ConnectionRecogniserImpl(transportId, crypto, db);
-		assertNull(c.acceptConnection(new byte[Constants.TAG_BYTES]));
+		assertNull(c.acceptConnection(new byte[TAG_LENGTH]));
 		context.assertIsSatisfied();
 	}
 
diff --git a/test/net/sf/briar/transport/PacketDecrypterImplTest.java b/test/net/sf/briar/transport/PacketDecrypterImplTest.java
index e4ec4f2d3cf80eb53b8c00933f0a450dc815c43d..c001a20aaf6b99168b276795d11e8d86ce4f043e 100644
--- a/test/net/sf/briar/transport/PacketDecrypterImplTest.java
+++ b/test/net/sf/briar/transport/PacketDecrypterImplTest.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+
 import java.io.ByteArrayInputStream;
 import java.util.Arrays;
 
@@ -33,25 +35,25 @@ public class PacketDecrypterImplTest extends TestCase {
 
 	@Test
 	public void testSingleBytePackets() throws Exception {
-		byte[] ciphertext = new byte[(Constants.TAG_BYTES + 1) * 2];
+		byte[] ciphertext = new byte[(TAG_LENGTH + 1) * 2];
 		ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
-		byte[] firstTag = new byte[Constants.TAG_BYTES];
-		assertEquals(Constants.TAG_BYTES, in.read(firstTag));
+		byte[] firstTag = new byte[TAG_LENGTH];
+		assertEquals(TAG_LENGTH, in.read(firstTag));
 		PacketDecrypter p = new PacketDecrypterImpl(firstTag, in, tagCipher,
 				packetCipher, tagKey, packetKey);
 		byte[] decryptedTag = p.readTag();
-		assertEquals(Constants.TAG_BYTES, decryptedTag.length);
+		assertEquals(TAG_LENGTH, decryptedTag.length);
 		assertTrue(p.getInputStream().read() > -1);
 		byte[] decryptedTag1 = p.readTag();
-		assertEquals(Constants.TAG_BYTES, decryptedTag1.length);
+		assertEquals(TAG_LENGTH, decryptedTag1.length);
 		assertTrue(p.getInputStream().read() > -1);		
 	}
 
 	@Test
 	public void testDecryption() throws Exception {
-		byte[] tag = new byte[Constants.TAG_BYTES];
+		byte[] tag = new byte[TAG_LENGTH];
 		byte[] packet = new byte[123];
-		byte[] tag1 = new byte[Constants.TAG_BYTES];
+		byte[] tag1 = new byte[TAG_LENGTH];
 		byte[] packet1 = new byte[234];
 		// Calculate the first expected decrypted tag
 		tagCipher.init(Cipher.DECRYPT_MODE, tagKey);
diff --git a/test/net/sf/briar/transport/PacketEncrypterImplTest.java b/test/net/sf/briar/transport/PacketEncrypterImplTest.java
index 2b06dfae38950a462040d2bd5a22d77dfa8b09ec..06ea1b66a910fc7e4f2a63cf2b1895b1a35abbf4 100644
--- a/test/net/sf/briar/transport/PacketEncrypterImplTest.java
+++ b/test/net/sf/briar/transport/PacketEncrypterImplTest.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+
 import java.io.ByteArrayOutputStream;
 import java.util.Arrays;
 
@@ -36,15 +38,15 @@ public class PacketEncrypterImplTest extends TestCase {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		PacketEncrypter p = new PacketEncrypterImpl(out, tagCipher,
 				packetCipher, tagKey, packetKey);
-		p.writeTag(new byte[Constants.TAG_BYTES]);
+		p.writeTag(new byte[TAG_LENGTH]);
 		p.getOutputStream().write((byte) 0);
 		p.finishPacket();
-		assertEquals(Constants.TAG_BYTES + 1, out.toByteArray().length);
+		assertEquals(TAG_LENGTH + 1, out.toByteArray().length);
 	}
 
 	@Test
 	public void testEncryption() throws Exception {
-		byte[] tag = new byte[Constants.TAG_BYTES];
+		byte[] tag = new byte[TAG_LENGTH];
 		byte[] packet = new byte[123];
 		// Calculate the expected encrypted tag
 		tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
@@ -63,14 +65,14 @@ public class PacketEncrypterImplTest extends TestCase {
 		p.getOutputStream().write(packet);
 		p.finishPacket();
 		byte[] ciphertext = out.toByteArray();
-		assertEquals(Constants.TAG_BYTES + packet.length, ciphertext.length);
+		assertEquals(TAG_LENGTH + packet.length, ciphertext.length);
 		// Check the tag
-		byte[] actualTag = new byte[Constants.TAG_BYTES];
-		System.arraycopy(ciphertext, 0, actualTag, 0, Constants.TAG_BYTES);
+		byte[] actualTag = new byte[TAG_LENGTH];
+		System.arraycopy(ciphertext, 0, actualTag, 0, TAG_LENGTH);
 		assertTrue(Arrays.equals(expectedTag, actualTag));
 		// Check the packet
 		byte[] actualPacket = new byte[packet.length];
-		System.arraycopy(ciphertext, Constants.TAG_BYTES, actualPacket, 0,
+		System.arraycopy(ciphertext, TAG_LENGTH, actualPacket, 0,
 				actualPacket.length);
 		assertTrue(Arrays.equals(expectedPacket, actualPacket));
 	}
diff --git a/test/net/sf/briar/transport/PacketReadWriteTest.java b/test/net/sf/briar/transport/PacketReadWriteTest.java
index 106dff792f7d086725d739e888a037e5ce0e0b7c..27b1f35491103804c773a42c5237103f566a7347 100644
--- a/test/net/sf/briar/transport/PacketReadWriteTest.java
+++ b/test/net/sf/briar/transport/PacketReadWriteTest.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
@@ -68,8 +70,8 @@ public class PacketReadWriteTest extends TestCase {
 		writer.finishPacket();
 		// Read the packets back
 		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
-		byte[] firstTag = new byte[Constants.TAG_BYTES];
-		assertEquals(Constants.TAG_BYTES, in.read(firstTag));
+		byte[] firstTag = new byte[TAG_LENGTH];
+		assertEquals(TAG_LENGTH, in.read(firstTag));
 		PacketDecrypter decrypter = new PacketDecrypterImpl(firstTag, in,
 				tagCipher, packetCipher, tagKey, packetKey);
 		PacketReader reader = new PacketReaderImpl(decrypter, mac, transportId,
diff --git a/test/net/sf/briar/transport/PacketReaderImplTest.java b/test/net/sf/briar/transport/PacketReaderImplTest.java
index f2124401b3c4444aa168febf541d3ee8ab433c02..d5e34c89c9c4e69dc96a210bc1997c5813cfe8e1 100644
--- a/test/net/sf/briar/transport/PacketReaderImplTest.java
+++ b/test/net/sf/briar/transport/PacketReaderImplTest.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+
 import java.io.ByteArrayInputStream;
 import java.io.EOFException;
 import java.io.IOException;
@@ -35,7 +37,7 @@ public class PacketReaderImplTest extends TestCase {
 	@Test
 	public void testFirstReadTriggersTag() throws Exception {
 		// TAG_BYTES for the tag, 1 byte for the packet
-		byte[] b = new byte[Constants.TAG_BYTES + 1];
+		byte[] b = new byte[TAG_LENGTH + 1];
 		ByteArrayInputStream in = new ByteArrayInputStream(b);
 		PacketDecrypter d = new NullPacketDecrypter(in);
 		PacketReader p = new PacketReaderImpl(d, mac, 0, 0L);
@@ -47,7 +49,7 @@ public class PacketReaderImplTest extends TestCase {
 	@Test
 	public void testFinishPacketAfterReadTriggersMac() throws Exception {
 		// TAG_BYTES for the tag, 1 byte for the packet
-		byte[] b = new byte[Constants.TAG_BYTES + 1];
+		byte[] b = new byte[TAG_LENGTH + 1];
 		// Calculate the MAC and append it to the packet
 		mac.update(b);
 		byte[] macBytes = mac.doFinal();
@@ -66,14 +68,14 @@ public class PacketReaderImplTest extends TestCase {
 	@Test
 	public void testModifyingPacketInvalidatesMac() throws Exception {
 		// TAG_BYTES for the tag, 1 byte for the packet
-		byte[] b = new byte[Constants.TAG_BYTES + 1];
+		byte[] b = new byte[TAG_LENGTH + 1];
 		// Calculate the MAC and append it to the packet
 		mac.update(b);
 		byte[] macBytes = mac.doFinal();
 		byte[] b1 = Arrays.copyOf(b, b.length + macBytes.length);
 		System.arraycopy(macBytes, 0, b1, b.length, macBytes.length);
 		// Modify the packet
-		b1[Constants.TAG_BYTES] = (byte) 1;
+		b1[TAG_LENGTH] = (byte) 1;
 		// Check that the PacketReader reads and fails to verify the MAC
 		ByteArrayInputStream in = new ByteArrayInputStream(b1);
 		PacketDecrypter d = new NullPacketDecrypter(in);
@@ -88,7 +90,7 @@ public class PacketReaderImplTest extends TestCase {
 	@Test
 	public void testExtraCallsToFinishPacketDoNothing() throws Exception {
 		// TAG_BYTES for the tag, 1 byte for the packet
-		byte[] b = new byte[Constants.TAG_BYTES + 1];
+		byte[] b = new byte[TAG_LENGTH + 1];
 		// Calculate the MAC and append it to the packet
 		mac.update(b);
 		byte[] macBytes = mac.doFinal();
@@ -121,7 +123,7 @@ public class PacketReaderImplTest extends TestCase {
 				+ "00000000" // 32 bits for the packet number
 				+ "00000000" // 32 bits for the block number
 		);
-		assertEquals(Constants.TAG_BYTES, tag.length);
+		assertEquals(TAG_LENGTH, tag.length);
 		byte[] tag1 = StringUtils.fromHexString(
 				"0000" // 16 bits reserved
 				+ "F00D" // 16 bits for the transport ID
@@ -129,7 +131,7 @@ public class PacketReaderImplTest extends TestCase {
 				+ "00000001" // 32 bits for the packet number
 				+ "00000000" // 32 bits for the block number
 		);
-		assertEquals(Constants.TAG_BYTES, tag1.length);
+		assertEquals(TAG_LENGTH, tag1.length);
 		// Calculate the MAC on the first packet and append it to the packet
 		mac.update(tag);
 		mac.update((byte) 0);
@@ -172,7 +174,7 @@ public class PacketReaderImplTest extends TestCase {
 		}
 
 		public byte[] readTag() throws IOException {
-			byte[] tag = new byte[Constants.TAG_BYTES];
+			byte[] tag = new byte[TAG_LENGTH];
 			int offset = 0;
 			while(offset < tag.length) {
 				int read = in.read(tag, offset, tag.length - offset);
diff --git a/test/net/sf/briar/transport/PacketWriterImplTest.java b/test/net/sf/briar/transport/PacketWriterImplTest.java
index aae1a074497e366d91756ee26f7567329f8f5858..f99c51e5be46bd487775720bee594667d54c9295 100644
--- a/test/net/sf/briar/transport/PacketWriterImplTest.java
+++ b/test/net/sf/briar/transport/PacketWriterImplTest.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -37,14 +39,14 @@ public class PacketWriterImplTest extends TestCase {
 		PacketWriter p = new PacketWriterImpl(e, mac, 0, 0L);
 		p.getOutputStream().write(0);
 		// There should be TAG_BYTES bytes for the tag, 1 byte for the packet
-		assertTrue(Arrays.equals(new byte[Constants.TAG_BYTES + 1],
+		assertTrue(Arrays.equals(new byte[TAG_LENGTH + 1],
 				out.toByteArray()));
 	}
 
 	@Test
 	public void testFinishPacketAfterWriteTriggersMac() throws Exception {
 		// Calculate what the MAC should be
-		mac.update(new byte[Constants.TAG_BYTES + 1]);
+		mac.update(new byte[TAG_LENGTH + 1]);
 		byte[] expectedMac = mac.doFinal();
 		// Check that the PacketWriter calculates and writes the correct MAC
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -53,10 +55,10 @@ public class PacketWriterImplTest extends TestCase {
 		p.getOutputStream().write(0);
 		p.finishPacket();
 		byte[] written = out.toByteArray();
-		assertEquals(Constants.TAG_BYTES + 1 + expectedMac.length,
+		assertEquals(TAG_LENGTH + 1 + expectedMac.length,
 				written.length);
 		byte[] actualMac = new byte[expectedMac.length];
-		System.arraycopy(written, Constants.TAG_BYTES + 1, actualMac, 0,
+		System.arraycopy(written, TAG_LENGTH + 1, actualMac, 0,
 				actualMac.length);
 		assertTrue(Arrays.equals(expectedMac, actualMac));
 	}
@@ -64,7 +66,7 @@ public class PacketWriterImplTest extends TestCase {
 	@Test
 	public void testExtraCallsToFinishPacketDoNothing() throws Exception {
 		// Calculate what the MAC should be
-		mac.update(new byte[Constants.TAG_BYTES + 1]);
+		mac.update(new byte[TAG_LENGTH + 1]);
 		byte[] expectedMac = mac.doFinal();
 		// Check that the PacketWriter calculates and writes the correct MAC
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -81,10 +83,10 @@ public class PacketWriterImplTest extends TestCase {
 		p.finishPacket();
 		p.finishPacket();
 		byte[] written = out.toByteArray();
-		assertEquals(Constants.TAG_BYTES + 1 + expectedMac.length,
+		assertEquals(TAG_LENGTH + 1 + expectedMac.length,
 				written.length);
 		byte[] actualMac = new byte[expectedMac.length];
-		System.arraycopy(written, Constants.TAG_BYTES + 1, actualMac, 0,
+		System.arraycopy(written, TAG_LENGTH + 1, actualMac, 0,
 				actualMac.length);
 		assertTrue(Arrays.equals(expectedMac, actualMac));
 	}
@@ -98,7 +100,7 @@ public class PacketWriterImplTest extends TestCase {
 				+ "00000000" // 32 bits for the packet number
 				+ "00000000" // 32 bits for the block number
 		);
-		assertEquals(Constants.TAG_BYTES, expectedTag.length);
+		assertEquals(TAG_LENGTH, expectedTag.length);
 		byte[] expectedTag1 = StringUtils.fromHexString(
 				"0000" // 16 bits reserved
 				+ "F00D" // 16 bits for the transport ID
@@ -106,7 +108,7 @@ public class PacketWriterImplTest extends TestCase {
 				+ "00000001" // 32 bits for the packet number
 				+ "00000000" // 32 bits for the block number
 		);
-		assertEquals(Constants.TAG_BYTES, expectedTag1.length);
+		assertEquals(TAG_LENGTH, expectedTag1.length);
 		// Calculate what the MAC on the first packet should be
 		mac.update(expectedTag);
 		mac.update((byte) 0);
@@ -126,27 +128,27 @@ public class PacketWriterImplTest extends TestCase {
 		p.getOutputStream().write(0);
 		p.finishPacket();
 		byte[] written = out.toByteArray();
-		assertEquals(Constants.TAG_BYTES + 1 + expectedMac.length
-				+ Constants.TAG_BYTES + 1 + expectedMac1.length,
+		assertEquals(TAG_LENGTH + 1 + expectedMac.length
+				+ TAG_LENGTH + 1 + expectedMac1.length,
 				written.length);
 		// Check the first packet's tag
-		byte[] actualTag = new byte[Constants.TAG_BYTES];
-		System.arraycopy(written, 0, actualTag, 0, Constants.TAG_BYTES);
+		byte[] actualTag = new byte[TAG_LENGTH];
+		System.arraycopy(written, 0, actualTag, 0, TAG_LENGTH);
 		assertTrue(Arrays.equals(expectedTag, actualTag));
 		// Check the first packet's MAC
 		byte[] actualMac = new byte[expectedMac.length];
-		System.arraycopy(written, Constants.TAG_BYTES + 1, actualMac, 0,
+		System.arraycopy(written, TAG_LENGTH + 1, actualMac, 0,
 				actualMac.length);
 		assertTrue(Arrays.equals(expectedMac, actualMac));
 		// Check the second packet's tag
-		byte[] actualTag1 = new byte[Constants.TAG_BYTES];
-		System.arraycopy(written, Constants.TAG_BYTES + 1 + expectedMac.length,
-				actualTag1, 0, Constants.TAG_BYTES);
+		byte[] actualTag1 = new byte[TAG_LENGTH];
+		System.arraycopy(written, TAG_LENGTH + 1 + expectedMac.length,
+				actualTag1, 0, TAG_LENGTH);
 		assertTrue(Arrays.equals(expectedTag1, actualTag1));
 		// Check the second packet's MAC
 		byte[] actualMac1 = new byte[expectedMac1.length];
-		System.arraycopy(written, Constants.TAG_BYTES + 1 + expectedMac.length
-				+ Constants.TAG_BYTES + 1, actualMac1, 0, actualMac1.length);
+		System.arraycopy(written, TAG_LENGTH + 1 + expectedMac.length
+				+ TAG_LENGTH + 1, actualMac1, 0, actualMac1.length);
 		assertTrue(Arrays.equals(expectedMac1, actualMac1));
 	}