diff --git a/briar-android/src/org/briarproject/android/PasswordActivity.java b/briar-android/src/org/briarproject/android/PasswordActivity.java
index 26ac3dee0938710792bb9389d3081c3cabc0c4c0..727985f1b1a989aed8eaa1fa00857b962334dca2 100644
--- a/briar-android/src/org/briarproject/android/PasswordActivity.java
+++ b/briar-android/src/org/briarproject/android/PasswordActivity.java
@@ -133,10 +133,7 @@ public class PasswordActivity extends RoboActivity {
 		continueButton.setVisibility(GONE);
 		progress.setVisibility(VISIBLE);
 		// Decrypt the database key in a background thread
-		int length = e.length();
-		final char[] password = new char[length];
-		e.getChars(0, length, password, 0);
-		e.delete(0, length);
+		final String password = e.toString();
 		cryptoExecutor.execute(new Runnable() {
 			public void run() {
 				byte[] key = crypto.decryptWithPassword(encrypted, password);
diff --git a/briar-android/src/org/briarproject/android/SetupActivity.java b/briar-android/src/org/briarproject/android/SetupActivity.java
index a71442eeb0cbe4fc841329863542656bd0222625..109ce0cee8077441187b78a7a22da2f9934fe8dd 100644
--- a/briar-android/src/org/briarproject/android/SetupActivity.java
+++ b/briar-android/src/org/briarproject/android/SetupActivity.java
@@ -19,7 +19,6 @@ import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP;
 import static org.briarproject.api.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
 import static org.briarproject.api.crypto.PasswordStrengthEstimator.WEAK;
 
-import java.util.Arrays;
 import java.util.concurrent.Executor;
 import java.util.logging.Logger;
 
@@ -43,7 +42,6 @@ import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 import android.os.Bundle;
-import android.text.Editable;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -187,18 +185,16 @@ OnEditorActionListener {
 		else strengthMeter.setVisibility(INVISIBLE);
 		String nickname = nicknameEntry.getText().toString();
 		int nicknameLength = StringUtils.toUtf8(nickname).length;
-		char[] firstPassword = getChars(passwordEntry.getText());
-		char[] secondPassword = getChars(passwordConfirmation.getText());
-		boolean passwordsMatch = Arrays.equals(firstPassword, secondPassword);
+		String firstPassword = passwordEntry.getText().toString();
+		String secondPassword = passwordConfirmation.getText().toString();
+		boolean passwordsMatch = firstPassword.equals(secondPassword);
 		float strength = strengthEstimator.estimateStrength(firstPassword);
-		for(int i = 0; i < firstPassword.length; i++) firstPassword[i] = 0;
-		for(int i = 0; i < secondPassword.length; i++) secondPassword[i] = 0;
 		strengthMeter.setStrength(strength);
 		if(nicknameLength > MAX_AUTHOR_NAME_LENGTH) {
 			feedback.setText(R.string.name_too_long);
-		} else if(firstPassword.length == 0) {
+		} else if(firstPassword.length() == 0) {
 			feedback.setText("");
-		} else if(secondPassword.length == 0 || passwordsMatch) {
+		} else if(secondPassword.length() == 0 || passwordsMatch) {
 			if(strength < PasswordStrengthEstimator.WEAK)
 				feedback.setText(R.string.password_too_weak);
 			else feedback.setText("");
@@ -212,13 +208,6 @@ OnEditorActionListener {
 				&& passwordsMatch && strength >= WEAK);
 	}
 
-	private char[] getChars(Editable e) {
-		int length = e.length();
-		char[] c = new char[length];
-		e.getChars(0, length, c, 0);
-		return c;
-	}
-
 	public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
 		// Hide the soft keyboard
 		Object o = getSystemService(INPUT_METHOD_SERVICE);
@@ -231,18 +220,14 @@ OnEditorActionListener {
 		feedback.setVisibility(GONE);
 		continueButton.setVisibility(GONE);
 		progress.setVisibility(VISIBLE);
-		// Copy the passwords and erase the originals
 		final String nickname = nicknameEntry.getText().toString();
-		final char[] password = getChars(passwordEntry.getText());
-		delete(passwordEntry.getText());
-		delete(passwordConfirmation.getText());
+		final String password = passwordEntry.getText().toString();
 		// Store the DB key and create the identity in a background thread
 		cryptoExecutor.execute(new Runnable() {
 			public void run() {
-				byte[] key = crypto.generateSecretKey().getEncoded();
+				byte[] key = crypto.generateSecretKey().getBytes();
 				databaseConfig.setEncryptionKey(key);
 				byte[] encrypted = encryptDatabaseKey(key, password);
-				for(int i = 0; i < password.length; i++) password[i] = 0;
 				storeEncryptedDatabaseKey(encrypted);
 				LocalAuthor localAuthor = createLocalAuthor(nickname);
 				showDashboard(referenceManager.putReference(localAuthor,
@@ -251,10 +236,6 @@ OnEditorActionListener {
 		});
 	}
 
-	private void delete(Editable e) {
-		e.delete(0, e.length());
-	}
-
 	private void storeEncryptedDatabaseKey(final byte[] encrypted) {
 		long now = System.currentTimeMillis();
 		SharedPreferences prefs = getSharedPreferences("db", MODE_PRIVATE);
@@ -266,7 +247,7 @@ OnEditorActionListener {
 			LOG.info("Key storage took " + duration + " ms");
 	}
 
-	private byte[] encryptDatabaseKey(byte[] key, char[] password) {
+	private byte[] encryptDatabaseKey(byte[] key, String password) {
 		long now = System.currentTimeMillis();
 		byte[] encrypted = crypto.encryptWithPassword(key, password);
 		long duration = System.currentTimeMillis() - now;
diff --git a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java
index ba9c86224b04d83b6ae67d1da2ed50b7f9f90b83..558077ae48fb986b319d693f5413d4a3026cfdfd 100644
--- a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java
+++ b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java
@@ -89,7 +89,7 @@ public interface CryptoComponent {
 	 * given password. The ciphertext will be decryptable using the same
 	 * password after the app restarts.
 	 */
-	byte[] encryptWithPassword(byte[] plaintext, char[] password);
+	byte[] encryptWithPassword(byte[] plaintext, String password);
 
 	/**
 	 * Decrypts and authenticates the given ciphertext that has been read from
@@ -97,5 +97,5 @@ public interface CryptoComponent {
 	 * given password. Returns null if the ciphertext cannot be decrypted and
 	 * authenticated (for example, if the password is wrong).
 	 */
-	byte[] decryptWithPassword(byte[] ciphertext, char[] password);
+	byte[] decryptWithPassword(byte[] ciphertext, String password);
 }
diff --git a/briar-api/src/org/briarproject/api/crypto/KeyManager.java b/briar-api/src/org/briarproject/api/crypto/KeyManager.java
index 77c41132e01387a4182e6e2e99c3f96a7e30b60f..02a43e9706656cd06dace79eb64730f1e2561ed6 100644
--- a/briar-api/src/org/briarproject/api/crypto/KeyManager.java
+++ b/briar-api/src/org/briarproject/api/crypto/KeyManager.java
@@ -16,9 +16,6 @@ public interface KeyManager extends Service {
 	 */
 	StreamContext getStreamContext(ContactId c, TransportId t);
 
-	/**
-	 * Called whenever an endpoint has been added. The initial secret is erased
-	 * before returning.
-	 */
+	/** Called whenever an endpoint has been added. */
 	void endpointAdded(Endpoint ep, int maxLatency, byte[] initialSecret);
 }
diff --git a/briar-api/src/org/briarproject/api/crypto/PasswordStrengthEstimator.java b/briar-api/src/org/briarproject/api/crypto/PasswordStrengthEstimator.java
index 9ffa2dc244da42bfe0d4a675721510a640b53754..93d27a6b32aaa142a86cfd4c53f054900cf7fc4d 100644
--- a/briar-api/src/org/briarproject/api/crypto/PasswordStrengthEstimator.java
+++ b/briar-api/src/org/briarproject/api/crypto/PasswordStrengthEstimator.java
@@ -12,5 +12,5 @@ public interface PasswordStrengthEstimator {
 	 * Returns an estimate between 0 (weakest) and 1 (strongest), inclusive,
 	 * of the strength of the given password.
 	 */
-	float estimateStrength(char[] password);
+	float estimateStrength(String password);
 }
diff --git a/briar-api/src/org/briarproject/api/crypto/SecretKey.java b/briar-api/src/org/briarproject/api/crypto/SecretKey.java
index 63d1f7661705087cc95ed9050072bba010bd0370..62b75a9452bfbc736179d0abe83050574228d8a8 100644
--- a/briar-api/src/org/briarproject/api/crypto/SecretKey.java
+++ b/briar-api/src/org/briarproject/api/crypto/SecretKey.java
@@ -1,21 +1,15 @@
 package org.briarproject.api.crypto;
 
 /** A secret key used for encryption and/or authentication. */
-public interface SecretKey {
+public class SecretKey {
 
-	/** Returns the encoded representation of this key. */
-	byte[] getEncoded();
+	private final byte[] key;
 
-	/**
-	 * Returns a copy of this key - erasing this key will erase the copy and
-	 * vice versa.
-	 */
-	SecretKey copy();
+	public SecretKey(byte[] key) {
+		this.key = key;
+	}
 
-	/**
-	 * Erases this key from memory. Any copies derived from this key via the
-	 * {@link #copy()} method, and any keys from which this key was derived via
-	 * the {@link #copy()} method, are also erased.
-	 */
-	void erase();
+	public byte[] getBytes() {
+		return key;
+	}
 }
diff --git a/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java b/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java
index 93807087d263c1d5f3ad43b100ea304a907b0441..bf80ca8c5fd07060da40d622129a4e5f3fb221b7 100644
--- a/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java
+++ b/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java
@@ -38,7 +38,7 @@ class AuthenticatedCipherImpl implements AuthenticatedCipher {
 
 	public void init(boolean encrypt, SecretKey key, byte[] iv, byte[] aad)
 			throws GeneralSecurityException {
-		KeyParameter k = new KeyParameter(key.getEncoded());
+		KeyParameter k = new KeyParameter(key.getBytes());
 		AEADParameters params = new AEADParameters(k, macLength * 8, iv, aad);
 		try {
 			cipher.init(encrypt, params);
diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java
index 4edd26a4fe9835f83f54054660f0442ed66e0a4e..29442f311f6e8adc1b315441dd0261965f277693 100644
--- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java
+++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java
@@ -7,8 +7,6 @@ import static org.briarproject.crypto.EllipticCurveConstants.P;
 import static org.briarproject.crypto.EllipticCurveConstants.PARAMETERS;
 import static org.briarproject.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
 import java.security.GeneralSecurityException;
 import java.security.SecureRandom;
 import java.util.ArrayList;
@@ -31,6 +29,7 @@ import org.briarproject.api.crypto.SecretKey;
 import org.briarproject.api.crypto.Signature;
 import org.briarproject.api.system.SeedProvider;
 import org.briarproject.util.ByteUtils;
+import org.briarproject.util.StringUtils;
 import org.spongycastle.crypto.AsymmetricCipherKeyPair;
 import org.spongycastle.crypto.BlockCipher;
 import org.spongycastle.crypto.CipherParameters;
@@ -48,7 +47,6 @@ import org.spongycastle.crypto.params.ECKeyGenerationParameters;
 import org.spongycastle.crypto.params.ECPrivateKeyParameters;
 import org.spongycastle.crypto.params.ECPublicKeyParameters;
 import org.spongycastle.crypto.params.KeyParameter;
-import org.spongycastle.util.Strings;
 
 class CryptoComponentImpl implements CryptoComponent {
 
@@ -114,7 +112,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	public SecretKey generateSecretKey() {
 		byte[] b = new byte[CIPHER_KEY_BYTES];
 		secureRandom.nextBytes(b);
-		return new SecretKeyImpl(b);
+		return new SecretKey(b);
 	}
 
 	public MessageDigest getMessageDigest() {
@@ -188,8 +186,6 @@ class CryptoComponentImpl implements CryptoComponent {
 		int[] codes = new int[2];
 		codes[0] = ByteUtils.readUint(alice, CODE_BITS);
 		codes[1] = ByteUtils.readUint(bob, CODE_BITS);
-		ByteUtils.erase(alice);
-		ByteUtils.erase(bob);
 		return codes;
 	}
 
@@ -223,9 +219,7 @@ class CryptoComponentImpl implements CryptoComponent {
 		byte[] raw = deriveSharedSecret(ourPriv, theirPub);
 		// Derive the cooked secret from the raw secret using the
 		// concatenation KDF
-		byte[] cooked = concatenationKdf(raw, MASTER, aliceInfo, bobInfo);
-		ByteUtils.erase(raw);
-		return cooked;
+		return concatenationKdf(raw, MASTER, aliceInfo, bobInfo);
 	}
 
 	// Package access for testing
@@ -296,8 +290,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	private SecretKey deriveKey(byte[] secret, byte[] label, long context) {
-		byte[] key = counterModeKdf(secret, label, context);
-		return new SecretKeyImpl(key);
+		return new SecretKey(counterModeKdf(secret, label, context));
 	}
 
 	public AuthenticatedCipher getFrameCipher() {
@@ -313,21 +306,19 @@ class CryptoComponentImpl implements CryptoComponent {
 		ByteUtils.writeUint32(streamNumber, tag, 0);
 		BlockCipher cipher = new AESLightEngine();
 		assert cipher.getBlockSize() == TAG_LENGTH;
-		KeyParameter k = new KeyParameter(tagKey.getEncoded());
+		KeyParameter k = new KeyParameter(tagKey.getBytes());
 		cipher.init(true, k);
 		cipher.processBlock(tag, 0, tag, 0);
-		ByteUtils.erase(k.getKey());
 	}
 
-	public byte[] encryptWithPassword(byte[] input, char[] password) {
+	public byte[] encryptWithPassword(byte[] input, String password) {
 		// Generate a random salt
 		byte[] salt = new byte[PBKDF_SALT_BYTES];
 		secureRandom.nextBytes(salt);
 		// Calibrate the KDF
 		int iterations = chooseIterationCount(PBKDF_TARGET_MILLIS);
 		// Derive the key from the password
-		byte[] keyBytes = pbkdf2(password, salt, iterations);
-		SecretKey key = new SecretKeyImpl(keyBytes);
+		SecretKey key = new SecretKey(pbkdf2(password, salt, iterations));
 		// Generate a random IV
 		byte[] iv = new byte[STORAGE_IV_BYTES];
 		secureRandom.nextBytes(iv);
@@ -348,12 +339,10 @@ class CryptoComponentImpl implements CryptoComponent {
 			return output;
 		} catch(GeneralSecurityException e) {
 			throw new RuntimeException(e);
-		} finally {
-			key.erase();
 		}
 	}
 
-	public byte[] decryptWithPassword(byte[] input, char[] password) {
+	public byte[] decryptWithPassword(byte[] input, String password) {
 		// The input contains the salt, iterations, IV, ciphertext and MAC
 		if(input.length < PBKDF_SALT_BYTES + 4 + STORAGE_IV_BYTES + MAC_BYTES)
 			return null; // Invalid
@@ -365,8 +354,7 @@ class CryptoComponentImpl implements CryptoComponent {
 		byte[] iv = new byte[STORAGE_IV_BYTES];
 		System.arraycopy(input, salt.length + 4, iv, 0, iv.length);
 		// Derive the key from the password
-		byte[] keyBytes = pbkdf2(password, salt, (int) iterations);
-		SecretKey key = new SecretKeyImpl(keyBytes);
+		SecretKey key = new SecretKey(pbkdf2(password, salt, (int) iterations));
 		// Initialise the cipher
 		AuthenticatedCipher cipher;
 		try {
@@ -374,7 +362,6 @@ class CryptoComponentImpl implements CryptoComponent {
 			cipher = new AuthenticatedCipherImpl(a, MAC_BYTES);
 			cipher.init(false, key, iv, null);
 		} catch(GeneralSecurityException e) {
-			key.erase();
 			throw new RuntimeException(e);
 		}
 		// Try to decrypt the ciphertext (may be invalid)
@@ -385,9 +372,7 @@ class CryptoComponentImpl implements CryptoComponent {
 			cipher.doFinal(input, inputOff, inputLen, output, 0);
 			return output;
 		} catch(GeneralSecurityException e) {
-			return null; // Invalid
-		} finally {
-			key.erase();
+			return null; // Invalid ciphertext
 		}
 	}
 
@@ -417,7 +402,6 @@ class CryptoComponentImpl implements CryptoComponent {
 		// The secret is the first CIPHER_KEY_BYTES bytes of the hash
 		byte[] output = new byte[CIPHER_KEY_BYTES];
 		System.arraycopy(hash, 0, output, 0, output.length);
-		ByteUtils.erase(hash);
 		return output;
 	}
 
@@ -447,20 +431,17 @@ class CryptoComponentImpl implements CryptoComponent {
 		prf.update((byte) CIPHER_KEY_BYTES); // Output length
 		prf.doFinal(mac, 0);
 		System.arraycopy(mac, 0, output, 0, output.length);
-		ByteUtils.erase(mac);
-		ByteUtils.erase(k.getKey());
 		return output;
 	}
 
 	// Password-based key derivation function - see PKCS#5 v2.1, section 5.2
-	private byte[] pbkdf2(char[] password, byte[] salt, int iterations) {
-		byte[] utf8 = toUtf8ByteArray(password);
+	private byte[] pbkdf2(String password, byte[] salt, int iterations) {
+		byte[] utf8 = StringUtils.toUtf8(password);
 		Digest digest = new SHA384Digest();
 		PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(digest);
 		gen.init(utf8, salt, iterations);
 		int keyLengthInBits = CIPHER_KEY_BYTES * 8;
 		CipherParameters p = gen.generateDerivedParameters(keyLengthInBits);
-		ByteUtils.erase(utf8);
 		return ((KeyParameter) p).getKey();
 	}
 
@@ -512,18 +493,4 @@ class CryptoComponentImpl implements CryptoComponent {
 		if(size % 2 == 1) return list.get(size / 2);
 		return list.get(size / 2 - 1) + list.get(size / 2) / 2;
 	}
-
-	private byte[] toUtf8ByteArray(char[] c) {
-		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		try {
-			Strings.toUTF8ByteArray(c, out);
-			byte[] utf8 = out.toByteArray();
-			// Erase the output stream's buffer
-			out.reset();
-			out.write(new byte[utf8.length]);
-			return utf8;
-		} catch(IOException e) {
-			throw new RuntimeException(e);
-		}
-	}
 }
diff --git a/briar-core/src/org/briarproject/crypto/PasswordStrengthEstimatorImpl.java b/briar-core/src/org/briarproject/crypto/PasswordStrengthEstimatorImpl.java
index aeec2ddc3bcc3127224796c101edd96c46efcc10..1fd99f52bfe2c8b79660a3be5df2e038c2daf6ad 100644
--- a/briar-core/src/org/briarproject/crypto/PasswordStrengthEstimatorImpl.java
+++ b/briar-core/src/org/briarproject/crypto/PasswordStrengthEstimatorImpl.java
@@ -13,9 +13,10 @@ class PasswordStrengthEstimatorImpl implements PasswordStrengthEstimator {
 	private static final double STRONG = Math.log(Math.pow(LOWER + UPPER +
 			DIGIT + OTHER, 10));
 
-	public float estimateStrength(char[] password) {
+	public float estimateStrength(String password) {
 		HashSet<Character> unique = new HashSet<Character>();
-		for(char c : password) unique.add(c);
+		int length = password.length();
+		for(int i = 0; i < length; i++) unique.add(password.charAt(i));
 		boolean lower = false, upper = false, digit = false, other = false;
 		for(char c : unique) {
 			if(Character.isLowerCase(c)) lower = true;
diff --git a/briar-core/src/org/briarproject/crypto/SecretKeyImpl.java b/briar-core/src/org/briarproject/crypto/SecretKeyImpl.java
deleted file mode 100644
index d7cdbdf05d784a596fd594c12bd3c164ffc3fdaa..0000000000000000000000000000000000000000
--- a/briar-core/src/org/briarproject/crypto/SecretKeyImpl.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.briarproject.crypto;
-
-import org.briarproject.api.crypto.SecretKey;
-import org.briarproject.util.ByteUtils;
-
-class SecretKeyImpl implements SecretKey {
-
-	private final byte[] key;
-
-	private boolean erased = false; // Locking: this
-
-	SecretKeyImpl(byte[] key) {
-		this.key = key;
-	}
-
-	public synchronized byte[] getEncoded() {
-		if(erased) throw new IllegalStateException();
-		return key;
-	}
-
-	public SecretKey copy() {
-		return new SecretKeyImpl(key.clone());
-	}
-
-	public synchronized void erase() {
-		if(erased) throw new IllegalStateException();
-		ByteUtils.erase(key);
-		erased = true;
-	}
-}
diff --git a/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java b/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java
index ff29697dfd469ee0e829ef0b24f33f294368454b..4127e99a7099dc8f42de842b3606434df0df0676 100644
--- a/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java
+++ b/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java
@@ -44,16 +44,11 @@ class StreamDecrypterImpl implements StreamDecrypter {
 		if(finalFrame) return -1;
 		// Read the frame
 		int ciphertextLength = 0;
-		try {
-			while(ciphertextLength < frameLength) {
-				int read = in.read(ciphertext, ciphertextLength,
-						frameLength - ciphertextLength);
-				if(read == -1) break; // We'll check the length later
-				ciphertextLength += read;
-			}
-		} catch(IOException e) {
-			frameKey.erase();
-			throw e;
+		while(ciphertextLength < frameLength) {
+			int read = in.read(ciphertext, ciphertextLength,
+					frameLength - ciphertextLength);
+			if(read == -1) break; // We'll check the length later
+			ciphertextLength += read;
 		}
 		int plaintextLength = ciphertextLength - MAC_LENGTH;
 		if(plaintextLength < HEADER_LENGTH) throw new EOFException();
diff --git a/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java b/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java
index 979ebb17c859e2251330c3672ab7b3e459385c33..07c9deaabf4affec9cfcc7892664351d766a9403 100644
--- a/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java
+++ b/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java
@@ -30,7 +30,6 @@ class StreamEncrypterFactoryImpl implements StreamEncrypterFactory {
 		byte[] tag = new byte[TAG_LENGTH];
 		SecretKey tagKey = crypto.deriveTagKey(secret, alice);
 		crypto.encodeTag(tag, tagKey, streamNumber);
-		tagKey.erase();
 		// Derive the frame key
 		SecretKey frameKey = crypto.deriveFrameKey(secret, streamNumber, alice);
 		// Create the encrypter
diff --git a/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java b/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java
index d3e2e43ce19af8d9742270d0d6cd52a6abb33988..43a6403912874e163f5a893361f1868713cca205 100644
--- a/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java
+++ b/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java
@@ -45,12 +45,7 @@ class StreamEncrypterImpl implements StreamEncrypter {
 		if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
 		// Write the tag if required
 		if(writeTag) {
-			try {
-				out.write(tag, 0, tag.length);
-			} catch(IOException e) {
-				frameKey.erase();
-				throw e;
-			}
+			out.write(tag, 0, tag.length);
 			writeTag = false;
 		}
 		// Don't pad the final frame
@@ -81,24 +76,14 @@ class StreamEncrypterImpl implements StreamEncrypter {
 			throw new RuntimeException(badCipher);
 		}
 		// Write the frame
-		try {
-			out.write(ciphertext, 0, ciphertextLength);
-		} catch(IOException e) {
-			frameKey.erase();
-			throw e;
-		}
+		out.write(ciphertext, 0, ciphertextLength);
 		frameNumber++;
 	}
 
 	public void flush() throws IOException {
 		// Write the tag if required
 		if(writeTag) {
-			try {
-				out.write(tag, 0, tag.length);
-			} catch(IOException e) {
-				frameKey.erase();
-				throw e;
-			}
+			out.write(tag, 0, tag.length);
 			writeTag = false;
 		}
 		out.flush();
diff --git a/briar-core/src/org/briarproject/db/H2Database.java b/briar-core/src/org/briarproject/db/H2Database.java
index d7f064ddb26b7f1c18a372504e1c640728b128e1..fc91e20dca23aab698dfa8ad5435d34f7898e28d 100644
--- a/briar-core/src/org/briarproject/db/H2Database.java
+++ b/briar-core/src/org/briarproject/db/H2Database.java
@@ -81,34 +81,18 @@ class H2Database extends JdbcDatabase {
 		}
 	}
 
+	@Override
 	protected Connection createConnection() throws SQLException {
 		byte[] key = config.getEncryptionKey();
 		if(key == null) throw new IllegalStateException();
-		char[] password = encodePassword(key);
 		Properties props = new Properties();
 		props.setProperty("user", "user");
-		props.put("password", password);
-		try {
-			return DriverManager.getConnection(url, props);
-		} finally {
-			for(int i = 0; i < password.length; i++) password[i] = 0;
-		}
-	}
-
-	private char[] encodePassword(byte[] key) {
-		// The database password is the hex-encoded key
-		char[] hex = StringUtils.toHexChars(key);
-		// Separate the database password from the user password with a space
-		char[] user = "password".toCharArray();
-		char[] combined = new char[hex.length + 1 + user.length];
-		System.arraycopy(hex, 0, combined, 0, hex.length);
-		combined[hex.length] = ' ';
-		System.arraycopy(user, 0, combined, hex.length + 1, user.length);
-		// Erase the hex-encoded key
-		for(int i = 0; i < hex.length; i++) hex[i] = 0;
-		return combined;
+		// Separate the file password from the user password with a space
+		props.put("password", StringUtils.toHexString(key) + " password");
+		return DriverManager.getConnection(url, props);
 	}
 
+	@Override
 	protected void flushBuffersToDisk(Statement s) throws SQLException {
 		// FIXME: Remove this after implementing BTPv2?
 		s.execute("CHECKPOINT SYNC");
diff --git a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java
index b72efb688db1d08dff6ea213022ccfa01ef1d7be..2b1a5c633ee8fbb63f13d1f2fcd57b514f7ad925 100644
--- a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java
+++ b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java
@@ -28,7 +28,6 @@ import org.briarproject.api.transport.StreamContext;
 import org.briarproject.api.transport.StreamReaderFactory;
 import org.briarproject.api.transport.StreamWriterFactory;
 import org.briarproject.api.transport.TagRecogniser;
-import org.briarproject.util.ByteUtils;
 
 class ConnectionManagerImpl implements ConnectionManager {
 
@@ -95,40 +94,28 @@ class ConnectionManagerImpl implements ConnectionManager {
 
 	private MessagingSession createIncomingSession(StreamContext ctx,
 			TransportConnectionReader r) throws IOException {
-		try {
-			InputStream streamReader = streamReaderFactory.createStreamReader(
-					r.getInputStream(), r.getMaxFrameLength(), ctx);
-			return messagingSessionFactory.createIncomingSession(
-					ctx.getContactId(), ctx.getTransportId(), streamReader);
-		} finally {
-			ByteUtils.erase(ctx.getSecret());
-		}
+		InputStream streamReader = streamReaderFactory.createStreamReader(
+				r.getInputStream(), r.getMaxFrameLength(), ctx);
+		return messagingSessionFactory.createIncomingSession(
+				ctx.getContactId(), ctx.getTransportId(), streamReader);
 	}
 
 	private MessagingSession createSimplexOutgoingSession(StreamContext ctx,
 			TransportConnectionWriter w) throws IOException {
-		try {
-			OutputStream streamWriter = streamWriterFactory.createStreamWriter(
-					w.getOutputStream(), w.getMaxFrameLength(), ctx);
-			return messagingSessionFactory.createSimplexOutgoingSession(
-					ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(),
-					streamWriter);
-		} finally {
-			ByteUtils.erase(ctx.getSecret());
-		}
+		OutputStream streamWriter = streamWriterFactory.createStreamWriter(
+				w.getOutputStream(), w.getMaxFrameLength(), ctx);
+		return messagingSessionFactory.createSimplexOutgoingSession(
+				ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(),
+				streamWriter);
 	}
 
 	private MessagingSession createDuplexOutgoingSession(StreamContext ctx,
 			TransportConnectionWriter w) throws IOException {
-		try {
-			OutputStream streamWriter = streamWriterFactory.createStreamWriter(
-					w.getOutputStream(), w.getMaxFrameLength(), ctx);
-			return messagingSessionFactory.createDuplexOutgoingSession(
-					ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(),
-					w.getMaxIdleTime(), streamWriter);
-		} finally {
-			ByteUtils.erase(ctx.getSecret());
-		}
+		OutputStream streamWriter = streamWriterFactory.createStreamWriter(
+				w.getOutputStream(), w.getMaxFrameLength(), ctx);
+		return messagingSessionFactory.createDuplexOutgoingSession(
+				ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(),
+				w.getMaxIdleTime(), streamWriter);
 	}
 
 	private class ManageIncomingSimplexConnection implements Runnable {
diff --git a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java
index 735e9f17bab18f14e525cbc0299463552a586350..089f724f8605a6d2043f1e26e6d52a7bedd2c481 100644
--- a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java
+++ b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java
@@ -33,7 +33,6 @@ import org.briarproject.api.transport.Endpoint;
 import org.briarproject.api.transport.StreamContext;
 import org.briarproject.api.transport.TagRecogniser;
 import org.briarproject.api.transport.TemporarySecret;
-import org.briarproject.util.ByteUtils;
 
 // FIXME: Don't make alien calls with a lock held
 class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
@@ -119,7 +118,6 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
 			Integer maxLatency = maxLatencies.get(s.getTransportId());
 			if(maxLatency == null) {
 				LOG.info("Discarding obsolete secret");
-				ByteUtils.erase(s.getSecret());
 				continue;
 			}
 			long rotation = maxLatency + MAX_CLOCK_DIFFERENCE;
@@ -143,7 +141,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
 		return dead;
 	}
 
-	// Replaces and erases the given secrets and returns any secrets created
+	// Replaces the given secrets and returns any secrets created
 	// Locking: this
 	private Collection<TemporarySecret> replaceDeadSecrets(long now,
 			Collection<TemporarySecret> dead) {
@@ -157,12 +155,10 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
 				// There's no other secret for this endpoint
 				newest.put(k, s);
 			} else if(exists.getPeriod() < s.getPeriod()) {
-				// There's an older secret - erase it and use this one instead
-				ByteUtils.erase(exists.getSecret());
+				// There's an older secret - use this one instead
 				newest.put(k, s);
 			} else {
-				// There's a newer secret - erase this one
-				ByteUtils.erase(s.getSecret());
+				// There's a newer secret - keep using it
 			}
 		}
 		Collection<TemporarySecret> created = new ArrayList<TemporarySecret>();
@@ -179,34 +175,23 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
 				throw new IllegalStateException();
 			// Derive the old, current and new secrets
 			byte[] b1 = s.getSecret();
-			for(long p = s.getPeriod() + 1; p < period; p++) {
-				byte[] temp = crypto.deriveNextSecret(b1, p);
-				ByteUtils.erase(b1);
-				b1 = temp;
-			}
+			for(long p = s.getPeriod() + 1; p < period; p++)
+				b1 = crypto.deriveNextSecret(b1, p);
 			byte[] b2 = crypto.deriveNextSecret(b1, period);
 			byte[] b3 = crypto.deriveNextSecret(b2, period + 1);
-			// Add the secrets to their respective maps - copies may already
-			// exist, in which case erase the new copies (the old copies are
-			// referenced by the connection recogniser)
+			// Add the secrets to their respective maps if not already present
 			EndpointKey k = e.getKey();
-			if(oldSecrets.containsKey(k)) {
-				ByteUtils.erase(b1);
-			} else {
+			if(!oldSecrets.containsKey(k)) {
 				TemporarySecret s1 = new TemporarySecret(s, period - 1, b1);
 				oldSecrets.put(k, s1);
 				created.add(s1);
 			}
-			if(currentSecrets.containsKey(k)) {
-				ByteUtils.erase(b2);
-			} else {
+			if(!currentSecrets.containsKey(k)) {
 				TemporarySecret s2 = new TemporarySecret(s, period, b2);
 				currentSecrets.put(k, s2);
 				created.add(s2);
 			}
-			if(newSecrets.containsKey(k)) {
-				ByteUtils.erase(b3);
-			} else {
+			if(!newSecrets.containsKey(k)) {
 				TemporarySecret s3 = new TemporarySecret(s, period + 1, b3);
 				newSecrets.put(k, s3);
 				created.add(s3);
@@ -220,18 +205,12 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
 		timer.cancel();
 		tagRecogniser.removeSecrets();
 		maxLatencies.clear();
-		removeAndEraseSecrets(oldSecrets);
-		removeAndEraseSecrets(currentSecrets);
-		removeAndEraseSecrets(newSecrets);
+		oldSecrets.clear();
+		currentSecrets.clear();
+		newSecrets.clear();
 		return true;
 	}
 
-	// Locking: this
-	private void removeAndEraseSecrets(Map<?, TemporarySecret> m) {
-		for(TemporarySecret s : m.values()) ByteUtils.erase(s.getSecret());
-		m.clear();
-	}
-
 	public synchronized StreamContext getStreamContext(ContactId c,
 			TransportId t) {
 		TemporarySecret s = currentSecrets.get(new EndpointKey(c, t));
@@ -250,8 +229,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
 			if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 			return null;
 		}
-		// Clone the secret - the original will be erased
-		byte[] secret = s.getSecret().clone();
+		byte[] secret = s.getSecret();
 		return new StreamContext(c, t, secret, streamNumber, s.getAlice());
 	}
 
@@ -265,11 +243,8 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
 		if(period < 1) throw new IllegalStateException();
 		// Derive the old, current and new secrets
 		byte[] b1 = initialSecret;
-		for(long p = 0; p < period; p++) {
-			byte[] temp = crypto.deriveNextSecret(b1, p);
-			ByteUtils.erase(b1);
-			b1 = temp;
-		}
+		for(long p = 0; p < period; p++)
+			b1 = crypto.deriveNextSecret(b1, p);
 		byte[] b2 = crypto.deriveNextSecret(b1, period);
 		byte[] b3 = crypto.deriveNextSecret(b2, period + 1);
 		TemporarySecret s1 = new TemporarySecret(ep, period - 1, b1);
@@ -341,28 +316,17 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
 	}
 
 	// Locking: this
-	private void removeAndEraseSecrets(ContactId c, Map<?, TemporarySecret> m) {
+	private void removeSecrets(ContactId c, Map<?, TemporarySecret> m) {
 		Iterator<TemporarySecret> it = m.values().iterator();
-		while(it.hasNext()) {
-			TemporarySecret s = it.next();
-			if(s.getContactId().equals(c)) {
-				ByteUtils.erase(s.getSecret());
-				it.remove();
-			}
-		}
+		while(it.hasNext())
+			if(it.next().getContactId().equals(c)) it.remove();
 	}
 
 	// Locking: this
-	private void removeAndEraseSecrets(TransportId t,
-			Map<?, TemporarySecret> m) {
+	private void removeSecrets(TransportId t, Map<?, TemporarySecret> m) {
 		Iterator<TemporarySecret> it = m.values().iterator();
-		while(it.hasNext()) {
-			TemporarySecret s = it.next();
-			if(s.getTransportId().equals(t)) {
-				ByteUtils.erase(s.getSecret());
-				it.remove();
-			}
-		}
+		while(it.hasNext())
+			if(it.next().getTransportId().equals(t)) it.remove();
 	}
 
 	private static class EndpointKey {
@@ -408,9 +372,9 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
 			ContactId c = event.getContactId();
 			tagRecogniser.removeSecrets(c);
 			synchronized(KeyManagerImpl.this) {
-				removeAndEraseSecrets(c, oldSecrets);
-				removeAndEraseSecrets(c, currentSecrets);
-				removeAndEraseSecrets(c, newSecrets);
+				removeSecrets(c, oldSecrets);
+				removeSecrets(c, currentSecrets);
+				removeSecrets(c, newSecrets);
 			}
 		}
 	}
@@ -445,9 +409,9 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
 			tagRecogniser.removeSecrets(t);
 			synchronized(KeyManagerImpl.this) {
 				maxLatencies.remove(t);
-				removeAndEraseSecrets(t, oldSecrets);
-				removeAndEraseSecrets(t, currentSecrets);
-				removeAndEraseSecrets(t, newSecrets);
+				removeSecrets(t, oldSecrets);
+				removeSecrets(t, currentSecrets);
+				removeSecrets(t, newSecrets);
 			}
 		}
 	}
diff --git a/briar-core/src/org/briarproject/transport/TransportTagRecogniser.java b/briar-core/src/org/briarproject/transport/TransportTagRecogniser.java
index 3c9508397c757219c331a469b0c61489a0c7fde1..285b4465e4543fdd5a1bb252b6d5b8c77ed02c5f 100644
--- a/briar-core/src/org/briarproject/transport/TransportTagRecogniser.java
+++ b/briar-core/src/org/briarproject/transport/TransportTagRecogniser.java
@@ -56,13 +56,10 @@ class TransportTagRecogniser {
 				assert duplicate == null;
 			}
 		}
-		key.erase();
 		// Store the updated reordering window in the DB
 		db.setReorderingWindow(t.contactId, transportId, t.period,
 				t.window.getCentre(), t.window.getBitmap());
-		// Clone the secret - the key manager will erase the original
-		byte[] secret = t.secret.clone();
-		return new StreamContext(t.contactId, transportId, secret,
+		return new StreamContext(t.contactId, transportId, t.secret,
 				t.streamNumber, t.alice);
 	}
 
@@ -84,7 +81,6 @@ class TransportTagRecogniser {
 			TagContext duplicate = tagMap.put(new Bytes(tag), added);
 			assert duplicate == null;
 		}
-		key.erase();
 		// Create a removal context to remove the window and the tags later
 		RemovalContext r = new RemovalContext(window, secret, alice);
 		removalMap.put(new RemovalKey(contactId, period), r);
@@ -107,7 +103,6 @@ class TransportTagRecogniser {
 			TagContext removed = tagMap.remove(new Bytes(tag));
 			assert removed != null;
 		}
-		key.erase();
 	}
 
 	synchronized void removeSecrets(ContactId c) {
diff --git a/briar-core/src/org/briarproject/util/ByteUtils.java b/briar-core/src/org/briarproject/util/ByteUtils.java
index ed40306e5931afcfed36dca9def9e540f2a7259f..9cc9e6bc8826f36847c1d14b639b8d2a897c7900 100644
--- a/briar-core/src/org/briarproject/util/ByteUtils.java
+++ b/briar-core/src/org/briarproject/util/ByteUtils.java
@@ -48,10 +48,6 @@ public class ByteUtils {
 				| ((b[offset + 2] & 0xFFL) << 8) | (b[offset + 3] & 0xFFL);
 	}
 
-	public static void erase(byte[] b) {
-		for(int i = 0; i < b.length; i++) b[i] = 0;
-	}
-
 	public static int readUint(byte[] b, int bits) {
 		if(b.length << 3 < bits) throw new IllegalArgumentException();
 		int result = 0;
diff --git a/briar-tests/build.xml b/briar-tests/build.xml
index 561a3fbe55f269efd55d54370c17649efb808a7d..eb4766a090b7d734a50b0f2c83bc06af304eccc6 100644
--- a/briar-tests/build.xml
+++ b/briar-tests/build.xml
@@ -100,8 +100,7 @@
 			<test name='org.briarproject.crypto.KeyDerivationTest'/>
 			<test name='org.briarproject.crypto.KeyEncodingAndParsingTest'/>
 			<test name="org.briarproject.crypto.PasswordBasedKdfTest"/>
-			<test name="org.briarproject.crypto.PasswordStrengthEstimatorTest"/>
-			<test name='org.briarproject.crypto.SecretKeyImplTest'/>
+			<test name="org.briarproject.crypto.PasswordStrengthEstimatorImplTest"/>
 			<test name='org.briarproject.crypto.StreamDecrypterImplTest'/>
 			<test name='org.briarproject.crypto.StreamEncrypterImplTest'/>
 			<test name='org.briarproject.db.BasicH2Test'/>
diff --git a/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java b/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java
index a3983b5a2eaf490f3030f72db9e9371a80fb9117..cfd5af2d57e179779eeea1b2fa133a09e5f98e71 100644
--- a/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java
+++ b/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java
@@ -116,8 +116,8 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 
 	private byte[] write() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		StreamContext ctx = new StreamContext(contactId, transportId,
-				secret.clone(), 0, true);
+		StreamContext ctx = new StreamContext(contactId, transportId, secret,
+				0, true);
 		OutputStream streamWriter = streamWriterFactory.createStreamWriter(out,
 				MAX_FRAME_LENGTH, ctx);
 		PacketWriter packetWriter = packetWriterFactory.createPacketWriter(
@@ -148,8 +148,8 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 		byte[] tag = new byte[TAG_LENGTH];
 		assertEquals(TAG_LENGTH, in.read(tag, 0, TAG_LENGTH));
 		// FIXME: Check that the expected tag was received
-		StreamContext ctx = new StreamContext(contactId, transportId,
-				secret.clone(), 0, false);
+		StreamContext ctx = new StreamContext(contactId, transportId, secret,
+				0, false);
 		InputStream streamReader = streamReaderFactory.createStreamReader(in,
 				MAX_FRAME_LENGTH, ctx);
 		PacketReader packetReader = packetReaderFactory.createPacketReader(
diff --git a/briar-tests/src/org/briarproject/crypto/KeyDerivationTest.java b/briar-tests/src/org/briarproject/crypto/KeyDerivationTest.java
index 54c4a3c1560d6363bbe277a740a358ae811aff30..d0d71a7eb77dadec8b18cdad72d6f1095780d492 100644
--- a/briar-tests/src/org/briarproject/crypto/KeyDerivationTest.java
+++ b/briar-tests/src/org/briarproject/crypto/KeyDerivationTest.java
@@ -30,9 +30,9 @@ public class KeyDerivationTest extends BriarTestCase {
 		keys.add(crypto.deriveTagKey(secret, true));
 		keys.add(crypto.deriveTagKey(secret, false));
 		for(int i = 0; i < 4; i++) {
-			byte[] keyI = keys.get(i).getEncoded();
+			byte[] keyI = keys.get(i).getBytes();
 			for(int j = 0; j < 4; j++) {
-				byte[] keyJ = keys.get(j).getEncoded();
+				byte[] keyJ = keys.get(j).getBytes();
 				assertEquals(i == j, Arrays.equals(keyI, keyJ));
 			}
 		}
@@ -59,9 +59,8 @@ public class KeyDerivationTest extends BriarTestCase {
 	@Test
 	public void testStreamNumberAffectsDerivation() {
 		List<byte[]> secrets = new ArrayList<byte[]>();
-		for(int i = 0; i < 20; i++) {
-			secrets.add(crypto.deriveNextSecret(secret.clone(), i));
-		}
+		for(int i = 0; i < 20; i++)
+			secrets.add(crypto.deriveNextSecret(secret, i));
 		for(int i = 0; i < 20; i++) {
 			byte[] secretI = secrets.get(i);
 			for(int j = 0; j < 20; j++) {
diff --git a/briar-tests/src/org/briarproject/crypto/PasswordBasedKdfTest.java b/briar-tests/src/org/briarproject/crypto/PasswordBasedKdfTest.java
index 151f78fb57777f1ecffa4df16620bce3e9f3c64c..cdc59b3323a7e88b37b48ccc9bf2df006ac63744 100644
--- a/briar-tests/src/org/briarproject/crypto/PasswordBasedKdfTest.java
+++ b/briar-tests/src/org/briarproject/crypto/PasswordBasedKdfTest.java
@@ -18,7 +18,7 @@ public class PasswordBasedKdfTest extends BriarTestCase {
 		Random random = new Random();
 		byte[] input = new byte[1234];
 		random.nextBytes(input);
-		char[] password = "password".toCharArray();
+		String password = "password";
 		byte[] ciphertext = crypto.encryptWithPassword(input, password);
 		byte[] output = crypto.decryptWithPassword(ciphertext, password);
 		assertArrayEquals(input, output);
@@ -29,7 +29,7 @@ public class PasswordBasedKdfTest extends BriarTestCase {
 		Random random = new Random();
 		byte[] input = new byte[1234];
 		random.nextBytes(input);
-		char[] password = "password".toCharArray();
+		String password = "password";
 		byte[] ciphertext = crypto.encryptWithPassword(input, password);
 		// Modify the ciphertext
 		int position = random.nextInt(ciphertext.length);
diff --git a/briar-tests/src/org/briarproject/crypto/PasswordStrengthEstimatorTest.java b/briar-tests/src/org/briarproject/crypto/PasswordStrengthEstimatorImplTest.java
similarity index 50%
rename from briar-tests/src/org/briarproject/crypto/PasswordStrengthEstimatorTest.java
rename to briar-tests/src/org/briarproject/crypto/PasswordStrengthEstimatorImplTest.java
index 9f703b378f7acaa13670691c8101a156279f132e..5407daf9ae72feb4331f2b71d87134d05b10db46 100644
--- a/briar-tests/src/org/briarproject/crypto/PasswordStrengthEstimatorTest.java
+++ b/briar-tests/src/org/briarproject/crypto/PasswordStrengthEstimatorImplTest.java
@@ -6,24 +6,23 @@ import org.briarproject.BriarTestCase;
 import org.briarproject.api.crypto.PasswordStrengthEstimator;
 import org.junit.Test;
 
-public class PasswordStrengthEstimatorTest extends BriarTestCase {
+public class PasswordStrengthEstimatorImplTest extends BriarTestCase {
 
 	@Test
 	public void testWeakPasswords() {
 		PasswordStrengthEstimator e = new PasswordStrengthEstimatorImpl();
-		assertTrue(e.estimateStrength("".toCharArray()) < QUITE_STRONG);
-		assertTrue(e.estimateStrength("password".toCharArray()) < QUITE_STRONG);
-		assertTrue(e.estimateStrength("letmein".toCharArray()) < QUITE_STRONG);
-		assertTrue(e.estimateStrength("123456".toCharArray()) < QUITE_STRONG);
+		assertTrue(e.estimateStrength("") < QUITE_STRONG);
+		assertTrue(e.estimateStrength("password") < QUITE_STRONG);
+		assertTrue(e.estimateStrength("letmein") < QUITE_STRONG);
+		assertTrue(e.estimateStrength("123456") < QUITE_STRONG);
 	}
 
 	@Test
 	public void testStrongPasswords() {
 		PasswordStrengthEstimator e = new PasswordStrengthEstimatorImpl();
 		// Industry standard
-		assertTrue(e.estimateStrength("Tr0ub4dor&3".toCharArray())
-				> QUITE_STRONG);
-		assertTrue(e.estimateStrength("correcthorsebatterystaple".toCharArray())
+		assertTrue(e.estimateStrength("Tr0ub4dor&3") > QUITE_STRONG);
+		assertTrue(e.estimateStrength("correcthorsebatterystaple")
 				> QUITE_STRONG);
 	}
 }
diff --git a/briar-tests/src/org/briarproject/crypto/SecretKeyImplTest.java b/briar-tests/src/org/briarproject/crypto/SecretKeyImplTest.java
deleted file mode 100644
index 20ee3605bf954d68df560c0d11bfb47d4bbeb599..0000000000000000000000000000000000000000
--- a/briar-tests/src/org/briarproject/crypto/SecretKeyImplTest.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.briarproject.crypto;
-
-import static org.junit.Assert.assertArrayEquals;
-
-import java.util.Random;
-
-import org.briarproject.BriarTestCase;
-import org.briarproject.api.crypto.SecretKey;
-import org.junit.Test;
-
-public class SecretKeyImplTest extends BriarTestCase {
-
-	private static final int KEY_BYTES = 32; // 256 bits
-
-	@Test
-	public void testCopiesAreErased() {
-		byte[] master = new byte[KEY_BYTES];
-		new Random().nextBytes(master);
-		SecretKey k = new SecretKeyImpl(master);
-		byte[] copy = k.getEncoded();
-		assertArrayEquals(master, copy);
-		k.erase();
-		byte[] blank = new byte[KEY_BYTES];
-		assertArrayEquals(blank, master);
-		assertArrayEquals(blank, copy);
-	}
-}
diff --git a/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java b/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java
index 3bce2a6e39d6b004dfa4daaa3feae094bf1b7ad0..d0a8359af4da6399c71cbbeb3b5acbbdc493552f 100644
--- a/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java
+++ b/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java
@@ -127,7 +127,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
 		db.addTransport(transportId, MAX_LATENCY);
 		Endpoint ep = new Endpoint(contactId, transportId, epoch, true);
 		db.addEndpoint(ep);
-		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone());
+		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret);
 		// Send Bob a message
 		String contentType = "text/plain";
 		long timestamp = System.currentTimeMillis();
@@ -190,7 +190,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
 		db.addTransport(transportId, MAX_LATENCY);
 		Endpoint ep = new Endpoint(contactId, transportId, epoch, false);
 		db.addEndpoint(ep);
-		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone());
+		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret);
 		// Set up an event listener
 		MessageListener listener = new MessageListener();
 		bob.getInstance(EventBus.class).addListener(listener);
diff --git a/briar-tests/src/org/briarproject/transport/KeyManagerImplTest.java b/briar-tests/src/org/briarproject/transport/KeyManagerImplTest.java
index c160b59db3dfdd6498ea96a8f8e767a6eb041e05..12880b1b8ea8789ce2c690f30eac6c2ed430e2d7 100644
--- a/briar-tests/src/org/briarproject/transport/KeyManagerImplTest.java
+++ b/briar-tests/src/org/briarproject/transport/KeyManagerImplTest.java
@@ -103,9 +103,9 @@ public class KeyManagerImplTest extends BriarTestCase {
 
 		// The secrets for periods 0 - 2 should be derived
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -123,11 +123,11 @@ public class KeyManagerImplTest extends BriarTestCase {
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(EPOCH));
 			oneOf(crypto).deriveNextSecret(initialSecret, 0);
-			will(returnValue(secret0.clone()));
+			will(returnValue(secret0));
 			oneOf(crypto).deriveNextSecret(secret0, 1);
-			will(returnValue(secret1.clone()));
+			will(returnValue(secret1));
 			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
+			will(returnValue(secret2));
 			oneOf(db).addSecrets(Arrays.asList(s0, s1, s2));
 			// The secrets for periods 0 - 2 should be added to the recogniser
 			oneOf(tagRecogniser).addSecret(s0);
@@ -140,7 +140,7 @@ public class KeyManagerImplTest extends BriarTestCase {
 		}});
 
 		assertTrue(keyManager.start());
-		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone());
+		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret);
 		keyManager.stop();
 
 		context.assertIsSatisfied();
@@ -161,9 +161,9 @@ public class KeyManagerImplTest extends BriarTestCase {
 
 		// The secrets for periods 0 - 2 should be derived
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -181,11 +181,11 @@ public class KeyManagerImplTest extends BriarTestCase {
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(EPOCH));
 			oneOf(crypto).deriveNextSecret(initialSecret, 0);
-			will(returnValue(secret0.clone()));
+			will(returnValue(secret0));
 			oneOf(crypto).deriveNextSecret(secret0, 1);
-			will(returnValue(secret1.clone()));
+			will(returnValue(secret1));
 			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
+			will(returnValue(secret2));
 			oneOf(db).addSecrets(Arrays.asList(s0, s1, s2));
 			// The secrets for periods 0 - 2 should be added to the recogniser
 			oneOf(tagRecogniser).addSecret(s0);
@@ -201,7 +201,7 @@ public class KeyManagerImplTest extends BriarTestCase {
 		}});
 
 		assertTrue(keyManager.start());
-		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone());
+		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret);
 		StreamContext ctx =
 				keyManager.getStreamContext(contactId, transportId);
 		assertNotNull(ctx);
@@ -230,9 +230,9 @@ public class KeyManagerImplTest extends BriarTestCase {
 
 		// The DB contains the secrets for periods 0 - 2
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -278,11 +278,11 @@ public class KeyManagerImplTest extends BriarTestCase {
 
 		// The DB contains the secrets for periods 0 - 2
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 		// The secret for period 3 should be derived and stored
-		final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3.clone());
+		final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -297,11 +297,11 @@ public class KeyManagerImplTest extends BriarTestCase {
 			will(returnValue(EPOCH + ROTATION_PERIOD));
 			// The secret for period 3 should be derived and stored
 			oneOf(crypto).deriveNextSecret(secret0, 1);
-			will(returnValue(secret1.clone()));
+			will(returnValue(secret1));
 			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
+			will(returnValue(secret2));
 			oneOf(crypto).deriveNextSecret(secret2, 3);
-			will(returnValue(secret3.clone()));
+			will(returnValue(secret3));
 			oneOf(db).addSecrets(Arrays.asList(s3));
 			// The secrets for periods 1 - 3 should be added to the recogniser
 			oneOf(tagRecogniser).addSecret(s1);
@@ -336,12 +336,12 @@ public class KeyManagerImplTest extends BriarTestCase {
 
 		// The DB contains the secrets for periods 0 - 2
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 		// The secrets for periods 3 and 4 should be derived and stored
-		final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3.clone());
-		final TemporarySecret s4 = new TemporarySecret(ep, 4, secret4.clone());
+		final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3);
+		final TemporarySecret s4 = new TemporarySecret(ep, 4, secret4);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -356,11 +356,11 @@ public class KeyManagerImplTest extends BriarTestCase {
 			will(returnValue(EPOCH + 3 * ROTATION_PERIOD - 1));
 			// The secrets for periods 3 and 4 should be derived from secret 1
 			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
+			will(returnValue(secret2));
 			oneOf(crypto).deriveNextSecret(secret2, 3);
-			will(returnValue(secret3.clone()));
+			will(returnValue(secret3));
 			oneOf(crypto).deriveNextSecret(secret3, 4);
-			will(returnValue(secret4.clone()));
+			will(returnValue(secret4));
 			// The new secrets should be stored
 			oneOf(db).addSecrets(Arrays.asList(s3, s4));
 			// The secrets for periods 2 - 4 should be added to the recogniser
@@ -396,9 +396,9 @@ public class KeyManagerImplTest extends BriarTestCase {
 
 		// The DB contains the secrets for periods 0 - 2
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -459,11 +459,11 @@ public class KeyManagerImplTest extends BriarTestCase {
 
 		// The DB contains the secrets for periods 0 - 2
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 		// The secret for period 3 should be derived and stored
-		final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3.clone());
+		final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -486,11 +486,11 @@ public class KeyManagerImplTest extends BriarTestCase {
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(EPOCH + ROTATION_PERIOD + 1));
 			oneOf(crypto).deriveNextSecret(secret0, 1);
-			will(returnValue(secret1.clone()));
+			will(returnValue(secret1));
 			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
+			will(returnValue(secret2));
 			oneOf(crypto).deriveNextSecret(secret2, 3);
-			will(returnValue(secret3.clone()));
+			will(returnValue(secret3));
 			oneOf(tagRecogniser).removeSecret(contactId, transportId, 0);
 			oneOf(db).addSecrets(Arrays.asList(s3));
 			oneOf(tagRecogniser).addSecret(s3);
@@ -533,12 +533,12 @@ public class KeyManagerImplTest extends BriarTestCase {
 
 		// The DB contains the secrets for periods 0 - 2
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 		// The secrets for periods 3 and 4 should be derived and stored
-		final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3.clone());
-		final TemporarySecret s4 = new TemporarySecret(ep, 4, secret4.clone());
+		final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3);
+		final TemporarySecret s4 = new TemporarySecret(ep, 4, secret4);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -561,11 +561,11 @@ public class KeyManagerImplTest extends BriarTestCase {
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(EPOCH + 2 * ROTATION_PERIOD + 1));
 			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
+			will(returnValue(secret2));
 			oneOf(crypto).deriveNextSecret(secret2, 3);
-			will(returnValue(secret3.clone()));
+			will(returnValue(secret3));
 			oneOf(crypto).deriveNextSecret(secret3, 4);
-			will(returnValue(secret4.clone()));
+			will(returnValue(secret4));
 			oneOf(tagRecogniser).removeSecret(contactId, transportId, 0);
 			oneOf(tagRecogniser).removeSecret(contactId, transportId, 1);
 			oneOf(db).addSecrets(Arrays.asList(s3, s4));
diff --git a/briar-tests/src/org/briarproject/transport/KeyRotationIntegrationTest.java b/briar-tests/src/org/briarproject/transport/KeyRotationIntegrationTest.java
index 70e8cfea3c9b2039873d833afe10e2f2d993640a..84b6f89289d70d4b868a349d3765cdd266d68167 100644
--- a/briar-tests/src/org/briarproject/transport/KeyRotationIntegrationTest.java
+++ b/briar-tests/src/org/briarproject/transport/KeyRotationIntegrationTest.java
@@ -40,6 +40,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 	private final TransportId transportId;
 	private final byte[] secret0, secret1, secret2, secret3, secret4;
 	private final byte[] key0, key1, key2, key3, key4;
+	private final SecretKey k0, k1, k2, k3, k4;
 	private final byte[] initialSecret;
 
 	public KeyRotationIntegrationTest() {
@@ -60,6 +61,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 		key2 = new byte[32];
 		key3 = new byte[32];
 		key4 = new byte[32];
+		k0 = new SecretKey(key0);
+		k1 = new SecretKey(key1);
+		k2 = new SecretKey(key2);
+		k3 = new SecretKey(key3);
+		k4 = new SecretKey(key4);
 		for(int i = 0; i < key0.length; i++) key0[i] = 1;
 		for(int i = 0; i < key1.length; i++) key1[i] = 2;
 		for(int i = 0; i < key2.length; i++) key2[i] = 3;
@@ -112,9 +118,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 		final EventBus eventBus = context.mock(EventBus.class);
 		final Clock clock = context.mock(Clock.class);
 		final Timer timer = context.mock(Timer.class);
-		final SecretKey k0 = context.mock(SecretKey.class, "k0");
-		final SecretKey k1 = context.mock(SecretKey.class, "k1");
-		final SecretKey k2 = context.mock(SecretKey.class, "k2");
 
 		final TagRecogniser tagRecogniser = new TagRecogniserImpl(crypto, db);
 		final KeyManagerImpl keyManager = new KeyManagerImpl(crypto, db,
@@ -122,9 +125,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 
 		// The secrets for periods 0 - 2 should be derived
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -142,11 +145,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(EPOCH));
 			oneOf(crypto).deriveNextSecret(initialSecret, 0);
-			will(returnValue(secret0.clone()));
+			will(returnValue(secret0));
 			oneOf(crypto).deriveNextSecret(secret0, 1);
-			will(returnValue(secret1.clone()));
+			will(returnValue(secret1));
 			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
+			will(returnValue(secret2));
 			oneOf(db).addSecrets(Arrays.asList(s0, s1, s2));
 			// The recogniser should derive the tags for period 0
 			oneOf(crypto).deriveTagKey(secret0, false);
@@ -155,10 +158,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k0).getEncoded();
-				will(returnValue(key0));
 			}
-			oneOf(k0).erase();
 			// The recogniser should derive the tags for period 1
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
@@ -166,10 +166,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k1).getEncoded();
-				will(returnValue(key1));
 			}
-			oneOf(k1).erase();
 			// The recogniser should derive the tags for period 2
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
@@ -177,10 +174,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k2).getEncoded();
-				will(returnValue(key2));
 			}
-			oneOf(k2).erase();
 			// stop()
 			// The recogniser should derive the tags for period 0
 			oneOf(crypto).deriveTagKey(secret0, false);
@@ -189,10 +183,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k0).getEncoded();
-				will(returnValue(key0));
 			}
-			oneOf(k0).erase();
 			// The recogniser should derive the tags for period 1
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
@@ -200,10 +191,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k1).getEncoded();
-				will(returnValue(key1));
 			}
-			oneOf(k1).erase();
 			// The recogniser should derive the tags for period 2
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
@@ -211,17 +199,14 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k2).getEncoded();
-				will(returnValue(key2));
 			}
-			oneOf(k2).erase();
 			// Remove the listener and stop the timer
 			oneOf(eventBus).removeListener(with(any(EventListener.class)));
 			oneOf(timer).cancel();
 		}});
 
 		assertTrue(keyManager.start());
-		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone());
+		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret);
 		keyManager.stop();
 
 		context.assertIsSatisfied();
@@ -235,9 +220,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 		final EventBus eventBus = context.mock(EventBus.class);
 		final Clock clock = context.mock(Clock.class);
 		final Timer timer = context.mock(Timer.class);
-		final SecretKey k0 = context.mock(SecretKey.class, "k0");
-		final SecretKey k1 = context.mock(SecretKey.class, "k1");
-		final SecretKey k2 = context.mock(SecretKey.class, "k2");
 
 		final TagRecogniser tagRecogniser = new TagRecogniserImpl(crypto, db);
 		final KeyManagerImpl keyManager = new KeyManagerImpl(crypto, db,
@@ -245,9 +227,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 
 		// The secrets for periods 0 - 2 should be derived
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -265,11 +247,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(EPOCH));
 			oneOf(crypto).deriveNextSecret(initialSecret, 0);
-			will(returnValue(secret0.clone()));
+			will(returnValue(secret0));
 			oneOf(crypto).deriveNextSecret(secret0, 1);
-			will(returnValue(secret1.clone()));
+			will(returnValue(secret1));
 			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
+			will(returnValue(secret2));
 			oneOf(db).addSecrets(Arrays.asList(s0, s1, s2));
 			// The recogniser should derive the tags for period 0
 			oneOf(crypto).deriveTagKey(secret0, false);
@@ -278,10 +260,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k0).getEncoded();
-				will(returnValue(key0));
 			}
-			oneOf(k0).erase();
 			// The recogniser should derive the tags for period 1
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
@@ -289,10 +268,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k1).getEncoded();
-				will(returnValue(key1));
 			}
-			oneOf(k1).erase();
 			// The recogniser should derive the tags for period 2
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
@@ -300,10 +276,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k2).getEncoded();
-				will(returnValue(key2));
 			}
-			oneOf(k2).erase();
 			// getConnectionContext()
 			oneOf(db).incrementStreamCounter(contactId, transportId, 1);
 			will(returnValue(0L));
@@ -315,10 +288,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k0).getEncoded();
-				will(returnValue(key0));
 			}
-			oneOf(k0).erase();
 			// The recogniser should derive the tags for period 1
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
@@ -326,10 +296,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k1).getEncoded();
-				will(returnValue(key1));
 			}
-			oneOf(k1).erase();
 			// The recogniser should derive the tags for period 2
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
@@ -337,17 +304,14 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k2).getEncoded();
-				will(returnValue(key2));
 			}
-			oneOf(k2).erase();
 			// Remove the listener and stop the timer
 			oneOf(eventBus).removeListener(with(any(EventListener.class)));
 			oneOf(timer).cancel();
 		}});
 
 		assertTrue(keyManager.start());
-		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone());
+		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret);
 		StreamContext ctx =
 				keyManager.getStreamContext(contactId, transportId);
 		assertNotNull(ctx);
@@ -369,9 +333,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 		final EventBus eventBus = context.mock(EventBus.class);
 		final Clock clock = context.mock(Clock.class);
 		final Timer timer = context.mock(Timer.class);
-		final SecretKey k0 = context.mock(SecretKey.class, "k0");
-		final SecretKey k1 = context.mock(SecretKey.class, "k1");
-		final SecretKey k2 = context.mock(SecretKey.class, "k2");
 
 		final TagRecogniser tagRecogniser = new TagRecogniserImpl(crypto, db);
 		final KeyManagerImpl keyManager = new KeyManagerImpl(crypto, db,
@@ -379,9 +340,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 
 		// The secrets for periods 0 - 2 should be derived
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -399,11 +360,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(EPOCH));
 			oneOf(crypto).deriveNextSecret(initialSecret, 0);
-			will(returnValue(secret0.clone()));
+			will(returnValue(secret0));
 			oneOf(crypto).deriveNextSecret(secret0, 1);
-			will(returnValue(secret1.clone()));
+			will(returnValue(secret1));
 			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
+			will(returnValue(secret2));
 			oneOf(db).addSecrets(Arrays.asList(s0, s1, s2));
 			// The recogniser should derive the tags for period 0
 			oneOf(crypto).deriveTagKey(secret0, false);
@@ -412,10 +373,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k0).getEncoded();
-				will(returnValue(key0));
 			}
-			oneOf(k0).erase();
 			// The recogniser should derive the tags for period 1
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
@@ -423,10 +381,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k1).getEncoded();
-				will(returnValue(key1));
 			}
-			oneOf(k1).erase();
 			// The recogniser should derive the tags for period 2
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
@@ -434,21 +389,15 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k2).getEncoded();
-				will(returnValue(key2));
 			}
-			oneOf(k2).erase();
 			// acceptConnection()
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
-			oneOf(crypto).encodeTag(with(any(byte[].class)),
-					with(k2), with(16L));
+			oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
+					with(16L));
 			will(new EncodeTagAction());
-			oneOf(k2).getEncoded();
-			will(returnValue(key2));
 			oneOf(db).setReorderingWindow(contactId, transportId, 2, 1,
 					new byte[] {0, 1, 0, 0});
-			oneOf(k2).erase();
 			// stop()
 			// The recogniser should derive the tags for period 0
 			oneOf(crypto).deriveTagKey(secret0, false);
@@ -457,10 +406,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k0).getEncoded();
-				will(returnValue(key0));
 			}
-			oneOf(k0).erase();
 			// The recogniser should derive the tags for period 1
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
@@ -468,10 +414,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k1).getEncoded();
-				will(returnValue(key1));
 			}
-			oneOf(k1).erase();
 			// The recogniser should derive the updated tags for period 2
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
@@ -479,17 +422,14 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k2).getEncoded();
-				will(returnValue(key2));
 			}
-			oneOf(k2).erase();
 			// Remove the listener and stop the timer
 			oneOf(eventBus).removeListener(with(any(EventListener.class)));
 			oneOf(timer).cancel();
 		}});
 
 		assertTrue(keyManager.start());
-		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone());
+		keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret);
 		// Recognise the tag for connection 0 in period 2
 		byte[] tag = new byte[TAG_LENGTH];
 		encodeTag(tag, key2, 0);
@@ -513,9 +453,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 		final EventBus eventBus = context.mock(EventBus.class);
 		final Clock clock = context.mock(Clock.class);
 		final Timer timer = context.mock(Timer.class);
-		final SecretKey k0 = context.mock(SecretKey.class, "k0");
-		final SecretKey k1 = context.mock(SecretKey.class, "k1");
-		final SecretKey k2 = context.mock(SecretKey.class, "k2");
 
 		final TagRecogniser tagRecogniser = new TagRecogniserImpl(crypto, db);
 		final KeyManagerImpl keyManager = new KeyManagerImpl(crypto, db,
@@ -523,9 +460,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 
 		// The DB contains the secrets for periods 0 - 2
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -545,10 +482,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k0).getEncoded();
-				will(returnValue(key0));
 			}
-			oneOf(k0).erase();
 			// The recogniser should derive the tags for period 1
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
@@ -556,10 +490,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k1).getEncoded();
-				will(returnValue(key1));
 			}
-			oneOf(k1).erase();
 			// The recogniser should derive the tags for period 2
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
@@ -567,10 +498,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k2).getEncoded();
-				will(returnValue(key2));
 			}
-			oneOf(k2).erase();
 			// Start the timer
 			oneOf(timer).scheduleAtFixedRate(with(keyManager),
 					with(any(long.class)), with(any(long.class)));
@@ -582,10 +510,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k0).getEncoded();
-				will(returnValue(key0));
 			}
-			oneOf(k0).erase();
 			// The recogniser should derive the tags for period 1
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
@@ -593,10 +518,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k1).getEncoded();
-				will(returnValue(key1));
 			}
-			oneOf(k1).erase();
 			// The recogniser should derive the tags for period 2
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
@@ -604,10 +526,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k2).getEncoded();
-				will(returnValue(key2));
 			}
-			oneOf(k2).erase();
 			// Remove the listener and stop the timer
 			oneOf(eventBus).removeListener(with(any(EventListener.class)));
 			oneOf(timer).cancel();
@@ -627,9 +546,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 		final EventBus eventBus = context.mock(EventBus.class);
 		final Clock clock = context.mock(Clock.class);
 		final Timer timer = context.mock(Timer.class);
-		final SecretKey k1 = context.mock(SecretKey.class, "k1");
-		final SecretKey k2 = context.mock(SecretKey.class, "k2");
-		final SecretKey k3 = context.mock(SecretKey.class, "k3");
 
 		final TagRecogniser tagRecogniser = new TagRecogniserImpl(crypto, db);
 		final KeyManagerImpl keyManager = new KeyManagerImpl(crypto, db,
@@ -637,11 +553,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 
 		// The DB contains the secrets for periods 0 - 2
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 		// The secret for period 3 should be derived and stored
-		final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3.clone());
+		final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -656,11 +572,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			will(returnValue(EPOCH + ROTATION_PERIOD));
 			// The secret for period 3 should be derived and stored
 			oneOf(crypto).deriveNextSecret(secret0, 1);
-			will(returnValue(secret1.clone()));
+			will(returnValue(secret1));
 			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
+			will(returnValue(secret2));
 			oneOf(crypto).deriveNextSecret(secret2, 3);
-			will(returnValue(secret3.clone()));
+			will(returnValue(secret3));
 			oneOf(db).addSecrets(Arrays.asList(s3));
 			// The recogniser should derive the tags for period 1
 			oneOf(crypto).deriveTagKey(secret1, false);
@@ -669,10 +585,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k1).getEncoded();
-				will(returnValue(key1));
 			}
-			oneOf(k1).erase();
 			// The recogniser should derive the tags for period 2
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
@@ -680,10 +593,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k2).getEncoded();
-				will(returnValue(key2));
 			}
-			oneOf(k2).erase();
 			// The recogniser should derive the tags for period 3
 			oneOf(crypto).deriveTagKey(secret3, false);
 			will(returnValue(k3));
@@ -691,10 +601,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k3).getEncoded();
-				will(returnValue(key3));
 			}
-			oneOf(k3).erase();
 			// Start the timer
 			oneOf(timer).scheduleAtFixedRate(with(keyManager),
 					with(any(long.class)), with(any(long.class)));
@@ -706,10 +613,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k1).getEncoded();
-				will(returnValue(key1));
 			}
-			oneOf(k1).erase();
 			// The recogniser should derive the tags for period 2
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
@@ -717,10 +621,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k2).getEncoded();
-				will(returnValue(key2));
 			}
-			oneOf(k2).erase();
 			// The recogniser should remove the tags for period 3
 			oneOf(crypto).deriveTagKey(secret3, false);
 			will(returnValue(k3));
@@ -728,10 +629,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k3).getEncoded();
-				will(returnValue(key3));
 			}
-			oneOf(k3).erase();
 			// Remove the listener and stop the timer
 			oneOf(eventBus).removeListener(with(any(EventListener.class)));
 			oneOf(timer).cancel();
@@ -751,9 +649,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 		final EventBus eventBus = context.mock(EventBus.class);
 		final Clock clock = context.mock(Clock.class);
 		final Timer timer = context.mock(Timer.class);
-		final SecretKey k2 = context.mock(SecretKey.class, "k2");
-		final SecretKey k3 = context.mock(SecretKey.class, "k3");
-		final SecretKey k4 = context.mock(SecretKey.class, "k4");
 
 		final TagRecogniser tagRecogniser = new TagRecogniserImpl(crypto, db);
 		final KeyManagerImpl keyManager = new KeyManagerImpl(crypto, db,
@@ -761,12 +656,12 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 
 		// The DB contains the secrets for periods 0 - 2
 		Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true);
-		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone());
-		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone());
-		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone());
+		final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0);
+		final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1);
+		final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2);
 		// The secrets for periods 3 and 4 should be derived and stored
-		final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3.clone());
-		final TemporarySecret s4 = new TemporarySecret(ep, 4, secret4.clone());
+		final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3);
+		final TemporarySecret s4 = new TemporarySecret(ep, 4, secret4);
 
 		context.checking(new Expectations() {{
 			// start()
@@ -781,11 +676,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			will(returnValue(EPOCH + 3 * ROTATION_PERIOD - 1));
 			// The secrets for periods 3 and 4 should be derived from secret 1
 			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
+			will(returnValue(secret2));
 			oneOf(crypto).deriveNextSecret(secret2, 3);
-			will(returnValue(secret3.clone()));
+			will(returnValue(secret3));
 			oneOf(crypto).deriveNextSecret(secret3, 4);
-			will(returnValue(secret4.clone()));
+			will(returnValue(secret4));
 			// The new secrets should be stored
 			oneOf(db).addSecrets(Arrays.asList(s3, s4));
 			// The recogniser should derive the tags for period 2
@@ -795,10 +690,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k2).getEncoded();
-				will(returnValue(key2));
 			}
-			oneOf(k2).erase();
 			// The recogniser should derive the tags for period 3
 			oneOf(crypto).deriveTagKey(secret3, false);
 			will(returnValue(k3));
@@ -806,10 +698,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k3).getEncoded();
-				will(returnValue(key3));
 			}
-			oneOf(k3).erase();
 			// The recogniser should derive the tags for period 4
 			oneOf(crypto).deriveTagKey(secret4, false);
 			will(returnValue(k4));
@@ -817,10 +706,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k4),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k4).getEncoded();
-				will(returnValue(key4));
 			}
-			oneOf(k4).erase();
 			// Start the timer
 			oneOf(timer).scheduleAtFixedRate(with(keyManager),
 					with(any(long.class)), with(any(long.class)));
@@ -832,10 +718,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k2).getEncoded();
-				will(returnValue(key2));
 			}
-			oneOf(k2).erase();
 			// The recogniser should remove the tags for period 3
 			oneOf(crypto).deriveTagKey(secret3, false);
 			will(returnValue(k3));
@@ -843,10 +726,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k3).getEncoded();
-				will(returnValue(key3));
 			}
-			oneOf(k3).erase();
 			// The recogniser should derive the tags for period 4
 			oneOf(crypto).deriveTagKey(secret4, false);
 			will(returnValue(k4));
@@ -854,10 +734,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k4),
 						with((long) i));
 				will(new EncodeTagAction());
-				oneOf(k4).getEncoded();
-				will(returnValue(key4));
 			}
-			oneOf(k4).erase();
 			// Remove the listener and stop the timer
 			oneOf(eventBus).removeListener(with(any(EventListener.class)));
 			oneOf(timer).cancel();
@@ -885,7 +762,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			byte[] tag = (byte[]) invocation.getParameter(0);
 			SecretKey key = (SecretKey) invocation.getParameter(1);
 			long streamNumber = (Long) invocation.getParameter(2);
-			encodeTag(tag, key.getEncoded(), streamNumber);
+			encodeTag(tag, key.getBytes(), streamNumber);
 			return null;
 		}
 	}
diff --git a/briar-tests/src/org/briarproject/transport/TransportTagRecogniserTest.java b/briar-tests/src/org/briarproject/transport/TransportTagRecogniserTest.java
index ba1e84d48a13f583801e135f55255faf8df808a1..340745489de7a8c5a4d2babb0b52da75cc933bfe 100644
--- a/briar-tests/src/org/briarproject/transport/TransportTagRecogniserTest.java
+++ b/briar-tests/src/org/briarproject/transport/TransportTagRecogniserTest.java
@@ -25,6 +25,7 @@ public class TransportTagRecogniserTest extends BriarTestCase {
 
 	private final ContactId contactId = new ContactId(234);
 	private final TransportId transportId = new TransportId("id");
+	private final SecretKey tagKey = new SecretKey(new byte[32]);
 
 	@Test
 	public void testAddAndRemoveSecret() {
@@ -33,7 +34,6 @@ public class TransportTagRecogniserTest extends BriarTestCase {
 		final byte[] secret = new byte[32];
 		new Random().nextBytes(secret);
 		final boolean alice = false;
-		final SecretKey tagKey = context.mock(SecretKey.class);
 		final DatabaseComponent db = context.mock(DatabaseComponent.class);
 		context.checking(new Expectations() {{
 			// Add secret
@@ -44,7 +44,6 @@ public class TransportTagRecogniserTest extends BriarTestCase {
 						with((long) i));
 				will(new EncodeTagAction());
 			}
-			oneOf(tagKey).erase();
 			// Remove secret
 			oneOf(crypto).deriveTagKey(secret, !alice);
 			will(returnValue(tagKey));
@@ -53,7 +52,6 @@ public class TransportTagRecogniserTest extends BriarTestCase {
 						with((long) i));
 				will(new EncodeTagAction());
 			}
-			oneOf(tagKey).erase();
 		}});
 		TemporarySecret s = new TemporarySecret(contactId, transportId, 123,
 				alice, 0, secret, 0, 0, new byte[4]);
@@ -71,7 +69,6 @@ public class TransportTagRecogniserTest extends BriarTestCase {
 		final byte[] secret = new byte[32];
 		new Random().nextBytes(secret);
 		final boolean alice = false;
-		final SecretKey tagKey = context.mock(SecretKey.class);
 		final DatabaseComponent db = context.mock(DatabaseComponent.class);
 		context.checking(new Expectations() {{
 			// Add secret
@@ -82,7 +79,6 @@ public class TransportTagRecogniserTest extends BriarTestCase {
 						with((long) i));
 				will(new EncodeTagAction());
 			}
-			oneOf(tagKey).erase();
 			// Recognise tag 0
 			oneOf(crypto).deriveTagKey(secret, !alice);
 			will(returnValue(tagKey));
@@ -93,7 +89,6 @@ public class TransportTagRecogniserTest extends BriarTestCase {
 			// The updated window should be stored
 			oneOf(db).setReorderingWindow(contactId, transportId, 0, 1,
 					new byte[] {0, 1, 0, 0});
-			oneOf(tagKey).erase();
 			// Recognise tag again - no expectations
 		}});
 		TemporarySecret s = new TemporarySecret(contactId, transportId, 123,