From 98cb077dd9af08d3f4290ffec9375f28e59b740d Mon Sep 17 00:00:00 2001
From: Torsten Grote <t@grobox.de>
Date: Fri, 18 Nov 2016 12:19:03 -0200
Subject: [PATCH] Migrate all custom signature code to new methods and add test

---
 .../IntroductionIntegrationTest.java          |   8 +-
 .../api/crypto/CryptoComponent.java           |   6 +-
 .../clients/ClientHelperImpl.java             |  13 +--
 .../contact/ContactExchangeTaskImpl.java      |  17 +--
 .../crypto/CryptoComponentImpl.java           |  41 ++++---
 .../introduction/IntroduceeManager.java       |  21 +---
 .../clients/ClientHelperImplTest.java         |  38 ++----
 .../crypto/KeyEncodingAndParsingTest.java     |   7 +-
 .../src/org/briarproject/crypto/MacTest.java  |  28 ++---
 .../briarproject/crypto/SignatureTest.java    | 109 ++++++++++++++++++
 .../introduction/IntroduceeManagerTest.java   |  46 ++------
 11 files changed, 179 insertions(+), 155 deletions(-)
 create mode 100644 briar-tests/src/org/briarproject/crypto/SignatureTest.java

diff --git a/briar-android-tests/src/test/java/org/briarproject/introduction/IntroductionIntegrationTest.java b/briar-android-tests/src/test/java/org/briarproject/introduction/IntroductionIntegrationTest.java
index 86ed51afb1..826524cc18 100644
--- a/briar-android-tests/src/test/java/org/briarproject/introduction/IntroductionIntegrationTest.java
+++ b/briar-android-tests/src/test/java/org/briarproject/introduction/IntroductionIntegrationTest.java
@@ -17,7 +17,6 @@ import org.briarproject.api.contact.ContactManager;
 import org.briarproject.api.crypto.CryptoComponent;
 import org.briarproject.api.crypto.KeyPair;
 import org.briarproject.api.crypto.SecretKey;
-import org.briarproject.api.crypto.Signature;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.data.BdfEntry;
 import org.briarproject.api.data.BdfList;
@@ -95,6 +94,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUE
 import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
 import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
 import static org.briarproject.api.sync.ValidationManager.State.INVALID;
+import static org.briarproject.introduction.IntroduceeManager.SIGNING_LABEL_RESPONSE;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -922,10 +922,8 @@ public class IntroductionIntegrationTest extends BriarIntegrationTest {
 		byte[] nonce1 = crypto.deriveSignatureNonce(secretKey, true);
 
 		// Signature 1
-		Signature signature = crypto.getSignature();
-		signature.initSign(keyPair1.getPrivate());
-		signature.update(nonce1);
-		byte[] sig1 = signature.sign();
+		byte[] sig1 = crypto.sign(SIGNING_LABEL_RESPONSE, nonce1,
+				keyPair1.getPrivate().getEncoded());
 
 		// MAC 1
 		SecretKey macKey1 = crypto.deriveMacKey(secretKey, true);
diff --git a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java
index 90830ac1d5..60a606889a 100644
--- a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java
+++ b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java
@@ -16,8 +16,6 @@ public interface CryptoComponent {
 
 	SecureRandom getSecureRandom();
 
-	Signature getSignature();
-
 	KeyPair generateAgreementKeyPair();
 
 	KeyParser getAgreementKeyParser();
@@ -149,7 +147,7 @@ public interface CryptoComponent {
 	 * @param label A label specific to this signature
 	 *              to ensure that the signature cannot be repurposed
 	 */
-	byte[] sign(String label, byte[] toSign, PrivateKey privateKey)
+	byte[] sign(String label, byte[] toSign, byte[] privateKey)
 			throws GeneralSecurityException;
 
 	/**
@@ -160,7 +158,7 @@ public interface CryptoComponent {
 	 *              to ensure that the signature cannot be repurposed
 	 * @return true if the signature was valid, false otherwise.
 	 */
-	boolean verify(String label, byte[] signedData, PublicKey publicKey,
+	boolean verify(String label, byte[] signedData, byte[] publicKey,
 			byte[] signature) throws GeneralSecurityException;
 
 	/**
diff --git a/briar-core/src/org/briarproject/clients/ClientHelperImpl.java b/briar-core/src/org/briarproject/clients/ClientHelperImpl.java
index 77a3caad1f..bca3812f35 100644
--- a/briar-core/src/org/briarproject/clients/ClientHelperImpl.java
+++ b/briar-core/src/org/briarproject/clients/ClientHelperImpl.java
@@ -3,9 +3,6 @@ package org.briarproject.clients;
 import org.briarproject.api.FormatException;
 import org.briarproject.api.clients.ClientHelper;
 import org.briarproject.api.crypto.CryptoComponent;
-import org.briarproject.api.crypto.KeyParser;
-import org.briarproject.api.crypto.PrivateKey;
-import org.briarproject.api.crypto.PublicKey;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.data.BdfList;
 import org.briarproject.api.data.BdfReader;
@@ -347,19 +344,13 @@ class ClientHelperImpl implements ClientHelper {
 	@Override
 	public byte[] sign(String label, BdfList toSign, byte[] privateKey)
 			throws FormatException, GeneralSecurityException {
-		KeyParser keyParser = crypto.getSignatureKeyParser();
-		PrivateKey key = keyParser.parsePrivateKey(privateKey);
-		return crypto.sign(label, toByteArray(toSign), key);
+		return crypto.sign(label, toByteArray(toSign), privateKey);
 	}
 
 	@Override
 	public void verifySignature(String label, byte[] sig, byte[] publicKey,
 			BdfList signed) throws FormatException, GeneralSecurityException {
-		// Parse the public key
-		KeyParser keyParser = crypto.getSignatureKeyParser();
-		PublicKey key = keyParser.parsePublicKey(publicKey);
-		// Verify the signature
-		if (!crypto.verify(label, toByteArray(signed), key, sig)) {
+		if (!crypto.verify(label, toByteArray(signed), publicKey, sig)) {
 			throw new GeneralSecurityException("Invalid signature");
 		}
 	}
diff --git a/briar-core/src/org/briarproject/contact/ContactExchangeTaskImpl.java b/briar-core/src/org/briarproject/contact/ContactExchangeTaskImpl.java
index 85eb36f9a6..ec825052cc 100644
--- a/briar-core/src/org/briarproject/contact/ContactExchangeTaskImpl.java
+++ b/briar-core/src/org/briarproject/contact/ContactExchangeTaskImpl.java
@@ -7,9 +7,7 @@ import org.briarproject.api.contact.ContactExchangeTask;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.contact.ContactManager;
 import org.briarproject.api.crypto.CryptoComponent;
-import org.briarproject.api.crypto.KeyParser;
 import org.briarproject.api.crypto.SecretKey;
-import org.briarproject.api.crypto.Signature;
 import org.briarproject.api.data.BdfList;
 import org.briarproject.api.data.BdfReader;
 import org.briarproject.api.data.BdfReaderFactory;
@@ -55,6 +53,8 @@ public class ContactExchangeTaskImpl extends Thread
 
 	private static final Logger LOG =
 			Logger.getLogger(ContactExchangeTaskImpl.class.getName());
+	private static final String SIGNING_LABEL_EXCHANGE =
+			"org.briarproject.briar.contact/EXCHANGE";
 
 	private final DatabaseComponent db;
 	private final AuthorFactory authorFactory;
@@ -219,12 +219,9 @@ public class ContactExchangeTaskImpl extends Thread
 	private void sendPseudonym(BdfWriter w, byte[] nonce)
 			throws GeneralSecurityException, IOException {
 		// Sign the nonce
-		Signature signature = crypto.getSignature();
-		KeyParser keyParser = crypto.getSignatureKeyParser();
 		byte[] privateKey = localAuthor.getPrivateKey();
-		signature.initSign(keyParser.parsePrivateKey(privateKey));
-		signature.update(nonce);
-		byte[] sig = signature.sign();
+		byte[] sig = crypto.sign(SIGNING_LABEL_EXCHANGE, nonce, privateKey);
+
 		// Write the name, public key and signature
 		w.writeListStart();
 		w.writeString(localAuthor.getName());
@@ -244,11 +241,7 @@ public class ContactExchangeTaskImpl extends Thread
 		r.readListEnd();
 		LOG.info("Received pseudonym");
 		// Verify the signature
-		Signature signature = crypto.getSignature();
-		KeyParser keyParser = crypto.getSignatureKeyParser();
-		signature.initVerify(keyParser.parsePublicKey(publicKey));
-		signature.update(nonce);
-		if (!signature.verify(sig)) {
+		if (!crypto.verify(SIGNING_LABEL_EXCHANGE, nonce, publicKey, sig)) {
 			if (LOG.isLoggable(INFO))
 				LOG.info("Invalid signature");
 			throw new GeneralSecurityException();
diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java
index 3ce6e0e61a..eb98217947 100644
--- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java
+++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java
@@ -1,7 +1,5 @@
 package org.briarproject.crypto;
 
-import com.google.common.primitives.Bytes;
-
 import org.briarproject.api.TransportId;
 import org.briarproject.api.crypto.CryptoComponent;
 import org.briarproject.api.crypto.KeyPair;
@@ -166,11 +164,6 @@ class CryptoComponentImpl implements CryptoComponent {
 		return secret;
 	}
 
-	@Override
-	public Signature getSignature() {
-		return new SignatureImpl(secureRandom);
-	}
-
 	@Override
 	public KeyPair generateAgreementKeyPair() {
 		AsymmetricCipherKeyPair keyPair =
@@ -402,25 +395,39 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	@Override
-	public byte[] sign(String label, byte[] toSign, PrivateKey privateKey)
+	public byte[] sign(String label, byte[] toSign, byte[] privateKey)
 			throws GeneralSecurityException {
-		Signature signature = getSignature();
-		signature.initSign(privateKey);
-		toSign = Bytes.concat(StringUtils.toUtf8(label), toSign);
-		signature.update(toSign);
+		Signature signature = new SignatureImpl(secureRandom);
+		KeyParser keyParser = getSignatureKeyParser();
+		PrivateKey key = keyParser.parsePrivateKey(privateKey);
+		signature.initSign(key);
+		updateSignature(signature, label, toSign);
 		return signature.sign();
 	}
 
 	@Override
-	public boolean verify(String label, byte[] signedData, PublicKey publicKey,
+	public boolean verify(String label, byte[] signedData, byte[] publicKey,
 			byte[] signature) throws GeneralSecurityException {
-		Signature sig = getSignature();
-		sig.initVerify(publicKey);
-		signedData = Bytes.concat(StringUtils.toUtf8(label), signedData);
-		sig.update(signedData);
+		Signature sig = new SignatureImpl(secureRandom);
+		KeyParser keyParser = getSignatureKeyParser();
+		PublicKey key = keyParser.parsePublicKey(publicKey);
+		sig.initVerify(key);
+		updateSignature(sig, label, signedData);
 		return sig.verify(signature);
 	}
 
+	private void updateSignature(Signature signature, String label,
+			byte[] toSign) {
+		byte[] labelBytes = StringUtils.toUtf8(label);
+		byte[] length = new byte[INT_32_BYTES];
+		ByteUtils.writeUint32(labelBytes.length, length, 0);
+		signature.update(length);
+		signature.update(labelBytes);
+		ByteUtils.writeUint32(toSign.length, length, 0);
+		signature.update(length);
+		signature.update(toSign);
+	}
+
 	@Override
 	public byte[] hash(byte[]... inputs) {
 		MessageDigest digest = getMessageDigest();
diff --git a/briar-core/src/org/briarproject/introduction/IntroduceeManager.java b/briar-core/src/org/briarproject/introduction/IntroduceeManager.java
index 450fc023a3..e0227b6bc4 100644
--- a/briar-core/src/org/briarproject/introduction/IntroduceeManager.java
+++ b/briar-core/src/org/briarproject/introduction/IntroduceeManager.java
@@ -13,7 +13,6 @@ import org.briarproject.api.crypto.KeyParser;
 import org.briarproject.api.crypto.PrivateKey;
 import org.briarproject.api.crypto.PublicKey;
 import org.briarproject.api.crypto.SecretKey;
-import org.briarproject.api.crypto.Signature;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.data.BdfList;
 import org.briarproject.api.db.DatabaseComponent;
@@ -88,11 +87,13 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE;
 import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ABORT;
 import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ACK;
 import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
+import static org.briarproject.api.introduction.IntroductionManager.CLIENT_ID;
 
 class IntroduceeManager {
 
 	private static final Logger LOG =
 			Logger.getLogger(IntroduceeManager.class.getName());
+	static final String SIGNING_LABEL_RESPONSE = CLIENT_ID + "/RESPONSE";
 
 	private final MessageSender messageSender;
 	private final DatabaseComponent db;
@@ -453,12 +454,8 @@ class IntroduceeManager {
 		localState.put(MAC_KEY, theirMacKey.getBytes());
 
 		// Sign our nonce with our long-term identity public key
-		Signature signature = cryptoComponent.getSignature();
-		KeyParser sigParser = cryptoComponent.getSignatureKeyParser();
-		PrivateKey privKey = sigParser.parsePrivateKey(author.getPrivateKey());
-		signature.initSign(privKey);
-		signature.update(ourNonce);
-		byte[] sig = signature.sign();
+		byte[] sig = cryptoComponent
+				.sign(SIGNING_LABEL_RESPONSE, ourNonce, author.getPrivateKey());
 
 		// Calculate a MAC over identity public key, ephemeral public key,
 		// transport properties and timestamp.
@@ -479,16 +476,10 @@ class IntroduceeManager {
 			throws FormatException, GeneralSecurityException {
 		byte[] nonce = localState.getRaw(NONCE);
 		byte[] sig = localState.getRaw(SIGNATURE);
-		byte[] keyBytes = localState.getRaw(PUBLIC_KEY);
+		byte[] key = localState.getRaw(PUBLIC_KEY);
 
-		// Parse the public key
-		KeyParser keyParser = cryptoComponent.getSignatureKeyParser();
-		PublicKey key = keyParser.parsePublicKey(keyBytes);
 		// Verify the signature
-		Signature signature = cryptoComponent.getSignature();
-		signature.initVerify(key);
-		signature.update(nonce);
-		if (!signature.verify(sig)) {
+		if (!cryptoComponent.verify(SIGNING_LABEL_RESPONSE, nonce, key, sig)) {
 			LOG.warning("Invalid nonce signature in ACK");
 			throw new GeneralSecurityException();
 		}
diff --git a/briar-tests/src/org/briarproject/clients/ClientHelperImplTest.java b/briar-tests/src/org/briarproject/clients/ClientHelperImplTest.java
index 7c79464517..ccea806ff2 100644
--- a/briar-tests/src/org/briarproject/clients/ClientHelperImplTest.java
+++ b/briar-tests/src/org/briarproject/clients/ClientHelperImplTest.java
@@ -5,10 +5,6 @@ import org.briarproject.TestUtils;
 import org.briarproject.api.FormatException;
 import org.briarproject.api.clients.ClientHelper;
 import org.briarproject.api.crypto.CryptoComponent;
-import org.briarproject.api.crypto.KeyParser;
-import org.briarproject.api.crypto.PrivateKey;
-import org.briarproject.api.crypto.PublicKey;
-import org.briarproject.api.crypto.Signature;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.data.BdfEntry;
 import org.briarproject.api.data.BdfList;
@@ -58,8 +54,6 @@ public class ClientHelperImplTest extends BriarTestCase {
 			context.mock(MetadataEncoder.class);
 	private final CryptoComponent cryptoComponent =
 			context.mock(CryptoComponent.class);
-	private final KeyParser keyParser = context.mock(KeyParser.class);
-	private final Signature signature = context.mock(Signature.class);
 	private final ClientHelper clientHelper;
 
 	private final GroupId groupId = new GroupId(getRandomId());
@@ -286,62 +280,46 @@ public class ClientHelperImplTest extends BriarTestCase {
 
 	@Test
 	public void testSign() throws Exception {
-		final byte[] privateKeyBytes = getRandomBytes(42);
-		final PrivateKey privateKey = context.mock(PrivateKey.class);
+		final byte[] privateKey = getRandomBytes(42);
 		final byte[] signed = getRandomBytes(42);
 
 		final byte[] bytes = expectToByteArray(list);
 		context.checking(new Expectations() {{
-			oneOf(cryptoComponent).getSignatureKeyParser();
-			will(returnValue(keyParser));
-			oneOf(keyParser).parsePrivateKey(privateKeyBytes);
-			will(returnValue(privateKey));
 			oneOf(cryptoComponent).sign(label, bytes, privateKey);
 			will(returnValue(signed));
 		}});
 
-		assertArrayEquals(signed,
-				clientHelper.sign(label, list, privateKeyBytes));
+		assertArrayEquals(signed, clientHelper.sign(label, list, privateKey));
 		context.assertIsSatisfied();
 	}
 
 	@Test
 	public void testVerifySignature() throws Exception {
-		final PublicKey publicKey = context.mock(PublicKey.class);
-		final byte[] publicKeyBytes = getRandomBytes(42);
-
+		final byte[] publicKey = getRandomBytes(42);
 		final byte[] bytes = expectToByteArray(list);
+
 		context.checking(new Expectations() {{
-			oneOf(cryptoComponent).getSignatureKeyParser();
-			will(returnValue(keyParser));
-			oneOf(keyParser).parsePublicKey(publicKeyBytes);
-			will(returnValue(publicKey));
 			oneOf(cryptoComponent).verify(label, bytes, publicKey, rawMessage);
 			will(returnValue(true));
 		}});
 
-		clientHelper.verifySignature(label, rawMessage, publicKeyBytes, list);
+		clientHelper.verifySignature(label, rawMessage, publicKey, list);
 		context.assertIsSatisfied();
 	}
 
 	@Test
 	public void testVerifyWrongSignature() throws Exception {
-		final PublicKey publicKey = context.mock(PublicKey.class);
-		final byte[] publicKeyBytes = getRandomBytes(42);
-
+		final byte[] publicKey = getRandomBytes(42);
 		final byte[] bytes = expectToByteArray(list);
+
 		context.checking(new Expectations() {{
-			oneOf(cryptoComponent).getSignatureKeyParser();
-			will(returnValue(keyParser));
-			oneOf(keyParser).parsePublicKey(publicKeyBytes);
-			will(returnValue(publicKey));
 			oneOf(cryptoComponent).verify(label, bytes, publicKey, rawMessage);
 			will(returnValue(false));
 		}});
 
 		try {
 			clientHelper
-					.verifySignature(label, rawMessage, publicKeyBytes, list);
+					.verifySignature(label, rawMessage, publicKey, list);
 			fail();
 		} catch (GeneralSecurityException e) {
 			// expected
diff --git a/briar-tests/src/org/briarproject/crypto/KeyEncodingAndParsingTest.java b/briar-tests/src/org/briarproject/crypto/KeyEncodingAndParsingTest.java
index d35da2762e..b7abf54fb4 100644
--- a/briar-tests/src/org/briarproject/crypto/KeyEncodingAndParsingTest.java
+++ b/briar-tests/src/org/briarproject/crypto/KeyEncodingAndParsingTest.java
@@ -7,7 +7,6 @@ import org.briarproject.api.crypto.KeyPair;
 import org.briarproject.api.crypto.KeyParser;
 import org.briarproject.api.crypto.PrivateKey;
 import org.briarproject.api.crypto.PublicKey;
-import org.briarproject.api.crypto.Signature;
 import org.junit.Test;
 
 import java.security.GeneralSecurityException;
@@ -102,15 +101,13 @@ public class KeyEncodingAndParsingTest extends BriarTestCase {
 
 	@Test
 	public void testSignatureLength() throws Exception {
-		Signature sig = crypto.getSignature();
 		// Generate 10 signature key pairs
 		for (int i = 0; i < 10; i++) {
 			KeyPair keyPair = crypto.generateSignatureKeyPair();
+			byte[] key = keyPair.getPrivate().getEncoded();
 			// Sign some random data and check the length of the signature
 			byte[] toBeSigned = TestUtils.getRandomBytes(1234);
-			sig.initSign(keyPair.getPrivate());
-			sig.update(toBeSigned);
-			byte[] signature = sig.sign();
+			byte[] signature = crypto.sign("label", toBeSigned, key);
 			assertTrue(signature.length <= MAX_SIGNATURE_LENGTH);
 		}
 	}
diff --git a/briar-tests/src/org/briarproject/crypto/MacTest.java b/briar-tests/src/org/briarproject/crypto/MacTest.java
index 336d90952c..c63fa66c29 100644
--- a/briar-tests/src/org/briarproject/crypto/MacTest.java
+++ b/briar-tests/src/org/briarproject/crypto/MacTest.java
@@ -16,18 +16,17 @@ public class MacTest extends BriarTestCase {
 
 	private final CryptoComponent crypto;
 
+	private final SecretKey k = TestUtils.getSecretKey();
+	private final byte[] inputBytes = TestUtils.getRandomBytes(123);
+	private final byte[] inputBytes1 = TestUtils.getRandomBytes(234);
+	private final byte[] inputBytes2 = new byte[0];
+
 	public MacTest() {
 		crypto = new CryptoComponentImpl(new TestSeedProvider());
 	}
 
 	@Test
 	public void testIdenticalKeysAndInputsProduceIdenticalMacs() {
-		// Generate a random key and some random input
-		byte[] keyBytes = TestUtils.getRandomBytes(SecretKey.LENGTH);
-		SecretKey k = new SecretKey(keyBytes);
-		byte[] inputBytes = TestUtils.getRandomBytes(123);
-		byte[] inputBytes1 = TestUtils.getRandomBytes(234);
-		byte[] inputBytes2 = new byte[0];
 		// Calculate the MAC twice - the results should be identical
 		byte[] mac = crypto.mac(k, inputBytes, inputBytes1, inputBytes2);
 		byte[] mac1 = crypto.mac(k, inputBytes, inputBytes1, inputBytes2);
@@ -36,14 +35,8 @@ public class MacTest extends BriarTestCase {
 
 	@Test
 	public void testDifferentKeysProduceDifferentMacs() {
-		// Generate two random keys and some random input
-		byte[] keyBytes = TestUtils.getRandomBytes(SecretKey.LENGTH);
-		SecretKey k = new SecretKey(keyBytes);
-		byte[] keyBytes1 = TestUtils.getRandomBytes(SecretKey.LENGTH);
-		SecretKey k1 = new SecretKey(keyBytes1);
-		byte[] inputBytes = TestUtils.getRandomBytes(123);
-		byte[] inputBytes1 = TestUtils.getRandomBytes(234);
-		byte[] inputBytes2 = new byte[0];
+		// Generate second random key
+		SecretKey k1 = TestUtils.getSecretKey();
 		// Calculate the MAC with each key - the results should be different
 		byte[] mac = crypto.mac(k, inputBytes, inputBytes1, inputBytes2);
 		byte[] mac1 = crypto.mac(k1, inputBytes, inputBytes1, inputBytes2);
@@ -52,16 +45,11 @@ public class MacTest extends BriarTestCase {
 
 	@Test
 	public void testDifferentInputsProduceDifferentMacs() {
-		// Generate a random key and some random input
-		byte[] keyBytes = TestUtils.getRandomBytes(SecretKey.LENGTH);
-		SecretKey k = new SecretKey(keyBytes);
-		byte[] inputBytes = TestUtils.getRandomBytes(123);
-		byte[] inputBytes1 = TestUtils.getRandomBytes(234);
-		byte[] inputBytes2 = new byte[0];
 		// Calculate the MAC with the inputs in different orders - the results
 		// should be different
 		byte[] mac = crypto.mac(k, inputBytes, inputBytes1, inputBytes2);
 		byte[] mac1 = crypto.mac(k, inputBytes2, inputBytes1, inputBytes);
 		assertFalse(Arrays.equals(mac, mac1));
 	}
+
 }
diff --git a/briar-tests/src/org/briarproject/crypto/SignatureTest.java b/briar-tests/src/org/briarproject/crypto/SignatureTest.java
new file mode 100644
index 0000000000..36d7185408
--- /dev/null
+++ b/briar-tests/src/org/briarproject/crypto/SignatureTest.java
@@ -0,0 +1,109 @@
+package org.briarproject.crypto;
+
+import org.briarproject.BriarTestCase;
+import org.briarproject.TestSeedProvider;
+import org.briarproject.TestUtils;
+import org.briarproject.api.crypto.CryptoComponent;
+import org.briarproject.api.crypto.KeyPair;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class SignatureTest extends BriarTestCase {
+
+	private final CryptoComponent crypto;
+
+	private final byte[] publicKey, privateKey;
+	private final String label = TestUtils.getRandomString(42);
+	private final byte[] inputBytes = TestUtils.getRandomBytes(123);
+
+	public SignatureTest() {
+		crypto = new CryptoComponentImpl(new TestSeedProvider());
+		KeyPair k = crypto.generateSignatureKeyPair();
+		publicKey = k.getPublic().getEncoded();
+		privateKey = k.getPrivate().getEncoded();
+	}
+
+	@Test
+	public void testIdenticalKeysAndInputsProduceIdenticalSignatures()
+			throws Exception {
+		// Calculate the Signature twice - the results should be identical
+		byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
+		byte[] sig2 = crypto.sign(label, inputBytes, privateKey);
+		assertArrayEquals(sig1, sig2);
+	}
+
+	@Test
+	public void testDifferentKeysProduceDifferentSignatures() throws Exception {
+		// Generate second private key
+		KeyPair k2 = crypto.generateSignatureKeyPair();
+		byte[] privateKey2 = k2.getPrivate().getEncoded();
+		// Calculate the signature with each key
+		byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
+		byte[] sig2 = crypto.sign(label, inputBytes, privateKey2);
+		assertFalse(Arrays.equals(sig1, sig2));
+	}
+
+	@Test
+	public void testDifferentInputsProduceDifferentSignatures()
+			throws Exception {
+		// Generate a second input
+		byte[] inputBytes2 = TestUtils.getRandomBytes(123);
+		// Calculate the signature with different inputs
+		// the results should be different
+		byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
+		byte[] sig2 = crypto.sign(label, inputBytes2, privateKey);
+		assertFalse(Arrays.equals(sig1, sig2));
+	}
+
+	@Test
+	public void testDifferentLabelsProduceDifferentSignatures()
+			throws Exception {
+		// Generate a second label
+		String label2 = TestUtils.getRandomString(42);
+		// Calculate the signature with different inputs
+		// the results should be different
+		byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
+		byte[] sig2 = crypto.sign(label2, inputBytes, privateKey);
+		assertFalse(Arrays.equals(sig1, sig2));
+	}
+
+	@Test
+	public void testSignatureVerification() throws Exception {
+		byte[] sig = crypto.sign(label, inputBytes, privateKey);
+		assertTrue(crypto.verify(label, inputBytes, publicKey, sig));
+	}
+
+	@Test
+	public void testDifferentKeyFailsVerification() throws Exception {
+		// Generate second private key
+		KeyPair k2 = crypto.generateSignatureKeyPair();
+		byte[] privateKey2 = k2.getPrivate().getEncoded();
+		// calculate the signature with different key, should fail to verify
+		byte[] sig = crypto.sign(label, inputBytes, privateKey2);
+		assertFalse(crypto.verify(label, inputBytes, publicKey, sig));
+	}
+
+	@Test
+	public void testDifferentInputFailsVerification() throws Exception {
+		// Generate a second input
+		byte[] inputBytes2 = TestUtils.getRandomBytes(123);
+		// calculate the signature with different input, should fail to verify
+		byte[] sig = crypto.sign(label, inputBytes, privateKey);
+		assertFalse(crypto.verify(label, inputBytes2, publicKey, sig));
+	}
+
+	@Test
+	public void testDifferentLabelFailsVerification() throws Exception {
+		// Generate a second label
+		String label2 = TestUtils.getRandomString(42);
+		// calculate the signature with different label, should fail to verify
+		byte[] sig = crypto.sign(label, inputBytes, privateKey);
+		assertFalse(crypto.verify(label2, inputBytes, publicKey, sig));
+	}
+
+}
diff --git a/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java b/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java
index 2ac86ea65f..c33b308c66 100644
--- a/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java
+++ b/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java
@@ -10,10 +10,7 @@ import org.briarproject.api.contact.Contact;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.contact.ContactManager;
 import org.briarproject.api.crypto.CryptoComponent;
-import org.briarproject.api.crypto.KeyParser;
-import org.briarproject.api.crypto.PublicKey;
 import org.briarproject.api.crypto.SecretKey;
-import org.briarproject.api.crypto.Signature;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.data.BdfEntry;
 import org.briarproject.api.data.BdfList;
@@ -77,6 +74,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ACK;
 import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUEST;
 import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
 import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
+import static org.briarproject.introduction.IntroduceeManager.SIGNING_LABEL_RESPONSE;
 import static org.hamcrest.Matchers.array;
 import static org.hamcrest.Matchers.samePropertyValuesAs;
 import static org.junit.Assert.assertFalse;
@@ -91,11 +89,8 @@ public class IntroduceeManagerTest extends BriarTestCase {
 	private final CryptoComponent cryptoComponent;
 	private final ClientHelper clientHelper;
 	private final IntroductionGroupFactory introductionGroupFactory;
-	private final MessageSender messageSender;
-	private final TransportPropertyManager transportPropertyManager;
 	private final AuthorFactory authorFactory;
 	private final ContactManager contactManager;
-	private final IdentityManager identityManager;
 	private final Clock clock;
 	private final Contact introducer;
 	private final Contact introducee1;
@@ -105,24 +100,24 @@ public class IntroduceeManagerTest extends BriarTestCase {
 	private final Transaction txn;
 	private final long time = 42L;
 	private final Message localStateMessage;
-	private final ClientId clientId;
 	private final SessionId sessionId;
 	private final Message message1;
 
 	public IntroduceeManagerTest() {
 		context = new Mockery();
 		context.setImposteriser(ClassImposteriser.INSTANCE);
-		messageSender = context.mock(MessageSender.class);
+		MessageSender messageSender = context.mock(MessageSender.class);
 		db = context.mock(DatabaseComponent.class);
 		cryptoComponent = context.mock(CryptoComponent.class);
 		clientHelper = context.mock(ClientHelper.class);
 		clock = context.mock(Clock.class);
 		introductionGroupFactory =
 				context.mock(IntroductionGroupFactory.class);
-		transportPropertyManager = context.mock(TransportPropertyManager.class);
+		TransportPropertyManager transportPropertyManager =
+				context.mock(TransportPropertyManager.class);
 		authorFactory = context.mock(AuthorFactory.class);
 		contactManager = context.mock(ContactManager.class);
-		identityManager = context.mock(IdentityManager.class);
+		IdentityManager identityManager = context.mock(IdentityManager.class);
 
 		introduceeManager = new IntroduceeManager(messageSender, db,
 				clientHelper, clock, cryptoComponent, transportPropertyManager,
@@ -152,7 +147,7 @@ public class IntroduceeManagerTest extends BriarTestCase {
 		introducee2 =
 				new Contact(contactId2, author2, localAuthorId, true, true);
 
-		clientId = IntroductionManagerImpl.CLIENT_ID;
+		ClientId clientId = IntroductionManagerImpl.CLIENT_ID;
 		localGroup1 = new Group(new GroupId(TestUtils.getRandomId()),
 				clientId, new byte[0]);
 		introductionGroup1 = new Group(new GroupId(TestUtils.getRandomId()),
@@ -270,20 +265,9 @@ public class IntroduceeManagerTest extends BriarTestCase {
 				new BdfEntry(SIGNATURE, sig)
 		);
 
-		final KeyParser keyParser = context.mock(KeyParser.class);
-		final PublicKey publicKey = context.mock(PublicKey.class);
-		final Signature signature = context.mock(Signature.class);
 		context.checking(new Expectations() {{
-			oneOf(cryptoComponent).getSignatureKeyParser();
-			will(returnValue(keyParser));
-			oneOf(keyParser)
-					.parsePublicKey(introducee2.getAuthor().getPublicKey());
-			will(returnValue(publicKey));
-			oneOf(cryptoComponent).getSignature();
-			will(returnValue(signature));
-			oneOf(signature).initVerify(publicKey);
-			oneOf(signature).update(nonce);
-			oneOf(signature).verify(sig);
+			oneOf(cryptoComponent).verify(SIGNING_LABEL_RESPONSE, nonce,
+					introducee2.getAuthor().getPublicKey(), sig);
 			will(returnValue(false));
 		}});
 
@@ -311,19 +295,9 @@ public class IntroduceeManagerTest extends BriarTestCase {
 		state.put(NONCE, nonce);
 		state.put(SIGNATURE, sig);
 
-		final KeyParser keyParser = context.mock(KeyParser.class);
-		final Signature signature = context.mock(Signature.class);
-		final PublicKey publicKey = context.mock(PublicKey.class);
 		context.checking(new Expectations() {{
-			oneOf(cryptoComponent).getSignatureKeyParser();
-			will(returnValue(keyParser));
-			oneOf(keyParser).parsePublicKey(publicKeyBytes);
-			will(returnValue(publicKey));
-			oneOf(cryptoComponent).getSignature();
-			will(returnValue(signature));
-			oneOf(signature).initVerify(publicKey);
-			oneOf(signature).update(nonce);
-			oneOf(signature).verify(sig);
+			oneOf(cryptoComponent).verify(SIGNING_LABEL_RESPONSE, nonce,
+					publicKeyBytes, sig);
 			will(returnValue(true));
 		}});
 		introduceeManager.verifySignature(state);
-- 
GitLab