diff --git a/briar-api/src/net/sf/briar/api/crypto/CryptoComponent.java b/briar-api/src/net/sf/briar/api/crypto/CryptoComponent.java
index 3515588e0164a9385740d5945ec9cb2268f6dfc1..a6ae9cbd3ac09b56541bdaeb3f23d8fda63d545f 100644
--- a/briar-api/src/net/sf/briar/api/crypto/CryptoComponent.java
+++ b/briar-api/src/net/sf/briar/api/crypto/CryptoComponent.java
@@ -5,8 +5,6 @@ import java.security.KeyPair;
 import java.security.SecureRandom;
 import java.security.Signature;
 
-import javax.crypto.Cipher;
-
 public interface CryptoComponent {
 
 	ErasableKey generateSecretKey();
@@ -82,18 +80,11 @@ public interface CryptoComponent {
 	ErasableKey deriveFrameKey(byte[] secret, long connection, boolean alice,
 			boolean initiator);
 
-	/**
-	 * Returns a cipher for generating the pseudo-random tags that are used to
-	 * recognise connections.
-	 */
-	Cipher getTagCipher();
-
 	/** Returns a cipher for encrypting and authenticating connections. */
 	AuthenticatedCipher getFrameCipher();
 
 	/** Encodes the pseudo-random tag that is used to recognise a connection. */
-	void encodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey,
-			long connection);
+	void encodeTag(byte[] tag, ErasableKey tagKey, long connection);
 
 	/**
 	 * Encrypts and authenticates the given plaintext so it can be written to
diff --git a/briar-core/src/net/sf/briar/crypto/CryptoComponentImpl.java b/briar-core/src/net/sf/briar/crypto/CryptoComponentImpl.java
index 90e7f08a2064fa3ef349b742f50dcd161238cc7a..da0a4b90bcbc2344f5026620118b7deac4fff3f5 100644
--- a/briar-core/src/net/sf/briar/crypto/CryptoComponentImpl.java
+++ b/briar-core/src/net/sf/briar/crypto/CryptoComponentImpl.java
@@ -15,7 +15,6 @@ import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.PrivateKey;
-import java.security.Provider;
 import java.security.PublicKey;
 import java.security.SecureRandom;
 import java.security.Security;
@@ -30,10 +29,7 @@ import java.security.spec.EllipticCurve;
 import java.util.Arrays;
 import java.util.logging.Logger;
 
-import javax.crypto.Cipher;
-import javax.crypto.CipherSpi;
 import javax.crypto.KeyAgreement;
-import javax.crypto.spec.IvParameterSpec;
 
 import net.sf.briar.api.crypto.AuthenticatedCipher;
 import net.sf.briar.api.crypto.CryptoComponent;
@@ -43,6 +39,7 @@ import net.sf.briar.api.crypto.MessageDigest;
 import net.sf.briar.api.crypto.PseudoRandom;
 import net.sf.briar.util.ByteUtils;
 
+import org.spongycastle.crypto.BlockCipher;
 import org.spongycastle.crypto.CipherParameters;
 import org.spongycastle.crypto.engines.AESFastEngine;
 import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
@@ -51,7 +48,6 @@ import org.spongycastle.crypto.modes.GCMBlockCipher;
 import org.spongycastle.crypto.params.KeyParameter;
 import org.spongycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi;
 import org.spongycastle.jcajce.provider.digest.SHA384;
-import org.spongycastle.jcajce.provider.symmetric.AES;
 import org.spongycastle.jce.provider.BouncyCastleProvider;
 import org.spongycastle.util.Strings;
 
@@ -61,21 +57,19 @@ class CryptoComponentImpl implements CryptoComponent {
 			Logger.getLogger(CryptoComponentImpl.class.getName());
 
 	private static final String PROVIDER = "SC"; // Spongy Castle
-	private static final String SECRET_KEY_ALGO = "AES";
-	private static final int SECRET_KEY_BYTES = 32; // 256 bits
+	private static final String CIPHER_ALGO = "AES";
+	private static final int CIPHER_BLOCK_BYTES = 16; // 128 bits
+	private static final int CIPHER_KEY_BYTES = 32; // 256 bits
 	private static final String AGREEMENT_ALGO = "ECDHC";
 	private static final String AGREEMENT_KEY_PAIR_ALGO = "ECDH";
 	private static final int AGREEMENT_KEY_PAIR_BITS = 384;
 	private static final String SIGNATURE_ALGO = "ECDSA";
 	private static final String SIGNATURE_KEY_PAIR_ALGO = "ECDSA";
 	private static final int SIGNATURE_KEY_PAIR_BITS = 384;
-	private static final String TAG_CIPHER_ALGO = "AES/ECB/NoPadding";
 	private static final int GCM_MAC_BYTES = 16; // 128 bits
 	private static final int STORAGE_IV_BYTES = 16; // 128 bits
 	private static final int PBKDF_SALT_BYTES = 16; // 128 bits
 	private static final int PBKDF_ITERATIONS = 1000;
-	private static final String KEY_DERIVATION_ALGO = "AES/CTR/NoPadding";
-	private static final int KEY_DERIVATION_IV_BYTES = 16; // 128 bits
 
 	// Labels for secret derivation
 	private static final byte[] MASTER = { 'M', 'A', 'S', 'T', 'E', 'R', '\0' };
@@ -96,11 +90,8 @@ class CryptoComponentImpl implements CryptoComponent {
 		{ 'B', '_', 'F', 'R', 'A', 'M', 'E', '_', 'A', '\0' };
 	private static final byte[] B_FRAME_B =
 		{ 'B', '_', 'F', 'R', 'A', 'M', 'E', '_', 'B', '\0' };
-	// Blank plaintext for key derivation
-	private static final byte[] KEY_DERIVATION_BLANK_PLAINTEXT =
-			new byte[SECRET_KEY_BYTES];
 	// Blank secret for argument validation
-	private static final byte[] BLANK_SECRET = new byte[SECRET_KEY_BYTES];
+	private static final byte[] BLANK_SECRET = new byte[CIPHER_KEY_BYTES];
 
 	// Parameters for NIST elliptic curve P-384 - see "Suite B Implementer's
 	// Guide to NIST SP 800-56A", section A.2
@@ -137,38 +128,34 @@ class CryptoComponentImpl implements CryptoComponent {
 	private static final ECParameterSpec P_384_PARAMS =
 			new ECParameterSpec(P_384_CURVE, P_384_G, P_384_N, P_384_H);
 
-	private final Provider provider;
 	private final KeyParser agreementKeyParser, signatureKeyParser;
 	private final KeyPairGenerator agreementKeyPairGenerator;
 	private final KeyPairGenerator signatureKeyPairGenerator;
 	private final SecureRandom secureRandom;
 
 	CryptoComponentImpl() {
-		provider = new BouncyCastleProvider();
-		Security.addProvider(provider);
+		Security.addProvider(new BouncyCastleProvider());
 		try {
 			KeyFactory agreementKeyFactory = KeyFactory.getInstance(
 					AGREEMENT_KEY_PAIR_ALGO, PROVIDER);
+			if(LOG.isLoggable(INFO)) {
+				LOG.info("Agreement KeyFactory: "
+						+ agreementKeyFactory.getClass().getName());
+			}
 			agreementKeyParser = new Sec1KeyParser(agreementKeyFactory,
 					P_384_PARAMS, P_384_Q, AGREEMENT_KEY_PAIR_BITS);
 			KeyFactory signatureKeyFactory = KeyFactory.getInstance(
 					SIGNATURE_KEY_PAIR_ALGO, PROVIDER);
+			if(LOG.isLoggable(INFO)) {
+				LOG.info("Signature KeyFactory: "
+						+ signatureKeyFactory.getClass().getName());
+			}
 			signatureKeyParser = new Sec1KeyParser(signatureKeyFactory,
 					P_384_PARAMS, P_384_Q, SIGNATURE_KEY_PAIR_BITS);
 			agreementKeyPairGenerator = new KeyPairGeneratorSpi.ECDH();
 			agreementKeyPairGenerator.initialize(AGREEMENT_KEY_PAIR_BITS);
 			signatureKeyPairGenerator = new KeyPairGeneratorSpi.ECDSA();
 			signatureKeyPairGenerator.initialize(SIGNATURE_KEY_PAIR_BITS);
-			if(LOG.isLoggable(INFO)) {
-				LOG.info("Agreement KeyFactory: "
-						+ agreementKeyFactory.getClass().getName());
-				LOG.info("Signature KeyFactory: "
-						+ signatureKeyFactory.getClass().getName());
-				LOG.info("Agreement KeyPairGenerator: "
-						+ agreementKeyPairGenerator.getClass().getName());
-				LOG.info("Signature KeyPairGenerator: "
-						+ signatureKeyPairGenerator.getClass().getName());
-			}
 		} catch(GeneralSecurityException e) {
 			throw new RuntimeException(e);
 		}
@@ -176,9 +163,9 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	public ErasableKey generateSecretKey() {
-		byte[] b = new byte[SECRET_KEY_BYTES];
+		byte[] b = new byte[CIPHER_KEY_BYTES];
 		secureRandom.nextBytes(b);
-		return new ErasableKeyImpl(b, SECRET_KEY_ALGO);
+		return new ErasableKeyImpl(b, CIPHER_ALGO);
 	}
 
 	public MessageDigest getMessageDigest() {
@@ -243,7 +230,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	public int[] deriveConfirmationCodes(byte[] secret) {
-		if(secret.length != SECRET_KEY_BYTES)
+		if(secret.length != CIPHER_KEY_BYTES)
 			throw new IllegalArgumentException();
 		if(Arrays.equals(secret, BLANK_SECRET))
 			throw new IllegalArgumentException();
@@ -258,7 +245,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	public byte[][] deriveInvitationNonces(byte[] secret) {
-		if(secret.length != SECRET_KEY_BYTES)
+		if(secret.length != CIPHER_KEY_BYTES)
 			throw new IllegalArgumentException();
 		if(Arrays.equals(secret, BLANK_SECRET))
 			throw new IllegalArgumentException();
@@ -305,7 +292,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	public byte[] deriveInitialSecret(byte[] secret, int transportIndex) {
-		if(secret.length != SECRET_KEY_BYTES)
+		if(secret.length != CIPHER_KEY_BYTES)
 			throw new IllegalArgumentException();
 		if(Arrays.equals(secret, BLANK_SECRET))
 			throw new IllegalArgumentException();
@@ -314,7 +301,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	public byte[] deriveNextSecret(byte[] secret, long period) {
-		if(secret.length != SECRET_KEY_BYTES)
+		if(secret.length != CIPHER_KEY_BYTES)
 			throw new IllegalArgumentException();
 		if(Arrays.equals(secret, BLANK_SECRET))
 			throw new IllegalArgumentException();
@@ -324,7 +311,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	public ErasableKey deriveTagKey(byte[] secret, boolean alice) {
-		if(secret.length != SECRET_KEY_BYTES)
+		if(secret.length != CIPHER_KEY_BYTES)
 			throw new IllegalArgumentException();
 		if(Arrays.equals(secret, BLANK_SECRET))
 			throw new IllegalArgumentException();
@@ -334,7 +321,7 @@ class CryptoComponentImpl implements CryptoComponent {
 
 	public ErasableKey deriveFrameKey(byte[] secret, long connection,
 			boolean alice, boolean initiator) {
-		if(secret.length != SECRET_KEY_BYTES)
+		if(secret.length != CIPHER_KEY_BYTES)
 			throw new IllegalArgumentException();
 		if(Arrays.equals(secret, BLANK_SECRET))
 			throw new IllegalArgumentException();
@@ -350,16 +337,12 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	private ErasableKey deriveKey(byte[] secret, byte[] label, long context) {
-		if(secret.length != SECRET_KEY_BYTES)
+		if(secret.length != CIPHER_KEY_BYTES)
 			throw new IllegalArgumentException();
 		if(Arrays.equals(secret, BLANK_SECRET))
 			throw new IllegalArgumentException();
 		byte[] key = counterModeKdf(secret, label, context);
-		return new ErasableKeyImpl(key, SECRET_KEY_ALGO);
-	}
-
-	public Cipher getTagCipher() {
-		return new CipherFromSpi(new AES.ECB(), provider, TAG_CIPHER_ALGO);
+		return new ErasableKeyImpl(key, CIPHER_ALGO);
 	}
 
 	public AuthenticatedCipher getFrameCipher() {
@@ -367,20 +350,15 @@ class CryptoComponentImpl implements CryptoComponent {
 		return new AuthenticatedCipherImpl(cipher, GCM_MAC_BYTES);
 	}
 
-	public void encodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey,
-			long connection) {
+	public void encodeTag(byte[] tag, ErasableKey tagKey, long connection) {
 		if(tag.length < TAG_LENGTH) throw new IllegalArgumentException();
 		if(connection < 0 || connection > MAX_32_BIT_UNSIGNED)
 			throw new IllegalArgumentException();
 		for(int i = 0; i < TAG_LENGTH; i++) tag[i] = 0;
 		ByteUtils.writeUint32(connection, tag, 0);
-		try {
-			tagCipher.init(ENCRYPT_MODE, tagKey);
-			int encrypted = tagCipher.doFinal(tag, 0, TAG_LENGTH, tag);
-			if(encrypted != TAG_LENGTH) throw new IllegalArgumentException();
-		} catch(GeneralSecurityException e) {
-			throw new IllegalArgumentException(e); // Unsuitable cipher or key
-		}
+		BlockCipher cipher = new AESFastEngine();
+		cipher.init(true, new KeyParameter(tagKey.getEncoded()));
+		cipher.processBlock(tag, 0, tag, 0);
 	}
 
 	public byte[] encryptWithPassword(byte[] input, char[] password) {
@@ -389,7 +367,7 @@ class CryptoComponentImpl implements CryptoComponent {
 		secureRandom.nextBytes(salt);
 		// Derive the key from the password
 		byte[] keyBytes = pbkdf2(password, salt);
-		ErasableKey key = new ErasableKeyImpl(keyBytes, SECRET_KEY_ALGO);
+		ErasableKey key = new ErasableKeyImpl(keyBytes, CIPHER_ALGO);
 		// Generate a random IV
 		byte[] iv = new byte[STORAGE_IV_BYTES];
 		secureRandom.nextBytes(iv);
@@ -424,7 +402,7 @@ class CryptoComponentImpl implements CryptoComponent {
 		System.arraycopy(input, salt.length, iv, 0, iv.length);
 		// Derive the key from the password
 		byte[] keyBytes = pbkdf2(password, salt);
-		ErasableKey key = new ErasableKeyImpl(keyBytes, SECRET_KEY_ALGO);
+		ErasableKey key = new ErasableKeyImpl(keyBytes, CIPHER_ALGO);
 		// Initialise the cipher
 		AuthenticatedCipher cipher;
 		try {
@@ -472,7 +450,7 @@ class CryptoComponentImpl implements CryptoComponent {
 			byte[] initiatorInfo, byte[] responderInfo) {
 		// The output of the hash function must be long enough to use as a key
 		MessageDigest messageDigest = getMessageDigest();
-		if(messageDigest.getDigestLength() < SECRET_KEY_BYTES)
+		if(messageDigest.getDigestLength() < CIPHER_KEY_BYTES)
 			throw new RuntimeException();
 		// All fields are length-prefixed
 		byte[] length = new byte[1];
@@ -490,7 +468,7 @@ class CryptoComponentImpl implements CryptoComponent {
 		messageDigest.update(responderInfo);
 		byte[] hash = messageDigest.digest();
 		// The secret is the first SECRET_KEY_BYTES bytes of the hash
-		byte[] output = new byte[SECRET_KEY_BYTES];
+		byte[] output = new byte[CIPHER_KEY_BYTES];
 		System.arraycopy(hash, 0, output, 0, output.length);
 		ByteUtils.erase(hash);
 		return output;
@@ -499,30 +477,24 @@ class CryptoComponentImpl implements CryptoComponent {
 	// Key derivation function based on a block cipher in CTR mode - see
 	// NIST SP 800-108, section 5.1
 	private byte[] counterModeKdf(byte[] secret, byte[] label, long context) {
-		if(secret.length != SECRET_KEY_BYTES)
+		if(secret.length != CIPHER_KEY_BYTES)
 			throw new IllegalArgumentException();
 		if(Arrays.equals(secret, BLANK_SECRET))
 			throw new IllegalArgumentException();
 		// The label and context must leave a byte free for the counter
-		if(label.length + 4 >= KEY_DERIVATION_IV_BYTES)
+		if(label.length + 4 >= CIPHER_BLOCK_BYTES)
 			throw new IllegalArgumentException();
-		byte[] ivBytes = new byte[KEY_DERIVATION_IV_BYTES];
-		System.arraycopy(label, 0, ivBytes, 0, label.length);
-		ByteUtils.writeUint32(context, ivBytes, label.length);
-		// Use the secret and the IV to encrypt a blank plaintext
-		IvParameterSpec iv = new IvParameterSpec(ivBytes);
-		ErasableKey key = new ErasableKeyImpl(secret, SECRET_KEY_ALGO);
-		try {
-			CipherSpi spi = new AES.ECB();
-			Cipher cipher = new CipherFromSpi(spi, provider,
-					KEY_DERIVATION_ALGO);
-			cipher.init(Cipher.ENCRYPT_MODE, key, iv);
-			byte[] output = cipher.doFinal(KEY_DERIVATION_BLANK_PLAINTEXT);
-			assert output.length == SECRET_KEY_BYTES;
-			return output;
-		} catch(GeneralSecurityException e) {
-			throw new RuntimeException(e);
+		byte[] counter = new byte[CIPHER_BLOCK_BYTES];
+		System.arraycopy(label, 0, counter, 0, label.length);
+		ByteUtils.writeUint32(context, counter, label.length);
+		BlockCipher cipher = new AESFastEngine();
+		cipher.init(true, new KeyParameter(secret));
+		byte[] output = new byte[CIPHER_KEY_BYTES];
+		for(int i = 0; i * CIPHER_BLOCK_BYTES < output.length; i++) {
+			counter[counter.length - 1] = (byte) i;
+			cipher.processBlock(counter, 0, output, i * CIPHER_BLOCK_BYTES);
 		}
+		return output;
 	}
 
 	// Password-based key derivation function - see PKCS#5 v2.1, section 5.2
@@ -532,7 +504,7 @@ class CryptoComponentImpl implements CryptoComponent {
 		byte[] utf8 = toUtf8ByteArray(password);
 		PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator();
 		gen.init(utf8, salt, PBKDF_ITERATIONS);
-		int keyLengthInBits = SECRET_KEY_BYTES * 8;
+		int keyLengthInBits = CIPHER_KEY_BYTES * 8;
 		CipherParameters p = gen.generateDerivedParameters(keyLengthInBits);
 		ByteUtils.erase(utf8);
 		return ((KeyParameter) p).getKey();
@@ -551,12 +523,4 @@ class CryptoComponentImpl implements CryptoComponent {
 			throw new RuntimeException(e);
 		}
 	}
-
-	private static class CipherFromSpi extends Cipher {
-
-		private CipherFromSpi(CipherSpi spi, Provider provider,
-				String transformation) {
-			super(spi, provider, transformation);
-		}
-	}
 }
diff --git a/briar-core/src/net/sf/briar/transport/ConnectionWriterFactoryImpl.java b/briar-core/src/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
index dbfe989cf045b01b8e1683db5e26fa4c742ce310..365ada7da594a5ca888d54d24eaccfbee201a2ef 100644
--- a/briar-core/src/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
+++ b/briar-core/src/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
@@ -4,8 +4,6 @@ import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
 
 import java.io.OutputStream;
 
-import javax.crypto.Cipher;
-
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.ErasableKey;
 import net.sf.briar.api.transport.ConnectionContext;
@@ -35,9 +33,8 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
 		FrameWriter encryption;
 		if(initiator) {
 			byte[] tag = new byte[TAG_LENGTH];
-			Cipher tagCipher = crypto.getTagCipher();
 			ErasableKey tagKey = crypto.deriveTagKey(secret, initiatorIsAlice);
-			crypto.encodeTag(tag, tagCipher, tagKey, connection);
+			crypto.encodeTag(tag, tagKey, connection);
 			tagKey.erase();
 			encryption = new OutgoingEncryptionLayer(out, capacity,
 					crypto.getFrameCipher(), frameKey, maxFrameLength, tag);
diff --git a/briar-core/src/net/sf/briar/transport/TransportConnectionRecogniser.java b/briar-core/src/net/sf/briar/transport/TransportConnectionRecogniser.java
index 4557cc17cb55061c26ca9ecb9451daf602740f1c..8071c8334a802504f5ec71756ed62b43de775c55 100644
--- a/briar-core/src/net/sf/briar/transport/TransportConnectionRecogniser.java
+++ b/briar-core/src/net/sf/briar/transport/TransportConnectionRecogniser.java
@@ -7,8 +7,6 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
-import javax.crypto.Cipher;
-
 import net.sf.briar.api.Bytes;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportId;
@@ -43,11 +41,10 @@ class TransportConnectionRecogniser {
 		TagContext t = tagMap.remove(new Bytes(tag));
 		if(t == null) return null; // The tag was not expected
 		// Update the connection window and the expected tags
-		Cipher cipher = crypto.getTagCipher();
 		ErasableKey key = crypto.deriveTagKey(t.secret, !t.alice);
 		for(long connection : t.window.setSeen(t.connection)) {
 			byte[] tag1 = new byte[TAG_LENGTH];
-			crypto.encodeTag(tag1, cipher, key, connection);
+			crypto.encodeTag(tag1, key, connection);
 			if(connection < t.connection) {
 				TagContext removed = tagMap.remove(new Bytes(tag1));
 				assert removed != null;
@@ -75,12 +72,11 @@ class TransportConnectionRecogniser {
 		long centre = s.getWindowCentre();
 		byte[] bitmap = s.getWindowBitmap();
 		// Create the connection window and the expected tags
-		Cipher cipher = crypto.getTagCipher();
 		ErasableKey key = crypto.deriveTagKey(secret, !alice);
 		ConnectionWindow window = new ConnectionWindow(centre, bitmap);
 		for(long connection : window.getUnseen()) {
 			byte[] tag = new byte[TAG_LENGTH];
-			crypto.encodeTag(tag, cipher, key, connection);
+			crypto.encodeTag(tag, key, connection);
 			TagContext added = new TagContext(contactId, alice, period,
 					secret, window, connection);
 			TagContext duplicate = tagMap.put(new Bytes(tag), added);
@@ -102,11 +98,10 @@ class TransportConnectionRecogniser {
 	// Locking: this
 	private void removeSecret(RemovalContext r) {
 		// Remove the expected tags
-		Cipher cipher = crypto.getTagCipher();
 		ErasableKey key = crypto.deriveTagKey(r.secret, !r.alice);
 		byte[] tag = new byte[TAG_LENGTH];
 		for(long connection : r.window.getUnseen()) {
-			crypto.encodeTag(tag, cipher, key, connection);
+			crypto.encodeTag(tag, key, connection);
 			TagContext removed = tagMap.remove(new Bytes(tag));
 			assert removed != null;
 		}
diff --git a/briar-tests/src/net/sf/briar/transport/KeyRotationIntegrationTest.java b/briar-tests/src/net/sf/briar/transport/KeyRotationIntegrationTest.java
index 93dfb3b4296befe2e39539c86411a4eda5f66b7e..b106b04778fa4dd4549d028b4a157061e2b927c1 100644
--- a/briar-tests/src/net/sf/briar/transport/KeyRotationIntegrationTest.java
+++ b/briar-tests/src/net/sf/briar/transport/KeyRotationIntegrationTest.java
@@ -7,9 +7,6 @@ import static org.junit.Assert.assertArrayEquals;
 import java.util.Arrays;
 import java.util.Collections;
 
-import javax.crypto.Cipher;
-import javax.crypto.NullCipher;
-
 import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.ContactId;
@@ -45,7 +42,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 	private final byte[] secret0, secret1, secret2, secret3, secret4;
 	private final byte[] key0, key1, key2, key3, key4;
 	private final byte[] initialSecret;
-	private final Cipher cipher;
 
 	public KeyRotationIntegrationTest() {
 		contactId = new ContactId(234);
@@ -72,7 +68,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 		for(int i = 0; i < key4.length; i++) key4[i] = 5;
 		initialSecret = new byte[32];
 		for(int i = 0; i < initialSecret.length; i++) initialSecret[i] = 123;
-		cipher = new NullCipher();
 	}
 
 	@Test
@@ -155,39 +150,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			will(returnValue(secret2.clone()));
 			oneOf(db).addSecrets(Arrays.asList(s0, s1, s2));
 			// The recogniser should derive the tags for period 0
-			oneOf(crypto).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret0, false);
 			will(returnValue(k0));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k0), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k1), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k2), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
+						with((long) i));
 				will(new EncodeTagAction());
 				oneOf(k2).getEncoded();
 				will(returnValue(key2));
@@ -195,39 +184,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			oneOf(k2).erase();
 			// stop()
 			// The recogniser should derive the tags for period 0
-			oneOf(crypto).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret0, false);
 			will(returnValue(k0));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k0), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k1), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k2), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
+						with((long) i));
 				will(new EncodeTagAction());
 				oneOf(k2).getEncoded();
 				will(returnValue(key2));
@@ -290,39 +273,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			will(returnValue(secret2.clone()));
 			oneOf(db).addSecrets(Arrays.asList(s0, s1, s2));
 			// The recogniser should derive the tags for period 0
-			oneOf(crypto).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret0, false);
 			will(returnValue(k0));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k0), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k1), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k2), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
+						with((long) i));
 				will(new EncodeTagAction());
 				oneOf(k2).getEncoded();
 				will(returnValue(key2));
@@ -333,39 +310,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			will(returnValue(0L));
 			// stop()
 			// The recogniser should derive the tags for period 0
-			oneOf(crypto).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret0, false);
 			will(returnValue(k0));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k0), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k1), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k2), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
+						with((long) i));
 				will(new EncodeTagAction());
 				oneOf(k2).getEncoded();
 				will(returnValue(key2));
@@ -436,50 +407,42 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			will(returnValue(secret2.clone()));
 			oneOf(db).addSecrets(Arrays.asList(s0, s1, s2));
 			// The recogniser should derive the tags for period 0
-			oneOf(crypto).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret0, false);
 			will(returnValue(k0));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k0), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k1), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k2), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
-			oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
+			oneOf(crypto).encodeTag(with(any(byte[].class)),
 					with(k2), with(16L));
 			will(new EncodeTagAction());
 			oneOf(k2).getEncoded();
@@ -489,39 +452,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			oneOf(k2).erase();
 			// stop()
 			// The recogniser should derive the tags for period 0
-			oneOf(crypto).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret0, false);
 			will(returnValue(k0));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k0), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k1), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
 			for(int i = 1; i < 17; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k2), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
+						with((long) i));
 				will(new EncodeTagAction());
 				oneOf(k2).getEncoded();
 				will(returnValue(key2));
@@ -584,39 +541,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(EPOCH));
 			// The recogniser should derive the tags for period 0
-			oneOf(crypto).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret0, false);
 			will(returnValue(k0));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k0), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k1), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k2), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
+						with((long) i));
 				will(new EncodeTagAction());
 				oneOf(k2).getEncoded();
 				will(returnValue(key2));
@@ -627,39 +578,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 					with(any(long.class)), with(any(long.class)));
 			// stop()
 			// The recogniser should remove the tags for period 0
-			oneOf(crypto).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret0, false);
 			will(returnValue(k0));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k0), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k1), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k2), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
+						with((long) i));
 				will(new EncodeTagAction());
 				oneOf(k2).getEncoded();
 				will(returnValue(key2));
@@ -720,39 +665,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			will(returnValue(secret3.clone()));
 			oneOf(db).addSecrets(Arrays.asList(s3));
 			// The recogniser should derive the tags for period 1
-			oneOf(crypto).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k1), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k2), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret3, false);
 			will(returnValue(k3));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k3), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3),
+						with((long) i));
 				will(new EncodeTagAction());
 				oneOf(k3).getEncoded();
 				will(returnValue(key3));
@@ -763,39 +702,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 					with(any(long.class)), with(any(long.class)));
 			// stop()
 			// The recogniser should derive the tags for period 1
-			oneOf(crypto).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret1, false);
 			will(returnValue(k1));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k1), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k2), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret3, false);
 			will(returnValue(k3));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k3), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3),
+						with((long) i));
 				will(new EncodeTagAction());
 				oneOf(k3).getEncoded();
 				will(returnValue(key3));
@@ -858,39 +791,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			// The new secrets should be stored
 			oneOf(db).addSecrets(Arrays.asList(s3, s4));
 			// The recogniser should derive the tags for period 2
-			oneOf(crypto).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k2), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret3, false);
 			will(returnValue(k3));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k3), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret4, false);
 			will(returnValue(k4));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k4), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k4),
+						with((long) i));
 				will(new EncodeTagAction());
 				oneOf(k4).getEncoded();
 				will(returnValue(key4));
@@ -901,39 +828,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 					with(any(long.class)), with(any(long.class)));
 			// stop()
 			// The recogniser should derive the tags for period 2
-			oneOf(crypto).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret2, false);
 			will(returnValue(k2));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k2), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret3, false);
 			will(returnValue(k3));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k3), with((long) i));
+				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).getTagCipher();
-			will(returnValue(cipher));
 			oneOf(crypto).deriveTagKey(secret4, false);
 			will(returnValue(k4));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
-						with(k4), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(k4),
+						with((long) i));
 				will(new EncodeTagAction());
 				oneOf(k4).getEncoded();
 				will(returnValue(key4));
@@ -964,10 +885,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 
 		public Object invoke(Invocation invocation) throws Throwable {
 			byte[] tag = (byte[]) invocation.getParameter(0);
-			ErasableKey key = (ErasableKey) invocation.getParameter(2);
-			long connection = (Long) invocation.getParameter(3);
-			byte[] rawKey = key.getEncoded();
-			encodeTag(tag, rawKey, connection);
+			ErasableKey key = (ErasableKey) invocation.getParameter(1);
+			long connection = (Long) invocation.getParameter(2);
+			encodeTag(tag, key.getEncoded(), connection);
 			return null;
 		}
 	}
diff --git a/briar-tests/src/net/sf/briar/transport/TransportConnectionRecogniserTest.java b/briar-tests/src/net/sf/briar/transport/TransportConnectionRecogniserTest.java
index 6f2cae4125aa748723f12e5c70d15cd91df8ebfe..3f5b2225d2fc8bd47973443c0aa125d6596ac171 100644
--- a/briar-tests/src/net/sf/briar/transport/TransportConnectionRecogniserTest.java
+++ b/briar-tests/src/net/sf/briar/transport/TransportConnectionRecogniserTest.java
@@ -5,9 +5,6 @@ import static org.junit.Assert.assertArrayEquals;
 
 import java.util.Random;
 
-import javax.crypto.Cipher;
-import javax.crypto.NullCipher;
-
 import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.ContactId;
@@ -31,7 +28,6 @@ public class TransportConnectionRecogniserTest extends BriarTestCase {
 	private final ContactId contactId = new ContactId(234);
 	private final TransportId transportId =
 			new TransportId(TestUtils.getRandomId());
-	private final Cipher tagCipher = new NullCipher();
 
 	@Test
 	public void testAddAndRemoveSecret() {
@@ -44,24 +40,20 @@ public class TransportConnectionRecogniserTest extends BriarTestCase {
 		final DatabaseComponent db = context.mock(DatabaseComponent.class);
 		context.checking(new Expectations() {{
 			// Add secret
-			oneOf(crypto).getTagCipher();
-			will(returnValue(tagCipher));
 			oneOf(crypto).deriveTagKey(secret, !alice);
 			will(returnValue(tagKey));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)),
-						with(tagCipher), with(tagKey), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(tagKey),
+						with((long) i));
 				will(new EncodeTagAction());
 			}
 			oneOf(tagKey).erase();
 			// Remove secret
-			oneOf(crypto).getTagCipher();
-			will(returnValue(tagCipher));
 			oneOf(crypto).deriveTagKey(secret, !alice);
 			will(returnValue(tagKey));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)),
-						with(tagCipher), with(tagKey), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(tagKey),
+						with((long) i));
 				will(new EncodeTagAction());
 			}
 			oneOf(tagKey).erase();
@@ -86,24 +78,20 @@ public class TransportConnectionRecogniserTest extends BriarTestCase {
 		final DatabaseComponent db = context.mock(DatabaseComponent.class);
 		context.checking(new Expectations() {{
 			// Add secret
-			oneOf(crypto).getTagCipher();
-			will(returnValue(tagCipher));
 			oneOf(crypto).deriveTagKey(secret, !alice);
 			will(returnValue(tagKey));
 			for(int i = 0; i < 16; i++) {
-				oneOf(crypto).encodeTag(with(any(byte[].class)),
-						with(tagCipher), with(tagKey), with((long) i));
+				oneOf(crypto).encodeTag(with(any(byte[].class)), with(tagKey),
+						with((long) i));
 				will(new EncodeTagAction());
 			}
 			oneOf(tagKey).erase();
 			// Accept connection 0
-			oneOf(crypto).getTagCipher();
-			will(returnValue(tagCipher));
 			oneOf(crypto).deriveTagKey(secret, !alice);
 			will(returnValue(tagKey));
 			// The window should slide to include connection 16
-			oneOf(crypto).encodeTag(with(any(byte[].class)), with(tagCipher),
-					with(tagKey), with(16L));
+			oneOf(crypto).encodeTag(with(any(byte[].class)), with(tagKey),
+					with(16L));
 			will(new EncodeTagAction());
 			// The updated window should be stored
 			oneOf(db).setConnectionWindow(contactId, transportId, 0, 1,
@@ -136,7 +124,7 @@ public class TransportConnectionRecogniserTest extends BriarTestCase {
 
 		public Object invoke(Invocation invocation) throws Throwable {
 			byte[] tag = (byte[]) invocation.getParameter(0);
-			long connection = (Long) invocation.getParameter(3);
+			long connection = (Long) invocation.getParameter(2);
 			// Encode a fake tag based on the connection number
 			ByteUtils.writeUint32(connection, tag, 0);
 			return null;