Include protocol version in shared secret derivation.

This commit is contained in:
akwizgran
2017-11-28 11:20:15 +00:00
parent 7bb51f77ec
commit 32e0b39771
8 changed files with 78 additions and 27 deletions

View File

@@ -41,11 +41,11 @@ public interface CryptoComponent {
* secret derived for another purpose * secret derived for another purpose
* @param theirPublicKey the public key of the remote party * @param theirPublicKey the public key of the remote party
* @param ourKeyPair the key pair of the local party * @param ourKeyPair the key pair of the local party
* @param alice true if the local party is Alice
* @return the shared secret * @return the shared secret
*/ */
SecretKey deriveSharedSecret(String label, PublicKey theirPublicKey, SecretKey deriveSharedSecret(String label, PublicKey theirPublicKey,
KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException; KeyPair ourKeyPair, byte[]... inputs)
throws GeneralSecurityException;
/** /**
* Signs the given byte[] with the given ECDSA private key. * Signs the given byte[] with the given ECDSA private key.

View File

@@ -227,18 +227,15 @@ class CryptoComponentImpl implements CryptoComponent {
@Override @Override
public SecretKey deriveSharedSecret(String label, PublicKey theirPublicKey, public SecretKey deriveSharedSecret(String label, PublicKey theirPublicKey,
KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException { KeyPair ourKeyPair, byte[]... inputs)
throws GeneralSecurityException {
PrivateKey ourPriv = ourKeyPair.getPrivate(); PrivateKey ourPriv = ourKeyPair.getPrivate();
byte[] raw = performRawKeyAgreement(ourPriv, theirPublicKey); byte[][] hashInputs = new byte[inputs.length + 1][];
byte[] alicePub, bobPub; hashInputs[0] = performRawKeyAgreement(ourPriv, theirPublicKey);
if (alice) { System.arraycopy(inputs, 0, hashInputs, 1, inputs.length);
alicePub = ourKeyPair.getPublic().getEncoded(); byte[] hash = hash(label, hashInputs);
bobPub = theirPublicKey.getEncoded(); if (hash.length != SecretKey.LENGTH) throw new IllegalStateException();
} else { return new SecretKey(hash);
alicePub = theirPublicKey.getEncoded();
bobPub = ourKeyPair.getPublic().getEncoded();
}
return new SecretKey(hash(label, raw, alicePub, bobPub));
} }
@Override @Override

View File

@@ -15,6 +15,7 @@ import java.security.GeneralSecurityException;
import java.util.Arrays; import java.util.Arrays;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_SECRET_LABEL; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_SECRET_LABEL;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL;
/** /**
@@ -142,8 +143,15 @@ class KeyAgreementProtocol {
private SecretKey deriveSharedSecret(PublicKey theirPublicKey) private SecretKey deriveSharedSecret(PublicKey theirPublicKey)
throws AbortException { throws AbortException {
try { try {
byte[] ourPublicKeyBytes = ourKeyPair.getPublic().getEncoded();
byte[] theirPublicKeyBytes = theirPublicKey.getEncoded();
byte[][] inputs = {
new byte[] {PROTOCOL_VERSION},
alice ? ourPublicKeyBytes : theirPublicKeyBytes,
alice ? theirPublicKeyBytes : ourPublicKeyBytes
};
return crypto.deriveSharedSecret(SHARED_SECRET_LABEL, return crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
theirPublicKey, ourKeyPair, alice); theirPublicKey, ourKeyPair, inputs);
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
throw new AbortException(e); throw new AbortException(e);
} }

View File

@@ -7,7 +7,10 @@ import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.TestSecureRandomProvider; import org.briarproject.bramble.test.TestSecureRandomProvider;
import org.junit.Test; import org.junit.Test;
import java.util.Random;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
public class KeyAgreementTest extends BrambleTestCase { public class KeyAgreementTest extends BrambleTestCase {
@@ -18,10 +21,14 @@ public class KeyAgreementTest extends BrambleTestCase {
new CryptoComponentImpl(new TestSecureRandomProvider()); new CryptoComponentImpl(new TestSecureRandomProvider());
KeyPair aPair = crypto.generateAgreementKeyPair(); KeyPair aPair = crypto.generateAgreementKeyPair();
KeyPair bPair = crypto.generateAgreementKeyPair(); KeyPair bPair = crypto.generateAgreementKeyPair();
Random random = new Random();
byte[][] inputs = new byte[random.nextInt(10) + 1][];
for (int i = 0; i < inputs.length; i++)
inputs[i] = getRandomBytes(random.nextInt(256));
SecretKey aShared = crypto.deriveSharedSecret(SHARED_SECRET_LABEL, SecretKey aShared = crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
bPair.getPublic(), aPair, true); bPair.getPublic(), aPair, inputs);
SecretKey bShared = crypto.deriveSharedSecret(SHARED_SECRET_LABEL, SecretKey bShared = crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
aPair.getPublic(), bPair, false); aPair.getPublic(), bPair, inputs);
assertArrayEquals(aShared.getBytes(), bShared.getBytes()); assertArrayEquals(aShared.getBytes(), bShared.getBytes());
} }
} }

View File

@@ -18,6 +18,7 @@ import org.junit.Test;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_SECRET_LABEL; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_SECRET_LABEL;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getSecretKey;
@@ -90,6 +91,10 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
will(returnValue(alicePubKeyBytes)); will(returnValue(alicePubKeyBytes));
allowing(crypto).getAgreementKeyParser(); allowing(crypto).getAgreementKeyParser();
will(returnValue(keyParser)); will(returnValue(keyParser));
allowing(alicePubKey).getEncoded();
will(returnValue(alicePubKeyBytes));
allowing(bobPubKey).getEncoded();
will(returnValue(bobPubKeyBytes));
// Alice sends her public key // Alice sends her public key
oneOf(transport).sendKey(alicePubKeyBytes); oneOf(transport).sendKey(alicePubKeyBytes);
@@ -108,7 +113,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
// Alice computes shared secret // Alice computes shared secret
oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, bobPubKey, oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, bobPubKey,
ourKeyPair, true); ourKeyPair, new byte[] {PROTOCOL_VERSION},
alicePubKeyBytes, bobPubKeyBytes);
will(returnValue(sharedSecret)); will(returnValue(sharedSecret));
// Alice sends her confirmation record // Alice sends her confirmation record
@@ -161,6 +167,10 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
will(returnValue(bobPubKeyBytes)); will(returnValue(bobPubKeyBytes));
allowing(crypto).getAgreementKeyParser(); allowing(crypto).getAgreementKeyParser();
will(returnValue(keyParser)); will(returnValue(keyParser));
allowing(alicePubKey).getEncoded();
will(returnValue(alicePubKeyBytes));
allowing(bobPubKey).getEncoded();
will(returnValue(bobPubKeyBytes));
// Bob receives Alice's public key // Bob receives Alice's public key
oneOf(transport).receiveKey(); oneOf(transport).receiveKey();
@@ -178,7 +188,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
// Bob computes shared secret // Bob computes shared secret
oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, alicePubKey, oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, alicePubKey,
ourKeyPair, false); ourKeyPair, new byte[] {PROTOCOL_VERSION},
alicePubKeyBytes, bobPubKeyBytes);
will(returnValue(sharedSecret)); will(returnValue(sharedSecret));
// Bob receives Alices's confirmation record // Bob receives Alices's confirmation record
@@ -246,7 +257,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
// Alice never computes shared secret // Alice never computes shared secret
never(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, badPubKey, never(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, badPubKey,
ourKeyPair, true); ourKeyPair, new byte[] {PROTOCOL_VERSION},
alicePubKeyBytes, bobPubKeyBytes);
}}); }});
// execute // execute
@@ -317,6 +329,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
will(returnValue(alicePubKeyBytes)); will(returnValue(alicePubKeyBytes));
allowing(crypto).getAgreementKeyParser(); allowing(crypto).getAgreementKeyParser();
will(returnValue(keyParser)); will(returnValue(keyParser));
allowing(bobPubKey).getEncoded();
will(returnValue(bobPubKeyBytes));
// Alice sends her public key // Alice sends her public key
oneOf(transport).sendKey(alicePubKeyBytes); oneOf(transport).sendKey(alicePubKeyBytes);
@@ -335,7 +349,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
// Alice computes shared secret // Alice computes shared secret
oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, bobPubKey, oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, bobPubKey,
ourKeyPair, true); ourKeyPair, new byte[] {PROTOCOL_VERSION},
alicePubKeyBytes, bobPubKeyBytes);
will(returnValue(sharedSecret)); will(returnValue(sharedSecret));
// Alice sends her confirmation record // Alice sends her confirmation record
@@ -389,6 +404,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
will(returnValue(bobPubKeyBytes)); will(returnValue(bobPubKeyBytes));
allowing(crypto).getAgreementKeyParser(); allowing(crypto).getAgreementKeyParser();
will(returnValue(keyParser)); will(returnValue(keyParser));
allowing(alicePubKey).getEncoded();
will(returnValue(alicePubKeyBytes));
// Bob receives Alice's public key // Bob receives Alice's public key
oneOf(transport).receiveKey(); oneOf(transport).receiveKey();
@@ -406,7 +423,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
// Bob computes shared secret // Bob computes shared secret
oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, alicePubKey, oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, alicePubKey,
ourKeyPair, false); ourKeyPair, new byte[] {PROTOCOL_VERSION},
alicePubKeyBytes, bobPubKeyBytes);
will(returnValue(sharedSecret)); will(returnValue(sharedSecret));
// Bob receives a bad confirmation record // Bob receives a bad confirmation record

View File

@@ -86,6 +86,11 @@ public interface IntroductionConstants {
int TASK_ACTIVATE_CONTACT = 1; int TASK_ACTIVATE_CONTACT = 1;
int TASK_ABORT = 2; int TASK_ABORT = 2;
/**
* The current version of the introduction protocol.
*/
int PROTOCOL_VERSION = 0;
/** /**
* Label for deriving the shared secret. * Label for deriving the shared secret.
*/ */

View File

@@ -76,6 +76,7 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_
import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_SIGNATURE; import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_SIGNATURE;
import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_TIME; import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_TIME;
import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_TRANSPORT; import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_TRANSPORT;
import static org.briarproject.briar.api.introduction.IntroductionConstants.PROTOCOL_VERSION;
import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY; import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY;
import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID; import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID;
import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US; import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US;
@@ -433,8 +434,13 @@ class IntroduceeManager {
// The shared secret is derived from the local ephemeral key pair // The shared secret is derived from the local ephemeral key pair
// and the remote ephemeral public key // and the remote ephemeral public key
byte[][] inputs = {
new byte[] {PROTOCOL_VERSION},
alice ? ourPublicKeyBytes : theirPublicKeyBytes,
alice ? theirPublicKeyBytes : ourPublicKeyBytes
};
return cryptoComponent.deriveSharedSecret(SHARED_SECRET_LABEL, return cryptoComponent.deriveSharedSecret(SHARED_SECRET_LABEL,
theirPublicKey, ourKeyPair, alice); theirPublicKey, ourKeyPair, inputs);
} }
/** /**

View File

@@ -65,6 +65,7 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_LABEL; import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_LABEL;
import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME; import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME;
import static org.briarproject.briar.api.introduction.IntroductionConstants.NONCE; import static org.briarproject.briar.api.introduction.IntroductionConstants.NONCE;
import static org.briarproject.briar.api.introduction.IntroductionConstants.PROTOCOL_VERSION;
import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY; import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY;
import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID;
import static org.briarproject.briar.api.introduction.IntroductionConstants.SHARED_SECRET_LABEL; import static org.briarproject.briar.api.introduction.IntroductionConstants.SHARED_SECRET_LABEL;
@@ -753,8 +754,13 @@ public class IntroductionIntegrationTest
KeyPair eKeyPair2 = crypto.generateAgreementKeyPair(); KeyPair eKeyPair2 = crypto.generateAgreementKeyPair();
// Nonce 1 // Nonce 1
byte[][] inputs = {
new byte[] {PROTOCOL_VERSION},
eKeyPair1.getPublic().getEncoded(),
eKeyPair2.getPublic().getEncoded()
};
SecretKey sharedSecret = crypto.deriveSharedSecret(SHARED_SECRET_LABEL, SecretKey sharedSecret = crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
eKeyPair2.getPublic(), eKeyPair1, true); eKeyPair2.getPublic(), eKeyPair1, inputs);
byte[] nonce1 = crypto.mac(ALICE_NONCE_LABEL, sharedSecret); byte[] nonce1 = crypto.mac(ALICE_NONCE_LABEL, sharedSecret);
// Signature 1 // Signature 1
@@ -787,20 +793,24 @@ public class IntroductionIntegrationTest
// replace ephemeral key pair and recalculate matching keys and nonce // replace ephemeral key pair and recalculate matching keys and nonce
KeyPair eKeyPair1f = crypto.generateAgreementKeyPair(); KeyPair eKeyPair1f = crypto.generateAgreementKeyPair();
byte[] ePublicKeyBytes1f = eKeyPair1f.getPublic().getEncoded(); byte[][] fakeInputs = {
new byte[] {PROTOCOL_VERSION},
eKeyPair1f.getPublic().getEncoded(),
eKeyPair2.getPublic().getEncoded()
};
sharedSecret = crypto.deriveSharedSecret(SHARED_SECRET_LABEL, sharedSecret = crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
eKeyPair2.getPublic(), eKeyPair1f, true); eKeyPair2.getPublic(), eKeyPair1f, fakeInputs);
nonce1 = crypto.mac(ALICE_NONCE_LABEL, sharedSecret); nonce1 = crypto.mac(ALICE_NONCE_LABEL, sharedSecret);
// recalculate MAC // recalculate MAC
macKey1 = crypto.deriveKey(ALICE_MAC_KEY_LABEL, sharedSecret); macKey1 = crypto.deriveKey(ALICE_MAC_KEY_LABEL, sharedSecret);
toMacList = BdfList.of(keyPair1.getPublic().getEncoded(), toMacList = BdfList.of(keyPair1.getPublic().getEncoded(),
ePublicKeyBytes1f, tp1, time1); eKeyPair1f.getPublic().getEncoded(), tp1, time1);
toMac = clientHelper.toByteArray(toMacList); toMac = clientHelper.toByteArray(toMacList);
mac1 = crypto.mac(MAC_LABEL, macKey1, toMac); mac1 = crypto.mac(MAC_LABEL, macKey1, toMac);
// update state with faked information // update state with faked information
state.put(E_PUBLIC_KEY, ePublicKeyBytes1f); state.put(E_PUBLIC_KEY, eKeyPair1f.getPublic().getEncoded());
state.put(MAC, mac1); state.put(MAC, mac1);
state.put(MAC_KEY, macKey1.getBytes()); state.put(MAC_KEY, macKey1.getBytes());
state.put(NONCE, nonce1); state.put(NONCE, nonce1);