diff --git a/api/net/sf/briar/api/crypto/ErasableKey.java b/api/net/sf/briar/api/crypto/ErasableKey.java
index 2a46356c95f168670a74a69093e8a32e3d435e1e..3503898ede179c0922a0e058f990c6441a83314e 100644
--- a/api/net/sf/briar/api/crypto/ErasableKey.java
+++ b/api/net/sf/briar/api/crypto/ErasableKey.java
@@ -4,6 +4,9 @@ import javax.crypto.SecretKey;
 
 public interface ErasableKey extends SecretKey {
 
+	/** Returns a copy of the key. */
+	ErasableKey copy();
+
 	/** Erases the key from memory. */
 	void erase();
 }
diff --git a/components/net/sf/briar/crypto/ErasableKeyImpl.java b/components/net/sf/briar/crypto/ErasableKeyImpl.java
index 595485f3bb4141ebbe9ba18780ad58ce5f7de6c4..5267e394d5b65feff23bf353e89189a1599695c8 100644
--- a/components/net/sf/briar/crypto/ErasableKeyImpl.java
+++ b/components/net/sf/briar/crypto/ErasableKeyImpl.java
@@ -33,6 +33,10 @@ class ErasableKeyImpl implements ErasableKey {
 		return "RAW";
 	}
 
+	public ErasableKey copy() {
+		return new ErasableKeyImpl(getEncoded(), algorithm);
+	}
+
 	public void erase() {
 		if(erased) throw new IllegalStateException();
 		ByteUtils.erase(key);
diff --git a/components/net/sf/briar/transport/ConnectionDecrypterImpl.java b/components/net/sf/briar/transport/ConnectionDecrypterImpl.java
index 3f6f426baa95681b357a159b86787fd73c91823f..0232dd4e71e28b877d44be6e96d0217f4dad92a8 100644
--- a/components/net/sf/briar/transport/ConnectionDecrypterImpl.java
+++ b/components/net/sf/briar/transport/ConnectionDecrypterImpl.java
@@ -43,45 +43,58 @@ implements ConnectionDecrypter {
 	}
 
 	public void readMac(byte[] mac) throws IOException {
-		if(betweenFrames) throw new IllegalStateException();
-		// If we have any plaintext in the buffer, copy it into the MAC
-		System.arraycopy(buf, bufOff, mac, 0, bufLen);
-		// Read the remainder of the MAC
-		int offset = bufLen;
-		while(offset < mac.length) {
-			int read = in.read(mac, offset, mac.length - offset);
-			if(read == -1) break;
-			offset += read;
-		}
-		if(offset < mac.length) throw new EOFException(); // Unexpected EOF
-		// Decrypt the remainder of the MAC
 		try {
-			int length = mac.length - bufLen;
-			int i = frameCipher.doFinal(mac, bufLen, length, mac, bufLen);
-			if(i < length) throw new RuntimeException();
-		} catch(BadPaddingException badCipher) {
-			throw new RuntimeException(badCipher);
-		} catch(IllegalBlockSizeException badCipher) {
-			throw new RuntimeException(badCipher);
-		} catch(ShortBufferException badCipher) {
-			throw new RuntimeException(badCipher);
+			if(betweenFrames) throw new IllegalStateException();
+			// If we have any plaintext in the buffer, copy it into the MAC
+			System.arraycopy(buf, bufOff, mac, 0, bufLen);
+			// Read the remainder of the MAC
+			int offset = bufLen;
+			while(offset < mac.length) {
+				int read = in.read(mac, offset, mac.length - offset);
+				if(read == -1) break;
+				offset += read;
+			}
+			if(offset < mac.length) throw new EOFException(); // Unexpected EOF
+			// Decrypt the remainder of the MAC
+			try {
+				int length = mac.length - bufLen;
+				int i = frameCipher.doFinal(mac, bufLen, length, mac, bufLen);
+				if(i < length) throw new RuntimeException();
+			} catch(BadPaddingException badCipher) {
+				throw new RuntimeException(badCipher);
+			} catch(IllegalBlockSizeException badCipher) {
+				throw new RuntimeException(badCipher);
+			} catch(ShortBufferException badCipher) {
+				throw new RuntimeException(badCipher);
+			}
+			bufOff = bufLen = 0;
+			betweenFrames = true;
+		} catch(IOException e) {
+			frameKey.erase();
+			throw e;
 		}
-		bufOff = bufLen = 0;
-		betweenFrames = true;
 	}
 
 	@Override
 	public int read() throws IOException {
-		if(betweenFrames) initialiseCipher();
-		if(bufLen == 0) {
-			if(!readBlock()) return -1;
-			bufOff = 0;
-			bufLen = buf.length;
+		try {
+			if(betweenFrames) initialiseCipher();
+			if(bufLen == 0) {
+				if(!readBlock()) {
+					frameKey.erase();
+					return -1;
+				}
+				bufOff = 0;
+				bufLen = buf.length;
+			}
+			int i = buf[bufOff];
+			bufOff++;
+			bufLen--;
+			return i < 0 ? i + 256 : i;
+		} catch(IOException e) {
+			frameKey.erase();
+			throw e;
 		}
-		int i = buf[bufOff];
-		bufOff++;
-		bufLen--;
-		return i < 0 ? i + 256 : i;
 	}
 
 	@Override
@@ -91,17 +104,25 @@ implements ConnectionDecrypter {
 
 	@Override
 	public int read(byte[] b, int off, int len) throws IOException {
-		if(betweenFrames) initialiseCipher();
-		if(bufLen == 0) {
-			if(!readBlock()) return -1;
-			bufOff = 0;
-			bufLen = buf.length;
+		try {
+			if(betweenFrames) initialiseCipher();
+			if(bufLen == 0) {
+				if(!readBlock()) {
+					frameKey.erase();
+					return -1;
+				}
+				bufOff = 0;
+				bufLen = buf.length;
+			}
+			int length = Math.min(len, bufLen);
+			System.arraycopy(buf, bufOff, b, off, length);
+			bufOff += length;
+			bufLen -= length;
+			return length;
+		} catch(IOException e) {
+			frameKey.erase();
+			throw e;
 		}
-		int length = Math.min(len, bufLen);
-		System.arraycopy(buf, bufOff, b, off, length);
-		bufOff += length;
-		bufLen -= length;
-		return length;
 	}
 
 	// Although we're using CTR mode, which doesn't require full blocks of
diff --git a/components/net/sf/briar/transport/ConnectionEncrypterImpl.java b/components/net/sf/briar/transport/ConnectionEncrypterImpl.java
index 5494b84bc1fbb1435389dd0188f381b3a1940614..79066fac1ce9336031c4f39007a682591684929d 100644
--- a/components/net/sf/briar/transport/ConnectionEncrypterImpl.java
+++ b/components/net/sf/briar/transport/ConnectionEncrypterImpl.java
@@ -46,6 +46,7 @@ implements ConnectionEncrypter {
 		}
 		if(encryptedIv.length != IV_LENGTH)
 			throw new IllegalArgumentException();
+		ivKey.erase();
 	}
 
 	public OutputStream getOutputStream() {
@@ -53,16 +54,21 @@ implements ConnectionEncrypter {
 	}
 
 	public void writeMac(byte[] mac) throws IOException {
-		if(!ivWritten || betweenFrames) throw new IllegalStateException();
 		try {
-			out.write(frameCipher.doFinal(mac));
-		} catch(BadPaddingException badCipher) {
-			throw new RuntimeException(badCipher);
-		} catch(IllegalBlockSizeException badCipher) {
-			throw new RuntimeException(badCipher);
+			if(!ivWritten || betweenFrames) throw new IllegalStateException();
+			try {
+				out.write(frameCipher.doFinal(mac));
+			} catch(BadPaddingException badCipher) {
+				throw new RuntimeException(badCipher);
+			} catch(IllegalBlockSizeException badCipher) {
+				throw new RuntimeException(badCipher);
+			}
+			capacity -= mac.length;
+			betweenFrames = true;
+		} catch(IOException e) {
+			frameKey.erase();
+			throw e;
 		}
-		capacity -= mac.length;
-		betweenFrames = true;
 	}
 
 	public long getRemainingCapacity() {
@@ -71,11 +77,16 @@ implements ConnectionEncrypter {
 
 	@Override
 	public void write(int b) throws IOException {
-		if(!ivWritten) writeIv();
-		if(betweenFrames) initialiseCipher();
-		byte[] ciphertext = frameCipher.update(new byte[] {(byte) b});
-		if(ciphertext != null) out.write(ciphertext);
-		capacity--;
+		try {
+			if(!ivWritten) writeIv();
+			if(betweenFrames) initialiseCipher();
+			byte[] ciphertext = frameCipher.update(new byte[] {(byte) b});
+			if(ciphertext != null) out.write(ciphertext);
+			capacity--;
+		} catch(IOException e) {
+			frameKey.erase();
+			throw e;
+		}
 	}
 
 	@Override
@@ -85,11 +96,16 @@ implements ConnectionEncrypter {
 
 	@Override
 	public void write(byte[] b, int off, int len) throws IOException {
-		if(!ivWritten) writeIv();
-		if(betweenFrames) initialiseCipher();
-		byte[] ciphertext = frameCipher.update(b, off, len);
-		if(ciphertext != null) out.write(ciphertext);
-		capacity -= len;
+		try {
+			if(!ivWritten) writeIv();
+			if(betweenFrames) initialiseCipher();
+			byte[] ciphertext = frameCipher.update(b, off, len);
+			if(ciphertext != null) out.write(ciphertext);
+			capacity -= len;
+		} catch(IOException e) {
+			frameKey.erase();
+			throw e;
+		}
 	}
 
 	private void writeIv() throws IOException {
diff --git a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java
index ffc95ca0c02a49af0e64f73d6d3fb24f2749fa5b..0109c7f469e658559d37facaa23f437b92abe5df 100644
--- a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java
+++ b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java
@@ -42,6 +42,7 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
 		} catch(InvalidKeyException badKey) {
 			throw new IllegalArgumentException(badKey);
 		}
+		ivKey.erase();
 		// Validate the IV
 		if(!IvEncoder.validateIv(iv, true, ctx))
 			throw new IllegalArgumentException();
diff --git a/components/net/sf/briar/transport/ConnectionReaderImpl.java b/components/net/sf/briar/transport/ConnectionReaderImpl.java
index c637458f14d8510bba7604d6f1d14aa148a1b3cd..28b37389c3195576143b86c38c363a172c128209 100644
--- a/components/net/sf/briar/transport/ConnectionReaderImpl.java
+++ b/components/net/sf/briar/transport/ConnectionReaderImpl.java
@@ -40,6 +40,7 @@ implements ConnectionReader {
 		} catch(InvalidKeyException e) {
 			throw new IllegalArgumentException(e);
 		}
+		macKey.erase();
 		maxPayloadLength = MAX_FRAME_LENGTH - 4 - mac.getMacLength();
 		header = new byte[4];
 		payload = new byte[maxPayloadLength];
diff --git a/components/net/sf/briar/transport/ConnectionRecogniserImpl.java b/components/net/sf/briar/transport/ConnectionRecogniserImpl.java
index fb5e59eff160a0e6ccb97c0e20fb497878631404..b4da6dc02ea1c50e1eab9fc7cdffa4aab0c38c3d 100644
--- a/components/net/sf/briar/transport/ConnectionRecogniserImpl.java
+++ b/components/net/sf/briar/transport/ConnectionRecogniserImpl.java
@@ -92,6 +92,7 @@ DatabaseListener {
 			byte[] secret = e.getValue();
 			ErasableKey ivKey = crypto.deriveIvKey(secret, true);
 			Bytes iv = new Bytes(encryptIv(i, unseen, ivKey));
+			ivKey.erase();
 			expected.put(iv, new ConnectionContextImpl(c, i, unseen, secret));
 		}
 	}
diff --git a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
index 0b91a80d773619c78825f12d16aaf52c3b8fe850..35b55f47c45ba97255943b36a36c61d7d29835bf 100644
--- a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
+++ b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
@@ -47,6 +47,7 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
 		} catch(InvalidKeyException badKey) {
 			throw new RuntimeException(badKey);
 		}
+		ivKey.erase();
 		// Validate the IV
 		if(!IvEncoder.validateIv(iv, true, ctx))
 			throw new IllegalArgumentException();
diff --git a/components/net/sf/briar/transport/ConnectionWriterImpl.java b/components/net/sf/briar/transport/ConnectionWriterImpl.java
index e66c373bc836608986039b0b5ff692ca515abd8a..61359e61525fdb4708b58eba8ff9aebf2c7dede7 100644
--- a/components/net/sf/briar/transport/ConnectionWriterImpl.java
+++ b/components/net/sf/briar/transport/ConnectionWriterImpl.java
@@ -41,6 +41,7 @@ implements ConnectionWriter {
 		} catch(InvalidKeyException badKey) {
 			throw new IllegalArgumentException(badKey);
 		}
+		macKey.erase();
 		maxPayloadLength = MAX_FRAME_LENGTH - 4 - mac.getMacLength();
 		buf = new ByteArrayOutputStream(maxPayloadLength);
 		header = new byte[4];
diff --git a/test/net/sf/briar/transport/FrameReadWriteTest.java b/test/net/sf/briar/transport/FrameReadWriteTest.java
index 07b00d9b9830e701fb6d30c41bff6e0260b46c46..b7fc4f51d85292d7462ca5521a5ed3503b136c5e 100644
--- a/test/net/sf/briar/transport/FrameReadWriteTest.java
+++ b/test/net/sf/briar/transport/FrameReadWriteTest.java
@@ -74,12 +74,16 @@ public class FrameReadWriteTest extends TestCase {
 		random.nextBytes(frame);
 		byte[] frame1 = new byte[321];
 		random.nextBytes(frame1);
+		// Copy the keys - the copies will be erased
+		ErasableKey frameCopy = frameKey.copy();
+		ErasableKey ivCopy = ivKey.copy();
+		ErasableKey macCopy = macKey.copy();
 		// Write the frames
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
-				Long.MAX_VALUE, iv, ivCipher, frameCipher, ivKey, frameKey);
+				Long.MAX_VALUE, iv, ivCipher, frameCipher, ivCopy, frameCopy);
 		ConnectionWriter writer = new ConnectionWriterImpl(encrypter, mac,
-				macKey);
+				macCopy);
 		OutputStream out1 = writer.getOutputStream();
 		out1.write(frame);
 		out1.flush();