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());