diff --git a/api/net/sf/briar/api/protocol/writers/BatchWriter.java b/api/net/sf/briar/api/protocol/writers/BatchWriter.java
index 7d0036b67d8e56702e205a8ab6a1776438ce8124..b4806166879ace9abbe2e36bd33e718321a76c21 100644
--- a/api/net/sf/briar/api/protocol/writers/BatchWriter.java
+++ b/api/net/sf/briar/api/protocol/writers/BatchWriter.java
@@ -7,7 +7,7 @@ import net.sf.briar.api.protocol.BatchId;
 /** An interface for creating a batch packet. */
 public interface BatchWriter {
 
-	/** Returns the capacity of the batch. */
+	/** Returns the capacity of the batch in bytes. */
 	int getCapacity();
 
 	/**
diff --git a/api/net/sf/briar/api/transport/ConnectionReaderFactory.java b/api/net/sf/briar/api/transport/ConnectionReaderFactory.java
index 01498fb9c115e1d5fc7351e63efcaca83121a525..9c09ac2342b615de24462c625bfc45d144b2cf37 100644
--- a/api/net/sf/briar/api/transport/ConnectionReaderFactory.java
+++ b/api/net/sf/briar/api/transport/ConnectionReaderFactory.java
@@ -4,6 +4,6 @@ import java.io.InputStream;
 
 public interface ConnectionReaderFactory {
 
-	ConnectionReader createConnectionReader(InputStream in, boolean initiator,
-			int transportId, long connection, byte[] secret);
+	ConnectionReader createConnectionReader(InputStream in, byte[] encryptedIv,
+			byte[] secret);
 }
diff --git a/api/net/sf/briar/api/transport/ConnectionRecogniserFactory.java b/api/net/sf/briar/api/transport/ConnectionRecogniserFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..a0a122087952c35ae461c67102f58bb60b92cd99
--- /dev/null
+++ b/api/net/sf/briar/api/transport/ConnectionRecogniserFactory.java
@@ -0,0 +1,6 @@
+package net.sf.briar.api.transport;
+
+public interface ConnectionRecogniserFactory {
+
+	ConnectionRecogniser createConnectionRecogniser(int transportId);
+}
diff --git a/api/net/sf/briar/api/transport/ConnectionWriter.java b/api/net/sf/briar/api/transport/ConnectionWriter.java
index ae3b5ab162ddf2d3e6a881ced775fd9607d879c5..bfe4721998064b1512522c197c804bddf5b4150a 100644
--- a/api/net/sf/briar/api/transport/ConnectionWriter.java
+++ b/api/net/sf/briar/api/transport/ConnectionWriter.java
@@ -12,5 +12,5 @@ public interface ConnectionWriter {
 	OutputStream getOutputStream();
 
 	/** Returns the maximum number of bytes that can be written. */
-	long getCapacity();
+	long getRemainingCapacity();
 }
diff --git a/api/net/sf/briar/api/transport/batch/BatchTransportWriter.java b/api/net/sf/briar/api/transport/batch/BatchTransportWriter.java
index 10f4b9f70d13867d367dc98d730241248f8d2583..c485b6b235cb665b3a1d57d515a499d2450ca188 100644
--- a/api/net/sf/briar/api/transport/batch/BatchTransportWriter.java
+++ b/api/net/sf/briar/api/transport/batch/BatchTransportWriter.java
@@ -9,7 +9,7 @@ import java.io.OutputStream;
  */
 public interface BatchTransportWriter {
 
-	/** Returns the maximum number of bytes that can be written. */
+	/** Returns the capacity of the transport in bytes. */
 	long getCapacity();
 
 	/** Returns an output stream for writing to the transport. */
diff --git a/components/net/sf/briar/transport/ConnectionDecrypterImpl.java b/components/net/sf/briar/transport/ConnectionDecrypterImpl.java
index 77f62df6de85df05b9a38c3886fd3fd493955350..dc48931a4dae092eb9a537373f8acf24e41a7121 100644
--- a/components/net/sf/briar/transport/ConnectionDecrypterImpl.java
+++ b/components/net/sf/briar/transport/ConnectionDecrypterImpl.java
@@ -22,19 +22,30 @@ implements ConnectionDecrypter {
 
 	private final Cipher frameCipher;
 	private final SecretKey frameKey;
-	private final byte[] buf, iv;
+	private final byte[] iv, buf;
 
 	private int bufOff = 0, bufLen = 0;
 	private long frame = 0L;
 	private boolean betweenFrames = true;
 
-	ConnectionDecrypterImpl(InputStream in, boolean initiator, int transportId,
-			long connection, Cipher frameCipher, SecretKey frameKey) {
+	ConnectionDecrypterImpl(InputStream in, byte[] encryptedIv, Cipher ivCipher,
+			Cipher frameCipher, SecretKey ivKey, SecretKey frameKey) {
 		super(in);
 		this.frameCipher = frameCipher;
 		this.frameKey = frameKey;
+		// Decrypt the IV
+		try {
+			ivCipher.init(Cipher.DECRYPT_MODE, ivKey);
+			iv = ivCipher.doFinal(encryptedIv);
+		} catch(BadPaddingException badCipher) {
+			throw new IllegalArgumentException(badCipher);
+		} catch(IllegalBlockSizeException badCipher) {
+			throw new IllegalArgumentException(badCipher);
+		} catch(InvalidKeyException badKey) {
+			throw new IllegalArgumentException(badKey);
+		}
+		if(iv.length != IV_LENGTH) throw new IllegalArgumentException();
 		buf = new byte[IV_LENGTH];
-		iv = IvEncoder.encodeIv(initiator, transportId, connection);
 	}
 
 	public InputStream getInputStream() {
diff --git a/components/net/sf/briar/transport/ConnectionEncrypter.java b/components/net/sf/briar/transport/ConnectionEncrypter.java
index 474c46fa9b3402ec8a623bfd648f9825b8601645..304cc1672b1e5155c222bfda553f64ff2d04771e 100644
--- a/components/net/sf/briar/transport/ConnectionEncrypter.java
+++ b/components/net/sf/briar/transport/ConnectionEncrypter.java
@@ -13,5 +13,5 @@ interface ConnectionEncrypter {
 	void writeMac(byte[] mac) throws IOException;
 
 	/** Returns the maximum number of bytes that can be written. */
-	long getCapacity();
+	long getRemainingCapacity();
 }
diff --git a/components/net/sf/briar/transport/ConnectionEncrypterImpl.java b/components/net/sf/briar/transport/ConnectionEncrypterImpl.java
index 1d8921236ea0f7778761137d6e01de6c427c321a..5c8c473ad4ed64f3483b836bf91a26e15584777d 100644
--- a/components/net/sf/briar/transport/ConnectionEncrypterImpl.java
+++ b/components/net/sf/briar/transport/ConnectionEncrypterImpl.java
@@ -18,29 +18,34 @@ import javax.crypto.spec.IvParameterSpec;
 class ConnectionEncrypterImpl extends FilterOutputStream
 implements ConnectionEncrypter {
 
-	private final Cipher ivCipher, frameCipher;
+	private final Cipher frameCipher;
 	private final SecretKey frameKey;
-	private final byte[] iv;
+	private final byte[] iv, encryptedIv;
 
 	private long capacity, frame = 0L;
 	private boolean ivWritten = false, betweenFrames = false;
 
-	ConnectionEncrypterImpl(OutputStream out, long capacity, boolean initiator,
-			int transportId, long connection, Cipher ivCipher,
-			Cipher frameCipher, SecretKey ivKey, SecretKey frameKey) {
+	ConnectionEncrypterImpl(OutputStream out, long capacity, byte[] iv,
+			Cipher ivCipher, Cipher frameCipher, SecretKey ivKey,
+			SecretKey frameKey) {
 		super(out);
-		this.ivCipher = ivCipher;
+		this.capacity = capacity;
+		this.iv = iv;
 		this.frameCipher = frameCipher;
 		this.frameKey = frameKey;
-		iv = IvEncoder.encodeIv(initiator, transportId, connection);
+		// Encrypt the IV
 		try {
 			ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
+			encryptedIv = ivCipher.doFinal(iv);
+		} catch(BadPaddingException badCipher) {
+			throw new IllegalArgumentException(badCipher);
+		} catch(IllegalBlockSizeException badCipher) {
+			throw new IllegalArgumentException(badCipher);
 		} catch(InvalidKeyException badKey) {
 			throw new IllegalArgumentException(badKey);
 		}
-		if(ivCipher.getOutputSize(IV_LENGTH) != IV_LENGTH)
+		if(encryptedIv.length != IV_LENGTH)
 			throw new IllegalArgumentException();
-		this.capacity = capacity;
 	}
 
 	public OutputStream getOutputStream() {
@@ -60,7 +65,7 @@ implements ConnectionEncrypter {
 		betweenFrames = true;
 	}
 
-	public long getCapacity() {
+	public long getRemainingCapacity() {
 		return capacity;
 	}
 
@@ -90,14 +95,8 @@ implements ConnectionEncrypter {
 	private void writeIv() throws IOException {
 		assert !ivWritten;
 		assert !betweenFrames;
-		try {
-			out.write(ivCipher.doFinal(iv));
-		} catch(BadPaddingException badCipher) {
-			throw new RuntimeException(badCipher);
-		} catch(IllegalBlockSizeException badCipher) {
-			throw new RuntimeException(badCipher);
-		}
-		capacity -= iv.length;
+		out.write(encryptedIv);
+		capacity -= encryptedIv.length;
 		ivWritten = true;
 		betweenFrames = true;
 	}
diff --git a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java
index 7629e025622c0e3b832b3244d161c6cb2b8ba207..df592f7602c3228faa1dc605d61cc700957d7462 100644
--- a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java
+++ b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java
@@ -1,7 +1,6 @@
 package net.sf.briar.transport;
 
 import java.io.InputStream;
-import java.security.InvalidKeyException;
 
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
@@ -23,19 +22,17 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
 	}
 
 	public ConnectionReader createConnectionReader(InputStream in,
-			boolean initiator, int transportId, long connection,
-			byte[] secret) {
-		SecretKey macKey = crypto.deriveIncomingMacKey(secret);
-		SecretKey frameKey = crypto.deriveIncomingFrameKey(secret);
+			byte[] encryptedIv, byte[] secret) {
+		// Create the decrypter
+		Cipher ivCipher = crypto.getIvCipher();
 		Cipher frameCipher = crypto.getFrameCipher();
-		Mac mac = crypto.getMac();
-		try {
-			mac.init(macKey);
-		} catch(InvalidKeyException e) {
-			throw new IllegalArgumentException(e);
-		}
+		SecretKey ivKey = crypto.deriveIncomingIvKey(secret);
+		SecretKey frameKey = crypto.deriveIncomingFrameKey(secret);
 		ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in,
-				initiator, transportId, connection, frameCipher, frameKey);
-		return new ConnectionReaderImpl(decrypter, mac);
+				encryptedIv, ivCipher, frameCipher, ivKey, frameKey);
+		// Create the reader
+		Mac mac = crypto.getMac();
+		SecretKey macKey = crypto.deriveIncomingMacKey(secret);
+		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 e30e629e0d6b0554141c0a19fd48faef271d1a99..a41559e8d3d9f50f69bc52b781552fc27f3002eb 100644
--- a/components/net/sf/briar/transport/ConnectionReaderImpl.java
+++ b/components/net/sf/briar/transport/ConnectionReaderImpl.java
@@ -7,9 +7,11 @@ import java.io.EOFException;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.security.InvalidKeyException;
 import java.util.Arrays;
 
 import javax.crypto.Mac;
+import javax.crypto.SecretKey;
 
 import net.sf.briar.api.FormatException;
 import net.sf.briar.api.transport.ConnectionReader;
@@ -27,10 +29,17 @@ implements ConnectionReader {
 	private int payloadOff = 0, payloadLen = 0;
 	private boolean betweenFrames = true;
 
-	ConnectionReaderImpl(ConnectionDecrypter decrypter, Mac mac) {
+	ConnectionReaderImpl(ConnectionDecrypter decrypter, Mac mac,
+			SecretKey macKey) {
 		super(decrypter.getInputStream());
 		this.decrypter = decrypter;
 		this.mac = mac;
+		// Initialise the MAC
+		try {
+			mac.init(macKey);
+		} catch(InvalidKeyException e) {
+			throw new IllegalArgumentException(e);
+		}
 		maxPayloadLength = MAX_FRAME_LENGTH - 4 - mac.getMacLength();
 		header = new byte[4];
 		payload = new byte[maxPayloadLength];
diff --git a/components/net/sf/briar/transport/ConnectionRecogniserFactoryImpl.java b/components/net/sf/briar/transport/ConnectionRecogniserFactoryImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a404399710f7b80cc71085db255dd63b79abdde
--- /dev/null
+++ b/components/net/sf/briar/transport/ConnectionRecogniserFactoryImpl.java
@@ -0,0 +1,25 @@
+package net.sf.briar.transport;
+
+import net.sf.briar.api.crypto.CryptoComponent;
+import net.sf.briar.api.db.DatabaseComponent;
+import net.sf.briar.api.transport.ConnectionRecogniser;
+import net.sf.briar.api.transport.ConnectionRecogniserFactory;
+
+import com.google.inject.Inject;
+
+class ConnectionRecogniserFactoryImpl implements ConnectionRecogniserFactory {
+
+	private final CryptoComponent crypto;
+	private final DatabaseComponent db;
+
+	@Inject
+	ConnectionRecogniserFactoryImpl(CryptoComponent crypto,
+			DatabaseComponent db) {
+		this.crypto = crypto;
+		this.db = db;
+	}
+
+	public ConnectionRecogniser createConnectionRecogniser(int transportId) {
+		return new ConnectionRecogniserImpl(transportId, crypto, db);
+	}
+}
diff --git a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
index 50b835d5c07df2a869c2aef2f441eab4fda78902..d5ca4310db1c812adf070533991472006f9a4fd3 100644
--- a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
+++ b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
@@ -1,7 +1,6 @@
 package net.sf.briar.transport;
 
 import java.io.OutputStream;
-import java.security.InvalidKeyException;
 
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
@@ -25,20 +24,17 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
 	public ConnectionWriter createConnectionWriter(OutputStream out,
 			long capacity, boolean initiator, int transportId, long connection,
 			byte[] secret) {
-		SecretKey macKey = crypto.deriveOutgoingMacKey(secret);
-		SecretKey ivKey = crypto.deriveOutgoingIvKey(secret);
-		SecretKey frameKey = crypto.deriveOutgoingFrameKey(secret);
+		// Create the encrypter
 		Cipher ivCipher = crypto.getIvCipher();
 		Cipher frameCipher = crypto.getFrameCipher();
-		Mac mac = crypto.getMac();
-		try {
-			mac.init(macKey);
-		} catch(InvalidKeyException badKey) {
-			throw new IllegalArgumentException(badKey);
-		}
+		SecretKey ivKey = crypto.deriveOutgoingIvKey(secret);
+		SecretKey frameKey = crypto.deriveOutgoingFrameKey(secret);
+		byte[] iv = IvEncoder.encodeIv(initiator, transportId, connection);
 		ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
-				capacity, initiator, transportId, connection, ivCipher,
-				frameCipher, ivKey, frameKey);
-		return new ConnectionWriterImpl(encrypter, mac);
+				capacity, iv, ivCipher, frameCipher, ivKey, frameKey);
+		// Create the writer
+		Mac mac = crypto.getMac();
+		SecretKey macKey = crypto.deriveOutgoingMacKey(secret);
+		return new ConnectionWriterImpl(encrypter, mac, macKey);
 	}
 }
diff --git a/components/net/sf/briar/transport/ConnectionWriterImpl.java b/components/net/sf/briar/transport/ConnectionWriterImpl.java
index a4bedfda63402d2a13c3579387fe1aa4e2c99ad7..62dc17fcfa5d3c39b0cc81a9a7472e9d046af1d8 100644
--- a/components/net/sf/briar/transport/ConnectionWriterImpl.java
+++ b/components/net/sf/briar/transport/ConnectionWriterImpl.java
@@ -7,8 +7,10 @@ import java.io.ByteArrayOutputStream;
 import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.security.InvalidKeyException;
 
 import javax.crypto.Mac;
+import javax.crypto.SecretKey;
 
 import net.sf.briar.api.transport.ConnectionWriter;
 import net.sf.briar.util.ByteUtils;
@@ -28,10 +30,17 @@ implements ConnectionWriter {
 
 	protected long frame = 0L;
 
-	ConnectionWriterImpl(ConnectionEncrypter encrypter, Mac mac) {
+	ConnectionWriterImpl(ConnectionEncrypter encrypter, Mac mac,
+			SecretKey macKey) {
 		super(encrypter.getOutputStream());
 		this.encrypter = encrypter;
 		this.mac = mac;
+		// Initialise the MAC
+		try {
+			mac.init(macKey);
+		} catch(InvalidKeyException badKey) {
+			throw new IllegalArgumentException(badKey);
+		}
 		maxPayloadLength = MAX_FRAME_LENGTH - 4 - mac.getMacLength();
 		buf = new ByteArrayOutputStream(maxPayloadLength);
 		header = new byte[4];
@@ -41,8 +50,8 @@ implements ConnectionWriter {
 		return this;
 	}
 
-	public long getCapacity() {
-		long capacity = encrypter.getCapacity();
+	public long getRemainingCapacity() {
+		long capacity = encrypter.getRemainingCapacity();
 		// If there's any data buffered, subtract it and its auth overhead
 		int overheadPerFrame = header.length + mac.getMacLength();
 		if(buf.size() > 0) capacity -= buf.size() + overheadPerFrame;
diff --git a/components/net/sf/briar/transport/PaddedConnectionWriter.java b/components/net/sf/briar/transport/PaddedConnectionWriter.java
index ebab1f3eae286b99e7d2cd60f59d84d291efb8e1..d93a922c4fc183019c530c4a059b8f18aff82265 100644
--- a/components/net/sf/briar/transport/PaddedConnectionWriter.java
+++ b/components/net/sf/briar/transport/PaddedConnectionWriter.java
@@ -5,6 +5,7 @@ import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 import java.io.IOException;
 
 import javax.crypto.Mac;
+import javax.crypto.SecretKey;
 
 import net.sf.briar.util.ByteUtils;
 
@@ -21,8 +22,9 @@ class PaddedConnectionWriter extends ConnectionWriterImpl {
 	private boolean closed = false;
 	private IOException exception = null;
 
-	PaddedConnectionWriter(ConnectionEncrypter encrypter, Mac mac) {
-		super(encrypter, mac);
+	PaddedConnectionWriter(ConnectionEncrypter encrypter, Mac mac,
+			SecretKey macKey) {
+		super(encrypter, mac, macKey);
 		padding = new byte[maxPayloadLength];
 	}
 
diff --git a/components/net/sf/briar/transport/TransportModule.java b/components/net/sf/briar/transport/TransportModule.java
index d952d534ec6223b77b09f7a97b0e2c2770e4ea60..5d7b4162cc64d57cf83b5d5b788e97db52fd1dee 100644
--- a/components/net/sf/briar/transport/TransportModule.java
+++ b/components/net/sf/briar/transport/TransportModule.java
@@ -1,6 +1,7 @@
 package net.sf.briar.transport;
 
 import net.sf.briar.api.transport.ConnectionReaderFactory;
+import net.sf.briar.api.transport.ConnectionRecogniserFactory;
 import net.sf.briar.api.transport.ConnectionWindowFactory;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
 
@@ -12,6 +13,8 @@ public class TransportModule extends AbstractModule {
 	protected void configure() {
 		bind(ConnectionReaderFactory.class).to(
 				ConnectionReaderFactoryImpl.class);
+		bind(ConnectionRecogniserFactory.class).to(
+				ConnectionRecogniserFactoryImpl.class);
 		bind(ConnectionWindowFactory.class).to(
 				ConnectionWindowFactoryImpl.class);
 		bind(ConnectionWriterFactory.class).to(
diff --git a/components/net/sf/briar/transport/batch/OutgoingBatchConnection.java b/components/net/sf/briar/transport/batch/OutgoingBatchConnection.java
index e3cdb16aed72388e0f2619635ecddd038ff01a78..ab154e78fe621725151623b0924172568f079718 100644
--- a/components/net/sf/briar/transport/batch/OutgoingBatchConnection.java
+++ b/components/net/sf/briar/transport/batch/OutgoingBatchConnection.java
@@ -33,13 +33,13 @@ class OutgoingBatchConnection {
 	void write() throws DbException, IOException {
 		OutputStream out = conn.getOutputStream();
 		// There should be enough space for a packet
-		long capacity = conn.getCapacity();
+		long capacity = conn.getRemainingCapacity();
 		if(capacity < MAX_PACKET_LENGTH) throw new IOException();
 		// Write a transport update
 		TransportWriter t = protoFactory.createTransportWriter(out);
 		db.generateTransportUpdate(contactId, t);
 		// If there's space, write a subscription update
-		capacity = conn.getCapacity();
+		capacity = conn.getRemainingCapacity();
 		if(capacity >= MAX_PACKET_LENGTH) {
 			SubscriptionWriter s = protoFactory.createSubscriptionWriter(out);
 			db.generateSubscriptionUpdate(contactId, s);
@@ -47,14 +47,14 @@ class OutgoingBatchConnection {
 		// Write acks until you can't write acks no more
 		AckWriter a = protoFactory.createAckWriter(out);
 		do {
-			capacity = conn.getCapacity();
+			capacity = conn.getRemainingCapacity();
 			int max = (int) Math.min(MAX_PACKET_LENGTH, capacity);
 			a.setMaxPacketLength(max);
 		} while(db.generateAck(contactId, a));
 		// Write batches until you can't write batches no more
 		BatchWriter b = protoFactory.createBatchWriter(out);
 		do {
-			capacity = conn.getCapacity();
+			capacity = conn.getRemainingCapacity();
 			int max = (int) Math.min(MAX_PACKET_LENGTH, capacity);
 			b.setMaxPacketLength(max);
 		} while(db.generateBatch(contactId, b));
diff --git a/test/net/sf/briar/FileReadWriteTest.java b/test/net/sf/briar/FileReadWriteTest.java
index 0b1e5878f1ee85c2095bb6145220ee94cd7ab182..a624fb2bcb973b78b14714d92bf1bf463ab2e810 100644
--- a/test/net/sf/briar/FileReadWriteTest.java
+++ b/test/net/sf/briar/FileReadWriteTest.java
@@ -45,6 +45,7 @@ import net.sf.briar.api.transport.ConnectionReaderFactory;
 import net.sf.briar.api.transport.ConnectionWriter;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
 import net.sf.briar.crypto.CryptoModule;
+import net.sf.briar.db.DatabaseModule;
 import net.sf.briar.protocol.ProtocolModule;
 import net.sf.briar.protocol.writers.ProtocolWritersModule;
 import net.sf.briar.serial.SerialModule;
@@ -83,8 +84,9 @@ public class FileReadWriteTest extends TestCase {
 	public FileReadWriteTest() throws Exception {
 		super();
 		Injector i = Guice.createInjector(new CryptoModule(),
-				new ProtocolModule(), new ProtocolWritersModule(),
-				new SerialModule(), new TransportModule());
+				new DatabaseModule(), new ProtocolModule(),
+				new ProtocolWritersModule(), new SerialModule(),
+				new TestDatabaseModule(testDir), new TransportModule());
 		connectionReaderFactory = i.getInstance(ConnectionReaderFactory.class);
 		connectionWriterFactory = i.getInstance(ConnectionWriterFactory.class);
 		protocolReaderFactory = i.getInstance(ProtocolReaderFactory.class);
@@ -191,7 +193,7 @@ public class FileReadWriteTest extends TestCase {
 		assertEquals(16, offset);
 		// Use Bob's secret for reading
 		ConnectionReader r = connectionReaderFactory.createConnectionReader(in,
-				true, transportId, connection, bobSecret);
+				iv, bobSecret);
 		in = r.getInputStream();
 		ProtocolReader protocolReader =
 			protocolReaderFactory.createProtocolReader(in);
diff --git a/test/net/sf/briar/TestDatabaseModule.java b/test/net/sf/briar/TestDatabaseModule.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d2b5b128e3b38bea955431771e63c4af454691e
--- /dev/null
+++ b/test/net/sf/briar/TestDatabaseModule.java
@@ -0,0 +1,34 @@
+package net.sf.briar;
+
+import java.io.File;
+
+import net.sf.briar.api.crypto.Password;
+import net.sf.briar.api.db.DatabaseDirectory;
+import net.sf.briar.api.db.DatabaseMaxSize;
+import net.sf.briar.api.db.DatabasePassword;
+
+import com.google.inject.AbstractModule;
+
+public class TestDatabaseModule extends AbstractModule {
+
+	private final File dir;
+	private final Password password;
+
+	public TestDatabaseModule(File dir) {
+		this.dir = dir;
+		this.password = new Password() {
+			public char[] getPassword() {
+				return "foo bar".toCharArray();
+			}
+		};
+	}
+
+	@Override
+	protected void configure() {
+		bind(File.class).annotatedWith(DatabaseDirectory.class).toInstance(dir);
+		bind(Password.class).annotatedWith(
+				DatabasePassword.class).toInstance(password);
+		bind(long.class).annotatedWith(
+				DatabaseMaxSize.class).toInstance(Long.MAX_VALUE);
+	}
+}
diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java
index 131fd465cfba34455d62b7689d9e002571f18d6a..5b545514e9c244da8a69cb40f2d0e65f6373a37f 100644
--- a/test/net/sf/briar/db/H2DatabaseTest.java
+++ b/test/net/sf/briar/db/H2DatabaseTest.java
@@ -13,6 +13,7 @@ import java.util.TreeMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import junit.framework.TestCase;
+import net.sf.briar.TestDatabaseModule;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.Rating;
@@ -71,8 +72,8 @@ public class H2DatabaseTest extends TestCase {
 	public H2DatabaseTest() throws Exception {
 		super();
 		Injector i = Guice.createInjector(new CryptoModule(),
-				new ProtocolModule(), new SerialModule(),
-				new TransportModule());
+				new DatabaseModule(), new ProtocolModule(), new SerialModule(),
+				new TransportModule(), new TestDatabaseModule(testDir));
 		connectionWindowFactory = i.getInstance(ConnectionWindowFactory.class);
 		groupFactory = i.getInstance(GroupFactory.class);
 		authorId = new AuthorId(TestUtils.getRandomId());
diff --git a/test/net/sf/briar/transport/ConnectionDecrypterImplTest.java b/test/net/sf/briar/transport/ConnectionDecrypterImplTest.java
index f785d681227ced75f78eb9b950ac170877ef86f8..62acd4369963245ebab51bcf2e0aeb582c36eb17 100644
--- a/test/net/sf/briar/transport/ConnectionDecrypterImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionDecrypterImplTest.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
+
 import java.io.ByteArrayInputStream;
 import java.util.Arrays;
 
@@ -22,8 +24,8 @@ public class ConnectionDecrypterImplTest extends TestCase {
 
 	private static final int MAC_LENGTH = 32;
 
-	private final Cipher frameCipher;
-	private final SecretKey frameKey;
+	private final Cipher ivCipher, frameCipher;
+	private final SecretKey ivKey, frameKey;
 	private final int transportId = 1234;
 	private final long connection = 12345L;
 
@@ -31,23 +33,12 @@ public class ConnectionDecrypterImplTest extends TestCase {
 		super();
 		Injector i = Guice.createInjector(new CryptoModule());
 		CryptoComponent crypto = i.getInstance(CryptoComponent.class);
+		ivCipher = crypto.getIvCipher();
 		frameCipher = crypto.getFrameCipher();
+		ivKey = crypto.generateSecretKey();
 		frameKey = crypto.generateSecretKey();
 	}
 
-	@Test
-	public void testSingleByteFrame() throws Exception {
-		// Create a fake ciphertext frame: one byte plus a MAC
-		byte[] ciphertext = new byte[1 + MAC_LENGTH];
-		ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
-		// Check that one byte plus a MAC can be read
-		ConnectionDecrypter d = new ConnectionDecrypterImpl(in, true,
-				transportId, connection, frameCipher, frameKey);
-		assertFalse(d.getInputStream().read() == -1);
-		d.readMac(new byte[MAC_LENGTH]);
-		assertTrue(d.getInputStream().read() == -1);
-	}
-
 	@Test
 	public void testInitiatorDecryption() throws Exception {
 		testDecryption(true);
@@ -59,34 +50,48 @@ public class ConnectionDecrypterImplTest extends TestCase {
 	}
 
 	private void testDecryption(boolean initiator) throws Exception {
+		// Calculate the plaintext and ciphertext for the IV
+		byte[] iv = IvEncoder.encodeIv(initiator, transportId, connection);
+		ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
+		byte[] encryptedIv  = ivCipher.doFinal(iv);
+		assertEquals(IV_LENGTH, encryptedIv.length);
 		// Calculate the expected plaintext for the first frame
 		byte[] ciphertext = new byte[123];
-		byte[] iv = IvEncoder.encodeIv(initiator, transportId, connection);
+		byte[] ciphertextMac = new byte[MAC_LENGTH];
 		IvParameterSpec ivSpec = new IvParameterSpec(iv);
 		frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
-		byte[] plaintext = frameCipher.doFinal(ciphertext);
+		byte[] plaintext = new byte[ciphertext.length + ciphertextMac.length];
+		int offset = frameCipher.update(ciphertext, 0, ciphertext.length,
+				plaintext);
+		frameCipher.doFinal(ciphertextMac, 0, ciphertextMac.length, plaintext,
+				offset);
 		// Calculate the expected plaintext for the second frame
 		byte[] ciphertext1 = new byte[1234];
 		IvEncoder.updateIv(iv, 1L);
 		ivSpec = new IvParameterSpec(iv);
 		frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
-		byte[] plaintext1 = frameCipher.doFinal(ciphertext1);
-		assertEquals(ciphertext1.length, plaintext1.length);
+		byte[] plaintext1 = new byte[ciphertext1.length + ciphertextMac.length];
+		offset = frameCipher.update(ciphertext1, 0, ciphertext1.length,
+				plaintext1);
+		frameCipher.doFinal(ciphertextMac, 0, ciphertextMac.length, plaintext1,
+				offset);
 		// Concatenate the ciphertexts
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		out.write(ciphertext);
+		out.write(ciphertextMac);
 		out.write(ciphertext1);
+		out.write(ciphertextMac);
 		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
 		// Use a ConnectionDecrypter to decrypt the ciphertext
-		ConnectionDecrypter d = new ConnectionDecrypterImpl(in, initiator,
-				transportId, connection, frameCipher, frameKey);
+		ConnectionDecrypter d = new ConnectionDecrypterImpl(in, encryptedIv,
+				ivCipher, frameCipher, ivKey, frameKey);
 		// First frame
-		byte[] decrypted = new byte[plaintext.length - MAC_LENGTH];
+		byte[] decrypted = new byte[ciphertext.length];
 		TestUtils.readFully(d.getInputStream(), decrypted);
 		byte[] decryptedMac = new byte[MAC_LENGTH];
 		d.readMac(decryptedMac);
 		// Second frame
-		byte[] decrypted1 = new byte[plaintext1.length - MAC_LENGTH];
+		byte[] decrypted1 = new byte[ciphertext1.length];
 		TestUtils.readFully(d.getInputStream(), decrypted1);
 		byte[] decryptedMac1 = new byte[MAC_LENGTH];
 		d.readMac(decryptedMac1);
diff --git a/test/net/sf/briar/transport/ConnectionEncrypterImplTest.java b/test/net/sf/briar/transport/ConnectionEncrypterImplTest.java
index b266b8f2d99e3138cfccfd5993f293a6dc03100d..49aa4e31fc1190496481f5a68636dd4407671fc2 100644
--- a/test/net/sf/briar/transport/ConnectionEncrypterImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionEncrypterImplTest.java
@@ -37,19 +37,6 @@ public class ConnectionEncrypterImplTest extends TestCase {
 		frameKey = crypto.generateSecretKey();
 	}
 
-	@Test
-	public void testSingleByteFrame() throws Exception {
-		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		ConnectionEncrypter e = new ConnectionEncrypterImpl(out, Long.MAX_VALUE,
-				true, transportId, connection, ivCipher, frameCipher, ivKey,
-				frameKey);
-		e.getOutputStream().write((byte) 0);
-		e.writeMac(new byte[MAC_LENGTH]);
-		byte[] ciphertext = out.toByteArray();
-		assertEquals(IV_LENGTH + 1 + MAC_LENGTH, ciphertext.length);
-		assertEquals(Long.MAX_VALUE - ciphertext.length, e.getCapacity());
-	}
-
 	@Test
 	public void testInitiatorEncryption() throws Exception {
 		testEncryption(true);
@@ -63,7 +50,6 @@ public class ConnectionEncrypterImplTest extends TestCase {
 	private void testEncryption(boolean initiator) throws Exception {
 		// Calculate the expected ciphertext for the IV
 		byte[] iv = IvEncoder.encodeIv(initiator, transportId, connection);
-		assertEquals(IV_LENGTH, iv.length);
 		ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
 		byte[] encryptedIv = ivCipher.doFinal(iv);
 		assertEquals(IV_LENGTH, encryptedIv.length);
@@ -95,9 +81,9 @@ public class ConnectionEncrypterImplTest extends TestCase {
 		byte[] expected = out.toByteArray();
 		// Use a ConnectionEncrypter to encrypt the plaintext
 		out.reset();
+		iv = IvEncoder.encodeIv(initiator, transportId, connection);
 		ConnectionEncrypter e = new ConnectionEncrypterImpl(out, Long.MAX_VALUE,
-				initiator, transportId, connection, ivCipher, frameCipher,
-				ivKey, frameKey);
+				iv, ivCipher, frameCipher, ivKey, frameKey);
 		e.getOutputStream().write(plaintext);
 		e.writeMac(plaintextMac);
 		e.getOutputStream().write(plaintext1);
@@ -105,6 +91,6 @@ public class ConnectionEncrypterImplTest extends TestCase {
 		byte[] actual = out.toByteArray();
 		// Check that the actual ciphertext matches the expected ciphertext
 		assertTrue(Arrays.equals(expected, actual));
-		assertEquals(Long.MAX_VALUE - actual.length, e.getCapacity());
+		assertEquals(Long.MAX_VALUE - actual.length, e.getRemainingCapacity());
 	}
 }
diff --git a/test/net/sf/briar/transport/ConnectionReaderImplTest.java b/test/net/sf/briar/transport/ConnectionReaderImplTest.java
index 8be9dd70af99098c6761a4f87ca373099b7d8f06..30f40fbb944162e76d6f7e3c348e55dc823b6bf0 100644
--- a/test/net/sf/briar/transport/ConnectionReaderImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionReaderImplTest.java
@@ -24,12 +24,13 @@ public class ConnectionReaderImplTest extends TransportTest {
 		byte[] frame = new byte[headerLength + payloadLength + macLength];
 		writeHeader(frame, payloadLength, 0);
 		// Calculate the MAC
+		mac.init(macKey);
 		mac.update(frame, 0, headerLength + payloadLength);
 		mac.doFinal(frame, headerLength + payloadLength);
 		// Read the frame
 		ByteArrayInputStream in = new ByteArrayInputStream(frame);
 		ConnectionDecrypter d = new NullConnectionDecrypter(in);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac);
+		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
 		try {
 			r.getInputStream().read();
 			fail();
@@ -42,12 +43,13 @@ public class ConnectionReaderImplTest extends TransportTest {
 		byte[] frame = new byte[headerLength + payloadLength + macLength];
 		writeHeader(frame, payloadLength, 0);
 		// Calculate the MAC
+		mac.init(macKey);
 		mac.update(frame, 0, headerLength + payloadLength);
 		mac.doFinal(frame, headerLength + payloadLength);
 		// Read the frame
 		ByteArrayInputStream in = new ByteArrayInputStream(frame);
 		ConnectionDecrypter d = new NullConnectionDecrypter(in);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac);
+		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
 		// There should be one byte available before EOF
 		assertEquals(0, r.getInputStream().read());
 		assertEquals(-1, r.getInputStream().read());
@@ -58,6 +60,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 		// First frame: max payload length
 		byte[] frame = new byte[MAX_FRAME_LENGTH];
 		writeHeader(frame, maxPayloadLength, 0);
+		mac.init(macKey);
 		mac.update(frame, 0, headerLength + maxPayloadLength);
 		mac.doFinal(frame, headerLength + maxPayloadLength);
 		// Second frame: max payload length plus one
@@ -72,7 +75,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 		// Read the first frame
 		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
 		ConnectionDecrypter d = new NullConnectionDecrypter(in);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac);
+		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
 		byte[] read = new byte[maxPayloadLength];
 		TestUtils.readFully(r.getInputStream(), read);
 		// Try to read the second frame
@@ -89,6 +92,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 		// First frame: max payload length, including padding
 		byte[] frame = new byte[MAX_FRAME_LENGTH];
 		writeHeader(frame, maxPayloadLength - paddingLength, paddingLength);
+		mac.init(macKey);
 		mac.update(frame, 0, headerLength + maxPayloadLength);
 		mac.doFinal(frame, headerLength + maxPayloadLength);
 		// Second frame: max payload length plus one, including padding
@@ -104,7 +108,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 		// Read the first frame
 		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
 		ConnectionDecrypter d = new NullConnectionDecrypter(in);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac);
+		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
 		byte[] read = new byte[maxPayloadLength - paddingLength];
 		TestUtils.readFully(r.getInputStream(), read);
 		// Try to read the second frame
@@ -120,6 +124,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 		// First frame: 123-byte payload
 		byte[] frame = new byte[headerLength + 123 + mac.getMacLength()];
 		writeHeader(frame, 123, 0);
+		mac.init(macKey);
 		mac.update(frame, 0, headerLength + 123);
 		mac.doFinal(frame, headerLength + 123);
 		// Second frame: 1234-byte payload
@@ -134,7 +139,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 		// Read the frames
 		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
 		ConnectionDecrypter d = new NullConnectionDecrypter(in);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac);
+		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
 		byte[] read = new byte[123];
 		TestUtils.readFully(r.getInputStream(), read);
 		assertTrue(Arrays.equals(new byte[123], read));
@@ -149,6 +154,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 		byte[] frame = new byte[headerLength + payloadLength + macLength];
 		writeHeader(frame, payloadLength, 0);
 		// Calculate the MAC
+		mac.init(macKey);
 		mac.update(frame, 0, headerLength + payloadLength);
 		mac.doFinal(frame, headerLength + payloadLength);
 		// Modify the payload
@@ -156,7 +162,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 		// Try to read the frame - not a single byte should be read
 		ByteArrayInputStream in = new ByteArrayInputStream(frame);
 		ConnectionDecrypter d = new NullConnectionDecrypter(in);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac);
+		ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
 		try {
 			r.getInputStream().read();
 			fail();
@@ -169,6 +175,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 		byte[] frame = new byte[headerLength + payloadLength + macLength];
 		writeHeader(frame, payloadLength, 0);
 		// Calculate the MAC
+		mac.init(macKey);
 		mac.update(frame, 0, headerLength + payloadLength);
 		mac.doFinal(frame, headerLength + payloadLength);
 		// Modify the MAC
@@ -176,7 +183,7 @@ public class ConnectionReaderImplTest extends TransportTest {
 		// Try to read the frame - not a single byte should be read
 		ByteArrayInputStream in = new ByteArrayInputStream(frame);
 		ConnectionDecrypter d = new NullConnectionDecrypter(in);
-		ConnectionReader r = new ConnectionReaderImpl(d, mac);
+		ConnectionReader r = new ConnectionReaderImpl(d, 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 985c962b0f051ba80913a587a792265be3ca4cd3..838d248e6243490815f48ba964ebd436104f99ae 100644
--- a/test/net/sf/briar/transport/ConnectionWriterImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionWriterImplTest.java
@@ -20,7 +20,7 @@ public class ConnectionWriterImplTest extends TransportTest {
 	public void testFlushWithoutWriteProducesNothing() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter e = new NullConnectionEncrypter(out);
-		ConnectionWriter w = new ConnectionWriterImpl(e, mac);
+		ConnectionWriter w = new ConnectionWriterImpl(e, mac, macKey);
 		w.getOutputStream().flush();
 		w.getOutputStream().flush();
 		w.getOutputStream().flush();
@@ -33,12 +33,13 @@ public class ConnectionWriterImplTest extends TransportTest {
 		byte[] frame = new byte[headerLength + payloadLength + macLength];
 		writeHeader(frame, payloadLength, 0);
 		// Calculate the MAC
+		mac.init(macKey);
 		mac.update(frame, 0, headerLength + payloadLength);
 		mac.doFinal(frame, headerLength + payloadLength);
 		// Check that the ConnectionWriter gets the same results
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter e = new NullConnectionEncrypter(out);
-		ConnectionWriter w = new ConnectionWriterImpl(e, mac);
+		ConnectionWriter w = new ConnectionWriterImpl(e, mac, macKey);
 		w.getOutputStream().write(0);
 		w.getOutputStream().flush();
 		assertTrue(Arrays.equals(frame, out.toByteArray()));
@@ -48,7 +49,7 @@ public class ConnectionWriterImplTest extends TransportTest {
 	public void testWriteByteToMaxLengthWritesFrame() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter e = new NullConnectionEncrypter(out);
-		ConnectionWriter w = new ConnectionWriterImpl(e, mac);
+		ConnectionWriter w = new ConnectionWriterImpl(e, 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);
@@ -62,7 +63,7 @@ public class ConnectionWriterImplTest extends TransportTest {
 	public void testWriteArrayToMaxLengthWritesFrame() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter e = new NullConnectionEncrypter(out);
-		ConnectionWriter w = new ConnectionWriterImpl(e, mac);
+		ConnectionWriter w = new ConnectionWriterImpl(e, mac, macKey);
 		OutputStream out1 = w.getOutputStream();
 		// The first maxPayloadLength - 1 bytes should be buffered
 		out1.write(new byte[maxPayloadLength - 1]);
@@ -77,6 +78,7 @@ public class ConnectionWriterImplTest extends TransportTest {
 		// First frame: 123-byte payload
 		byte[] frame = new byte[headerLength + 123 + macLength];
 		writeHeader(frame, 123, 0);
+		mac.init(macKey);
 		mac.update(frame, 0, headerLength + 123);
 		mac.doFinal(frame, headerLength + 123);
 		// Second frame: 1234-byte payload
@@ -92,7 +94,7 @@ public class ConnectionWriterImplTest extends TransportTest {
 		// Check that the ConnectionWriter gets the same results
 		out.reset();
 		ConnectionEncrypter e = new NullConnectionEncrypter(out);
-		ConnectionWriter w = new ConnectionWriterImpl(e, mac);
+		ConnectionWriter w = new ConnectionWriterImpl(e, 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/ConnectionWriterTest.java b/test/net/sf/briar/transport/ConnectionWriterTest.java
index 91b60d61333fdecaf8fde7d3832b6d09bcd9f3ee..ba11c37be5a3a2343ceba33c9f8fa049a1052a30 100644
--- a/test/net/sf/briar/transport/ConnectionWriterTest.java
+++ b/test/net/sf/briar/transport/ConnectionWriterTest.java
@@ -4,11 +4,16 @@ import static net.sf.briar.api.protocol.ProtocolConstants.MAX_PACKET_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MIN_CONNECTION_LENGTH;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 
 import junit.framework.TestCase;
+import net.sf.briar.TestDatabaseModule;
 import net.sf.briar.api.transport.ConnectionWriter;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
 import net.sf.briar.crypto.CryptoModule;
+import net.sf.briar.db.DatabaseModule;
+import net.sf.briar.protocol.ProtocolModule;
+import net.sf.briar.serial.SerialModule;
 
 import org.junit.Test;
 
@@ -25,7 +30,8 @@ public class ConnectionWriterTest extends TestCase {
 	public ConnectionWriterTest() throws Exception {
 		super();
 		Injector i = Guice.createInjector(new CryptoModule(),
-				new TransportModule());
+				new DatabaseModule(), new ProtocolModule(), new SerialModule(),
+				new TestDatabaseModule(new File(".")), new TransportModule());
 		connectionWriterFactory = i.getInstance(ConnectionWriterFactory.class);
 	}
 
@@ -36,7 +42,7 @@ public class ConnectionWriterTest extends TestCase {
 		ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out,
 				MIN_CONNECTION_LENGTH, true, transportId, connection, secret);
 		// Check that the connection writer thinks there's room for a packet
-		long capacity = w.getCapacity();
+		long capacity = w.getRemainingCapacity();
 		assertTrue(capacity >= MAX_PACKET_LENGTH);
 		assertTrue(capacity <= MIN_CONNECTION_LENGTH);
 		// Check that there really is room for a packet
diff --git a/test/net/sf/briar/transport/FrameReadWriteTest.java b/test/net/sf/briar/transport/FrameReadWriteTest.java
index 4418ece226842d558126f94bafb51c6bb9d853b1..2752a5277ad1cb495b86fcd2ac90585fd2674034 100644
--- a/test/net/sf/briar/transport/FrameReadWriteTest.java
+++ b/test/net/sf/briar/transport/FrameReadWriteTest.java
@@ -60,9 +60,8 @@ public class FrameReadWriteTest extends TestCase {
 	}
 
 	private void testWriteAndRead(boolean initiator) throws Exception {
-		// Calculate the expected ciphertext for the IV
+		// Create and encrypt the IV
 		byte[] iv = IvEncoder.encodeIv(initiator, transportId, connection);
-		assertEquals(IV_LENGTH, iv.length);
 		ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
 		byte[] encryptedIv = ivCipher.doFinal(iv);
 		assertEquals(IV_LENGTH, encryptedIv.length);
@@ -74,23 +73,24 @@ public class FrameReadWriteTest extends TestCase {
 		// Write the frames
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
-				Long.MAX_VALUE, initiator, transportId, connection, ivCipher,
-				frameCipher, ivKey, frameKey);
-		mac.init(macKey);
-		ConnectionWriter writer = new ConnectionWriterImpl(encrypter, mac);
+				Long.MAX_VALUE, iv, ivCipher, frameCipher, ivKey, frameKey);
+		ConnectionWriter writer = new ConnectionWriterImpl(encrypter, mac,
+				macKey);
 		OutputStream out1 = writer.getOutputStream();
 		out1.write(frame);
 		out1.flush();
 		out1.write(frame1);
 		out1.flush();
-		// Read the frames back
+		// Read the IV back
 		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
 		byte[] recoveredIv = new byte[IV_LENGTH];
 		assertEquals(IV_LENGTH, in.read(recoveredIv));
 		assertTrue(Arrays.equals(encryptedIv, recoveredIv));
+		// Read the frames back
 		ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in,
-				initiator, transportId, connection, frameCipher, frameKey);
-		ConnectionReader reader = new ConnectionReaderImpl(decrypter, mac);
+				recoveredIv, ivCipher, frameCipher, ivKey, frameKey);
+		ConnectionReader reader = new ConnectionReaderImpl(decrypter, mac,
+				macKey);
 		InputStream in1 = reader.getInputStream();
 		byte[] recovered = new byte[frame.length];
 		int offset = 0;
diff --git a/test/net/sf/briar/transport/NullConnectionEncrypter.java b/test/net/sf/briar/transport/NullConnectionEncrypter.java
index de5744d68e4b6eb3fbeb0408e6c0d0609d2cddd8..aa08e4fa79cc8ee8f2dbd5a7c58f5d270410ccc5 100644
--- a/test/net/sf/briar/transport/NullConnectionEncrypter.java
+++ b/test/net/sf/briar/transport/NullConnectionEncrypter.java
@@ -28,7 +28,7 @@ implements ConnectionEncrypter {
 		capacity -= mac.length;
 	}
 
-	public long getCapacity() {
+	public long getRemainingCapacity() {
 		return capacity;
 	}
 
diff --git a/test/net/sf/briar/transport/PaddedConnectionWriterTest.java b/test/net/sf/briar/transport/PaddedConnectionWriterTest.java
index 11c5a4ee22e96c01ab863fba6b202c4167d09451..cb35529079486f1aab7195ffe3121c9cb02a7340 100644
--- a/test/net/sf/briar/transport/PaddedConnectionWriterTest.java
+++ b/test/net/sf/briar/transport/PaddedConnectionWriterTest.java
@@ -24,7 +24,7 @@ public class PaddedConnectionWriterTest extends TransportTest {
 	public void testWriteByteDoesNotBlockUntilBufferIsFull() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter e = new NullConnectionEncrypter(out, Long.MAX_VALUE);
-		ConnectionWriter w = new PaddedConnectionWriter(e, mac);
+		ConnectionWriter w = new PaddedConnectionWriter(e, mac, macKey);
 		final OutputStream out1 = w.getOutputStream();
 		final CountDownLatch latch = new CountDownLatch(1);
 		final AtomicBoolean finished = new AtomicBoolean(false);
@@ -53,7 +53,7 @@ public class PaddedConnectionWriterTest extends TransportTest {
 	public void testWriteByteBlocksWhenBufferIsFull() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter e = new NullConnectionEncrypter(out, Long.MAX_VALUE);
-		PaddedConnectionWriter w = new PaddedConnectionWriter(e, mac);
+		PaddedConnectionWriter w = new PaddedConnectionWriter(e, mac, macKey);
 		final OutputStream out1 = w.getOutputStream();
 		final CountDownLatch latch = new CountDownLatch(1);
 		final AtomicBoolean finished = new AtomicBoolean(false);
@@ -87,7 +87,7 @@ public class PaddedConnectionWriterTest extends TransportTest {
 	public void testWriteArrayDoesNotBlockUntilBufferIsFull() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter e = new NullConnectionEncrypter(out, Long.MAX_VALUE);
-		ConnectionWriter w = new PaddedConnectionWriter(e, mac);
+		ConnectionWriter w = new PaddedConnectionWriter(e, mac, macKey);
 		final OutputStream out1 = w.getOutputStream();
 		final CountDownLatch latch = new CountDownLatch(1);
 		final AtomicBoolean finished = new AtomicBoolean(false);
@@ -116,7 +116,7 @@ public class PaddedConnectionWriterTest extends TransportTest {
 	public void testWriteArrayBlocksWhenBufferIsFull() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter e = new NullConnectionEncrypter(out, Long.MAX_VALUE);
-		PaddedConnectionWriter w = new PaddedConnectionWriter(e, mac);
+		PaddedConnectionWriter w = new PaddedConnectionWriter(e, mac, macKey);
 		final OutputStream out1 = w.getOutputStream();
 		final CountDownLatch latch = new CountDownLatch(1);
 		final AtomicBoolean finished = new AtomicBoolean(false);
@@ -150,7 +150,7 @@ public class PaddedConnectionWriterTest extends TransportTest {
 	public void testWriteFullFrameInsertsPadding() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter e = new NullConnectionEncrypter(out, Long.MAX_VALUE);
-		PaddedConnectionWriter w = new PaddedConnectionWriter(e, mac);
+		PaddedConnectionWriter w = new PaddedConnectionWriter(e, mac, macKey);
 		w.getOutputStream().write(0);
 		w.writeFullFrame();
 		// A full frame should have been written
diff --git a/test/net/sf/briar/transport/TransportTest.java b/test/net/sf/briar/transport/TransportTest.java
index e73af2174ebde21404cad1e3719bb4c94a6fbc0a..21e8ce23103849946f6a6869a6ab162b297236de 100644
--- a/test/net/sf/briar/transport/TransportTest.java
+++ b/test/net/sf/briar/transport/TransportTest.java
@@ -3,18 +3,20 @@ package net.sf.briar.transport;
 import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 
 import javax.crypto.Mac;
+import javax.crypto.SecretKey;
 
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-
+import junit.framework.TestCase;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.crypto.CryptoModule;
 import net.sf.briar.util.ByteUtils;
-import junit.framework.TestCase;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
 
 public abstract class TransportTest extends TestCase {
 
 	protected final Mac mac;
+	protected final SecretKey macKey;
 	protected final int headerLength = 4, macLength, maxPayloadLength;
 
 	public TransportTest() throws Exception {
@@ -22,7 +24,7 @@ public abstract class TransportTest extends TestCase {
 		Injector i = Guice.createInjector(new CryptoModule());
 		CryptoComponent crypto = i.getInstance(CryptoComponent.class);
 		mac = crypto.getMac();
-		mac.init(crypto.generateSecretKey());
+		macKey = crypto.generateSecretKey();
 		macLength = mac.getMacLength();
 		maxPayloadLength = MAX_FRAME_LENGTH - headerLength - macLength;
 	}
diff --git a/test/net/sf/briar/transport/batch/TestBatchTransportReader.java b/test/net/sf/briar/transport/batch/TestBatchTransportReader.java
index 0ecc5cf0de37b2d8d293422477dae917abbf3563..4688d70360c1c937c4abdc2a07b2f1c41bc0a929 100644
--- a/test/net/sf/briar/transport/batch/TestBatchTransportReader.java
+++ b/test/net/sf/briar/transport/batch/TestBatchTransportReader.java
@@ -1,38 +1,24 @@
 package net.sf.briar.transport.batch;
 
-import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
 import net.sf.briar.api.transport.batch.BatchTransportReader;
 
-class TestBatchTransportReader extends FilterInputStream
-implements BatchTransportReader {
+class TestBatchTransportReader implements BatchTransportReader {
+
+	private final InputStream in;
 
 	TestBatchTransportReader(InputStream in) {
-		super(in);
+		this.in = in;
 	}
 
 	public InputStream getInputStream() {
-		return this;
+		return in;
 	}
 
 	public void dispose() throws IOException {
-		// Nothing to do
-	}
-
-	@Override
-	public int read() throws IOException {
-		return in.read();
-	}
-
-	@Override
-	public int read(byte[] b) throws IOException {
-		return read(b, 0, b.length);
-	}
-
-	@Override
-	public int read(byte[] b, int off, int len) throws IOException {
-		return in.read(b, off, len);
+		// The input stream may have been left open
+		in.close();
 	}
 }
diff --git a/test/net/sf/briar/transport/batch/TestBatchTransportWriter.java b/test/net/sf/briar/transport/batch/TestBatchTransportWriter.java
index c0ff7c54fe5b75c0f75a18906c24f83ac45fd529..bd2a3520861d71bfcaa5aecf9fdc701914edf81e 100644
--- a/test/net/sf/briar/transport/batch/TestBatchTransportWriter.java
+++ b/test/net/sf/briar/transport/batch/TestBatchTransportWriter.java
@@ -1,18 +1,17 @@
 package net.sf.briar.transport.batch;
 
-import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 
 import net.sf.briar.api.transport.batch.BatchTransportWriter;
 
-class TestBatchTransportWriter extends FilterOutputStream
-implements BatchTransportWriter {
+class TestBatchTransportWriter implements BatchTransportWriter {
 
-	private int capacity;
+	private final OutputStream out;
+	private final int capacity;
 
 	TestBatchTransportWriter(OutputStream out, int capacity) {
-		super(out);
+		this.out = out;
 		this.capacity = capacity;
 	}
 
@@ -21,29 +20,11 @@ implements BatchTransportWriter {
 	}
 
 	public OutputStream getOutputStream() {
-		return this;
+		return out;
 	}
 
 	public void dispose() throws IOException {
-		// Nothing to do
-	}
-
-	@Override
-	public void write(int b) throws IOException {
-		if(capacity < 1) throw new IllegalArgumentException();
-		out.write(b);
-		capacity--;
-	}
-
-	@Override
-	public void write(byte[] b) throws IOException {
-		write(b, 0, b.length);
-	}
-
-	@Override
-	public void write(byte[] b, int off, int len) throws IOException {
-		if(len > capacity) throw new IllegalArgumentException();
-		out.write(b, off, len);
-		capacity -= len;
+		// The output stream may have been left open
+		out.close();
 	}
 }