diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java
index 5fef176712f94c093c3922f4a1d888d808167987..90f9da6f092f76f6ac9bdc3208f9b1ecc98622bb 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java
@@ -36,22 +36,14 @@ public interface CryptoComponent {
 	 * Derives a nonce from the given secret key that can be used for key
 	 * binding.
 	 *
+	 * TODO: This just calls mac(), remove it
+	 *
 	 * @param label a namespaced label indicating the purpose of this nonce,
 	 * to prevent it from being repurposed or colliding with a nonce derived
 	 * for another purpose
 	 */
 	byte[] deriveKeyBindingNonce(String label, SecretKey k);
 
-	/**
-	 * Derives a commitment to the provided public key.
-	 * <p/>
-	 * Used by the key exchange protocol.
-	 *
-	 * @param publicKey the public key
-	 * @return the commitment to the provided public key.
-	 */
-	byte[] deriveKeyCommitment(PublicKey publicKey);
-
 	/**
 	 * Derives a common shared secret from two public keys and one of the
 	 * corresponding private keys.
@@ -67,25 +59,6 @@ public interface CryptoComponent {
 	SecretKey deriveSharedSecret(String label, PublicKey theirPublicKey,
 			KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException;
 
-	/**
-	 * Derives the content of a confirmation record.
-	 * <p/>
-	 * Used by the key exchange protocol.
-	 *
-	 * @param sharedSecret the common shared secret
-	 * @param theirPayload the key exchange payload of the remote party
-	 * @param ourPayload the key exchange payload of the local party
-	 * @param theirPublicKey the ephemeral public key of the remote party
-	 * @param ourKeyPair our ephemeral key pair of the local party
-	 * @param alice true if the local party is Alice
-	 * @param aliceRecord true if the confirmation record is for use by Alice
-	 * @return the confirmation record
-	 */
-	byte[] deriveConfirmationRecord(SecretKey sharedSecret,
-			byte[] theirPayload, byte[] ourPayload,
-			PublicKey theirPublicKey, KeyPair ourKeyPair,
-			boolean alice, boolean aliceRecord);
-
 	/**
 	 * Signs the given byte[] with the given ECDSA private key.
 	 *
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/KeyAgreementCrypto.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/KeyAgreementCrypto.java
new file mode 100644
index 0000000000000000000000000000000000000000..1dcf7ebf8bf2e56b29f6f2d1d93cc54036ca7790
--- /dev/null
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/KeyAgreementCrypto.java
@@ -0,0 +1,50 @@
+package org.briarproject.bramble.api.crypto;
+
+public interface KeyAgreementCrypto {
+
+	/**
+	 * Hash label for public key commitment.
+	 */
+	String COMMIT_LABEL = "org.briarproject.bramble.keyagreement/COMMIT";
+
+	/**
+	 * Key derivation label for confirmation record.
+	 */
+	String CONFIRMATION_KEY_LABEL =
+			"org.briarproject.bramble.keyagreement/CONFIRMATION_KEY";
+
+	/**
+	 * MAC label for confirmation record.
+	 */
+	String CONFIRMATION_MAC_LABEL =
+			"org.briarproject.bramble.keyagreement/CONFIRMATION_MAC";
+
+	/**
+	 * Derives a commitment to the provided public key.
+	 * <p/>
+	 * Used by the key exchange protocol.
+	 *
+	 * @param publicKey the public key
+	 * @return the commitment to the provided public key.
+	 */
+	byte[] deriveKeyCommitment(PublicKey publicKey);
+
+	/**
+	 * Derives the content of a confirmation record.
+	 * <p/>
+	 * Used by the key exchange protocol.
+	 *
+	 * @param sharedSecret the common shared secret
+	 * @param theirPayload the key exchange payload of the remote party
+	 * @param ourPayload the key exchange payload of the local party
+	 * @param theirPublicKey the ephemeral public key of the remote party
+	 * @param ourKeyPair our ephemeral key pair of the local party
+	 * @param alice true if the local party is Alice
+	 * @param aliceRecord true if the confirmation record is for use by Alice
+	 * @return the confirmation record
+	 */
+	byte[] deriveConfirmationRecord(SecretKey sharedSecret,
+			byte[] theirPayload, byte[] ourPayload,
+			PublicKey theirPublicKey, KeyPair ourKeyPair,
+			boolean alice, boolean aliceRecord);
+}
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/keyagreement/KeyAgreementTaskFactory.java b/bramble-api/src/main/java/org/briarproject/bramble/api/keyagreement/KeyAgreementTaskFactory.java
deleted file mode 100644
index 40d875cc9d792e53a34c3d6f52ac6611c6fd9dea..0000000000000000000000000000000000000000
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/keyagreement/KeyAgreementTaskFactory.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.briarproject.bramble.api.keyagreement;
-
-import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
-
-/**
- * Manages tasks for conducting key agreements with remote peers.
- */
-@NotNullByDefault
-public interface KeyAgreementTaskFactory {
-
-	/**
-	 * Gets the current key agreement task.
-	 */
-	KeyAgreementTask createTask();
-}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java
index 4a04c28a195f7460d5fa2cb34d66a2d08d3eea62..5e2985ef8e71b06286ba91e90b20ecf6b778d3e0 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java
@@ -39,7 +39,6 @@ import java.util.logging.Logger;
 import javax.inject.Inject;
 
 import static java.util.logging.Level.INFO;
-import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
 import static org.briarproject.bramble.crypto.EllipticCurveConstants.PARAMETERS;
 import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
 
@@ -56,16 +55,6 @@ class CryptoComponentImpl implements CryptoComponent {
 	private static final int PBKDF_TARGET_MILLIS = 500;
 	private static final int PBKDF_SAMPLES = 30;
 
-	// Hash label for BQP public key commitment derivation
-	private static final String COMMIT_LABEL =
-			"org.briarproject.bramble.keyagreement/COMMIT";
-	// KDF label for BQP confirmation key derivation
-	private static final String CONFIRMATION_KEY_LABEL =
-			"org.briarproject.bramble.keyagreement/CONFIRMATION_KEY";
-	// MAC label for BQP confirmation record
-	private static final String CONFIRMATION_MAC_LABEL =
-			"org.briarproject.bramble.keyagreement/CONFIRMATION_MAC";
-
 	private final SecureRandom secureRandom;
 	private final ECKeyPairGenerator agreementKeyPairGenerator;
 	private final ECKeyPairGenerator signatureKeyPairGenerator;
@@ -230,23 +219,13 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	@Override
-	public SecretKey deriveKey(String label, SecretKey k,
-			byte[]... inputs) {
-		return new SecretKey(macKdf(label, k, inputs));
+	public SecretKey deriveKey(String label, SecretKey k, byte[]... inputs) {
+		return new SecretKey(mac(label, k, inputs));
 	}
 
 	@Override
 	public byte[] deriveKeyBindingNonce(String label, SecretKey k) {
-		return macKdf(label, k);
-	}
-
-	@Override
-	public byte[] deriveKeyCommitment(PublicKey publicKey) {
-		byte[] hash = hash(COMMIT_LABEL, publicKey.getEncoded());
-		// The output is the first COMMIT_LENGTH bytes of the hash
-		byte[] commitment = new byte[COMMIT_LENGTH];
-		System.arraycopy(hash, 0, commitment, 0, COMMIT_LENGTH);
-		return commitment;
+		return mac(label, k);
 	}
 
 	@Override
@@ -265,32 +244,6 @@ class CryptoComponentImpl implements CryptoComponent {
 		return new SecretKey(hash(label, raw, alicePub, bobPub));
 	}
 
-	@Override
-	public byte[] deriveConfirmationRecord(SecretKey sharedSecret,
-			byte[] theirPayload, byte[] ourPayload, PublicKey theirPublicKey,
-			KeyPair ourKeyPair, boolean alice, boolean aliceRecord) {
-		SecretKey ck = deriveKey(CONFIRMATION_KEY_LABEL, sharedSecret);
-		byte[] alicePayload, alicePub, bobPayload, bobPub;
-		if (alice) {
-			alicePayload = ourPayload;
-			alicePub = ourKeyPair.getPublic().getEncoded();
-			bobPayload = theirPayload;
-			bobPub = theirPublicKey.getEncoded();
-		} else {
-			alicePayload = theirPayload;
-			alicePub = theirPublicKey.getEncoded();
-			bobPayload = ourPayload;
-			bobPub = ourKeyPair.getPublic().getEncoded();
-		}
-		if (aliceRecord) {
-			return macKdf(CONFIRMATION_MAC_LABEL, ck, alicePayload, alicePub,
-					bobPayload, bobPub);
-		} else {
-			return macKdf(CONFIRMATION_MAC_LABEL, ck, bobPayload, bobPub,
-					alicePayload, alicePub);
-		}
-	}
-
 	@Override
 	public byte[] sign(String label, byte[] toSign, byte[] privateKey)
 			throws GeneralSecurityException {
@@ -464,15 +417,6 @@ class CryptoComponentImpl implements CryptoComponent {
 		return AsciiArmour.wrap(b, lineLength);
 	}
 
-	// Key derivation function based on a pseudo-random function - see
-	// NIST SP 800-108, section 5.1
-	private byte[] macKdf(String label, SecretKey k, byte[]... inputs) {
-		byte[] mac = mac(label, k, inputs);
-		// The output of the PRF must be usable as a key
-		if (mac.length != SecretKey.LENGTH) throw new IllegalStateException();
-		return mac;
-	}
-
 	// Password-based key derivation function - see PKCS#5 v2.1, section 5.2
 	private byte[] pbkdf2(String password, byte[] salt, int iterations) {
 		byte[] utf8 = StringUtils.toUtf8(password);
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoModule.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoModule.java
index 99889104594bf89ee4550b02730cced465ef51b9..a40b656282556a5660b23973a5b611f4793dec3e 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoModule.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoModule.java
@@ -3,6 +3,7 @@ package org.briarproject.bramble.crypto;
 import org.briarproject.bramble.TimeLoggingExecutor;
 import org.briarproject.bramble.api.crypto.CryptoComponent;
 import org.briarproject.bramble.api.crypto.CryptoExecutor;
+import org.briarproject.bramble.api.crypto.KeyAgreementCrypto;
 import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
 import org.briarproject.bramble.api.crypto.StreamDecrypterFactory;
 import org.briarproject.bramble.api.crypto.StreamEncrypterFactory;
@@ -95,6 +96,12 @@ public class CryptoModule {
 				cipherProvider);
 	}
 
+	@Provides
+	KeyAgreementCrypto provideKeyAgreementCrypto(
+			KeyAgreementCryptoImpl keyAgreementCrypto) {
+		return keyAgreementCrypto;
+	}
+
 	@Provides
 	@Singleton
 	@CryptoExecutor
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/KeyAgreementCryptoImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/KeyAgreementCryptoImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..db2f19a7bc604b1200e47dfda0ed6e855fc2fcef
--- /dev/null
+++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/KeyAgreementCryptoImpl.java
@@ -0,0 +1,56 @@
+package org.briarproject.bramble.crypto;
+
+import org.briarproject.bramble.api.crypto.CryptoComponent;
+import org.briarproject.bramble.api.crypto.KeyAgreementCrypto;
+import org.briarproject.bramble.api.crypto.KeyPair;
+import org.briarproject.bramble.api.crypto.PublicKey;
+import org.briarproject.bramble.api.crypto.SecretKey;
+
+import javax.inject.Inject;
+
+import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
+
+class KeyAgreementCryptoImpl implements KeyAgreementCrypto {
+
+	private final CryptoComponent crypto;
+
+	@Inject
+	KeyAgreementCryptoImpl(CryptoComponent crypto) {
+		this.crypto = crypto;
+	}
+
+	@Override
+	public byte[] deriveKeyCommitment(PublicKey publicKey) {
+		byte[] hash = crypto.hash(COMMIT_LABEL, publicKey.getEncoded());
+		// The output is the first COMMIT_LENGTH bytes of the hash
+		byte[] commitment = new byte[COMMIT_LENGTH];
+		System.arraycopy(hash, 0, commitment, 0, COMMIT_LENGTH);
+		return commitment;
+	}
+
+	@Override
+	public byte[] deriveConfirmationRecord(SecretKey sharedSecret,
+			byte[] theirPayload, byte[] ourPayload, PublicKey theirPublicKey,
+			KeyPair ourKeyPair, boolean alice, boolean aliceRecord) {
+		SecretKey ck = crypto.deriveKey(CONFIRMATION_KEY_LABEL, sharedSecret);
+		byte[] alicePayload, alicePub, bobPayload, bobPub;
+		if (alice) {
+			alicePayload = ourPayload;
+			alicePub = ourKeyPair.getPublic().getEncoded();
+			bobPayload = theirPayload;
+			bobPub = theirPublicKey.getEncoded();
+		} else {
+			alicePayload = theirPayload;
+			alicePub = theirPublicKey.getEncoded();
+			bobPayload = ourPayload;
+			bobPub = ourKeyPair.getPublic().getEncoded();
+		}
+		if (aliceRecord) {
+			return crypto.mac(CONFIRMATION_MAC_LABEL, ck, alicePayload,
+					alicePub, bobPayload, bobPub);
+		} else {
+			return crypto.mac(CONFIRMATION_MAC_LABEL, ck, bobPayload, bobPub,
+					alicePayload, alicePub);
+		}
+	}
+}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementConnector.java b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementConnector.java
index 2ed0b95211f0d5153db2717063600b287c642e6c..89bf01ee0d8fd0d88cbb8b4c14103b5b752d1ed0 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementConnector.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementConnector.java
@@ -1,6 +1,6 @@
 package org.briarproject.bramble.keyagreement;
 
-import org.briarproject.bramble.api.crypto.CryptoComponent;
+import org.briarproject.bramble.api.crypto.KeyAgreementCrypto;
 import org.briarproject.bramble.api.crypto.KeyPair;
 import org.briarproject.bramble.api.data.BdfList;
 import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
@@ -46,7 +46,7 @@ class KeyAgreementConnector {
 
 	private final Callbacks callbacks;
 	private final Clock clock;
-	private final CryptoComponent crypto;
+	private final KeyAgreementCrypto keyAgreementCrypto;
 	private final PluginManager pluginManager;
 	private final CompletionService<KeyAgreementConnection> connect;
 
@@ -58,11 +58,11 @@ class KeyAgreementConnector {
 	private volatile boolean alice = false;
 
 	KeyAgreementConnector(Callbacks callbacks, Clock clock,
-			CryptoComponent crypto, PluginManager pluginManager,
+			KeyAgreementCrypto keyAgreementCrypto, PluginManager pluginManager,
 			Executor ioExecutor) {
 		this.callbacks = callbacks;
 		this.clock = clock;
-		this.crypto = crypto;
+		this.keyAgreementCrypto = keyAgreementCrypto;
 		this.pluginManager = pluginManager;
 		connect = new ExecutorCompletionService<>(ioExecutor);
 	}
@@ -70,8 +70,8 @@ class KeyAgreementConnector {
 	public Payload listen(KeyPair localKeyPair) {
 		LOG.info("Starting BQP listeners");
 		// Derive commitment
-		byte[] commitment =
-				crypto.deriveKeyCommitment(localKeyPair.getPublic());
+		byte[] commitment = keyAgreementCrypto.deriveKeyCommitment(
+				localKeyPair.getPublic());
 		// Start all listeners and collect their descriptors
 		List<TransportDescriptor> descriptors = new ArrayList<>();
 		for (DuplexPlugin plugin : pluginManager.getKeyAgreementPlugins()) {
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementModule.java b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementModule.java
index 9875387db916d282d9bc382077b25d37a8d40286..e7ec82dabb1b8b010c73e5188ef00f8d536714d3 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementModule.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementModule.java
@@ -1,19 +1,10 @@
 package org.briarproject.bramble.keyagreement;
 
-import org.briarproject.bramble.api.crypto.CryptoComponent;
 import org.briarproject.bramble.api.data.BdfReaderFactory;
 import org.briarproject.bramble.api.data.BdfWriterFactory;
-import org.briarproject.bramble.api.event.EventBus;
-import org.briarproject.bramble.api.keyagreement.KeyAgreementTaskFactory;
+import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
 import org.briarproject.bramble.api.keyagreement.PayloadEncoder;
 import org.briarproject.bramble.api.keyagreement.PayloadParser;
-import org.briarproject.bramble.api.lifecycle.IoExecutor;
-import org.briarproject.bramble.api.plugin.PluginManager;
-import org.briarproject.bramble.api.system.Clock;
-
-import java.util.concurrent.Executor;
-
-import javax.inject.Singleton;
 
 import dagger.Module;
 import dagger.Provides;
@@ -22,13 +13,9 @@ import dagger.Provides;
 public class KeyAgreementModule {
 
 	@Provides
-	@Singleton
-	KeyAgreementTaskFactory provideKeyAgreementTaskFactory(Clock clock,
-			CryptoComponent crypto, EventBus eventBus,
-			@IoExecutor Executor ioExecutor, PayloadEncoder payloadEncoder,
-			PluginManager pluginManager) {
-		return new KeyAgreementTaskFactoryImpl(clock, crypto, eventBus,
-				ioExecutor, payloadEncoder, pluginManager);
+	KeyAgreementTask provideKeyAgreementTask(
+			KeyAgreementTaskImpl keyAgreementTask) {
+		return keyAgreementTask;
 	}
 
 	@Provides
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocol.java b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocol.java
index be4895ff06152b6faf591da9cd7a342cc710d2bd..a5c24c6e4231101717ba2fc892f98875196b666c 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocol.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocol.java
@@ -1,6 +1,7 @@
 package org.briarproject.bramble.keyagreement;
 
 import org.briarproject.bramble.api.crypto.CryptoComponent;
+import org.briarproject.bramble.api.crypto.KeyAgreementCrypto;
 import org.briarproject.bramble.api.crypto.KeyPair;
 import org.briarproject.bramble.api.crypto.KeyParser;
 import org.briarproject.bramble.api.crypto.PublicKey;
@@ -62,6 +63,7 @@ class KeyAgreementProtocol {
 
 	private final Callbacks callbacks;
 	private final CryptoComponent crypto;
+	private final KeyAgreementCrypto keyAgreementCrypto;
 	private final PayloadEncoder payloadEncoder;
 	private final KeyAgreementTransport transport;
 	private final Payload theirPayload, ourPayload;
@@ -69,11 +71,13 @@ class KeyAgreementProtocol {
 	private final boolean alice;
 
 	KeyAgreementProtocol(Callbacks callbacks, CryptoComponent crypto,
+			KeyAgreementCrypto keyAgreementCrypto,
 			PayloadEncoder payloadEncoder, KeyAgreementTransport transport,
 			Payload theirPayload, Payload ourPayload, KeyPair ourKeyPair,
 			boolean alice) {
 		this.callbacks = callbacks;
 		this.crypto = crypto;
+		this.keyAgreementCrypto = keyAgreementCrypto;
 		this.payloadEncoder = payloadEncoder;
 		this.transport = transport;
 		this.theirPayload = theirPayload;
@@ -126,7 +130,7 @@ class KeyAgreementProtocol {
 		KeyParser keyParser = crypto.getAgreementKeyParser();
 		try {
 			PublicKey publicKey = keyParser.parsePublicKey(publicKeyBytes);
-			byte[] expected = crypto.deriveKeyCommitment(publicKey);
+			byte[] expected = keyAgreementCrypto.deriveKeyCommitment(publicKey);
 			if (!Arrays.equals(expected, theirPayload.getCommitment()))
 				throw new AbortException();
 			return publicKey;
@@ -147,7 +151,7 @@ class KeyAgreementProtocol {
 
 	private void sendConfirm(SecretKey s, PublicKey theirPublicKey)
 			throws IOException {
-		byte[] confirm = crypto.deriveConfirmationRecord(s,
+		byte[] confirm = keyAgreementCrypto.deriveConfirmationRecord(s,
 				payloadEncoder.encode(theirPayload),
 				payloadEncoder.encode(ourPayload),
 				theirPublicKey, ourKeyPair,
@@ -158,7 +162,7 @@ class KeyAgreementProtocol {
 	private void receiveConfirm(SecretKey s, PublicKey theirPublicKey)
 			throws AbortException {
 		byte[] confirm = transport.receiveConfirm();
-		byte[] expected = crypto.deriveConfirmationRecord(s,
+		byte[] expected = keyAgreementCrypto.deriveConfirmationRecord(s,
 				payloadEncoder.encode(theirPayload),
 				payloadEncoder.encode(ourPayload),
 				theirPublicKey, ourKeyPair,
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskFactoryImpl.java
deleted file mode 100644
index 4d9dc00cf684cb5d2cf4d2454719768d218015f0..0000000000000000000000000000000000000000
--- a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskFactoryImpl.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.briarproject.bramble.keyagreement;
-
-import org.briarproject.bramble.api.crypto.CryptoComponent;
-import org.briarproject.bramble.api.event.EventBus;
-import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
-import org.briarproject.bramble.api.keyagreement.KeyAgreementTaskFactory;
-import org.briarproject.bramble.api.keyagreement.PayloadEncoder;
-import org.briarproject.bramble.api.lifecycle.IoExecutor;
-import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
-import org.briarproject.bramble.api.plugin.PluginManager;
-import org.briarproject.bramble.api.system.Clock;
-
-import java.util.concurrent.Executor;
-
-import javax.annotation.concurrent.Immutable;
-import javax.inject.Inject;
-
-@Immutable
-@NotNullByDefault
-class KeyAgreementTaskFactoryImpl implements KeyAgreementTaskFactory {
-
-	private final Clock clock;
-	private final CryptoComponent crypto;
-	private final EventBus eventBus;
-	private final Executor ioExecutor;
-	private final PayloadEncoder payloadEncoder;
-	private final PluginManager pluginManager;
-
-	@Inject
-	KeyAgreementTaskFactoryImpl(Clock clock, CryptoComponent crypto,
-			EventBus eventBus, @IoExecutor Executor ioExecutor,
-			PayloadEncoder payloadEncoder, PluginManager pluginManager) {
-		this.clock = clock;
-		this.crypto = crypto;
-		this.eventBus = eventBus;
-		this.ioExecutor = ioExecutor;
-		this.payloadEncoder = payloadEncoder;
-		this.pluginManager = pluginManager;
-	}
-
-	@Override
-	public KeyAgreementTask createTask() {
-		return new KeyAgreementTaskImpl(clock, crypto, eventBus, payloadEncoder,
-				pluginManager, ioExecutor);
-	}
-}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskImpl.java
index de6dcecf753b19c351413aa7dfeab9fbc11f8fe7..e0d97313dc9ed6b1e8dc76427b1ea76502ebf50e 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskImpl.java
@@ -1,6 +1,7 @@
 package org.briarproject.bramble.keyagreement;
 
 import org.briarproject.bramble.api.crypto.CryptoComponent;
+import org.briarproject.bramble.api.crypto.KeyAgreementCrypto;
 import org.briarproject.bramble.api.crypto.KeyPair;
 import org.briarproject.bramble.api.crypto.SecretKey;
 import org.briarproject.bramble.api.event.EventBus;
@@ -14,6 +15,7 @@ import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFinishedEvent
 import org.briarproject.bramble.api.keyagreement.event.KeyAgreementListeningEvent;
 import org.briarproject.bramble.api.keyagreement.event.KeyAgreementStartedEvent;
 import org.briarproject.bramble.api.keyagreement.event.KeyAgreementWaitingEvent;
+import org.briarproject.bramble.api.lifecycle.IoExecutor;
 import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
 import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
 import org.briarproject.bramble.api.plugin.PluginManager;
@@ -23,6 +25,8 @@ import java.io.IOException;
 import java.util.concurrent.Executor;
 import java.util.logging.Logger;
 
+import javax.inject.Inject;
+
 import static java.util.logging.Level.WARNING;
 
 @MethodsNotNullByDefault
@@ -35,6 +39,7 @@ class KeyAgreementTaskImpl extends Thread implements
 			Logger.getLogger(KeyAgreementTaskImpl.class.getName());
 
 	private final CryptoComponent crypto;
+	private final KeyAgreementCrypto keyAgreementCrypto;
 	private final EventBus eventBus;
 	private final PayloadEncoder payloadEncoder;
 	private final KeyPair localKeyPair;
@@ -43,14 +48,17 @@ class KeyAgreementTaskImpl extends Thread implements
 	private Payload localPayload;
 	private Payload remotePayload;
 
+	@Inject
 	KeyAgreementTaskImpl(Clock clock, CryptoComponent crypto,
-			EventBus eventBus, PayloadEncoder payloadEncoder,
-			PluginManager pluginManager, Executor ioExecutor) {
+			KeyAgreementCrypto keyAgreementCrypto, EventBus eventBus,
+			PayloadEncoder payloadEncoder, PluginManager pluginManager,
+			@IoExecutor Executor ioExecutor) {
 		this.crypto = crypto;
+		this.keyAgreementCrypto = keyAgreementCrypto;
 		this.eventBus = eventBus;
 		this.payloadEncoder = payloadEncoder;
 		localKeyPair = crypto.generateAgreementKeyPair();
-		connector = new KeyAgreementConnector(this, clock, crypto,
+		connector = new KeyAgreementConnector(this, clock, keyAgreementCrypto,
 				pluginManager, ioExecutor);
 	}
 
@@ -100,8 +108,8 @@ class KeyAgreementTaskImpl extends Thread implements
 		// Run BQP protocol over the connection
 		LOG.info("Starting BQP protocol");
 		KeyAgreementProtocol protocol = new KeyAgreementProtocol(this, crypto,
-				payloadEncoder, transport, remotePayload, localPayload,
-				localKeyPair, alice);
+				keyAgreementCrypto, payloadEncoder, transport, remotePayload,
+				localPayload, localKeyPair, alice);
 		try {
 			SecretKey master = protocol.perform();
 			KeyAgreementResult result =
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocolTest.java b/bramble-core/src/test/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocolTest.java
index 25d882d78224e387cd41efde0bb7c43e45d4b585..c6c55ce0407b765f9832aa3c88eaa59ef3aaf64f 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocolTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocolTest.java
@@ -1,6 +1,7 @@
 package org.briarproject.bramble.keyagreement;
 
 import org.briarproject.bramble.api.crypto.CryptoComponent;
+import org.briarproject.bramble.api.crypto.KeyAgreementCrypto;
 import org.briarproject.bramble.api.crypto.KeyPair;
 import org.briarproject.bramble.api.crypto.KeyParser;
 import org.briarproject.bramble.api.crypto.PublicKey;
@@ -55,6 +56,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 	@Mock
 	CryptoComponent crypto;
 	@Mock
+	KeyAgreementCrypto keyAgreementCrypto;
+	@Mock
 	KeyParser keyParser;
 	@Mock
 	PayloadEncoder payloadEncoder;
@@ -72,9 +75,9 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 		SecretKey sharedSecret = getSecretKey();
 		SecretKey masterSecret = getSecretKey();
 
-		KeyAgreementProtocol protocol =
-				new KeyAgreementProtocol(callbacks, crypto, payloadEncoder,
-						transport, theirPayload, ourPayload, ourKeyPair, true);
+		KeyAgreementProtocol protocol = new KeyAgreementProtocol(callbacks,
+				crypto, keyAgreementCrypto, payloadEncoder, transport,
+				theirPayload, ourPayload, ourKeyPair, true);
 
 		// expectations
 		context.checking(new Expectations() {{
@@ -100,7 +103,7 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(bobPubKey));
 
 			// Alice verifies Bob's public key
-			oneOf(crypto).deriveKeyCommitment(bobPubKey);
+			oneOf(keyAgreementCrypto).deriveKeyCommitment(bobPubKey);
 			will(returnValue(bobCommit));
 
 			// Alice computes shared secret
@@ -109,8 +112,9 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(sharedSecret));
 
 			// Alice sends her confirmation record
-			oneOf(crypto).deriveConfirmationRecord(sharedSecret, bobPayload,
-					alicePayload, bobPubKey, ourKeyPair, true, true);
+			oneOf(keyAgreementCrypto).deriveConfirmationRecord(sharedSecret,
+					bobPayload, alicePayload, bobPubKey, ourKeyPair,
+					true, true);
 			will(returnValue(aliceConfirm));
 			oneOf(transport).sendConfirm(aliceConfirm);
 
@@ -119,8 +123,9 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(bobConfirm));
 
 			// Alice verifies Bob's confirmation record
-			oneOf(crypto).deriveConfirmationRecord(sharedSecret, bobPayload,
-					alicePayload, bobPubKey, ourKeyPair, true, false);
+			oneOf(keyAgreementCrypto).deriveConfirmationRecord(sharedSecret,
+					bobPayload, alicePayload, bobPubKey, ourKeyPair,
+					true, false);
 			will(returnValue(bobConfirm));
 
 			// Alice computes master secret
@@ -141,9 +146,9 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 		SecretKey sharedSecret = getSecretKey();
 		SecretKey masterSecret = getSecretKey();
 
-		KeyAgreementProtocol protocol =
-				new KeyAgreementProtocol(callbacks, crypto, payloadEncoder,
-						transport, theirPayload, ourPayload, ourKeyPair, false);
+		KeyAgreementProtocol protocol = new KeyAgreementProtocol(callbacks,
+				crypto, keyAgreementCrypto, payloadEncoder, transport,
+				theirPayload, ourPayload, ourKeyPair, false);
 
 		// expectations
 		context.checking(new Expectations() {{
@@ -165,7 +170,7 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(alicePubKey));
 
 			// Bob verifies Alice's public key
-			oneOf(crypto).deriveKeyCommitment(alicePubKey);
+			oneOf(keyAgreementCrypto).deriveKeyCommitment(alicePubKey);
 			will(returnValue(aliceCommit));
 
 			// Bob sends his public key
@@ -181,13 +186,15 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(aliceConfirm));
 
 			// Bob verifies Alice's confirmation record
-			oneOf(crypto).deriveConfirmationRecord(sharedSecret, alicePayload,
-					bobPayload, alicePubKey, ourKeyPair, false, true);
+			oneOf(keyAgreementCrypto).deriveConfirmationRecord(sharedSecret,
+					alicePayload, bobPayload, alicePubKey, ourKeyPair,
+					false, true);
 			will(returnValue(aliceConfirm));
 
 			// Bob sends his confirmation record
-			oneOf(crypto).deriveConfirmationRecord(sharedSecret, alicePayload,
-					bobPayload, alicePubKey, ourKeyPair, false, false);
+			oneOf(keyAgreementCrypto).deriveConfirmationRecord(sharedSecret,
+					alicePayload, bobPayload, alicePubKey, ourKeyPair,
+					false, false);
 			will(returnValue(bobConfirm));
 			oneOf(transport).sendConfirm(bobConfirm);
 
@@ -207,9 +214,9 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 		Payload ourPayload = new Payload(aliceCommit, null);
 		KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
 
-		KeyAgreementProtocol protocol =
-				new KeyAgreementProtocol(callbacks, crypto, payloadEncoder,
-						transport, theirPayload, ourPayload, ourKeyPair, true);
+		KeyAgreementProtocol protocol = new KeyAgreementProtocol(callbacks,
+				crypto, keyAgreementCrypto, payloadEncoder, transport,
+				theirPayload, ourPayload, ourKeyPair, true);
 
 		// expectations
 		context.checking(new Expectations() {{
@@ -231,7 +238,7 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(badPubKey));
 
 			// Alice verifies Bob's public key
-			oneOf(crypto).deriveKeyCommitment(badPubKey);
+			oneOf(keyAgreementCrypto).deriveKeyCommitment(badPubKey);
 			will(returnValue(badCommit));
 
 			// Alice aborts
@@ -253,9 +260,9 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 		Payload ourPayload = new Payload(bobCommit, null);
 		KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
 
-		KeyAgreementProtocol protocol =
-				new KeyAgreementProtocol(callbacks, crypto, payloadEncoder,
-						transport, theirPayload, ourPayload, ourKeyPair, false);
+		KeyAgreementProtocol protocol = new KeyAgreementProtocol(callbacks,
+				crypto, keyAgreementCrypto, payloadEncoder, transport,
+				theirPayload, ourPayload, ourKeyPair, false);
 
 		// expectations
 		context.checking(new Expectations() {{
@@ -273,7 +280,7 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(badPubKey));
 
 			// Bob verifies Alice's public key
-			oneOf(crypto).deriveKeyCommitment(badPubKey);
+			oneOf(keyAgreementCrypto).deriveKeyCommitment(badPubKey);
 			will(returnValue(badCommit));
 
 			// Bob aborts
@@ -295,9 +302,9 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 		KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
 		SecretKey sharedSecret = getSecretKey();
 
-		KeyAgreementProtocol protocol =
-				new KeyAgreementProtocol(callbacks, crypto, payloadEncoder,
-						transport, theirPayload, ourPayload, ourKeyPair, true);
+		KeyAgreementProtocol protocol = new KeyAgreementProtocol(callbacks,
+				crypto, keyAgreementCrypto, payloadEncoder, transport,
+				theirPayload, ourPayload, ourKeyPair, true);
 
 		// expectations
 		context.checking(new Expectations() {{
@@ -323,7 +330,7 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(bobPubKey));
 
 			// Alice verifies Bob's public key
-			oneOf(crypto).deriveKeyCommitment(bobPubKey);
+			oneOf(keyAgreementCrypto).deriveKeyCommitment(bobPubKey);
 			will(returnValue(bobCommit));
 
 			// Alice computes shared secret
@@ -332,8 +339,9 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(sharedSecret));
 
 			// Alice sends her confirmation record
-			oneOf(crypto).deriveConfirmationRecord(sharedSecret, bobPayload,
-					alicePayload, bobPubKey, ourKeyPair, true, true);
+			oneOf(keyAgreementCrypto).deriveConfirmationRecord(sharedSecret,
+					bobPayload, alicePayload, bobPubKey, ourKeyPair,
+					true, true);
 			will(returnValue(aliceConfirm));
 			oneOf(transport).sendConfirm(aliceConfirm);
 
@@ -342,8 +350,9 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(badConfirm));
 
 			// Alice verifies Bob's confirmation record
-			oneOf(crypto).deriveConfirmationRecord(sharedSecret, bobPayload,
-					alicePayload, bobPubKey, ourKeyPair, true, false);
+			oneOf(keyAgreementCrypto).deriveConfirmationRecord(sharedSecret,
+					bobPayload, alicePayload, bobPubKey, ourKeyPair,
+					true, false);
 			will(returnValue(bobConfirm));
 
 			// Alice aborts
@@ -365,9 +374,9 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 		KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
 		SecretKey sharedSecret = getSecretKey();
 
-		KeyAgreementProtocol protocol =
-				new KeyAgreementProtocol(callbacks, crypto, payloadEncoder,
-						transport, theirPayload, ourPayload, ourKeyPair, false);
+		KeyAgreementProtocol protocol = new KeyAgreementProtocol(callbacks,
+				crypto, keyAgreementCrypto, payloadEncoder, transport,
+				theirPayload, ourPayload, ourKeyPair, false);
 
 		// expectations
 		context.checking(new Expectations() {{
@@ -389,7 +398,7 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(alicePubKey));
 
 			// Bob verifies Alice's public key
-			oneOf(crypto).deriveKeyCommitment(alicePubKey);
+			oneOf(keyAgreementCrypto).deriveKeyCommitment(alicePubKey);
 			will(returnValue(aliceCommit));
 
 			// Bob sends his public key
@@ -405,16 +414,18 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(badConfirm));
 
 			// Bob verifies Alice's confirmation record
-			oneOf(crypto).deriveConfirmationRecord(sharedSecret, alicePayload,
-					bobPayload, alicePubKey, ourKeyPair, false, true);
+			oneOf(keyAgreementCrypto).deriveConfirmationRecord(sharedSecret,
+					alicePayload, bobPayload, alicePubKey, ourKeyPair,
+					false, true);
 			will(returnValue(aliceConfirm));
 
 			// Bob aborts
 			oneOf(transport).sendAbort(false);
 
 			// Bob never sends his confirmation record
-			never(crypto).deriveConfirmationRecord(sharedSecret, alicePayload,
-					bobPayload, alicePubKey, ourKeyPair, false, false);
+			never(keyAgreementCrypto).deriveConfirmationRecord(sharedSecret,
+					alicePayload, bobPayload, alicePubKey, ourKeyPair,
+					false, false);
 		}});
 
 		// execute
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
index 763c50332da6d0ff26bf6ee5f683281c1900b95f..1c6cc9d86f359dc248f9c30f54198fc4274d94c6 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
@@ -12,7 +12,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
 import org.briarproject.bramble.api.db.DatabaseExecutor;
 import org.briarproject.bramble.api.event.EventBus;
 import org.briarproject.bramble.api.identity.IdentityManager;
-import org.briarproject.bramble.api.keyagreement.KeyAgreementTaskFactory;
+import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
 import org.briarproject.bramble.api.keyagreement.PayloadEncoder;
 import org.briarproject.bramble.api.keyagreement.PayloadParser;
 import org.briarproject.bramble.api.lifecycle.IoExecutor;
@@ -125,7 +125,7 @@ public interface AndroidComponent
 
 	ContactExchangeTask contactExchangeTask();
 
-	KeyAgreementTaskFactory keyAgreementTaskFactory();
+	KeyAgreementTask keyAgreementTask();
 
 	PayloadEncoder payloadEncoder();
 
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ShowQrCodeFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ShowQrCodeFragment.java
index 54df56f3ae9caab020390a4e14aacd670a42c82d..fd0d46445404da75628165430afafab21f88aec5 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ShowQrCodeFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ShowQrCodeFragment.java
@@ -24,7 +24,6 @@ import com.google.zxing.Result;
 import org.briarproject.bramble.api.event.Event;
 import org.briarproject.bramble.api.event.EventBus;
 import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
-import org.briarproject.bramble.api.keyagreement.KeyAgreementTaskFactory;
 import org.briarproject.bramble.api.keyagreement.Payload;
 import org.briarproject.bramble.api.keyagreement.PayloadEncoder;
 import org.briarproject.bramble.api.keyagreement.PayloadParser;
@@ -48,6 +47,7 @@ import java.util.logging.Logger;
 
 import javax.annotation.Nullable;
 import javax.inject.Inject;
+import javax.inject.Provider;
 
 import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
 import static android.bluetooth.BluetoothAdapter.EXTRA_STATE;
@@ -68,7 +68,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
 	private static final Logger LOG = Logger.getLogger(TAG);
 
 	@Inject
-	KeyAgreementTaskFactory keyAgreementTaskFactory;
+	Provider<KeyAgreementTask> keyAgreementTaskProvider;
 	@Inject
 	PayloadEncoder payloadEncoder;
 	@Inject
@@ -187,7 +187,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
 	@UiThread
 	private void startListening() {
 		KeyAgreementTask oldTask = task;
-		KeyAgreementTask newTask = keyAgreementTaskFactory.createTask();
+		KeyAgreementTask newTask = keyAgreementTaskProvider.get();
 		task = newTask;
 		ioExecutor.execute(() -> {
 			if (oldTask != null) oldTask.stopListening();