From 4d7a23779a1ae32b5535ce4c09c637ec4652eae9 Mon Sep 17 00:00:00 2001 From: str4d Date: Wed, 27 Jan 2016 20:21:05 +0000 Subject: [PATCH 1/3] Rename crypto methods and constants for Bluetooth key agreement --- .../invitation/AddContactActivity.java | 2 +- .../api/crypto/CryptoComponent.java | 10 +-- .../crypto/CryptoComponentImpl.java | 80 +++++++++---------- .../invitation/AliceConnector.java | 12 +-- .../briarproject/invitation/BobConnector.java | 12 +-- .../briarproject/invitation/Connector.java | 2 +- .../briarproject/crypto/KeyAgreementTest.java | 6 +- .../crypto/KeyEncodingAndParsingTest.java | 16 ++-- 8 files changed, 70 insertions(+), 70 deletions(-) diff --git a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java index 3ee032a58..dc594a4f6 100644 --- a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java +++ b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java @@ -244,7 +244,7 @@ implements InvitationListener { int getLocalInvitationCode() { if (localInvitationCode == -1) - localInvitationCode = crypto.generateInvitationCode(); + localInvitationCode = crypto.generateBTInvitationCode(); return localInvitationCode; } diff --git a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java index 836628c90..65b12c961 100644 --- a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java +++ b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java @@ -27,35 +27,35 @@ public interface CryptoComponent { KeyParser getSignatureKeyParser(); /** Generates a random invitation code. */ - int generateInvitationCode(); + int generateBTInvitationCode(); /** * Derives a shared master secret from two public keys and one of the * corresponding private keys. * @param alice whether the private key belongs to Alice or Bob. */ - SecretKey deriveMasterSecret(byte[] theirPublicKey, KeyPair ourKeyPair, + SecretKey deriveBTMasterSecret(byte[] theirPublicKey, KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException; /** * Derives a confirmation code from the given master secret. * @param alice whether the code is for use by Alice or Bob. */ - int deriveConfirmationCode(SecretKey master, boolean alice); + int deriveBTConfirmationCode(SecretKey master, boolean alice); /** * Derives a header key for an invitation stream from the given master * secret. * @param alice whether the key is for use by Alice or Bob. */ - SecretKey deriveInvitationKey(SecretKey master, boolean alice); + SecretKey deriveBTInvitationKey(SecretKey master, boolean alice); /** * Derives a nonce from the given master secret for one of the parties to * sign. * @param alice whether the nonce is for use by Alice or Bob. */ - byte[] deriveSignatureNonce(SecretKey master, boolean alice); + byte[] deriveBTSignatureNonce(SecretKey master, boolean alice); /** * Derives initial transport keys for the given transport in the given diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java index 4decd4083..79759d995 100644 --- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java +++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java @@ -62,17 +62,17 @@ class CryptoComponentImpl implements CryptoComponent { return s.getBytes(Charset.forName("US-ASCII")); } - // KDF label for master key derivation - private static final byte[] MASTER = ascii("MASTER"); - // KDF labels for confirmation code derivation - private static final byte[] A_CONFIRM = ascii("ALICE_CONFIRMATION_CODE"); - private static final byte[] B_CONFIRM = ascii("BOB_CONFIRMATION_CODE"); - // KDF labels for invitation stream header key derivation - private static final byte[] A_INVITE = ascii("ALICE_INVITATION_KEY"); - private static final byte[] B_INVITE = ascii("BOB_INVITATION_KEY"); - // KDF labels for signature nonce derivation - private static final byte[] A_NONCE = ascii("ALICE_SIGNATURE_NONCE"); - private static final byte[] B_NONCE = ascii("BOB_SIGNATURE_NONCE"); + // KDF label for bluetooth master key derivation + private static final byte[] BT_MASTER = ascii("MASTER"); + // KDF labels for bluetooth confirmation code derivation + private static final byte[] BT_A_CONFIRM = ascii("ALICE_CONFIRMATION_CODE"); + private static final byte[] BT_B_CONFIRM = ascii("BOB_CONFIRMATION_CODE"); + // KDF labels for bluetooth invitation stream header key derivation + private static final byte[] BT_A_INVITE = ascii("ALICE_INVITATION_KEY"); + private static final byte[] BT_B_INVITE = ascii("BOB_INVITATION_KEY"); + // KDF labels for bluetooth signature nonce derivation + private static final byte[] BT_A_NONCE = ascii("ALICE_SIGNATURE_NONCE"); + private static final byte[] BT_B_NONCE = ascii("BOB_SIGNATURE_NONCE"); // KDF labels for tag key derivation private static final byte[] A_TAG = ascii("ALICE_TAG_KEY"); private static final byte[] B_TAG = ascii("BOB_TAG_KEY"); @@ -128,6 +128,25 @@ class CryptoComponentImpl implements CryptoComponent { return secureRandom; } + // Package access for testing + byte[] performRawKeyAgreement(PrivateKey priv, PublicKey pub) + throws GeneralSecurityException { + if (!(priv instanceof Sec1PrivateKey)) + throw new IllegalArgumentException(); + if (!(pub instanceof Sec1PublicKey)) + throw new IllegalArgumentException(); + ECPrivateKeyParameters ecPriv = ((Sec1PrivateKey) priv).getKey(); + ECPublicKeyParameters ecPub = ((Sec1PublicKey) pub).getKey(); + long now = System.currentTimeMillis(); + ECDHCBasicAgreement agreement = new ECDHCBasicAgreement(); + agreement.init(ecPriv); + byte[] secret = agreement.calculateAgreement(ecPub).toByteArray(); + long duration = System.currentTimeMillis() - now; + if (LOG.isLoggable(INFO)) + LOG.info("Deriving shared secret took " + duration + " ms"); + return secret; + } + public Signature getSignature() { return new SignatureImpl(secureRandom); } @@ -170,14 +189,14 @@ class CryptoComponentImpl implements CryptoComponent { return signatureKeyParser; } - public int generateInvitationCode() { + public int generateBTInvitationCode() { int codeBytes = (CODE_BITS + 7) / 8; byte[] random = new byte[codeBytes]; secureRandom.nextBytes(random); return ByteUtils.readUint(random, CODE_BITS); } - public SecretKey deriveMasterSecret(byte[] theirPublicKey, + public SecretKey deriveBTMasterSecret(byte[] theirPublicKey, KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException { MessageDigest messageDigest = getMessageDigest(); byte[] ourPublicKey = ourKeyPair.getPublic().getEncoded(); @@ -194,41 +213,22 @@ class CryptoComponentImpl implements CryptoComponent { PrivateKey ourPriv = ourKeyPair.getPrivate(); PublicKey theirPub = agreementKeyParser.parsePublicKey(theirPublicKey); // The raw secret comes from the key agreement algorithm - byte[] raw = deriveSharedSecret(ourPriv, theirPub); + byte[] raw = performRawKeyAgreement(ourPriv, theirPub); // Derive the master secret from the raw secret using the hash KDF - return new SecretKey(hashKdf(raw, MASTER, aliceInfo, bobInfo)); + return new SecretKey(hashKdf(raw, BT_MASTER, aliceInfo, bobInfo)); } - // Package access for testing - byte[] deriveSharedSecret(PrivateKey priv, PublicKey pub) - throws GeneralSecurityException { - if (!(priv instanceof Sec1PrivateKey)) - throw new IllegalArgumentException(); - if (!(pub instanceof Sec1PublicKey)) - throw new IllegalArgumentException(); - ECPrivateKeyParameters ecPriv = ((Sec1PrivateKey) priv).getKey(); - ECPublicKeyParameters ecPub = ((Sec1PublicKey) pub).getKey(); - long now = System.currentTimeMillis(); - ECDHCBasicAgreement agreement = new ECDHCBasicAgreement(); - agreement.init(ecPriv); - byte[] secret = agreement.calculateAgreement(ecPub).toByteArray(); - long duration = System.currentTimeMillis() - now; - if (LOG.isLoggable(INFO)) - LOG.info("Deriving shared secret took " + duration + " ms"); - return secret; - } - - public int deriveConfirmationCode(SecretKey master, boolean alice) { - byte[] b = macKdf(master, alice ? A_CONFIRM : B_CONFIRM); + public int deriveBTConfirmationCode(SecretKey master, boolean alice) { + byte[] b = macKdf(master, alice ? BT_A_CONFIRM : BT_B_CONFIRM); return ByteUtils.readUint(b, CODE_BITS); } - public SecretKey deriveInvitationKey(SecretKey master, boolean alice) { - return new SecretKey(macKdf(master, alice ? A_INVITE : B_INVITE)); + public SecretKey deriveBTInvitationKey(SecretKey master, boolean alice) { + return new SecretKey(macKdf(master, alice ? BT_A_INVITE : BT_B_INVITE)); } - public byte[] deriveSignatureNonce(SecretKey master, boolean alice) { - return macKdf(master, alice ? A_NONCE : B_NONCE); + public byte[] deriveBTSignatureNonce(SecretKey master, boolean alice) { + return macKdf(master, alice ? BT_A_NONCE : BT_B_NONCE); } public TransportKeys deriveTransportKeys(TransportId t, diff --git a/briar-core/src/org/briarproject/invitation/AliceConnector.java b/briar-core/src/org/briarproject/invitation/AliceConnector.java index 7d7807b80..47c7b0a16 100644 --- a/briar-core/src/org/briarproject/invitation/AliceConnector.java +++ b/briar-core/src/org/briarproject/invitation/AliceConnector.java @@ -93,8 +93,8 @@ class AliceConnector extends Connector { } // The key agreement succeeded - derive the confirmation codes if (LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded"); - int aliceCode = crypto.deriveConfirmationCode(master, true); - int bobCode = crypto.deriveConfirmationCode(master, false); + int aliceCode = crypto.deriveBTConfirmationCode(master, true); + int bobCode = crypto.deriveBTConfirmationCode(master, false); group.keyAgreementSucceeded(aliceCode, bobCode); // Exchange confirmation results boolean localMatched, remoteMatched; @@ -128,8 +128,8 @@ class AliceConnector extends Connector { if (LOG.isLoggable(INFO)) LOG.info(pluginName + " confirmation succeeded"); // Derive the header keys - SecretKey aliceHeaderKey = crypto.deriveInvitationKey(master, true); - SecretKey bobHeaderKey = crypto.deriveInvitationKey(master, false); + SecretKey aliceHeaderKey = crypto.deriveBTInvitationKey(master, true); + SecretKey bobHeaderKey = crypto.deriveBTInvitationKey(master, false); // Create the readers InputStream streamReader = streamReaderFactory.createInvitationStreamReader(in, @@ -141,8 +141,8 @@ class AliceConnector extends Connector { aliceHeaderKey); w = bdfWriterFactory.createWriter(streamWriter); // Derive the invitation nonces - byte[] aliceNonce = crypto.deriveSignatureNonce(master, true); - byte[] bobNonce = crypto.deriveSignatureNonce(master, false); + byte[] aliceNonce = crypto.deriveBTSignatureNonce(master, true); + byte[] bobNonce = crypto.deriveBTSignatureNonce(master, false); // Exchange pseudonyms, signed nonces, and timestamps Author remoteAuthor; long remoteTimestamp; diff --git a/briar-core/src/org/briarproject/invitation/BobConnector.java b/briar-core/src/org/briarproject/invitation/BobConnector.java index 84e0f2987..945c56d1c 100644 --- a/briar-core/src/org/briarproject/invitation/BobConnector.java +++ b/briar-core/src/org/briarproject/invitation/BobConnector.java @@ -93,8 +93,8 @@ class BobConnector extends Connector { } // The key agreement succeeded - derive the confirmation codes if (LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded"); - int aliceCode = crypto.deriveConfirmationCode(master, true); - int bobCode = crypto.deriveConfirmationCode(master, false); + int aliceCode = crypto.deriveBTConfirmationCode(master, true); + int bobCode = crypto.deriveBTConfirmationCode(master, false); group.keyAgreementSucceeded(bobCode, aliceCode); // Exchange confirmation results boolean localMatched, remoteMatched; @@ -128,8 +128,8 @@ class BobConnector extends Connector { if (LOG.isLoggable(INFO)) LOG.info(pluginName + " confirmation succeeded"); // Derive the header keys - SecretKey aliceHeaderKey = crypto.deriveInvitationKey(master, true); - SecretKey bobHeaderKey = crypto.deriveInvitationKey(master, false); + SecretKey aliceHeaderKey = crypto.deriveBTInvitationKey(master, true); + SecretKey bobHeaderKey = crypto.deriveBTInvitationKey(master, false); // Create the readers InputStream streamReader = streamReaderFactory.createInvitationStreamReader(in, @@ -141,8 +141,8 @@ class BobConnector extends Connector { bobHeaderKey); w = bdfWriterFactory.createWriter(streamWriter); // Derive the nonces - byte[] aliceNonce = crypto.deriveSignatureNonce(master, true); - byte[] bobNonce = crypto.deriveSignatureNonce(master, false); + byte[] aliceNonce = crypto.deriveBTSignatureNonce(master, true); + byte[] bobNonce = crypto.deriveBTSignatureNonce(master, false); // Exchange pseudonyms, signed nonces and timestamps Author remoteAuthor; long remoteTimestamp; diff --git a/briar-core/src/org/briarproject/invitation/Connector.java b/briar-core/src/org/briarproject/invitation/Connector.java index a89aef88a..1a5ca82fb 100644 --- a/briar-core/src/org/briarproject/invitation/Connector.java +++ b/briar-core/src/org/briarproject/invitation/Connector.java @@ -146,7 +146,7 @@ abstract class Connector extends Thread { // Derive the master secret if (LOG.isLoggable(INFO)) LOG.info(pluginName + " deriving master secret"); - return crypto.deriveMasterSecret(key, keyPair, alice); + return crypto.deriveBTMasterSecret(key, keyPair, alice); } protected void sendConfirmation(BdfWriter w, boolean confirmed) diff --git a/briar-tests/src/org/briarproject/crypto/KeyAgreementTest.java b/briar-tests/src/org/briarproject/crypto/KeyAgreementTest.java index 732e63872..1544638c3 100644 --- a/briar-tests/src/org/briarproject/crypto/KeyAgreementTest.java +++ b/briar-tests/src/org/briarproject/crypto/KeyAgreementTest.java @@ -13,15 +13,15 @@ import static org.junit.Assert.assertArrayEquals; public class KeyAgreementTest extends BriarTestCase { @Test - public void testKeyAgreement() throws Exception { + public void testBTKeyAgreement() throws Exception { SeedProvider seedProvider = new TestSeedProvider(); CryptoComponent crypto = new CryptoComponentImpl(seedProvider); KeyPair aPair = crypto.generateAgreementKeyPair(); byte[] aPub = aPair.getPublic().getEncoded(); KeyPair bPair = crypto.generateAgreementKeyPair(); byte[] bPub = bPair.getPublic().getEncoded(); - SecretKey aMaster = crypto.deriveMasterSecret(aPub, bPair, true); - SecretKey bMaster = crypto.deriveMasterSecret(bPub, aPair, false); + SecretKey aMaster = crypto.deriveBTMasterSecret(aPub, bPair, true); + SecretKey bMaster = crypto.deriveBTMasterSecret(bPub, aPair, false); assertArrayEquals(aMaster.getBytes(), bMaster.getBytes()); } } diff --git a/briar-tests/src/org/briarproject/crypto/KeyEncodingAndParsingTest.java b/briar-tests/src/org/briarproject/crypto/KeyEncodingAndParsingTest.java index b380dee52..556deb171 100644 --- a/briar-tests/src/org/briarproject/crypto/KeyEncodingAndParsingTest.java +++ b/briar-tests/src/org/briarproject/crypto/KeyEncodingAndParsingTest.java @@ -27,12 +27,12 @@ public class KeyEncodingAndParsingTest extends BriarTestCase { KeyPair bPair = crypto.generateAgreementKeyPair(); // Derive the shared secret PublicKey aPub = aPair.getPublic(); - byte[] secret = crypto.deriveSharedSecret(bPair.getPrivate(), aPub); + byte[] secret = crypto.performRawKeyAgreement(bPair.getPrivate(), aPub); // Encode and parse the public key - no exceptions should be thrown aPub = parser.parsePublicKey(aPub.getEncoded()); aPub = parser.parsePublicKey(aPub.getEncoded()); // Derive the shared secret again - it should be the same - byte[] secret1 = crypto.deriveSharedSecret(bPair.getPrivate(), aPub); + byte[] secret1 = crypto.performRawKeyAgreement(bPair.getPrivate(), aPub); assertArrayEquals(secret, secret1); } @@ -44,12 +44,12 @@ public class KeyEncodingAndParsingTest extends BriarTestCase { KeyPair bPair = crypto.generateAgreementKeyPair(); // Derive the shared secret PrivateKey bPriv = bPair.getPrivate(); - byte[] secret = crypto.deriveSharedSecret(bPriv, aPair.getPublic()); + byte[] secret = crypto.performRawKeyAgreement(bPriv, aPair.getPublic()); // Encode and parse the private key - no exceptions should be thrown bPriv = parser.parsePrivateKey(bPriv.getEncoded()); bPriv = parser.parsePrivateKey(bPriv.getEncoded()); // Derive the shared secret again - it should be the same - byte[] secret1 = crypto.deriveSharedSecret(bPriv, aPair.getPublic()); + byte[] secret1 = crypto.performRawKeyAgreement(bPriv, aPair.getPublic()); assertArrayEquals(secret, secret1); } @@ -90,12 +90,12 @@ public class KeyEncodingAndParsingTest extends BriarTestCase { KeyPair bPair = crypto.generateSignatureKeyPair(); // Derive the shared secret PublicKey aPub = aPair.getPublic(); - byte[] secret = crypto.deriveSharedSecret(bPair.getPrivate(), aPub); + byte[] secret = crypto.performRawKeyAgreement(bPair.getPrivate(), aPub); // Encode and parse the public key - no exceptions should be thrown aPub = parser.parsePublicKey(aPub.getEncoded()); aPub = parser.parsePublicKey(aPub.getEncoded()); // Derive the shared secret again - it should be the same - byte[] secret1 = crypto.deriveSharedSecret(bPair.getPrivate(), aPub); + byte[] secret1 = crypto.performRawKeyAgreement(bPair.getPrivate(), aPub); assertArrayEquals(secret, secret1); } @@ -107,12 +107,12 @@ public class KeyEncodingAndParsingTest extends BriarTestCase { KeyPair bPair = crypto.generateSignatureKeyPair(); // Derive the shared secret PrivateKey bPriv = bPair.getPrivate(); - byte[] secret = crypto.deriveSharedSecret(bPriv, aPair.getPublic()); + byte[] secret = crypto.performRawKeyAgreement(bPriv, aPair.getPublic()); // Encode and parse the private key - no exceptions should be thrown bPriv = parser.parsePrivateKey(bPriv.getEncoded()); bPriv = parser.parsePrivateKey(bPriv.getEncoded()); // Derive the shared secret again - it should be the same - byte[] secret1 = crypto.deriveSharedSecret(bPriv, aPair.getPublic()); + byte[] secret1 = crypto.performRawKeyAgreement(bPriv, aPair.getPublic()); assertArrayEquals(secret, secret1); } From 77e4ec381ac7600e8233d48ec6dd7b3f6dd81fec Mon Sep 17 00:00:00 2001 From: str4d Date: Thu, 28 Jan 2016 06:53:20 +0000 Subject: [PATCH 2/3] Implement BQP crypto --- .../api/crypto/CryptoComponent.java | 54 +++++++++++++++++ .../keyagreement/KeyAgreementConstants.java | 8 +++ .../crypto/CryptoComponentImpl.java | 59 +++++++++++++++++++ .../briarproject/crypto/KeyAgreementTest.java | 13 ++++ 4 files changed, 134 insertions(+) create mode 100644 briar-api/src/org/briarproject/api/keyagreement/KeyAgreementConstants.java diff --git a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java index 65b12c961..ac0842472 100644 --- a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java +++ b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java @@ -57,6 +57,60 @@ public interface CryptoComponent { */ byte[] deriveBTSignatureNonce(SecretKey master, boolean alice); + /** + * Derives a commitment to the provided public key. + *

+ * Part of BQP. + * + * @param publicKey the public key + * @return the commitment to the provided public key. + */ + byte[] deriveKeyCommitment(byte[] publicKey); + + /** + * Derives a common shared secret from two public keys and one of the + * corresponding private keys. + *

+ * Part of BQP. + * + * @param theirPublicKey the ephemeral public key of the remote party + * @param ourKeyPair our ephemeral keypair + * @param alice true if ourKeyPair belongs to Alice + * @return the shared secret + * @throws GeneralSecurityException + */ + SecretKey deriveSharedSecret(byte[] theirPublicKey, KeyPair ourKeyPair, + boolean alice) throws GeneralSecurityException; + + /** + * Derives the content of a confirmation record. + *

+ * Part of BQP. + * + * @param sharedSecret the common shared secret + * @param theirPayload the commit payload from the remote party + * @param ourPayload the commit payload we sent + * @param theirPublicKey the ephemeral public key of the remote party + * @param ourKeyPair our ephemeral keypair + * @param alice true if ourKeyPair belongs to 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, + byte[] theirPublicKey, KeyPair ourKeyPair, + boolean alice, boolean aliceRecord); + + /** + * Derives a master secret from the given shared secret. + *

+ * Part of BQP. + * + * @param sharedSecret the common shared secret + * @return the master secret + */ + SecretKey deriveMasterSecret(SecretKey sharedSecret); + /** * Derives initial transport keys for the given transport in the given * rotation period from the given master secret. diff --git a/briar-api/src/org/briarproject/api/keyagreement/KeyAgreementConstants.java b/briar-api/src/org/briarproject/api/keyagreement/KeyAgreementConstants.java new file mode 100644 index 000000000..521789244 --- /dev/null +++ b/briar-api/src/org/briarproject/api/keyagreement/KeyAgreementConstants.java @@ -0,0 +1,8 @@ +package org.briarproject.api.keyagreement; + + +public interface KeyAgreementConstants { + + /** The length of the BQP key commitment in bytes. */ + int COMMIT_LENGTH = 16; +} diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java index 79759d995..07916ab5b 100644 --- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java +++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java @@ -40,6 +40,7 @@ import javax.inject.Inject; import static java.util.logging.Level.INFO; import static org.briarproject.api.invitation.InvitationConstants.CODE_BITS; +import static org.briarproject.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH; import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; import static org.briarproject.crypto.EllipticCurveConstants.PARAMETERS; import static org.briarproject.util.ByteUtils.INT_32_BYTES; @@ -73,6 +74,14 @@ class CryptoComponentImpl implements CryptoComponent { // KDF labels for bluetooth signature nonce derivation private static final byte[] BT_A_NONCE = ascii("ALICE_SIGNATURE_NONCE"); private static final byte[] BT_B_NONCE = ascii("BOB_SIGNATURE_NONCE"); + // Hash label for BQP public key commitment derivation + private static final byte[] COMMIT = ascii("COMMIT"); + // Hash label for BQP shared secret derivation + private static final byte[] SHARED_SECRET = ascii("SHARED_SECRET"); + // KDF label for BQP confirmation key derivation + private static final byte[] CONFIRMATION_KEY = ascii("CONFIRMATION_KEY"); + // KDF label for BQP master key derivation + private static final byte[] MASTER_KEY = ascii("MASTER_KEY"); // KDF labels for tag key derivation private static final byte[] A_TAG = ascii("ALICE_TAG_KEY"); private static final byte[] B_TAG = ascii("BOB_TAG_KEY"); @@ -231,6 +240,56 @@ class CryptoComponentImpl implements CryptoComponent { return macKdf(master, alice ? BT_A_NONCE : BT_B_NONCE); } + public byte[] deriveKeyCommitment(byte[] publicKey) { + byte[] hash = hash(COMMIT, publicKey); + // 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; + } + + public SecretKey deriveSharedSecret(byte[] theirPublicKey, + KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException { + PrivateKey ourPriv = ourKeyPair.getPrivate(); + PublicKey theirPub = agreementKeyParser.parsePublicKey(theirPublicKey); + byte[] raw = performRawKeyAgreement(ourPriv, theirPub); + byte[] alicePub, bobPub; + if (alice) { + alicePub = ourKeyPair.getPublic().getEncoded(); + bobPub = theirPublicKey; + } else { + alicePub = theirPublicKey; + bobPub = ourKeyPair.getPublic().getEncoded(); + } + return new SecretKey(hash(SHARED_SECRET, raw, alicePub, bobPub)); + } + + public byte[] deriveConfirmationRecord(SecretKey sharedSecret, + byte[] theirPayload, byte[] ourPayload, byte[] theirPublicKey, + KeyPair ourKeyPair, boolean alice, boolean aliceRecord) { + SecretKey ck = new SecretKey(macKdf(sharedSecret, CONFIRMATION_KEY)); + byte[] alicePayload, alicePub, bobPayload, bobPub; + if (alice) { + alicePayload = ourPayload; + alicePub = ourKeyPair.getPublic().getEncoded(); + bobPayload = theirPayload; + bobPub = theirPublicKey; + } else { + alicePayload = theirPayload; + alicePub = theirPublicKey; + bobPayload = ourPayload; + bobPub = ourKeyPair.getPublic().getEncoded(); + } + if (aliceRecord) + return macKdf(ck, alicePayload, alicePub, bobPayload, bobPub); + else + return macKdf(ck, bobPayload, bobPub, alicePayload, alicePub); + } + + public SecretKey deriveMasterSecret(SecretKey sharedSecret) { + return new SecretKey(macKdf(sharedSecret, MASTER_KEY)); + } + public TransportKeys deriveTransportKeys(TransportId t, SecretKey master, long rotationPeriod, boolean alice) { // Keys for the previous period are derived from the master secret diff --git a/briar-tests/src/org/briarproject/crypto/KeyAgreementTest.java b/briar-tests/src/org/briarproject/crypto/KeyAgreementTest.java index 1544638c3..ff04f23d6 100644 --- a/briar-tests/src/org/briarproject/crypto/KeyAgreementTest.java +++ b/briar-tests/src/org/briarproject/crypto/KeyAgreementTest.java @@ -24,4 +24,17 @@ public class KeyAgreementTest extends BriarTestCase { SecretKey bMaster = crypto.deriveBTMasterSecret(bPub, aPair, false); assertArrayEquals(aMaster.getBytes(), bMaster.getBytes()); } + + @Test + public void testKeyAgreement() throws Exception { + SeedProvider seedProvider = new TestSeedProvider(); + CryptoComponent crypto = new CryptoComponentImpl(seedProvider); + KeyPair aPair = crypto.generateAgreementKeyPair(); + byte[] aPub = aPair.getPublic().getEncoded(); + KeyPair bPair = crypto.generateAgreementKeyPair(); + byte[] bPub = bPair.getPublic().getEncoded(); + SecretKey aShared = crypto.deriveSharedSecret(bPub, aPair, true); + SecretKey bShared = crypto.deriveSharedSecret(aPub, bPair, false); + assertArrayEquals(aShared.getBytes(), bShared.getBytes()); + } } From c822623677ab452428b5f69080c1736a52cfa311 Mon Sep 17 00:00:00 2001 From: str4d Date: Tue, 2 Feb 2016 02:31:30 +0000 Subject: [PATCH 3/3] Migrate Bluetooth protocol to BQP's master secret derivation --- .../api/crypto/CryptoComponent.java | 24 ++++++++++------ .../crypto/CryptoComponentImpl.java | 28 ++++--------------- .../briarproject/invitation/Connector.java | 2 +- .../briarproject/crypto/KeyAgreementTest.java | 4 +-- 4 files changed, 25 insertions(+), 33 deletions(-) diff --git a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java index ac0842472..0ba779202 100644 --- a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java +++ b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java @@ -29,14 +29,6 @@ public interface CryptoComponent { /** Generates a random invitation code. */ int generateBTInvitationCode(); - /** - * Derives a shared master secret from two public keys and one of the - * corresponding private keys. - * @param alice whether the private key belongs to Alice or Bob. - */ - SecretKey deriveBTMasterSecret(byte[] theirPublicKey, KeyPair ourKeyPair, - boolean alice) throws GeneralSecurityException; - /** * Derives a confirmation code from the given master secret. * @param alice whether the code is for use by Alice or Bob. @@ -111,6 +103,22 @@ public interface CryptoComponent { */ SecretKey deriveMasterSecret(SecretKey sharedSecret); + /** + * Derives a master secret from two public keys and one of the corresponding + * private keys. + *

+ * Part of BQP. This is a helper method that calls + * deriveMasterSecret(deriveSharedSecret(theirPublicKey, ourKeyPair, alice)) + * + * @param theirPublicKey the ephemeral public key of the remote party + * @param ourKeyPair our ephemeral keypair + * @param alice true if ourKeyPair belongs to Alice + * @return the shared secret + * @throws GeneralSecurityException + */ + SecretKey deriveMasterSecret(byte[] theirPublicKey, KeyPair ourKeyPair, + boolean alice) throws GeneralSecurityException; + /** * Derives initial transport keys for the given transport in the given * rotation period from the given master secret. diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java index 07916ab5b..2a779f3fe 100644 --- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java +++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java @@ -205,28 +205,6 @@ class CryptoComponentImpl implements CryptoComponent { return ByteUtils.readUint(random, CODE_BITS); } - public SecretKey deriveBTMasterSecret(byte[] theirPublicKey, - KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException { - MessageDigest messageDigest = getMessageDigest(); - byte[] ourPublicKey = ourKeyPair.getPublic().getEncoded(); - byte[] ourHash = messageDigest.digest(ourPublicKey); - byte[] theirHash = messageDigest.digest(theirPublicKey); - byte[] aliceInfo, bobInfo; - if (alice) { - aliceInfo = ourHash; - bobInfo = theirHash; - } else { - aliceInfo = theirHash; - bobInfo = ourHash; - } - PrivateKey ourPriv = ourKeyPair.getPrivate(); - PublicKey theirPub = agreementKeyParser.parsePublicKey(theirPublicKey); - // The raw secret comes from the key agreement algorithm - byte[] raw = performRawKeyAgreement(ourPriv, theirPub); - // Derive the master secret from the raw secret using the hash KDF - return new SecretKey(hashKdf(raw, BT_MASTER, aliceInfo, bobInfo)); - } - public int deriveBTConfirmationCode(SecretKey master, boolean alice) { byte[] b = macKdf(master, alice ? BT_A_CONFIRM : BT_B_CONFIRM); return ByteUtils.readUint(b, CODE_BITS); @@ -290,6 +268,12 @@ class CryptoComponentImpl implements CryptoComponent { return new SecretKey(macKdf(sharedSecret, MASTER_KEY)); } + public SecretKey deriveMasterSecret(byte[] theirPublicKey, + KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException { + return deriveMasterSecret(deriveSharedSecret( + theirPublicKey,ourKeyPair, alice)); + } + public TransportKeys deriveTransportKeys(TransportId t, SecretKey master, long rotationPeriod, boolean alice) { // Keys for the previous period are derived from the master secret diff --git a/briar-core/src/org/briarproject/invitation/Connector.java b/briar-core/src/org/briarproject/invitation/Connector.java index 1a5ca82fb..a89aef88a 100644 --- a/briar-core/src/org/briarproject/invitation/Connector.java +++ b/briar-core/src/org/briarproject/invitation/Connector.java @@ -146,7 +146,7 @@ abstract class Connector extends Thread { // Derive the master secret if (LOG.isLoggable(INFO)) LOG.info(pluginName + " deriving master secret"); - return crypto.deriveBTMasterSecret(key, keyPair, alice); + return crypto.deriveMasterSecret(key, keyPair, alice); } protected void sendConfirmation(BdfWriter w, boolean confirmed) diff --git a/briar-tests/src/org/briarproject/crypto/KeyAgreementTest.java b/briar-tests/src/org/briarproject/crypto/KeyAgreementTest.java index ff04f23d6..17d9768db 100644 --- a/briar-tests/src/org/briarproject/crypto/KeyAgreementTest.java +++ b/briar-tests/src/org/briarproject/crypto/KeyAgreementTest.java @@ -20,8 +20,8 @@ public class KeyAgreementTest extends BriarTestCase { byte[] aPub = aPair.getPublic().getEncoded(); KeyPair bPair = crypto.generateAgreementKeyPair(); byte[] bPub = bPair.getPublic().getEncoded(); - SecretKey aMaster = crypto.deriveBTMasterSecret(aPub, bPair, true); - SecretKey bMaster = crypto.deriveBTMasterSecret(bPub, aPair, false); + SecretKey aMaster = crypto.deriveMasterSecret(aPub, bPair, true); + SecretKey bMaster = crypto.deriveMasterSecret(bPub, aPair, false); assertArrayEquals(aMaster.getBytes(), bMaster.getBytes()); }