diff --git a/api/net/sf/briar/api/crypto/KeyManager.java b/api/net/sf/briar/api/crypto/KeyManager.java
index ad406eceaed790d70bc4b7a9abb7ed2b8135f611..a5a841687ae2d1b129009d9c29ea22b69635ce3b 100644
--- a/api/net/sf/briar/api/crypto/KeyManager.java
+++ b/api/net/sf/briar/api/crypto/KeyManager.java
@@ -1,15 +1,15 @@
 package net.sf.briar.api.crypto;
 
 import net.sf.briar.api.ContactId;
+import net.sf.briar.api.db.ContactTransport;
 import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.transport.ConnectionContext;
 
 public interface KeyManager {
 
 	/**
-	 * Starts the key manager and returns true if the manager started
-	 * successfully. This method must be called after the database has been
-	 * opened.
+	 * Starts the key manager and returns true if it started successfully. This
+	 * method must be called after the database has been opened.
 	 */
 	boolean start();
 
@@ -22,4 +22,10 @@ public interface KeyManager {
 	 * support the transport.
 	 */
 	ConnectionContext getConnectionContext(ContactId c, TransportId t);
+
+	/**
+	 * Called whenever a contact transport has been added. The initial secret
+	 * is erased before returning.
+	 */
+	void contactTransportAdded(ContactTransport ct, byte[] initialSecret);
 }
diff --git a/api/net/sf/briar/api/db/TemporarySecret.java b/api/net/sf/briar/api/db/TemporarySecret.java
index db2aa95dc78a2bfd4c5693f1809f9ff52ebbd9cb..0289b07373ff4a1bdc3393b7280cfa323e717950 100644
--- a/api/net/sf/briar/api/db/TemporarySecret.java
+++ b/api/net/sf/briar/api/db/TemporarySecret.java
@@ -30,10 +30,10 @@ public class TemporarySecret extends ContactTransport {
 				secret, 0L, 0L, new byte[CONNECTION_WINDOW_SIZE / 8]);
 	}
 
-	/** Creates a temporary secret derived from the given temporary secret. */
-	public TemporarySecret(TemporarySecret old, long period, byte[] secret) {
-		this(old.getContactId(), old.getTransportId(), old.getEpoch(),
-				old.getClockDifference(), old.getLatency(), old.getAlice(),
+	/** Creates a temporary secret derived from the given contact transport. */
+	public TemporarySecret(ContactTransport ct, long period, byte[] secret) {
+		this(ct.getContactId(), ct.getTransportId(), ct.getEpoch(),
+				ct.getClockDifference(), ct.getLatency(), ct.getAlice(),
 				period, secret);
 	}
 
diff --git a/components/net/sf/briar/transport/KeyManagerImpl.java b/components/net/sf/briar/transport/KeyManagerImpl.java
index 97aa506f3c6badfe2d88e0e998b6618f31759a1c..c1cd7741d6dc6f80379ccfdb64609a4622f0da1d 100644
--- a/components/net/sf/briar/transport/KeyManagerImpl.java
+++ b/components/net/sf/briar/transport/KeyManagerImpl.java
@@ -1,6 +1,7 @@
 package net.sf.briar.transport;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -13,6 +14,7 @@ import java.util.logging.Logger;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.KeyManager;
+import net.sf.briar.api.db.ContactTransport;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DbException;
 import net.sf.briar.api.db.TemporarySecret;
@@ -26,8 +28,6 @@ import net.sf.briar.util.ByteUtils;
 
 import com.google.inject.Inject;
 
-// FIXME: When a contact transport is added we need to load its secrets
-
 class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
 
 	private static final int MS_BETWEEN_CHECKS = 60 * 1000;
@@ -94,9 +94,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
 			Collection<TemporarySecret> secrets) {
 		Collection<TemporarySecret> dead = new ArrayList<TemporarySecret>();
 		for(TemporarySecret s : secrets) {
-			ContactId c = s.getContactId();
-			TransportId t = s.getTransportId();
-			ContactTransportKey k = new ContactTransportKey(c, t);
+			ContactTransportKey k = new ContactTransportKey(s);
 			long rotationPeriod = getRotationPeriod(s);
 			long creationTime = getCreationTime(s);
 			long activationTime = creationTime + s.getClockDifference();
@@ -128,9 +126,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
 			Collection<TemporarySecret> dead) {
 		Collection<TemporarySecret> created = new ArrayList<TemporarySecret>();
 		for(TemporarySecret s : dead) {
-			ContactId c = s.getContactId();
-			TransportId t = s.getTransportId();
-			ContactTransportKey k = new ContactTransportKey(c, t);
+			ContactTransportKey k = new ContactTransportKey(s);
 			if(incomingNew.containsKey(k)) throw new IllegalStateException();
 			byte[] secret = s.getSecret();
 			long period = s.getPeriod();
@@ -153,8 +149,8 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
 				// Derive the two current incoming secrets
 				byte[] secret1, secret2;
 				secret1 = secret;
-				for(long l = period; l < currentPeriod; l++) {
-					byte[] temp = crypto.deriveNextSecret(secret1, l);
+				for(long p = period; p < currentPeriod; p++) {
+					byte[] temp = crypto.deriveNextSecret(secret1, p);
 					ByteUtils.erase(secret1);
 					secret1 = temp;
 				}
@@ -181,7 +177,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
 		return created;
 	}
 
-	private long getRotationPeriod(TemporarySecret s) {
+	private long getRotationPeriod(ContactTransport s) {
 		return 2 * s.getClockDifference() + s.getLatency();
 	}
 
@@ -219,6 +215,49 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
 		return new ConnectionContext(c, t, secret, connection, s.getAlice());
 	}
 
+	public synchronized void contactTransportAdded(ContactTransport ct,
+			byte[] initialSecret) {		
+		long now = System.currentTimeMillis();
+		long rotationPeriod = getRotationPeriod(ct);
+		long elapsed = now - ct.getEpoch();
+		long currentPeriod = elapsed / rotationPeriod;
+		if(currentPeriod < 1) throw new IllegalArgumentException();
+		// Derive the two current incoming secrets
+		byte[] secret1, secret2;
+		secret1 = initialSecret;
+		for(long p = 0; p < currentPeriod; p++) {
+			byte[] temp = crypto.deriveNextSecret(secret1, p);
+			ByteUtils.erase(secret1);
+			secret1 = temp;
+		}
+		secret2 = crypto.deriveNextSecret(secret1, currentPeriod);
+		// One of the incoming secrets is the current outgoing secret
+		ContactTransportKey k = new ContactTransportKey(ct);
+		TemporarySecret s1, s2;
+		s1 = new TemporarySecret(ct, currentPeriod - 1, secret1);
+		incomingOld.put(k, s1);
+		s2 = new TemporarySecret(ct, currentPeriod, secret2);
+		incomingNew.put(k, s2);
+		if(elapsed % rotationPeriod < ct.getClockDifference()) {
+			// The outgoing secret is the newer incoming secret
+			outgoing.put(k, s2);
+		} else {
+			// The outgoing secret is the older incoming secret
+			outgoing.put(k, s1);
+		}
+		// Store the new secrets
+		try {
+			db.addSecrets(Arrays.asList(s1, s2));
+		} catch(DbException e) {
+			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
+		}
+		// Pass the new secrets to the recogniser
+		recogniser.addSecret(s1);
+		recogniser.addSecret(s2);
+		// Erase the initial secret
+		ByteUtils.erase(initialSecret);
+	}
+
 	@Override
 	public synchronized void run() {
 		// Rebuild the maps because we may be running a whole period late
@@ -287,6 +326,10 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
 			this.transportId = transportId;
 		}
 
+		private ContactTransportKey(ContactTransport ct) {
+			this(ct.getContactId(), ct.getTransportId());
+		}
+
 		@Override
 		public int hashCode() {
 			return contactId.hashCode() + transportId.hashCode();
diff --git a/test/net/sf/briar/protocol/simplex/SimplexProtocolIntegrationTest.java b/test/net/sf/briar/protocol/simplex/SimplexProtocolIntegrationTest.java
index 5caec2ff58dcda71df781c2020a25ecdfb4e5324..8448a0934a012221c49400f20d4cb4e4bd4fa2c1 100644
--- a/test/net/sf/briar/protocol/simplex/SimplexProtocolIntegrationTest.java
+++ b/test/net/sf/briar/protocol/simplex/SimplexProtocolIntegrationTest.java
@@ -14,8 +14,8 @@ import net.sf.briar.TestDatabaseModule;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.crypto.KeyManager;
+import net.sf.briar.api.db.ContactTransport;
 import net.sf.briar.api.db.DatabaseComponent;
-import net.sf.briar.api.db.TemporarySecret;
 import net.sf.briar.api.db.event.DatabaseEvent;
 import net.sf.briar.api.db.event.DatabaseListener;
 import net.sf.briar.api.db.event.MessagesAddedEvent;
@@ -57,7 +57,7 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase {
 	private final File aliceDir = new File(testDir, "alice");
 	private final File bobDir = new File(testDir, "bob");
 	private final TransportId transportId;
-	private final byte[] secret;
+	private final byte[] initialSecret;
 	private final long epoch;
 
 	private Injector alice, bob;
@@ -66,8 +66,8 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase {
 		super();
 		transportId = new TransportId(TestUtils.getRandomId());
 		// Create matching secrets for Alice and Bob
-		secret = new byte[32];
-		new Random().nextBytes(secret);
+		initialSecret = new byte[32];
+		new Random().nextBytes(initialSecret);
 		long rotationPeriod = 2 * CLOCK_DIFFERENCE + LATENCY;
 		epoch = System.currentTimeMillis() - 2 * rotationPeriod;
 	}
@@ -103,15 +103,15 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase {
 		// Open Alice's database
 		DatabaseComponent db = alice.getInstance(DatabaseComponent.class);
 		db.open(false);
-		// Add Bob as a contact
-		ContactId contactId = db.addContact();
-		TemporarySecret s = new TemporarySecret(contactId, transportId, epoch,
-				CLOCK_DIFFERENCE, LATENCY, true, 0L, secret);
-		db.addContactTransport(s);
-		db.addSecrets(Collections.singletonList(s));
 		// Start Alice's key manager
 		KeyManager km = alice.getInstance(KeyManager.class);
 		km.start();
+		// Add Bob as a contact
+		ContactId contactId = db.addContact();
+		ContactTransport ct = new ContactTransport(contactId, transportId,
+				epoch, CLOCK_DIFFERENCE, LATENCY, true);
+		db.addContactTransport(ct);
+		km.contactTransportAdded(ct, initialSecret.clone());
 		// Send Bob a message
 		String subject = "Hello";
 		byte[] body = "Hi Bob!".getBytes("UTF-8");
@@ -147,18 +147,18 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase {
 		// Open Bob's database
 		DatabaseComponent db = bob.getInstance(DatabaseComponent.class);
 		db.open(false);
-		// Set up a database listener
-		MessageListener listener = new MessageListener();
-		db.addListener(listener);
-		// Add Alice as a contact
-		ContactId contactId = db.addContact();
-		TemporarySecret s = new TemporarySecret(contactId, transportId, epoch,
-				CLOCK_DIFFERENCE, LATENCY, false, 0L, secret);
-		db.addContactTransport(s);
-		db.addSecrets(Collections.singletonList(s));
 		// Start Bob's key manager
 		KeyManager km = bob.getInstance(KeyManager.class);
 		km.start();
+		// Add Alice as a contact
+		ContactId contactId = db.addContact();
+		ContactTransport ct = new ContactTransport(contactId, transportId,
+				epoch, CLOCK_DIFFERENCE, LATENCY, false);
+		db.addContactTransport(ct);
+		km.contactTransportAdded(ct, initialSecret.clone());
+		// Set up a database listener
+		MessageListener listener = new MessageListener();
+		db.addListener(listener);
 		// Fake a transport update from Alice
 		TransportUpdate transportUpdate = new TransportUpdate() {
 
@@ -216,7 +216,8 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase {
 		private boolean messagesAdded = false;
 
 		public void eventOccurred(DatabaseEvent e) {
-			if(e instanceof MessagesAddedEvent) messagesAdded = true;
+			if(e instanceof MessagesAddedEvent)
+				messagesAdded = true;
 		}
 	}
 }