diff --git a/api/net/sf/briar/api/crypto/SecretStorageKey.java b/api/net/sf/briar/api/crypto/SecretStorageKey.java
deleted file mode 100644
index 12fbffa940e290eb882c22a881cd8c73fd682181..0000000000000000000000000000000000000000
--- a/api/net/sf/briar/api/crypto/SecretStorageKey.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.sf.briar.api.crypto;
-
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import com.google.inject.BindingAnnotation;
-
-/**
- * Annotation for injecting the key that is used for encrypting and decrypting
- * secrets stored in the database.
- */
-@BindingAnnotation
-@Target({ PARAMETER })
-@Retention(RUNTIME)
-public @interface SecretStorageKey {}
diff --git a/components/net/sf/briar/crypto/CryptoComponentImpl.java b/components/net/sf/briar/crypto/CryptoComponentImpl.java
index 78c7badbf34510d7cc2decc4563da8764671be2b..f0b3173dea8144e75c6a9f0d8ba5c3702817f82d 100644
--- a/components/net/sf/briar/crypto/CryptoComponentImpl.java
+++ b/components/net/sf/briar/crypto/CryptoComponentImpl.java
@@ -1,8 +1,6 @@
 package net.sf.briar.crypto;
 
 import java.io.UnsupportedEncodingException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.NoSuchAlgorithmException;
@@ -10,22 +8,17 @@ import java.security.NoSuchProviderException;
 import java.security.SecureRandom;
 import java.security.Security;
 import java.security.Signature;
-import java.util.Arrays;
 
-import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
 import javax.crypto.KeyGenerator;
 import javax.crypto.Mac;
 import javax.crypto.NoSuchPaddingException;
 import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.KeyParser;
 import net.sf.briar.api.crypto.MessageDigest;
-import net.sf.briar.api.crypto.SecretStorageKey;
 
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
@@ -37,7 +30,6 @@ class CryptoComponentImpl implements CryptoComponent {
 	private static final String DIGEST_ALGO = "SHA-256";
 	private static final String KEY_PAIR_ALGO = "ECDSA";
 	private static final int KEY_PAIR_BITS = 256;
-	private static final String SECRET_STORAGE_ALGO = "AES/CTR/NoPadding";
 	private static final String FRAME_CIPHER_ALGO = "AES/CTR/NoPadding";
 	private static final String SECRET_KEY_ALGO = "AES";
 	private static final int SECRET_KEY_BITS = 256;
@@ -45,15 +37,13 @@ class CryptoComponentImpl implements CryptoComponent {
 	private static final String MAC_ALGO = "HMacSHA256";
 	private static final String SIGNATURE_ALGO = "ECDSA";
 
-	private final SecretKey secretStorageKey;
 	private final KeyParser keyParser;
 	private final KeyPairGenerator keyPairGenerator;
 	private final KeyGenerator keyGenerator;
 
 	@Inject
-	CryptoComponentImpl(@SecretStorageKey SecretKey secretStorageKey) {
+	CryptoComponentImpl() {
 		Security.addProvider(new BouncyCastleProvider());
-		this.secretStorageKey = secretStorageKey;
 		try {
 			keyParser = new KeyParserImpl(KEY_PAIR_ALGO, PROVIDER);
 			keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALGO,
@@ -75,54 +65,29 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	private SecretKey deriveFrameKey(SharedSecret s, boolean alice) {
-		if(alice) return deriveKey("F_A", s.getIv(), s.getCiphertext());
-		else return deriveKey("F_B", s.getIv(), s.getCiphertext());
+		if(alice) return deriveKey("F_A", s.getSecret());
+		else return deriveKey("F_B", s.getSecret());
 	}
 
-	private SecretKey deriveKey(String name, IvParameterSpec iv,
-			byte[] ciphertext) {
+	private SecretKey deriveKey(String name, byte[] secret) {
 		MessageDigest digest = getMessageDigest();
 		try {
 			digest.update(name.getBytes("UTF-8"));
 		} catch(UnsupportedEncodingException e) {
 			throw new RuntimeException(e);
 		}
-		byte[] decrypted = decryptSharedSecret(iv, ciphertext);
-		digest.update(decrypted);
-		Arrays.fill(decrypted, (byte) 0); // Destroy the plaintext secret
+		digest.update(secret);
 		return new SecretKeySpec(digest.digest(), SECRET_KEY_ALGO);
 	}
 
-	private byte[] decryptSharedSecret(IvParameterSpec iv, byte[] ciphertext) {
-		try {
-			Cipher c = Cipher.getInstance(SECRET_STORAGE_ALGO, PROVIDER);
-			c.init(Cipher.DECRYPT_MODE, secretStorageKey, iv);
-			return c.doFinal(ciphertext);
-		} catch(BadPaddingException e) {
-			throw new RuntimeException(e);
-		} catch(IllegalBlockSizeException e) {
-			throw new RuntimeException(e);
-		} catch(InvalidAlgorithmParameterException e) {
-			throw new RuntimeException(e);
-		} catch(InvalidKeyException e) {
-			throw new RuntimeException(e);
-		} catch(NoSuchAlgorithmException e) {
-			throw new RuntimeException(e);
-		} catch(NoSuchPaddingException e) {
-			throw new RuntimeException(e);
-		} catch(NoSuchProviderException e) {
-			throw new RuntimeException(e);
-		}
-	}
-
 	public SecretKey deriveIncomingIvKey(byte[] secret) {
 		SharedSecret s = new SharedSecret(secret);
 		return deriveIvKey(s, !s.getAlice());
 	}
 
 	private SecretKey deriveIvKey(SharedSecret s, boolean alice) {
-		if(alice) return deriveKey("I_A", s.getIv(), s.getCiphertext());
-		else return deriveKey("I_B", s.getIv(), s.getCiphertext());
+		if(alice) return deriveKey("I_A", s.getSecret());
+		else return deriveKey("I_B", s.getSecret());
 	}
 
 	public SecretKey deriveIncomingMacKey(byte[] secret) {
@@ -131,8 +96,8 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	private SecretKey deriveMacKey(SharedSecret s, boolean alice) {
-		if(alice) return deriveKey("M_A", s.getIv(), s.getCiphertext());
-		else return deriveKey("M_B", s.getIv(), s.getCiphertext());
+		if(alice) return deriveKey("M_A", s.getSecret());
+		else return deriveKey("M_B", s.getSecret());
 	}
 
 	public SecretKey deriveOutgoingFrameKey(byte[] secret) {
diff --git a/components/net/sf/briar/crypto/CryptoModule.java b/components/net/sf/briar/crypto/CryptoModule.java
index 31dbc46ac7ddf6045240e8f23f61a469de42b767..517111b601dbc49bb54e725919f95df32950ca06 100644
--- a/components/net/sf/briar/crypto/CryptoModule.java
+++ b/components/net/sf/briar/crypto/CryptoModule.java
@@ -1,10 +1,6 @@
 package net.sf.briar.crypto;
 
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-
 import net.sf.briar.api.crypto.CryptoComponent;
-import net.sf.briar.api.crypto.SecretStorageKey;
 
 import com.google.inject.AbstractModule;
 import com.google.inject.Singleton;
@@ -15,8 +11,5 @@ public class CryptoModule extends AbstractModule {
 	protected void configure() {
 		bind(CryptoComponent.class).to(
 				CryptoComponentImpl.class).in(Singleton.class);
-		// FIXME: Use a real key
-		bind(SecretKey.class).annotatedWith(SecretStorageKey.class).toInstance(
-				new SecretKeySpec(new byte[32], "AES"));
 	}
 }
diff --git a/components/net/sf/briar/crypto/SharedSecret.java b/components/net/sf/briar/crypto/SharedSecret.java
index 111e544f72518dd98ba06c333180cda700b06165..0f2a984b9abd1352a608091480fdcc47abcc9fc2 100644
--- a/components/net/sf/briar/crypto/SharedSecret.java
+++ b/components/net/sf/briar/crypto/SharedSecret.java
@@ -1,29 +1,19 @@
 package net.sf.briar.crypto;
 
-import javax.crypto.spec.IvParameterSpec;
-
 /**
- * An encrypted shared secret from which authentication and encryption keys can
- * be derived. The encrypted secret carries an IV for encrypting and decrypting
- * it and a flag indicating whether Alice's keys or Bob's keys should be
- * derived from the secret.
- * <p>
- * When two parties agree on a shared secret, they must determine which of them
- * will derive Alice's keys and which Bob's. Each party then encrypts the
- * secret with an independent key and IV.
+ * A shared secret from which authentication and encryption keys can be derived.
+ * The secret carries a flag indicating whether Alice's keys or Bob's keys
+ * should be derived from the secret. When two parties agree on a shared secret,
+ * they must decide which of them will derive Alice's keys and which Bob's.
  */
 class SharedSecret {
 
-	static final int IV_BYTES = 16;
-
-	private final IvParameterSpec iv;
 	private final boolean alice;
-	private final byte[] ciphertext;
+	private final byte[] secret;
 
-	SharedSecret(byte[] secret) {
-		if(secret.length < IV_BYTES + 2) throw new IllegalArgumentException();
-		iv = new IvParameterSpec(secret, 0, IV_BYTES);
-		switch(secret[IV_BYTES]) {
+	SharedSecret(byte[] b) {
+		if(b.length < 2) throw new IllegalArgumentException();
+		switch(b[0]) {
 		case 0:
 			alice = false;
 			break;
@@ -33,21 +23,13 @@ class SharedSecret {
 		default:
 			throw new IllegalArgumentException();
 		}
-		ciphertext = new byte[secret.length - IV_BYTES - 1];
-		System.arraycopy(secret, IV_BYTES + 1, ciphertext, 0,
-				ciphertext.length);
+		secret = new byte[b.length - 1];
+		System.arraycopy(b, 1, secret, 0, secret.length);
 	}
 
-	SharedSecret(IvParameterSpec iv, boolean alice, byte[] ciphertext) {
-		if(iv.getIV().length != IV_BYTES) throw new IllegalArgumentException();
-		this.iv = iv;
+	SharedSecret(boolean alice, byte[] secret) {
 		this.alice = alice;
-		this.ciphertext = ciphertext;
-	}
-
-	/** Returns the IV used for encrypting and decrypting the secret. */
-	IvParameterSpec getIv() {
-		return iv;
+		this.secret = secret;
 	}
 
 	/**
@@ -58,22 +40,19 @@ class SharedSecret {
 		return alice;
 	}
 
-	/** Returns the encrypted shared secret. */
-	byte[] getCiphertext() {
-		return ciphertext;
+	/** Returns the shared secret. */
+	byte[] getSecret() {
+		return secret;
 	}
 
 	/**
-	 * Returns a raw representation of the encrypted shared secret, suitable
-	 * for storing in the database.
+	 * Returns a raw representation of this object, suitable for storing in the
+	 * database.
 	 */
 	byte[] getBytes() {
-		byte[] b = new byte[IV_BYTES + 1 + ciphertext.length];
-		byte[] ivBytes = iv.getIV();
-		assert ivBytes.length == IV_BYTES;
-		System.arraycopy(ivBytes, 0, b, 0, IV_BYTES);
-		if(alice) b[IV_BYTES] = (byte) 1;
-		System.arraycopy(ciphertext, 0, b, IV_BYTES + 1, ciphertext.length);
+		byte[] b = new byte[1 + secret.length];
+		if(alice) b[0] = (byte) 1;
+		System.arraycopy(secret, 0, b, 1, secret.length);
 		return b;
 	}
 }
diff --git a/test/net/sf/briar/ProtocolIntegrationTest.java b/test/net/sf/briar/ProtocolIntegrationTest.java
index 262625603d1f57a9b724c144dd7c955739659796..f7afcc9a62b6c144c22dcc3b8c88614ce9db65ad 100644
--- a/test/net/sf/briar/ProtocolIntegrationTest.java
+++ b/test/net/sf/briar/ProtocolIntegrationTest.java
@@ -97,9 +97,9 @@ public class ProtocolIntegrationTest extends TestCase {
 		assertEquals(crypto.getMessageDigest().getDigestLength(),
 				UniqueId.LENGTH);
 		// Create matching secrets: one for Alice, one for Bob
-		aliceSecret = new byte[45];
-		aliceSecret[16] = (byte) 1;
-		bobSecret = new byte[45];
+		aliceSecret = new byte[123];
+		aliceSecret[0] = (byte) 1;
+		bobSecret = new byte[123];
 		// Create two groups: one restricted, one unrestricted
 		GroupFactory groupFactory = i.getInstance(GroupFactory.class);
 		group = groupFactory.createGroup("Unrestricted group", null);
diff --git a/test/net/sf/briar/crypto/CryptoComponentTest.java b/test/net/sf/briar/crypto/CryptoComponentTest.java
index 8e64765e2f81fd3b7c22b5a2cf17e43f0b7ff2a0..fcc74391e085688334d66516e12fb4ae1aa5bdfc 100644
--- a/test/net/sf/briar/crypto/CryptoComponentTest.java
+++ b/test/net/sf/briar/crypto/CryptoComponentTest.java
@@ -22,7 +22,7 @@ public class CryptoComponentTest extends TestCase {
 	public void testKeyDerivation() {
 		// Create matching secrets: one for Alice, one for Bob
 		byte[] aliceSecret = new byte[123];
-		aliceSecret[SharedSecret.IV_BYTES] = (byte) 1;
+		aliceSecret[0] = (byte) 1;
 		byte[] bobSecret = new byte[123];
 		// Check that Alice's incoming keys match Bob's outgoing keys
 		assertEquals(crypto.deriveIncomingMacKey(aliceSecret),
diff --git a/test/net/sf/briar/crypto/SharedSecretTest.java b/test/net/sf/briar/crypto/SharedSecretTest.java
index 4b5327245e8b8d3b81129722ea418328bef43cd7..aa23d79aee3bed06484f990ff3fe6a507eb03a82 100644
--- a/test/net/sf/briar/crypto/SharedSecretTest.java
+++ b/test/net/sf/briar/crypto/SharedSecretTest.java
@@ -15,22 +15,22 @@ public class SharedSecretTest extends TestCase {
 		Random random = new Random();
 		byte[] secret = new byte[40];
 		random.nextBytes(secret);
-		secret[SharedSecret.IV_BYTES] = (byte) 0;
+		secret[0] = (byte) 0;
 		SharedSecret s = new SharedSecret(secret);
 		assertArrayEquals(secret, s.getBytes());
-		secret[SharedSecret.IV_BYTES] = (byte) 1;
+		secret[0] = (byte) 1;
 		s = new SharedSecret(secret);
 		assertArrayEquals(secret, s.getBytes());
 		// The Alice flag must be either 0 or 1
-		secret[SharedSecret.IV_BYTES] = (byte) 2;
+		secret[0] = (byte) 2;
 		try {
 			s = new SharedSecret(secret);
 			fail();
 		} catch(IllegalArgumentException expected) {}
-		// The ciphertext must be at least 1 byte long
-		secret = new byte[SharedSecret.IV_BYTES + 1];
+		// The secret must be at least 1 byte long
+		secret = new byte[1];
 		random.nextBytes(secret);
-		secret[SharedSecret.IV_BYTES] = (byte) 0;
+		secret[0] = (byte) 0;
 		try {
 			s = new SharedSecret(secret);
 			fail();
diff --git a/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java b/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java
index 74b739f89103d807ad02bb75c793a6552e36c97d..d972415507c63d6b2f445806d4583c290026e24e 100644
--- a/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java
+++ b/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java
@@ -63,9 +63,9 @@ public class BatchConnectionReadWriteTest extends TestCase {
 		transportId = new TransportId(TestUtils.getRandomId());
 		transportIndex = new TransportIndex(1);
 		// Create matching secrets for Alice and Bob
-		aliceSecret = new byte[100];
-		aliceSecret[16] = (byte) 1;
-		bobSecret = new byte[100];
+		aliceSecret = new byte[123];
+		aliceSecret[0] = (byte) 1;
+		bobSecret = new byte[123];
 	}
 
 	@Before