diff --git a/api/net/sf/briar/api/crypto/CryptoComponent.java b/api/net/sf/briar/api/crypto/CryptoComponent.java
index e01c1aea2fc6a616a12e1a0fe3a1d085eeed86d4..d3f8d0353219d8a7a065910208082ab64f317fe9 100644
--- a/api/net/sf/briar/api/crypto/CryptoComponent.java
+++ b/api/net/sf/briar/api/crypto/CryptoComponent.java
@@ -23,9 +23,11 @@ public interface CryptoComponent {
 
 	byte[] deriveNextSecret(byte[] secret, int index, long connection);
 
-	KeyPair generateKeyPair();
+	KeyPair generateAgreementKeyPair();
 
-	KeyParser getKeyParser();
+	KeyPair generateSignatureKeyPair();
+
+	KeyParser getSignatureKeyParser();
 
 	ErasableKey generateTestKey();
 
diff --git a/components/net/sf/briar/crypto/CryptoComponentImpl.java b/components/net/sf/briar/crypto/CryptoComponentImpl.java
index 46056f137cebd1a6d16a769dbcbbb78ee0273d17..4fd74b05f29644792a652935282647f441cca913 100644
--- a/components/net/sf/briar/crypto/CryptoComponentImpl.java
+++ b/components/net/sf/briar/crypto/CryptoComponentImpl.java
@@ -30,14 +30,16 @@ import com.google.inject.Inject;
 class CryptoComponentImpl implements CryptoComponent {
 
 	private static final String PROVIDER = "BC";
-	private static final String KEY_PAIR_ALGO = "ECDSA";
-	private static final int KEY_PAIR_BITS = 384;
-	private static final String KEY_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 AGREEMENT_ALGO = "ECDHC";
 	private static final String SECRET_KEY_ALGO = "AES";
 	private static final int SECRET_KEY_BYTES = 32; // 256 bits
 	private static final int KEY_DERIVATION_IV_BYTES = 16; // 128 bits
 	private static final String KEY_DERIVATION_ALGO = "AES/CTR/NoPadding";
 	private static final String DIGEST_ALGO = "SHA-384";
+	private static final String SIGNATURE_KEY_PAIR_ALGO = "ECDSA";
+	private static final int SIGNATURE_KEY_PAIR_BITS = 384;
 	private static final String SIGNATURE_ALGO = "ECDSA";
 	private static final String TAG_CIPHER_ALGO = "AES/ECB/NoPadding";
 	private static final String FRAME_CIPHER_ALGO = "AES/CTR/NoPadding";
@@ -59,18 +61,25 @@ class CryptoComponentImpl implements CryptoComponent {
 	private static final byte[] KEY_DERIVATION_INPUT =
 			new byte[SECRET_KEY_BYTES];
 
-	private final KeyParser keyParser;
-	private final KeyPairGenerator keyPairGenerator;
+	private final KeyParser agreementKeyParser, signatureKeyParser;
+	private final KeyPairGenerator agreementKeyPairGenerator;
+	private final KeyPairGenerator signatureKeyPairGenerator;
 	private final SecureRandom secureRandom;
 
 	@Inject
 	CryptoComponentImpl() {
 		Security.addProvider(new BouncyCastleProvider());
 		try {
-			keyParser = new KeyParserImpl(KEY_PAIR_ALGO, PROVIDER);
-			keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALGO,
+			agreementKeyParser = new KeyParserImpl(AGREEMENT_KEY_PAIR_ALGO,
 					PROVIDER);
-			keyPairGenerator.initialize(KEY_PAIR_BITS);
+			signatureKeyParser = new KeyParserImpl(SIGNATURE_KEY_PAIR_ALGO,
+					PROVIDER);
+			agreementKeyPairGenerator = KeyPairGenerator.getInstance(
+					AGREEMENT_KEY_PAIR_ALGO, PROVIDER);
+			agreementKeyPairGenerator.initialize(AGREEMENT_KEY_PAIR_BITS);
+			signatureKeyPairGenerator = KeyPairGenerator.getInstance(
+					SIGNATURE_KEY_PAIR_ALGO, PROVIDER);
+			signatureKeyPairGenerator.initialize(SIGNATURE_KEY_PAIR_BITS);
 		} catch(GeneralSecurityException e) {
 			throw new RuntimeException(e);
 		}
@@ -130,7 +139,8 @@ class CryptoComponentImpl implements CryptoComponent {
 			byte[] theirPublicKey, PrivateKey ourPrivateKey, int invitationCode,
 			boolean initiator) {
 		try {
-			PublicKey theirPublic = keyParser.parsePublicKey(theirPublicKey);
+			PublicKey theirPublic = agreementKeyParser.parsePublicKey(
+					theirPublicKey);
 			MessageDigest messageDigest = getMessageDigest();
 			byte[] ourHash = messageDigest.digest(ourPublicKey);
 			byte[] theirHash = messageDigest.digest(theirPublicKey);
@@ -147,8 +157,8 @@ class CryptoComponentImpl implements CryptoComponent {
 			byte[] publicInfo = new byte[4];
 			ByteUtils.writeUint32(invitationCode, publicInfo, 0);
 			// The raw secret comes from the key agreement algorithm
-			KeyAgreement keyAgreement = KeyAgreement.getInstance(
-					KEY_AGREEMENT_ALGO, PROVIDER);
+			KeyAgreement keyAgreement = KeyAgreement.getInstance(AGREEMENT_ALGO,
+					PROVIDER);
 			keyAgreement.init(ourPrivateKey);
 			keyAgreement.doPhase(theirPublic, true);
 			byte[] rawSecret = keyAgreement.generateSecret();
@@ -220,12 +230,16 @@ class CryptoComponentImpl implements CryptoComponent {
 		return code;
 	}
 
-	public KeyPair generateKeyPair() {
-		return keyPairGenerator.generateKeyPair();
+	public KeyPair generateAgreementKeyPair() {
+		return agreementKeyPairGenerator.generateKeyPair();
+	}
+
+	public KeyPair generateSignatureKeyPair() {
+		return signatureKeyPairGenerator.generateKeyPair();
 	}
 
-	public KeyParser getKeyParser() {
-		return keyParser;
+	public KeyParser getSignatureKeyParser() {
+		return signatureKeyParser;
 	}
 
 	public ErasableKey generateTestKey() {
diff --git a/components/net/sf/briar/plugins/InvitationStarterImpl.java b/components/net/sf/briar/plugins/InvitationStarterImpl.java
index 29ddd721c8def90580bbe80c64a7713da8313b2c..0df6981e2f4e735945a9886369533b744583b902 100644
--- a/components/net/sf/briar/plugins/InvitationStarterImpl.java
+++ b/components/net/sf/briar/plugins/InvitationStarterImpl.java
@@ -106,7 +106,7 @@ class InvitationStarterImpl implements InvitationStarter {
 				return;
 			}
 			// Use an ephemeral key pair for key agreement
-			KeyPair ourKeyPair = crypto.generateKeyPair();
+			KeyPair ourKeyPair = crypto.generateAgreementKeyPair();
 			MessageDigest messageDigest = crypto.getMessageDigest();
 			byte[] ourKey = ourKeyPair.getPublic().getEncoded();
 			byte[] ourHash = messageDigest.digest(ourKey);
diff --git a/components/net/sf/briar/protocol/UnverifiedBatchImpl.java b/components/net/sf/briar/protocol/UnverifiedBatchImpl.java
index a1e24354c8cfae89a24ee9cd725725cf08f34da1..8f1e22c5825535eeb9a43012c8a1ab601e3c9b49 100644
--- a/components/net/sf/briar/protocol/UnverifiedBatchImpl.java
+++ b/components/net/sf/briar/protocol/UnverifiedBatchImpl.java
@@ -57,7 +57,7 @@ class UnverifiedBatchImpl implements UnverifiedBatch {
 		// Verify the author's signature, if there is one
 		Author author = m.getAuthor();
 		if(author != null) {
-			if(keyParser == null) keyParser = crypto.getKeyParser();
+			if(keyParser == null) keyParser = crypto.getSignatureKeyParser();
 			PublicKey k = keyParser.parsePublicKey(author.getPublicKey());
 			if(signature == null) signature = crypto.getSignature();
 			signature.initVerify(k);
@@ -68,7 +68,7 @@ class UnverifiedBatchImpl implements UnverifiedBatch {
 		// Verify the group's signature, if there is one
 		Group group = m.getGroup();
 		if(group != null && group.getPublicKey() != null) {
-			if(keyParser == null) keyParser = crypto.getKeyParser();
+			if(keyParser == null) keyParser = crypto.getSignatureKeyParser();
 			PublicKey k = keyParser.parsePublicKey(group.getPublicKey());
 			if(signature == null) signature = crypto.getSignature();
 			signature.initVerify(k);
diff --git a/test/net/sf/briar/ProtocolIntegrationTest.java b/test/net/sf/briar/ProtocolIntegrationTest.java
index 1d313a3de50add697ec01b585d55af96f564cdac..56a55cf84e786ed41df06c1dd3ffec1f11fc6389 100644
--- a/test/net/sf/briar/ProtocolIntegrationTest.java
+++ b/test/net/sf/briar/ProtocolIntegrationTest.java
@@ -100,12 +100,12 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 		// Create two groups: one restricted, one unrestricted
 		GroupFactory groupFactory = i.getInstance(GroupFactory.class);
 		group = groupFactory.createGroup("Unrestricted group", null);
-		KeyPair groupKeyPair = crypto.generateKeyPair();
+		KeyPair groupKeyPair = crypto.generateSignatureKeyPair();
 		group1 = groupFactory.createGroup("Restricted group",
 				groupKeyPair.getPublic().getEncoded());
 		// Create an author
 		AuthorFactory authorFactory = i.getInstance(AuthorFactory.class);
-		KeyPair authorKeyPair = crypto.generateKeyPair();
+		KeyPair authorKeyPair = crypto.generateSignatureKeyPair();
 		author = authorFactory.createAuthor(authorName,
 				authorKeyPair.getPublic().getEncoded());
 		// Create two messages to each group: one anonymous, one pseudonymous
diff --git a/test/net/sf/briar/plugins/InvitationStarterImplTest.java b/test/net/sf/briar/plugins/InvitationStarterImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8dfe5dace6d5dbae98f9798538d0283302c98068
--- /dev/null
+++ b/test/net/sf/briar/plugins/InvitationStarterImplTest.java
@@ -0,0 +1,44 @@
+package net.sf.briar.plugins;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import java.security.KeyPair;
+import java.security.PrivateKey;
+
+import net.sf.briar.BriarTestCase;
+import net.sf.briar.api.crypto.CryptoComponent;
+import net.sf.briar.crypto.CryptoModule;
+
+import org.junit.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+public class InvitationStarterImplTest extends BriarTestCase {
+
+	private final CryptoComponent crypto;
+
+	public InvitationStarterImplTest() {
+		super();
+		Injector i = Guice.createInjector(new CryptoModule());
+		crypto = i.getInstance(CryptoComponent.class);
+	}
+
+	@Test
+	public void testKeyAgreement() {
+		KeyPair a = crypto.generateAgreementKeyPair();
+		byte[] aPub = a.getPublic().getEncoded();
+		PrivateKey aPriv = a.getPrivate();
+		KeyPair b = crypto.generateAgreementKeyPair();
+		byte[] bPub = b.getPublic().getEncoded();
+		PrivateKey bPriv = b.getPrivate();
+		byte[][] aSecrets = crypto.deriveInitialSecrets(aPub, bPub, aPriv, 123,
+				true);
+		byte[][] bSecrets = crypto.deriveInitialSecrets(bPub, aPub, bPriv, 123,
+				false);
+		assertEquals(2, aSecrets.length);
+		assertEquals(2, bSecrets.length);
+		assertArrayEquals(aSecrets[0], bSecrets[0]);
+		assertArrayEquals(aSecrets[1], bSecrets[1]);
+	}
+}
diff --git a/test/net/sf/briar/protocol/ConstantsTest.java b/test/net/sf/briar/protocol/ConstantsTest.java
index 29316c9e2be368803930ce8620208a51309be8d6..12f11454712ca57ac051c1b0dd31faef4ac1f9c1 100644
--- a/test/net/sf/briar/protocol/ConstantsTest.java
+++ b/test/net/sf/briar/protocol/ConstantsTest.java
@@ -108,8 +108,8 @@ public class ConstantsTest extends BriarTestCase {
 		byte[] authorPublic = new byte[MAX_PUBLIC_KEY_LENGTH];
 		Author author = authorFactory.createAuthor(authorName, authorPublic);
 		// Create a maximum-length message
-		PrivateKey groupPrivate = crypto.generateKeyPair().getPrivate();
-		PrivateKey authorPrivate = crypto.generateKeyPair().getPrivate();
+		PrivateKey groupPrivate = crypto.generateSignatureKeyPair().getPrivate();
+		PrivateKey authorPrivate = crypto.generateSignatureKeyPair().getPrivate();
 		String subject = createRandomString(MAX_SUBJECT_LENGTH);
 		byte[] body = new byte[MAX_BODY_LENGTH];
 		Message message = messageFactory.createMessage(null, group,
diff --git a/test/net/sf/briar/protocol/UnverifiedBatchImplTest.java b/test/net/sf/briar/protocol/UnverifiedBatchImplTest.java
index a1540b75fa4b9f0dc8a48372fd2d822e3048c61a..d2c3a5c5b79fa9820c530116862cad1390dca046 100644
--- a/test/net/sf/briar/protocol/UnverifiedBatchImplTest.java
+++ b/test/net/sf/briar/protocol/UnverifiedBatchImplTest.java
@@ -122,8 +122,8 @@ public class UnverifiedBatchImplTest extends BriarTestCase {
 	@Test
 	public void testSignatures() throws Exception {
 		final int signedByAuthor = 100, signedByGroup = 110;
-		final KeyPair authorKeyPair = crypto.generateKeyPair();
-		final KeyPair groupKeyPair = crypto.generateKeyPair();
+		final KeyPair authorKeyPair = crypto.generateSignatureKeyPair();
+		final KeyPair groupKeyPair = crypto.generateSignatureKeyPair();
 		Signature signature = crypto.getSignature();
 		// Calculate the expected author and group signatures
 		signature.initSign(authorKeyPair.getPrivate());
@@ -202,7 +202,7 @@ public class UnverifiedBatchImplTest extends BriarTestCase {
 	@Test
 	public void testExceptionThrownIfMessageIsModified() throws Exception {
 		final int signedByAuthor = 100;
-		final KeyPair authorKeyPair = crypto.generateKeyPair();
+		final KeyPair authorKeyPair = crypto.generateSignatureKeyPair();
 		Signature signature = crypto.getSignature();
 		// Calculate the expected author signature
 		signature.initSign(authorKeyPair.getPrivate());