From 77e4ec381ac7600e8233d48ec6dd7b3f6dd81fec Mon Sep 17 00:00:00 2001 From: str4d <str4d@mail.i2p> Date: Thu, 28 Jan 2016 06:53:20 +0000 Subject: [PATCH] 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 65b12c961c..ac0842472c 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. + * <p/> + * 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. + * <p/> + * 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. + * <p/> + * 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. + * <p/> + * 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 0000000000..521789244d --- /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 79759d995b..07916ab5ba 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 1544638c32..ff04f23d68 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()); + } } -- GitLab