mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 05:09:53 +01:00
Implement BQP crypto
This commit is contained in:
@@ -57,6 +57,60 @@ public interface CryptoComponent {
|
|||||||
*/
|
*/
|
||||||
byte[] deriveBTSignatureNonce(SecretKey master, boolean alice);
|
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
|
* Derives initial transport keys for the given transport in the given
|
||||||
* rotation period from the given master secret.
|
* rotation period from the given master secret.
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static org.briarproject.api.invitation.InvitationConstants.CODE_BITS;
|
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.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.briarproject.crypto.EllipticCurveConstants.PARAMETERS;
|
import static org.briarproject.crypto.EllipticCurveConstants.PARAMETERS;
|
||||||
import static org.briarproject.util.ByteUtils.INT_32_BYTES;
|
import static org.briarproject.util.ByteUtils.INT_32_BYTES;
|
||||||
@@ -73,6 +74,14 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
// KDF labels for bluetooth signature nonce derivation
|
// KDF labels for bluetooth signature nonce derivation
|
||||||
private static final byte[] BT_A_NONCE = ascii("ALICE_SIGNATURE_NONCE");
|
private static final byte[] BT_A_NONCE = ascii("ALICE_SIGNATURE_NONCE");
|
||||||
private static final byte[] BT_B_NONCE = ascii("BOB_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
|
// KDF labels for tag key derivation
|
||||||
private static final byte[] A_TAG = ascii("ALICE_TAG_KEY");
|
private static final byte[] A_TAG = ascii("ALICE_TAG_KEY");
|
||||||
private static final byte[] B_TAG = ascii("BOB_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);
|
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,
|
public TransportKeys deriveTransportKeys(TransportId t,
|
||||||
SecretKey master, long rotationPeriod, boolean alice) {
|
SecretKey master, long rotationPeriod, boolean alice) {
|
||||||
// Keys for the previous period are derived from the master secret
|
// Keys for the previous period are derived from the master secret
|
||||||
|
|||||||
@@ -24,4 +24,17 @@ public class KeyAgreementTest extends BriarTestCase {
|
|||||||
SecretKey bMaster = crypto.deriveBTMasterSecret(bPub, aPair, false);
|
SecretKey bMaster = crypto.deriveBTMasterSecret(bPub, aPair, false);
|
||||||
assertArrayEquals(aMaster.getBytes(), bMaster.getBytes());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user