mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Include namespaced labels in crypto operations.
This commit is contained in:
@@ -12,6 +12,27 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||
@NotNullByDefault
|
||||
public interface ContactExchangeTask {
|
||||
|
||||
/**
|
||||
* Label for deriving Alice's header key from the master secret.
|
||||
*/
|
||||
String ALICE_KEY_LABEL =
|
||||
"org.briarproject.bramble.contact/ALICE_HEADER_KEY";
|
||||
|
||||
/**
|
||||
* Label for deriving Bob's header key from the master secret.
|
||||
*/
|
||||
String BOB_KEY_LABEL = "org.briarproject.bramble.contact/BOB_HEADER_KEY";
|
||||
|
||||
/**
|
||||
* Label for deriving Alice's key binding nonce from the master secret.
|
||||
*/
|
||||
String ALICE_NONCE_LABEL = "org.briarproject.bramble.contact/ALICE_NONCE";
|
||||
|
||||
/**
|
||||
* Label for deriving Bob's key binding nonce from the master secret.
|
||||
*/
|
||||
String BOB_NONCE_LABEL = "org.briarproject.bramble.contact/BOB_NONCE";
|
||||
|
||||
/**
|
||||
* Exchanges contact information with a remote peer.
|
||||
*/
|
||||
|
||||
@@ -27,95 +27,74 @@ public interface CryptoComponent {
|
||||
KeyParser getMessageKeyParser();
|
||||
|
||||
/**
|
||||
* Derives a stream header key from the given master secret.
|
||||
* @param alice whether the key is for use by Alice or Bob.
|
||||
* Derives another secret key from the given secret key.
|
||||
*
|
||||
* @param label a namespaced label indicating the purpose of the derived
|
||||
* key, to prevent it from being repurposed or colliding with a key derived
|
||||
* for another purpose
|
||||
*/
|
||||
SecretKey deriveHeaderKey(SecretKey master, boolean alice);
|
||||
SecretKey deriveKey(String label, SecretKey k, byte[]... inputs);
|
||||
|
||||
/**
|
||||
* Derives a message authentication code key from the given master secret.
|
||||
* @param alice whether the key is for use by Alice or Bob.
|
||||
* Derives a nonce from the given secret key that can be used for key
|
||||
* binding.
|
||||
*
|
||||
* @param label a namespaced label indicating the purpose of this nonce,
|
||||
* to prevent it from being repurposed or colliding with a nonce derived
|
||||
* for another purpose
|
||||
*/
|
||||
SecretKey deriveMacKey(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[] deriveKeyBindingNonce(String label, SecretKey k);
|
||||
|
||||
/**
|
||||
* Derives a commitment to the provided public key.
|
||||
* <p/>
|
||||
* Part of BQP.
|
||||
* Used by the key exchange protocol.
|
||||
*
|
||||
* @param publicKey the public key
|
||||
* @return the commitment to the provided public key.
|
||||
*/
|
||||
byte[] deriveKeyCommitment(byte[] publicKey);
|
||||
byte[] deriveKeyCommitment(PublicKey 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
|
||||
* @param label a namespaced label indicating the purpose of this shared
|
||||
* secret, to prevent it from being repurposed or colliding with a shared
|
||||
* secret derived for another purpose
|
||||
* @param theirPublicKey the public key of the remote party
|
||||
* @param ourKeyPair the key pair of the local party
|
||||
* @param alice true if the local party is Alice
|
||||
* @return the shared secret
|
||||
*/
|
||||
SecretKey deriveSharedSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
|
||||
boolean alice) throws GeneralSecurityException;
|
||||
SecretKey deriveSharedSecret(String label, PublicKey theirPublicKey,
|
||||
KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Derives the content of a confirmation record.
|
||||
* <p/>
|
||||
* Part of BQP.
|
||||
* Used by the key exchange protocol.
|
||||
*
|
||||
* @param sharedSecret the common shared secret
|
||||
* @param theirPayload the commit payload from the remote party
|
||||
* @param ourPayload the commit payload we sent
|
||||
* @param theirPayload the key exchange payload of the remote party
|
||||
* @param ourPayload the key exchange payload of the local party
|
||||
* @param theirPublicKey the ephemeral public key of the remote party
|
||||
* @param ourKeyPair our ephemeral keypair
|
||||
* @param alice true if ourKeyPair belongs to Alice
|
||||
* @param ourKeyPair our ephemeral key pair of the local party
|
||||
* @param alice true if the local party is 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,
|
||||
PublicKey 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 a master secret from two public keys and one of the corresponding
|
||||
* private keys.
|
||||
* <p/>
|
||||
* 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
|
||||
*/
|
||||
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.
|
||||
* <p/>
|
||||
* Used by the transport security protocol.
|
||||
*
|
||||
* @param alice whether the keys are for use by Alice or Bob.
|
||||
*/
|
||||
TransportKeys deriveTransportKeys(TransportId t, SecretKey master,
|
||||
@@ -124,18 +103,25 @@ public interface CryptoComponent {
|
||||
/**
|
||||
* Rotates the given transport keys to the given rotation period. If the
|
||||
* keys are for a future rotation period they are not rotated.
|
||||
* <p/>
|
||||
* Used by the transport security protocol.
|
||||
*/
|
||||
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
|
||||
|
||||
/** Encodes the pseudo-random tag that is used to recognise a stream. */
|
||||
/**
|
||||
* Encodes the pseudo-random tag that is used to recognise a stream.
|
||||
* <p/>
|
||||
* Used by the transport security protocol.
|
||||
*/
|
||||
void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion,
|
||||
long streamNumber);
|
||||
|
||||
/**
|
||||
* Signs the given byte[] with the given ECDSA private key.
|
||||
*
|
||||
* @param label A label specific to this signature
|
||||
* to ensure that the signature cannot be repurposed
|
||||
* @param label a namespaced label indicating the purpose of this
|
||||
* signature, to prevent it from being repurposed or colliding with a
|
||||
* signature created for another purpose
|
||||
*/
|
||||
byte[] sign(String label, byte[] toSign, byte[] privateKey)
|
||||
throws GeneralSecurityException;
|
||||
@@ -153,8 +139,9 @@ public interface CryptoComponent {
|
||||
* Verifies that the given signature is valid for the signed data
|
||||
* and the given ECDSA public key.
|
||||
*
|
||||
* @param label A label that was specific to this signature
|
||||
* to ensure that the signature cannot be repurposed
|
||||
* @param label a namespaced label indicating the purpose of this
|
||||
* signature, to prevent it from being repurposed or colliding with a
|
||||
* signature created for another purpose
|
||||
* @return true if the signature was valid, false otherwise.
|
||||
*/
|
||||
boolean verify(String label, byte[] signedData, byte[] publicKey,
|
||||
@@ -175,23 +162,22 @@ public interface CryptoComponent {
|
||||
* Returns the hash of the given inputs. The inputs are unambiguously
|
||||
* combined by prefixing each input with its length.
|
||||
*
|
||||
* @param label A label specific to this hash to ensure that hashes
|
||||
* calculated for distinct purposes don't collide.
|
||||
* @param label a namespaced label indicating the purpose of this hash, to
|
||||
* prevent it from being repurposed or colliding with a hash created for
|
||||
* another purpose
|
||||
*/
|
||||
byte[] hash(String label, byte[]... inputs);
|
||||
|
||||
/**
|
||||
* Returns the length of hashes produced by
|
||||
* the {@link CryptoComponent#hash(String, byte[]...)} method.
|
||||
*/
|
||||
int getHashLength();
|
||||
|
||||
/**
|
||||
* Returns a message authentication code with the given key over the
|
||||
* given inputs. The inputs are unambiguously combined by prefixing each
|
||||
* input with its length.
|
||||
*
|
||||
* @param label a namespaced label indicating the purpose of this MAC, to
|
||||
* prevent it from being repurposed or colliding with a MAC created for
|
||||
* another purpose
|
||||
*/
|
||||
byte[] mac(SecretKey macKey, byte[]... inputs);
|
||||
byte[] mac(String label, SecretKey macKey, byte[]... inputs);
|
||||
|
||||
/**
|
||||
* Encrypts and authenticates the given plaintext so it can be written to
|
||||
|
||||
@@ -16,7 +16,7 @@ public class AuthorId extends UniqueId {
|
||||
/**
|
||||
* Label for hashing authors to calculate their identities.
|
||||
*/
|
||||
public static final String LABEL = "org.briarproject.bramble.AUTHOR_ID";
|
||||
public static final String LABEL = "org.briarproject.bramble/AUTHOR_ID";
|
||||
|
||||
public AuthorId(byte[] id) {
|
||||
super(id);
|
||||
|
||||
@@ -5,7 +5,7 @@ public interface KeyAgreementConstants {
|
||||
/**
|
||||
* The current version of the BQP protocol.
|
||||
*/
|
||||
byte PROTOCOL_VERSION = 2;
|
||||
byte PROTOCOL_VERSION = 3;
|
||||
|
||||
/**
|
||||
* The length of the record header in bytes.
|
||||
@@ -22,7 +22,10 @@ public interface KeyAgreementConstants {
|
||||
*/
|
||||
int COMMIT_LENGTH = 16;
|
||||
|
||||
long CONNECTION_TIMEOUT = 20 * 1000; // Milliseconds
|
||||
/**
|
||||
* The connection timeout in milliseconds.
|
||||
*/
|
||||
long CONNECTION_TIMEOUT = 20 * 1000;
|
||||
|
||||
/**
|
||||
* The transport identifier for Bluetooth.
|
||||
@@ -33,4 +36,16 @@ public interface KeyAgreementConstants {
|
||||
* The transport identifier for LAN.
|
||||
*/
|
||||
int TRANSPORT_ID_LAN = 1;
|
||||
|
||||
/**
|
||||
* Label for deriving the shared secret.
|
||||
*/
|
||||
String SHARED_SECRET_LABEL =
|
||||
"org.briarproject.bramble.keyagreement/SHARED_SECRET";
|
||||
|
||||
/**
|
||||
* Label for deriving the master secret.
|
||||
*/
|
||||
String MASTER_SECRET_LABEL =
|
||||
"org.briarproject.bramble.keyagreement/MASTER_SECRET";
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public class GroupId extends UniqueId {
|
||||
/**
|
||||
* Label for hashing groups to calculate their identifiers.
|
||||
*/
|
||||
public static final String LABEL = "org.briarproject.bramble.GROUP_ID";
|
||||
public static final String LABEL = "org.briarproject.bramble/GROUP_ID";
|
||||
|
||||
public GroupId(byte[] id) {
|
||||
super(id);
|
||||
|
||||
@@ -16,7 +16,7 @@ public class MessageId extends UniqueId {
|
||||
/**
|
||||
* Label for hashing messages to calculate their identifiers.
|
||||
*/
|
||||
public static final String LABEL = "org.briarproject.bramble.MESSAGE_ID";
|
||||
public static final String LABEL = "org.briarproject.bramble/MESSAGE_ID";
|
||||
|
||||
public MessageId(byte[] id) {
|
||||
super(id);
|
||||
|
||||
@@ -141,8 +141,9 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
}
|
||||
|
||||
// Derive the header keys for the transport streams
|
||||
SecretKey aliceHeaderKey = crypto.deriveHeaderKey(masterSecret, true);
|
||||
SecretKey bobHeaderKey = crypto.deriveHeaderKey(masterSecret, false);
|
||||
SecretKey aliceHeaderKey = crypto.deriveKey(ALICE_KEY_LABEL,
|
||||
masterSecret);
|
||||
SecretKey bobHeaderKey = crypto.deriveKey(BOB_KEY_LABEL, masterSecret);
|
||||
|
||||
// Create the readers
|
||||
InputStream streamReader =
|
||||
@@ -156,8 +157,10 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
BdfWriter w = bdfWriterFactory.createWriter(streamWriter);
|
||||
|
||||
// Derive the nonces to be signed
|
||||
byte[] aliceNonce = crypto.deriveSignatureNonce(masterSecret, true);
|
||||
byte[] bobNonce = crypto.deriveSignatureNonce(masterSecret, false);
|
||||
byte[] aliceNonce = crypto.deriveKeyBindingNonce(ALICE_NONCE_LABEL,
|
||||
masterSecret);
|
||||
byte[] bobNonce = crypto.deriveKeyBindingNonce(BOB_NONCE_LABEL,
|
||||
masterSecret);
|
||||
|
||||
// Exchange pseudonyms, signed nonces, and timestamps
|
||||
long localTimestamp = clock.currentTimeMillis();
|
||||
@@ -312,8 +315,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
private void tryToClose(DuplexTransportConnection conn,
|
||||
boolean exception) {
|
||||
private void tryToClose(DuplexTransportConnection conn, boolean exception) {
|
||||
try {
|
||||
LOG.info("Closing connection");
|
||||
conn.getReader().dispose(exception, true);
|
||||
|
||||
@@ -30,7 +30,6 @@ import org.spongycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.spongycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.spongycastle.crypto.params.KeyParameter;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Provider;
|
||||
@@ -65,39 +64,25 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
private static final int PBKDF_SALT_BYTES = 32; // 256 bits
|
||||
private static final int PBKDF_TARGET_MILLIS = 500;
|
||||
private static final int PBKDF_SAMPLES = 30;
|
||||
private static final int HASH_SIZE = 256 / 8;
|
||||
|
||||
private static byte[] ascii(String s) {
|
||||
return s.getBytes(Charset.forName("US-ASCII"));
|
||||
}
|
||||
|
||||
// KDF labels for contact exchange 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 contact exchange signature nonce derivation
|
||||
private static final byte[] A_SIG_NONCE = ascii("ALICE_SIGNATURE_NONCE");
|
||||
private static final byte[] B_SIG_NONCE = ascii("BOB_SIGNATURE_NONCE");
|
||||
// Hash label for BQP public key commitment derivation
|
||||
private static final String COMMIT =
|
||||
"org.briarproject.bramble.COMMIT";
|
||||
// Hash label for shared secret derivation
|
||||
private static final String SHARED_SECRET =
|
||||
"org.briarproject.bramble.SHARED_SECRET";
|
||||
private static final String COMMIT_LABEL =
|
||||
"org.briarproject.bramble.keyagreement/COMMIT";
|
||||
// KDF label for BQP confirmation key derivation
|
||||
private static final byte[] CONFIRMATION_KEY = ascii("CONFIRMATION_KEY");
|
||||
// KDF label for master key derivation
|
||||
private static final byte[] MASTER_KEY = ascii("MASTER_KEY");
|
||||
private static final String CONFIRMATION_KEY_LABEL =
|
||||
"org.briarproject.bramble.keyagreement/CONFIRMATION_KEY";
|
||||
// MAC label for BQP confirmation record
|
||||
private static final String CONFIRMATION_MAC_LABEL =
|
||||
"org.briarproject.bramble.keyagreement/CONFIRMATION_MAC";
|
||||
|
||||
// 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");
|
||||
private static final String A_TAG = "ALICE_TAG_KEY";
|
||||
private static final String B_TAG = "BOB_TAG_KEY";
|
||||
// KDF labels for header key derivation
|
||||
private static final byte[] A_HEADER = ascii("ALICE_HEADER_KEY");
|
||||
private static final byte[] B_HEADER = ascii("BOB_HEADER_KEY");
|
||||
// KDF labels for MAC key derivation
|
||||
private static final byte[] A_MAC = ascii("ALICE_MAC_KEY");
|
||||
private static final byte[] B_MAC = ascii("BOB_MAC_KEY");
|
||||
private static final String A_HEADER = "ALICE_HEADER_KEY";
|
||||
private static final String B_HEADER = "BOB_HEADER_KEY";
|
||||
// KDF label for key rotation
|
||||
private static final byte[] ROTATE = ascii("ROTATE");
|
||||
private static final String ROTATE = "ROTATE";
|
||||
|
||||
private final SecureRandom secureRandom;
|
||||
private final ECKeyPairGenerator agreementKeyPairGenerator;
|
||||
@@ -263,25 +248,19 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretKey deriveHeaderKey(SecretKey master,
|
||||
boolean alice) {
|
||||
return new SecretKey(macKdf(master, alice ? A_INVITE : B_INVITE));
|
||||
public SecretKey deriveKey(String label, SecretKey k,
|
||||
byte[]... inputs) {
|
||||
return new SecretKey(macKdf(label, k, inputs));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretKey deriveMacKey(SecretKey master, boolean alice) {
|
||||
return new SecretKey(macKdf(master, alice ? A_MAC : B_MAC));
|
||||
public byte[] deriveKeyBindingNonce(String label, SecretKey k) {
|
||||
return macKdf(label, k);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] deriveSignatureNonce(SecretKey master,
|
||||
boolean alice) {
|
||||
return macKdf(master, alice ? A_SIG_NONCE : B_SIG_NONCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] deriveKeyCommitment(byte[] publicKey) {
|
||||
byte[] hash = hash(COMMIT, publicKey);
|
||||
public byte[] deriveKeyCommitment(PublicKey publicKey) {
|
||||
byte[] hash = hash(COMMIT_LABEL, publicKey.getEncoded());
|
||||
// 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);
|
||||
@@ -289,55 +268,45 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretKey deriveSharedSecret(byte[] theirPublicKey,
|
||||
public SecretKey deriveSharedSecret(String label, PublicKey theirPublicKey,
|
||||
KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException {
|
||||
PrivateKey ourPriv = ourKeyPair.getPrivate();
|
||||
PublicKey theirPub = agreementKeyParser.parsePublicKey(theirPublicKey);
|
||||
byte[] raw = performRawKeyAgreement(ourPriv, theirPub);
|
||||
byte[] raw = performRawKeyAgreement(ourPriv, theirPublicKey);
|
||||
byte[] alicePub, bobPub;
|
||||
if (alice) {
|
||||
alicePub = ourKeyPair.getPublic().getEncoded();
|
||||
bobPub = theirPublicKey;
|
||||
bobPub = theirPublicKey.getEncoded();
|
||||
} else {
|
||||
alicePub = theirPublicKey;
|
||||
alicePub = theirPublicKey.getEncoded();
|
||||
bobPub = ourKeyPair.getPublic().getEncoded();
|
||||
}
|
||||
return new SecretKey(hash(SHARED_SECRET, raw, alicePub, bobPub));
|
||||
return new SecretKey(hash(label, raw, alicePub, bobPub));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] deriveConfirmationRecord(SecretKey sharedSecret,
|
||||
byte[] theirPayload, byte[] ourPayload, byte[] theirPublicKey,
|
||||
byte[] theirPayload, byte[] ourPayload, PublicKey theirPublicKey,
|
||||
KeyPair ourKeyPair, boolean alice, boolean aliceRecord) {
|
||||
SecretKey ck = new SecretKey(macKdf(sharedSecret, CONFIRMATION_KEY));
|
||||
SecretKey ck = deriveKey(CONFIRMATION_KEY_LABEL, sharedSecret);
|
||||
byte[] alicePayload, alicePub, bobPayload, bobPub;
|
||||
if (alice) {
|
||||
alicePayload = ourPayload;
|
||||
alicePub = ourKeyPair.getPublic().getEncoded();
|
||||
bobPayload = theirPayload;
|
||||
bobPub = theirPublicKey;
|
||||
bobPub = theirPublicKey.getEncoded();
|
||||
} else {
|
||||
alicePayload = theirPayload;
|
||||
alicePub = theirPublicKey;
|
||||
alicePub = theirPublicKey.getEncoded();
|
||||
bobPayload = ourPayload;
|
||||
bobPub = ourKeyPair.getPublic().getEncoded();
|
||||
}
|
||||
if (aliceRecord)
|
||||
return macKdf(ck, alicePayload, alicePub, bobPayload, bobPub);
|
||||
else
|
||||
return macKdf(ck, bobPayload, bobPub, alicePayload, alicePub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretKey deriveMasterSecret(SecretKey sharedSecret) {
|
||||
return new SecretKey(macKdf(sharedSecret, MASTER_KEY));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretKey deriveMasterSecret(byte[] theirPublicKey,
|
||||
KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException {
|
||||
return deriveMasterSecret(deriveSharedSecret(
|
||||
theirPublicKey, ourKeyPair, alice));
|
||||
if (aliceRecord) {
|
||||
return macKdf(CONFIRMATION_MAC_LABEL, ck, alicePayload, alicePub,
|
||||
bobPayload, bobPub);
|
||||
} else {
|
||||
return macKdf(CONFIRMATION_MAC_LABEL, ck, bobPayload, bobPub,
|
||||
alicePayload, alicePub);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -396,19 +365,19 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
private SecretKey rotateKey(SecretKey k, long rotationPeriod) {
|
||||
byte[] period = new byte[INT_64_BYTES];
|
||||
ByteUtils.writeUint64(rotationPeriod, period, 0);
|
||||
return new SecretKey(macKdf(k, ROTATE, period));
|
||||
return deriveKey(ROTATE, k, period);
|
||||
}
|
||||
|
||||
private SecretKey deriveTagKey(SecretKey master, TransportId t,
|
||||
boolean alice) {
|
||||
byte[] id = StringUtils.toUtf8(t.getString());
|
||||
return new SecretKey(macKdf(master, alice ? A_TAG : B_TAG, id));
|
||||
return deriveKey(alice ? A_TAG : B_TAG, master, id);
|
||||
}
|
||||
|
||||
private SecretKey deriveHeaderKey(SecretKey master, TransportId t,
|
||||
boolean alice) {
|
||||
byte[] id = StringUtils.toUtf8(t.getString());
|
||||
return new SecretKey(macKdf(master, alice ? A_HEADER : B_HEADER, id));
|
||||
return deriveKey(alice ? A_HEADER : B_HEADER, master, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -513,14 +482,13 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHashLength() {
|
||||
return HASH_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] mac(SecretKey macKey, byte[]... inputs) {
|
||||
public byte[] mac(String label, SecretKey macKey, byte[]... inputs) {
|
||||
byte[] labelBytes = StringUtils.toUtf8(label);
|
||||
Digest mac = new Blake2sDigest(macKey.getBytes());
|
||||
byte[] length = new byte[INT_32_BYTES];
|
||||
ByteUtils.writeUint32(labelBytes.length, length, 0);
|
||||
mac.update(length, 0, length.length);
|
||||
mac.update(labelBytes, 0, labelBytes.length);
|
||||
for (byte[] input : inputs) {
|
||||
ByteUtils.writeUint32(input.length, length, 0);
|
||||
mac.update(length, 0, length.length);
|
||||
@@ -614,26 +582,11 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
|
||||
// Key derivation function based on a pseudo-random function - see
|
||||
// NIST SP 800-108, section 5.1
|
||||
private byte[] macKdf(SecretKey key, byte[]... inputs) {
|
||||
// Initialise the PRF
|
||||
Digest prf = new Blake2sDigest(key.getBytes());
|
||||
// The output of the PRF must be long enough to use as a key
|
||||
int macLength = prf.getDigestSize();
|
||||
if (macLength < SecretKey.LENGTH) throw new IllegalStateException();
|
||||
// Calculate the PRF over the concatenated length-prefixed inputs
|
||||
byte[] length = new byte[INT_32_BYTES];
|
||||
for (byte[] input : inputs) {
|
||||
ByteUtils.writeUint32(input.length, length, 0);
|
||||
prf.update(length, 0, length.length);
|
||||
prf.update(input, 0, input.length);
|
||||
}
|
||||
byte[] mac = new byte[macLength];
|
||||
prf.doFinal(mac, 0);
|
||||
// The output is the first SecretKey.LENGTH bytes of the MAC
|
||||
if (mac.length == SecretKey.LENGTH) return mac;
|
||||
byte[] truncated = new byte[SecretKey.LENGTH];
|
||||
System.arraycopy(mac, 0, truncated, 0, truncated.length);
|
||||
return truncated;
|
||||
private byte[] macKdf(String label, SecretKey k, byte[]... inputs) {
|
||||
byte[] mac = mac(label, k, inputs);
|
||||
// The output of the PRF must be usable as a key
|
||||
if (mac.length != SecretKey.LENGTH) throw new IllegalStateException();
|
||||
return mac;
|
||||
}
|
||||
|
||||
// Password-based key derivation function - see PKCS#5 v2.1, section 5.2
|
||||
|
||||
@@ -70,8 +70,8 @@ class KeyAgreementConnector {
|
||||
public Payload listen(KeyPair localKeyPair) {
|
||||
LOG.info("Starting BQP listeners");
|
||||
// Derive commitment
|
||||
byte[] commitment = crypto.deriveKeyCommitment(
|
||||
localKeyPair.getPublic().getEncoded());
|
||||
byte[] commitment =
|
||||
crypto.deriveKeyCommitment(localKeyPair.getPublic());
|
||||
// Start all listeners and collect their descriptors
|
||||
List<TransportDescriptor> descriptors = new ArrayList<>();
|
||||
for (DuplexPlugin plugin : pluginManager.getKeyAgreementPlugins()) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package org.briarproject.bramble.keyagreement;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||
import org.briarproject.bramble.api.crypto.KeyParser;
|
||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.keyagreement.Payload;
|
||||
import org.briarproject.bramble.api.keyagreement.PayloadEncoder;
|
||||
@@ -11,6 +13,9 @@ import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_SECRET_LABEL;
|
||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL;
|
||||
|
||||
/**
|
||||
* Implementation of the BQP protocol.
|
||||
* <p/>
|
||||
@@ -86,7 +91,7 @@ class KeyAgreementProtocol {
|
||||
*/
|
||||
SecretKey perform() throws AbortException, IOException {
|
||||
try {
|
||||
byte[] theirPublicKey;
|
||||
PublicKey theirPublicKey;
|
||||
if (alice) {
|
||||
sendKey();
|
||||
// Alice waits here until Bob obtains her payload.
|
||||
@@ -104,7 +109,7 @@ class KeyAgreementProtocol {
|
||||
receiveConfirm(s, theirPublicKey);
|
||||
sendConfirm(s, theirPublicKey);
|
||||
}
|
||||
return crypto.deriveMasterSecret(s);
|
||||
return crypto.deriveKey(MASTER_SECRET_LABEL, s);
|
||||
} catch (AbortException e) {
|
||||
sendAbort(e.getCause() != null);
|
||||
throw e;
|
||||
@@ -115,25 +120,32 @@ class KeyAgreementProtocol {
|
||||
transport.sendKey(ourKeyPair.getPublic().getEncoded());
|
||||
}
|
||||
|
||||
private byte[] receiveKey() throws AbortException {
|
||||
byte[] publicKey = transport.receiveKey();
|
||||
private PublicKey receiveKey() throws AbortException {
|
||||
byte[] publicKeyBytes = transport.receiveKey();
|
||||
callbacks.initialRecordReceived();
|
||||
byte[] expected = crypto.deriveKeyCommitment(publicKey);
|
||||
if (!Arrays.equals(expected, theirPayload.getCommitment()))
|
||||
KeyParser keyParser = crypto.getAgreementKeyParser();
|
||||
try {
|
||||
PublicKey publicKey = keyParser.parsePublicKey(publicKeyBytes);
|
||||
byte[] expected = crypto.deriveKeyCommitment(publicKey);
|
||||
if (!Arrays.equals(expected, theirPayload.getCommitment()))
|
||||
throw new AbortException();
|
||||
return publicKey;
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new AbortException();
|
||||
return publicKey;
|
||||
}
|
||||
}
|
||||
|
||||
private SecretKey deriveSharedSecret(byte[] theirPublicKey)
|
||||
private SecretKey deriveSharedSecret(PublicKey theirPublicKey)
|
||||
throws AbortException {
|
||||
try {
|
||||
return crypto.deriveSharedSecret(theirPublicKey, ourKeyPair, alice);
|
||||
return crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
|
||||
theirPublicKey, ourKeyPair, alice);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new AbortException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendConfirm(SecretKey s, byte[] theirPublicKey)
|
||||
private void sendConfirm(SecretKey s, PublicKey theirPublicKey)
|
||||
throws IOException {
|
||||
byte[] confirm = crypto.deriveConfirmationRecord(s,
|
||||
payloadEncoder.encode(theirPayload),
|
||||
@@ -143,7 +155,7 @@ class KeyAgreementProtocol {
|
||||
transport.sendConfirm(confirm);
|
||||
}
|
||||
|
||||
private void receiveConfirm(SecretKey s, byte[] theirPublicKey)
|
||||
private void receiveConfirm(SecretKey s, PublicKey theirPublicKey)
|
||||
throws AbortException {
|
||||
byte[] confirm = transport.receiveConfirm();
|
||||
byte[] expected = crypto.deriveConfirmationRecord(s,
|
||||
|
||||
@@ -3,40 +3,25 @@ package org.briarproject.bramble.crypto;
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.system.SecureRandomProvider;
|
||||
import org.briarproject.bramble.test.BrambleTestCase;
|
||||
import org.briarproject.bramble.test.TestSecureRandomProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class KeyAgreementTest extends BrambleTestCase {
|
||||
|
||||
@Test
|
||||
public void testDeriveMasterSecret() throws Exception {
|
||||
SecureRandomProvider
|
||||
secureRandomProvider = new TestSecureRandomProvider();
|
||||
CryptoComponent crypto = new CryptoComponentImpl(secureRandomProvider);
|
||||
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);
|
||||
assertArrayEquals(aMaster.getBytes(), bMaster.getBytes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeriveSharedSecret() throws Exception {
|
||||
SecureRandomProvider
|
||||
secureRandomProvider = new TestSecureRandomProvider();
|
||||
CryptoComponent crypto = new CryptoComponentImpl(secureRandomProvider);
|
||||
CryptoComponent crypto =
|
||||
new CryptoComponentImpl(new TestSecureRandomProvider());
|
||||
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);
|
||||
SecretKey aShared = crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
|
||||
bPair.getPublic(), aPair, true);
|
||||
SecretKey bShared = crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
|
||||
aPair.getPublic(), bPair, false);
|
||||
assertArrayEquals(aShared.getBytes(), bShared.getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,42 +4,49 @@ import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.test.BrambleTestCase;
|
||||
import org.briarproject.bramble.test.TestSecureRandomProvider;
|
||||
import org.briarproject.bramble.test.TestUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
public class MacTest extends BrambleTestCase {
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
private final CryptoComponent crypto =
|
||||
new CryptoComponentImpl(new TestSecureRandomProvider());
|
||||
|
||||
private final SecretKey k = TestUtils.getSecretKey();
|
||||
private final byte[] inputBytes = TestUtils.getRandomBytes(123);
|
||||
private final byte[] inputBytes1 = TestUtils.getRandomBytes(234);
|
||||
private final byte[] inputBytes2 = new byte[0];
|
||||
|
||||
public MacTest() {
|
||||
crypto = new CryptoComponentImpl(new TestSecureRandomProvider());
|
||||
}
|
||||
private final SecretKey key1 = getSecretKey(), key2 = getSecretKey();
|
||||
private final String label1 = getRandomString(123);
|
||||
private final String label2 = getRandomString(123);
|
||||
private final byte[] input1 = getRandomBytes(123);
|
||||
private final byte[] input2 = getRandomBytes(234);
|
||||
private final byte[] input3 = new byte[0];
|
||||
|
||||
@Test
|
||||
public void testIdenticalKeysAndInputsProduceIdenticalMacs() {
|
||||
// Calculate the MAC twice - the results should be identical
|
||||
byte[] mac = crypto.mac(k, inputBytes, inputBytes1, inputBytes2);
|
||||
byte[] mac1 = crypto.mac(k, inputBytes, inputBytes1, inputBytes2);
|
||||
byte[] mac = crypto.mac(label1, key1, input1, input2, input3);
|
||||
byte[] mac1 = crypto.mac(label1, key1, input1, input2, input3);
|
||||
assertArrayEquals(mac, mac1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentLabelsProduceDifferentMacs() {
|
||||
// Calculate the MAC with each label - the results should be different
|
||||
byte[] mac = crypto.mac(label1, key1, input1, input2, input3);
|
||||
byte[] mac1 = crypto.mac(label2, key1, input1, input2, input3);
|
||||
assertFalse(Arrays.equals(mac, mac1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentKeysProduceDifferentMacs() {
|
||||
// Generate second random key
|
||||
SecretKey k1 = TestUtils.getSecretKey();
|
||||
// Calculate the MAC with each key - the results should be different
|
||||
byte[] mac = crypto.mac(k, inputBytes, inputBytes1, inputBytes2);
|
||||
byte[] mac1 = crypto.mac(k1, inputBytes, inputBytes1, inputBytes2);
|
||||
byte[] mac = crypto.mac(label1, key1, input1, input2, input3);
|
||||
byte[] mac1 = crypto.mac(label1, key2, input1, input2, input3);
|
||||
assertFalse(Arrays.equals(mac, mac1));
|
||||
}
|
||||
|
||||
@@ -47,8 +54,8 @@ public class MacTest extends BrambleTestCase {
|
||||
public void testDifferentInputsProduceDifferentMacs() {
|
||||
// Calculate the MAC with the inputs in different orders - the results
|
||||
// should be different
|
||||
byte[] mac = crypto.mac(k, inputBytes, inputBytes1, inputBytes2);
|
||||
byte[] mac1 = crypto.mac(k, inputBytes2, inputBytes1, inputBytes);
|
||||
byte[] mac = crypto.mac(label1, key1, input1, input2, input3);
|
||||
byte[] mac1 = crypto.mac(label1, key1, input3, input2, input1);
|
||||
assertFalse(Arrays.equals(mac, mac1));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@ package org.briarproject.bramble.keyagreement;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||
import org.briarproject.bramble.api.crypto.KeyParser;
|
||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.keyagreement.Payload;
|
||||
import org.briarproject.bramble.api.keyagreement.PayloadEncoder;
|
||||
import org.briarproject.bramble.test.BrambleTestCase;
|
||||
import org.briarproject.bramble.test.TestUtils;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.auto.Mock;
|
||||
import org.jmock.integration.junit4.JUnitRuleMockery;
|
||||
@@ -16,6 +16,10 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
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.SHARED_SECRET_LABEL;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
@@ -28,34 +32,31 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
private static final byte[] ALICE_PUBKEY = TestUtils.getRandomBytes(32);
|
||||
private static final byte[] ALICE_COMMIT =
|
||||
TestUtils.getRandomBytes(COMMIT_LENGTH);
|
||||
private static final byte[] ALICE_PAYLOAD =
|
||||
TestUtils.getRandomBytes(COMMIT_LENGTH + 8);
|
||||
private final PublicKey alicePubKey =
|
||||
context.mock(PublicKey.class, "alice");
|
||||
private final byte[] alicePubKeyBytes = getRandomBytes(32);
|
||||
private final byte[] aliceCommit = getRandomBytes(COMMIT_LENGTH);
|
||||
private final byte[] alicePayload = getRandomBytes(COMMIT_LENGTH + 8);
|
||||
private final byte[] aliceConfirm = getRandomBytes(SecretKey.LENGTH);
|
||||
|
||||
private static final byte[] BOB_PUBKEY = TestUtils.getRandomBytes(32);
|
||||
private static final byte[] BOB_COMMIT =
|
||||
TestUtils.getRandomBytes(COMMIT_LENGTH);
|
||||
private static final byte[] BOB_PAYLOAD =
|
||||
TestUtils.getRandomBytes(COMMIT_LENGTH + 19);
|
||||
private final PublicKey bobPubKey = context.mock(PublicKey.class, "bob");
|
||||
private final byte[] bobPubKeyBytes = getRandomBytes(32);
|
||||
private final byte[] bobCommit = getRandomBytes(COMMIT_LENGTH);
|
||||
private final byte[] bobPayload = getRandomBytes(COMMIT_LENGTH + 19);
|
||||
private final byte[] bobConfirm = getRandomBytes(SecretKey.LENGTH);
|
||||
|
||||
private static final byte[] ALICE_CONFIRM =
|
||||
TestUtils.getRandomBytes(SecretKey.LENGTH);
|
||||
private static final byte[] BOB_CONFIRM =
|
||||
TestUtils.getRandomBytes(SecretKey.LENGTH);
|
||||
|
||||
private static final byte[] BAD_PUBKEY = TestUtils.getRandomBytes(32);
|
||||
private static final byte[] BAD_COMMIT =
|
||||
TestUtils.getRandomBytes(COMMIT_LENGTH);
|
||||
private static final byte[] BAD_CONFIRM =
|
||||
TestUtils.getRandomBytes(SecretKey.LENGTH);
|
||||
private final PublicKey badPubKey = context.mock(PublicKey.class, "bad");
|
||||
private final byte[] badPubKeyBytes = getRandomBytes(32);
|
||||
private final byte[] badCommit = getRandomBytes(COMMIT_LENGTH);
|
||||
private final byte[] badConfirm = getRandomBytes(SecretKey.LENGTH);
|
||||
|
||||
@Mock
|
||||
KeyAgreementProtocol.Callbacks callbacks;
|
||||
@Mock
|
||||
CryptoComponent crypto;
|
||||
@Mock
|
||||
KeyParser keyParser;
|
||||
@Mock
|
||||
PayloadEncoder payloadEncoder;
|
||||
@Mock
|
||||
KeyAgreementTransport transport;
|
||||
@@ -65,11 +66,11 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
@Test
|
||||
public void testAliceProtocol() throws Exception {
|
||||
// set up
|
||||
Payload theirPayload = new Payload(BOB_COMMIT, null);
|
||||
Payload ourPayload = new Payload(ALICE_COMMIT, null);
|
||||
Payload theirPayload = new Payload(bobCommit, null);
|
||||
Payload ourPayload = new Payload(aliceCommit, null);
|
||||
KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
|
||||
SecretKey sharedSecret = TestUtils.getSecretKey();
|
||||
SecretKey masterSecret = TestUtils.getSecretKey();
|
||||
SecretKey sharedSecret = getSecretKey();
|
||||
SecretKey masterSecret = getSecretKey();
|
||||
|
||||
KeyAgreementProtocol protocol =
|
||||
new KeyAgreementProtocol(callbacks, crypto, payloadEncoder,
|
||||
@@ -79,46 +80,51 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
context.checking(new Expectations() {{
|
||||
// Helpers
|
||||
allowing(payloadEncoder).encode(ourPayload);
|
||||
will(returnValue(ALICE_PAYLOAD));
|
||||
will(returnValue(alicePayload));
|
||||
allowing(payloadEncoder).encode(theirPayload);
|
||||
will(returnValue(BOB_PAYLOAD));
|
||||
will(returnValue(bobPayload));
|
||||
allowing(ourPubKey).getEncoded();
|
||||
will(returnValue(ALICE_PUBKEY));
|
||||
will(returnValue(alicePubKeyBytes));
|
||||
allowing(crypto).getAgreementKeyParser();
|
||||
will(returnValue(keyParser));
|
||||
|
||||
// Alice sends her public key
|
||||
oneOf(transport).sendKey(ALICE_PUBKEY);
|
||||
oneOf(transport).sendKey(alicePubKeyBytes);
|
||||
|
||||
// Alice receives Bob's public key
|
||||
oneOf(callbacks).connectionWaiting();
|
||||
oneOf(transport).receiveKey();
|
||||
will(returnValue(BOB_PUBKEY));
|
||||
will(returnValue(bobPubKeyBytes));
|
||||
oneOf(callbacks).initialRecordReceived();
|
||||
oneOf(keyParser).parsePublicKey(bobPubKeyBytes);
|
||||
will(returnValue(bobPubKey));
|
||||
|
||||
// Alice verifies Bob's public key
|
||||
oneOf(crypto).deriveKeyCommitment(BOB_PUBKEY);
|
||||
will(returnValue(BOB_COMMIT));
|
||||
oneOf(crypto).deriveKeyCommitment(bobPubKey);
|
||||
will(returnValue(bobCommit));
|
||||
|
||||
// Alice computes shared secret
|
||||
oneOf(crypto).deriveSharedSecret(BOB_PUBKEY, ourKeyPair, true);
|
||||
oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, bobPubKey,
|
||||
ourKeyPair, true);
|
||||
will(returnValue(sharedSecret));
|
||||
|
||||
// Alice sends her confirmation record
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, BOB_PAYLOAD,
|
||||
ALICE_PAYLOAD, BOB_PUBKEY, ourKeyPair, true, true);
|
||||
will(returnValue(ALICE_CONFIRM));
|
||||
oneOf(transport).sendConfirm(ALICE_CONFIRM);
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, bobPayload,
|
||||
alicePayload, bobPubKey, ourKeyPair, true, true);
|
||||
will(returnValue(aliceConfirm));
|
||||
oneOf(transport).sendConfirm(aliceConfirm);
|
||||
|
||||
// Alice receives Bob's confirmation record
|
||||
oneOf(transport).receiveConfirm();
|
||||
will(returnValue(BOB_CONFIRM));
|
||||
will(returnValue(bobConfirm));
|
||||
|
||||
// Alice verifies Bob's confirmation record
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, BOB_PAYLOAD,
|
||||
ALICE_PAYLOAD, BOB_PUBKEY, ourKeyPair, true, false);
|
||||
will(returnValue(BOB_CONFIRM));
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, bobPayload,
|
||||
alicePayload, bobPubKey, ourKeyPair, true, false);
|
||||
will(returnValue(bobConfirm));
|
||||
|
||||
// Alice computes master secret
|
||||
oneOf(crypto).deriveMasterSecret(sharedSecret);
|
||||
oneOf(crypto).deriveKey(MASTER_SECRET_LABEL, sharedSecret);
|
||||
will(returnValue(masterSecret));
|
||||
}});
|
||||
|
||||
@@ -129,11 +135,11 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
@Test
|
||||
public void testBobProtocol() throws Exception {
|
||||
// set up
|
||||
Payload theirPayload = new Payload(ALICE_COMMIT, null);
|
||||
Payload ourPayload = new Payload(BOB_COMMIT, null);
|
||||
Payload theirPayload = new Payload(aliceCommit, null);
|
||||
Payload ourPayload = new Payload(bobCommit, null);
|
||||
KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
|
||||
SecretKey sharedSecret = TestUtils.getSecretKey();
|
||||
SecretKey masterSecret = TestUtils.getSecretKey();
|
||||
SecretKey sharedSecret = getSecretKey();
|
||||
SecretKey masterSecret = getSecretKey();
|
||||
|
||||
KeyAgreementProtocol protocol =
|
||||
new KeyAgreementProtocol(callbacks, crypto, payloadEncoder,
|
||||
@@ -143,45 +149,50 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
context.checking(new Expectations() {{
|
||||
// Helpers
|
||||
allowing(payloadEncoder).encode(ourPayload);
|
||||
will(returnValue(BOB_PAYLOAD));
|
||||
will(returnValue(bobPayload));
|
||||
allowing(payloadEncoder).encode(theirPayload);
|
||||
will(returnValue(ALICE_PAYLOAD));
|
||||
will(returnValue(alicePayload));
|
||||
allowing(ourPubKey).getEncoded();
|
||||
will(returnValue(BOB_PUBKEY));
|
||||
will(returnValue(bobPubKeyBytes));
|
||||
allowing(crypto).getAgreementKeyParser();
|
||||
will(returnValue(keyParser));
|
||||
|
||||
// Bob receives Alice's public key
|
||||
oneOf(transport).receiveKey();
|
||||
will(returnValue(ALICE_PUBKEY));
|
||||
will(returnValue(alicePubKeyBytes));
|
||||
oneOf(callbacks).initialRecordReceived();
|
||||
oneOf(keyParser).parsePublicKey(alicePubKeyBytes);
|
||||
will(returnValue(alicePubKey));
|
||||
|
||||
// Bob verifies Alice's public key
|
||||
oneOf(crypto).deriveKeyCommitment(ALICE_PUBKEY);
|
||||
will(returnValue(ALICE_COMMIT));
|
||||
oneOf(crypto).deriveKeyCommitment(alicePubKey);
|
||||
will(returnValue(aliceCommit));
|
||||
|
||||
// Bob sends his public key
|
||||
oneOf(transport).sendKey(BOB_PUBKEY);
|
||||
oneOf(transport).sendKey(bobPubKeyBytes);
|
||||
|
||||
// Bob computes shared secret
|
||||
oneOf(crypto).deriveSharedSecret(ALICE_PUBKEY, ourKeyPair, false);
|
||||
oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, alicePubKey,
|
||||
ourKeyPair, false);
|
||||
will(returnValue(sharedSecret));
|
||||
|
||||
// Bob receives Alices's confirmation record
|
||||
oneOf(transport).receiveConfirm();
|
||||
will(returnValue(ALICE_CONFIRM));
|
||||
will(returnValue(aliceConfirm));
|
||||
|
||||
// Bob verifies Alice's confirmation record
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, ALICE_PAYLOAD,
|
||||
BOB_PAYLOAD, ALICE_PUBKEY, ourKeyPair, false, true);
|
||||
will(returnValue(ALICE_CONFIRM));
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, alicePayload,
|
||||
bobPayload, alicePubKey, ourKeyPair, false, true);
|
||||
will(returnValue(aliceConfirm));
|
||||
|
||||
// Bob sends his confirmation record
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, ALICE_PAYLOAD,
|
||||
BOB_PAYLOAD, ALICE_PUBKEY, ourKeyPair, false, false);
|
||||
will(returnValue(BOB_CONFIRM));
|
||||
oneOf(transport).sendConfirm(BOB_CONFIRM);
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, alicePayload,
|
||||
bobPayload, alicePubKey, ourKeyPair, false, false);
|
||||
will(returnValue(bobConfirm));
|
||||
oneOf(transport).sendConfirm(bobConfirm);
|
||||
|
||||
// Bob computes master secret
|
||||
oneOf(crypto).deriveMasterSecret(sharedSecret);
|
||||
oneOf(crypto).deriveKey(MASTER_SECRET_LABEL, sharedSecret);
|
||||
will(returnValue(masterSecret));
|
||||
}});
|
||||
|
||||
@@ -192,8 +203,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
@Test(expected = AbortException.class)
|
||||
public void testAliceProtocolAbortOnBadKey() throws Exception {
|
||||
// set up
|
||||
Payload theirPayload = new Payload(BOB_COMMIT, null);
|
||||
Payload ourPayload = new Payload(ALICE_COMMIT, null);
|
||||
Payload theirPayload = new Payload(bobCommit, null);
|
||||
Payload ourPayload = new Payload(aliceCommit, null);
|
||||
KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
|
||||
|
||||
KeyAgreementProtocol protocol =
|
||||
@@ -204,26 +215,31 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
context.checking(new Expectations() {{
|
||||
// Helpers
|
||||
allowing(ourPubKey).getEncoded();
|
||||
will(returnValue(ALICE_PUBKEY));
|
||||
will(returnValue(alicePubKeyBytes));
|
||||
allowing(crypto).getAgreementKeyParser();
|
||||
will(returnValue(keyParser));
|
||||
|
||||
// Alice sends her public key
|
||||
oneOf(transport).sendKey(ALICE_PUBKEY);
|
||||
oneOf(transport).sendKey(alicePubKeyBytes);
|
||||
|
||||
// Alice receives a bad public key
|
||||
oneOf(callbacks).connectionWaiting();
|
||||
oneOf(transport).receiveKey();
|
||||
will(returnValue(BAD_PUBKEY));
|
||||
will(returnValue(badPubKeyBytes));
|
||||
oneOf(callbacks).initialRecordReceived();
|
||||
oneOf(keyParser).parsePublicKey(badPubKeyBytes);
|
||||
will(returnValue(badPubKey));
|
||||
|
||||
// Alice verifies Bob's public key
|
||||
oneOf(crypto).deriveKeyCommitment(BAD_PUBKEY);
|
||||
will(returnValue(BAD_COMMIT));
|
||||
oneOf(crypto).deriveKeyCommitment(badPubKey);
|
||||
will(returnValue(badCommit));
|
||||
|
||||
// Alice aborts
|
||||
oneOf(transport).sendAbort(false);
|
||||
|
||||
// Alice never computes shared secret
|
||||
never(crypto).deriveSharedSecret(BAD_PUBKEY, ourKeyPair, true);
|
||||
never(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, badPubKey,
|
||||
ourKeyPair, true);
|
||||
}});
|
||||
|
||||
// execute
|
||||
@@ -233,8 +249,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
@Test(expected = AbortException.class)
|
||||
public void testBobProtocolAbortOnBadKey() throws Exception {
|
||||
// set up
|
||||
Payload theirPayload = new Payload(ALICE_COMMIT, null);
|
||||
Payload ourPayload = new Payload(BOB_COMMIT, null);
|
||||
Payload theirPayload = new Payload(aliceCommit, null);
|
||||
Payload ourPayload = new Payload(bobCommit, null);
|
||||
KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
|
||||
|
||||
KeyAgreementProtocol protocol =
|
||||
@@ -245,22 +261,26 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
context.checking(new Expectations() {{
|
||||
// Helpers
|
||||
allowing(ourPubKey).getEncoded();
|
||||
will(returnValue(BOB_PUBKEY));
|
||||
will(returnValue(bobPubKeyBytes));
|
||||
allowing(crypto).getAgreementKeyParser();
|
||||
will(returnValue(keyParser));
|
||||
|
||||
// Bob receives a bad public key
|
||||
oneOf(transport).receiveKey();
|
||||
will(returnValue(BAD_PUBKEY));
|
||||
will(returnValue(badPubKeyBytes));
|
||||
oneOf(callbacks).initialRecordReceived();
|
||||
oneOf(keyParser).parsePublicKey(badPubKeyBytes);
|
||||
will(returnValue(badPubKey));
|
||||
|
||||
// Bob verifies Alice's public key
|
||||
oneOf(crypto).deriveKeyCommitment(BAD_PUBKEY);
|
||||
will(returnValue(BAD_COMMIT));
|
||||
oneOf(crypto).deriveKeyCommitment(badPubKey);
|
||||
will(returnValue(badCommit));
|
||||
|
||||
// Bob aborts
|
||||
oneOf(transport).sendAbort(false);
|
||||
|
||||
// Bob never sends his public key
|
||||
never(transport).sendKey(BOB_PUBKEY);
|
||||
never(transport).sendKey(bobPubKeyBytes);
|
||||
}});
|
||||
|
||||
// execute
|
||||
@@ -270,10 +290,10 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
@Test(expected = AbortException.class)
|
||||
public void testAliceProtocolAbortOnBadConfirm() throws Exception {
|
||||
// set up
|
||||
Payload theirPayload = new Payload(BOB_COMMIT, null);
|
||||
Payload ourPayload = new Payload(ALICE_COMMIT, null);
|
||||
Payload theirPayload = new Payload(bobCommit, null);
|
||||
Payload ourPayload = new Payload(aliceCommit, null);
|
||||
KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
|
||||
SecretKey sharedSecret = TestUtils.getSecretKey();
|
||||
SecretKey sharedSecret = getSecretKey();
|
||||
|
||||
KeyAgreementProtocol protocol =
|
||||
new KeyAgreementProtocol(callbacks, crypto, payloadEncoder,
|
||||
@@ -283,49 +303,54 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
context.checking(new Expectations() {{
|
||||
// Helpers
|
||||
allowing(payloadEncoder).encode(ourPayload);
|
||||
will(returnValue(ALICE_PAYLOAD));
|
||||
will(returnValue(alicePayload));
|
||||
allowing(payloadEncoder).encode(theirPayload);
|
||||
will(returnValue(BOB_PAYLOAD));
|
||||
will(returnValue(bobPayload));
|
||||
allowing(ourPubKey).getEncoded();
|
||||
will(returnValue(ALICE_PUBKEY));
|
||||
will(returnValue(alicePubKeyBytes));
|
||||
allowing(crypto).getAgreementKeyParser();
|
||||
will(returnValue(keyParser));
|
||||
|
||||
// Alice sends her public key
|
||||
oneOf(transport).sendKey(ALICE_PUBKEY);
|
||||
oneOf(transport).sendKey(alicePubKeyBytes);
|
||||
|
||||
// Alice receives Bob's public key
|
||||
oneOf(callbacks).connectionWaiting();
|
||||
oneOf(transport).receiveKey();
|
||||
will(returnValue(BOB_PUBKEY));
|
||||
will(returnValue(bobPubKeyBytes));
|
||||
oneOf(callbacks).initialRecordReceived();
|
||||
oneOf(keyParser).parsePublicKey(bobPubKeyBytes);
|
||||
will(returnValue(bobPubKey));
|
||||
|
||||
// Alice verifies Bob's public key
|
||||
oneOf(crypto).deriveKeyCommitment(BOB_PUBKEY);
|
||||
will(returnValue(BOB_COMMIT));
|
||||
oneOf(crypto).deriveKeyCommitment(bobPubKey);
|
||||
will(returnValue(bobCommit));
|
||||
|
||||
// Alice computes shared secret
|
||||
oneOf(crypto).deriveSharedSecret(BOB_PUBKEY, ourKeyPair, true);
|
||||
oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, bobPubKey,
|
||||
ourKeyPair, true);
|
||||
will(returnValue(sharedSecret));
|
||||
|
||||
// Alice sends her confirmation record
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, BOB_PAYLOAD,
|
||||
ALICE_PAYLOAD, BOB_PUBKEY, ourKeyPair, true, true);
|
||||
will(returnValue(ALICE_CONFIRM));
|
||||
oneOf(transport).sendConfirm(ALICE_CONFIRM);
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, bobPayload,
|
||||
alicePayload, bobPubKey, ourKeyPair, true, true);
|
||||
will(returnValue(aliceConfirm));
|
||||
oneOf(transport).sendConfirm(aliceConfirm);
|
||||
|
||||
// Alice receives a bad confirmation record
|
||||
oneOf(transport).receiveConfirm();
|
||||
will(returnValue(BAD_CONFIRM));
|
||||
will(returnValue(badConfirm));
|
||||
|
||||
// Alice verifies Bob's confirmation record
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, BOB_PAYLOAD,
|
||||
ALICE_PAYLOAD, BOB_PUBKEY, ourKeyPair, true, false);
|
||||
will(returnValue(BOB_CONFIRM));
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, bobPayload,
|
||||
alicePayload, bobPubKey, ourKeyPair, true, false);
|
||||
will(returnValue(bobConfirm));
|
||||
|
||||
// Alice aborts
|
||||
oneOf(transport).sendAbort(false);
|
||||
|
||||
// Alice never computes master secret
|
||||
never(crypto).deriveMasterSecret(sharedSecret);
|
||||
never(crypto).deriveKey(MASTER_SECRET_LABEL, sharedSecret);
|
||||
}});
|
||||
|
||||
// execute
|
||||
@@ -335,10 +360,10 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
@Test(expected = AbortException.class)
|
||||
public void testBobProtocolAbortOnBadConfirm() throws Exception {
|
||||
// set up
|
||||
Payload theirPayload = new Payload(ALICE_COMMIT, null);
|
||||
Payload ourPayload = new Payload(BOB_COMMIT, null);
|
||||
Payload theirPayload = new Payload(aliceCommit, null);
|
||||
Payload ourPayload = new Payload(bobCommit, null);
|
||||
KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
|
||||
SecretKey sharedSecret = TestUtils.getSecretKey();
|
||||
SecretKey sharedSecret = getSecretKey();
|
||||
|
||||
KeyAgreementProtocol protocol =
|
||||
new KeyAgreementProtocol(callbacks, crypto, payloadEncoder,
|
||||
@@ -348,43 +373,48 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
||||
context.checking(new Expectations() {{
|
||||
// Helpers
|
||||
allowing(payloadEncoder).encode(ourPayload);
|
||||
will(returnValue(BOB_PAYLOAD));
|
||||
will(returnValue(bobPayload));
|
||||
allowing(payloadEncoder).encode(theirPayload);
|
||||
will(returnValue(ALICE_PAYLOAD));
|
||||
will(returnValue(alicePayload));
|
||||
allowing(ourPubKey).getEncoded();
|
||||
will(returnValue(BOB_PUBKEY));
|
||||
will(returnValue(bobPubKeyBytes));
|
||||
allowing(crypto).getAgreementKeyParser();
|
||||
will(returnValue(keyParser));
|
||||
|
||||
// Bob receives Alice's public key
|
||||
oneOf(transport).receiveKey();
|
||||
will(returnValue(ALICE_PUBKEY));
|
||||
will(returnValue(alicePubKeyBytes));
|
||||
oneOf(callbacks).initialRecordReceived();
|
||||
oneOf(keyParser).parsePublicKey(alicePubKeyBytes);
|
||||
will(returnValue(alicePubKey));
|
||||
|
||||
// Bob verifies Alice's public key
|
||||
oneOf(crypto).deriveKeyCommitment(ALICE_PUBKEY);
|
||||
will(returnValue(ALICE_COMMIT));
|
||||
oneOf(crypto).deriveKeyCommitment(alicePubKey);
|
||||
will(returnValue(aliceCommit));
|
||||
|
||||
// Bob sends his public key
|
||||
oneOf(transport).sendKey(BOB_PUBKEY);
|
||||
oneOf(transport).sendKey(bobPubKeyBytes);
|
||||
|
||||
// Bob computes shared secret
|
||||
oneOf(crypto).deriveSharedSecret(ALICE_PUBKEY, ourKeyPair, false);
|
||||
oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, alicePubKey,
|
||||
ourKeyPair, false);
|
||||
will(returnValue(sharedSecret));
|
||||
|
||||
// Bob receives a bad confirmation record
|
||||
oneOf(transport).receiveConfirm();
|
||||
will(returnValue(BAD_CONFIRM));
|
||||
will(returnValue(badConfirm));
|
||||
|
||||
// Bob verifies Alice's confirmation record
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, ALICE_PAYLOAD,
|
||||
BOB_PAYLOAD, ALICE_PUBKEY, ourKeyPair, false, true);
|
||||
will(returnValue(ALICE_CONFIRM));
|
||||
oneOf(crypto).deriveConfirmationRecord(sharedSecret, alicePayload,
|
||||
bobPayload, alicePubKey, ourKeyPair, false, true);
|
||||
will(returnValue(aliceConfirm));
|
||||
|
||||
// Bob aborts
|
||||
oneOf(transport).sendAbort(false);
|
||||
|
||||
// Bob never sends his confirmation record
|
||||
never(crypto).deriveConfirmationRecord(sharedSecret, ALICE_PAYLOAD,
|
||||
BOB_PAYLOAD, ALICE_PUBKEY, ourKeyPair, false, false);
|
||||
never(crypto).deriveConfirmationRecord(sharedSecret, alicePayload,
|
||||
bobPayload, alicePubKey, ourKeyPair, false, false);
|
||||
}});
|
||||
|
||||
// execute
|
||||
|
||||
@@ -86,4 +86,44 @@ public interface IntroductionConstants {
|
||||
int TASK_ACTIVATE_CONTACT = 1;
|
||||
int TASK_ABORT = 2;
|
||||
|
||||
/**
|
||||
* Label for deriving the shared secret.
|
||||
*/
|
||||
String SHARED_SECRET_LABEL =
|
||||
"org.briarproject.briar.introduction/SHARED_SECRET";
|
||||
|
||||
/**
|
||||
* Label for deriving Alice's key binding nonce from the shared secret.
|
||||
*/
|
||||
String ALICE_NONCE_LABEL =
|
||||
"org.briarproject.briar.introduction/ALICE_NONCE";
|
||||
|
||||
/**
|
||||
* Label for deriving Bob's key binding nonce from the shared secret.
|
||||
*/
|
||||
String BOB_NONCE_LABEL =
|
||||
"org.briarproject.briar.introduction/BOB_NONCE";
|
||||
|
||||
/**
|
||||
* Label for deriving Alice's MAC key from the shared secret.
|
||||
*/
|
||||
String ALICE_MAC_KEY_LABEL =
|
||||
"org.briarproject.briar.introduction/ALICE_MAC_KEY";
|
||||
|
||||
/**
|
||||
* Label for deriving Bob's MAC key from the shared secret.
|
||||
*/
|
||||
String BOB_MAC_KEY_LABEL =
|
||||
"org.briarproject.briar.introduction/BOB_MAC_KEY";
|
||||
|
||||
/**
|
||||
* Label for signing the introduction response.
|
||||
*/
|
||||
String SIGNING_LABEL =
|
||||
"org.briarproject.briar.introduction/RESPONSE_SIGNATURE";
|
||||
|
||||
/**
|
||||
* Label for MACing the introduction response.
|
||||
*/
|
||||
String MAC_LABEL = "org.briarproject.briar.introduction/RESPONSE_MAC";
|
||||
}
|
||||
|
||||
@@ -50,7 +50,11 @@ import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||
import static org.briarproject.briar.api.introduction.IntroduceeProtocolState.AWAIT_REQUEST;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.ACCEPT;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.ADDED_CONTACT_ID;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.ALICE_MAC_KEY_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.ALICE_NONCE_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.ANSWERED;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.BOB_MAC_KEY_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.BOB_NONCE_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_ID_1;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.EXISTS;
|
||||
@@ -60,6 +64,7 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.INTR
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.LOCAL_AUTHOR_ID;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_KEY;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_ID;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_TIME;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME;
|
||||
@@ -76,7 +81,9 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.REMO
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCEE;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.SHARED_SECRET_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNATURE;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNING_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.STATE;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.STORAGE_ID;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TASK;
|
||||
@@ -89,7 +96,6 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
@@ -98,9 +104,6 @@ class IntroduceeManager {
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(IntroduceeManager.class.getName());
|
||||
|
||||
static final String SIGNING_LABEL_RESPONSE =
|
||||
CLIENT_ID.getString() + "/RESPONSE";
|
||||
|
||||
private final MessageSender messageSender;
|
||||
private final DatabaseComponent db;
|
||||
private final ClientHelper clientHelper;
|
||||
@@ -288,8 +291,7 @@ class IntroduceeManager {
|
||||
|
||||
@Nullable
|
||||
private BdfDictionary performTasks(Transaction txn,
|
||||
BdfDictionary localState)
|
||||
throws FormatException, DbException {
|
||||
BdfDictionary localState) throws FormatException, DbException {
|
||||
|
||||
if (!localState.containsKey(TASK) || localState.get(TASK) == NULL_VALUE)
|
||||
return null;
|
||||
@@ -306,22 +308,21 @@ class IntroduceeManager {
|
||||
}
|
||||
|
||||
// figure out who takes which role by comparing public keys
|
||||
byte[] publicKeyBytes = localState.getRaw(OUR_PUBLIC_KEY);
|
||||
byte[] theirEphemeralKey = localState.getRaw(E_PUBLIC_KEY);
|
||||
int comp = Bytes.COMPARATOR.compare(new Bytes(publicKeyBytes),
|
||||
new Bytes(theirEphemeralKey));
|
||||
byte[] ourPublicKeyBytes = localState.getRaw(OUR_PUBLIC_KEY);
|
||||
byte[] theirPublicKeyBytes = localState.getRaw(E_PUBLIC_KEY);
|
||||
int comp = Bytes.COMPARATOR.compare(new Bytes(ourPublicKeyBytes),
|
||||
new Bytes(theirPublicKeyBytes));
|
||||
boolean alice = comp < 0;
|
||||
|
||||
// get our local author
|
||||
LocalAuthor author = identityManager.getLocalAuthor(txn);
|
||||
|
||||
SecretKey secretKey;
|
||||
byte[] privateKeyBytes = localState.getRaw(OUR_PRIVATE_KEY);
|
||||
byte[] ourPrivateKeyBytes = localState.getRaw(OUR_PRIVATE_KEY);
|
||||
try {
|
||||
// derive secret master key
|
||||
secretKey =
|
||||
deriveSecretKey(publicKeyBytes, privateKeyBytes, alice,
|
||||
theirEphemeralKey);
|
||||
secretKey = deriveSecretKey(ourPublicKeyBytes,
|
||||
ourPrivateKeyBytes, alice, theirPublicKeyBytes);
|
||||
// derive MAC keys and nonces, sign our nonce and calculate MAC
|
||||
deriveMacKeysAndNonces(localState, author, secretKey, alice);
|
||||
} catch (GeneralSecurityException e) {
|
||||
@@ -410,34 +411,36 @@ class IntroduceeManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
private SecretKey deriveSecretKey(byte[] publicKeyBytes,
|
||||
byte[] privateKeyBytes, boolean alice, byte[] theirPublicKey)
|
||||
throws GeneralSecurityException {
|
||||
private SecretKey deriveSecretKey(byte[] ourPublicKeyBytes,
|
||||
byte[] ourPrivateKeyBytes, boolean alice,
|
||||
byte[] theirPublicKeyBytes) throws GeneralSecurityException {
|
||||
// parse the local ephemeral key pair
|
||||
KeyParser keyParser = cryptoComponent.getAgreementKeyParser();
|
||||
PublicKey publicKey;
|
||||
PrivateKey privateKey;
|
||||
PublicKey ourPublicKey;
|
||||
PrivateKey ourPrivateKey;
|
||||
try {
|
||||
publicKey = keyParser.parsePublicKey(publicKeyBytes);
|
||||
privateKey = keyParser.parsePrivateKey(privateKeyBytes);
|
||||
ourPublicKey = keyParser.parsePublicKey(ourPublicKeyBytes);
|
||||
ourPrivateKey = keyParser.parsePrivateKey(ourPrivateKeyBytes);
|
||||
} catch (GeneralSecurityException e) {
|
||||
if (LOG.isLoggable(WARNING)) {
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
throw new RuntimeException("Our own ephemeral key is invalid");
|
||||
}
|
||||
KeyPair keyPair = new KeyPair(publicKey, privateKey);
|
||||
KeyPair ourKeyPair = new KeyPair(ourPublicKey, ourPrivateKey);
|
||||
PublicKey theirPublicKey =
|
||||
keyParser.parsePublicKey(theirPublicKeyBytes);
|
||||
|
||||
// The master 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
|
||||
return cryptoComponent
|
||||
.deriveMasterSecret(theirPublicKey, keyPair, alice);
|
||||
return cryptoComponent.deriveSharedSecret(SHARED_SECRET_LABEL,
|
||||
theirPublicKey, ourKeyPair, alice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Derives nonces, signs our nonce and calculates MAC
|
||||
* <p>
|
||||
* Derives two nonces and two mac keys from the secret master key.
|
||||
* Derives two nonces and two MAC keys from the shared secret key.
|
||||
* The other introducee's nonce and MAC key are added to the localState.
|
||||
* <p>
|
||||
* Our nonce is signed with the local author's long-term private key.
|
||||
@@ -448,21 +451,23 @@ class IntroduceeManager {
|
||||
private void deriveMacKeysAndNonces(BdfDictionary localState,
|
||||
LocalAuthor author, SecretKey secretKey, boolean alice)
|
||||
throws FormatException, GeneralSecurityException {
|
||||
// Derive two nonces and a MAC key from the secret master key
|
||||
byte[] ourNonce =
|
||||
cryptoComponent.deriveSignatureNonce(secretKey, alice);
|
||||
byte[] theirNonce =
|
||||
cryptoComponent.deriveSignatureNonce(secretKey, !alice);
|
||||
SecretKey macKey = cryptoComponent.deriveMacKey(secretKey, alice);
|
||||
SecretKey theirMacKey = cryptoComponent.deriveMacKey(secretKey, !alice);
|
||||
// Derive two nonces and MAC keys from the shared secret key
|
||||
byte[] ourNonce = cryptoComponent.deriveKeyBindingNonce(
|
||||
alice ? ALICE_NONCE_LABEL : BOB_NONCE_LABEL, secretKey);
|
||||
byte[] theirNonce = cryptoComponent.deriveKeyBindingNonce(
|
||||
alice ? BOB_NONCE_LABEL : ALICE_NONCE_LABEL, secretKey);
|
||||
SecretKey ourMacKey = cryptoComponent.deriveKey(
|
||||
alice ? ALICE_MAC_KEY_LABEL : BOB_MAC_KEY_LABEL, secretKey);
|
||||
SecretKey theirMacKey = cryptoComponent.deriveKey(
|
||||
alice ? BOB_MAC_KEY_LABEL : ALICE_MAC_KEY_LABEL, secretKey);
|
||||
|
||||
// Save the other nonce and MAC key for the verification
|
||||
localState.put(NONCE, theirNonce);
|
||||
localState.put(MAC_KEY, theirMacKey.getBytes());
|
||||
|
||||
// Sign our nonce with our long-term identity public key
|
||||
byte[] sig = cryptoComponent
|
||||
.sign(SIGNING_LABEL_RESPONSE, ourNonce, author.getPrivateKey());
|
||||
byte[] sig = cryptoComponent.sign(SIGNING_LABEL, ourNonce,
|
||||
author.getPrivateKey());
|
||||
|
||||
// Calculate a MAC over identity public key, ephemeral public key,
|
||||
// transport properties and timestamp.
|
||||
@@ -472,7 +477,7 @@ class IntroduceeManager {
|
||||
BdfList toMacList = BdfList.of(author.getPublicKey(),
|
||||
publicKeyBytes, tp, ourTime);
|
||||
byte[] toMac = clientHelper.toByteArray(toMacList);
|
||||
byte[] mac = cryptoComponent.mac(macKey, toMac);
|
||||
byte[] mac = cryptoComponent.mac(MAC_LABEL, ourMacKey, toMac);
|
||||
|
||||
// Add MAC and signature to localState, so it can be included in ACK
|
||||
localState.put(OUR_MAC, mac);
|
||||
@@ -486,7 +491,7 @@ class IntroduceeManager {
|
||||
byte[] key = localState.getRaw(PUBLIC_KEY);
|
||||
|
||||
// Verify the signature
|
||||
if (!cryptoComponent.verify(SIGNING_LABEL_RESPONSE, nonce, key, sig)) {
|
||||
if (!cryptoComponent.verify(SIGNING_LABEL, nonce, key, sig)) {
|
||||
LOG.warning("Invalid nonce signature in ACK");
|
||||
throw new GeneralSecurityException();
|
||||
}
|
||||
@@ -506,7 +511,7 @@ class IntroduceeManager {
|
||||
long timestamp = localState.getLong(TIME);
|
||||
BdfList toMacList = BdfList.of(pubKey, ePubKey, tp, timestamp);
|
||||
byte[] toMac = clientHelper.toByteArray(toMacList);
|
||||
byte[] calculatedMac = cryptoComponent.mac(macKey, toMac);
|
||||
byte[] calculatedMac = cryptoComponent.mac(MAC_LABEL, macKey, toMac);
|
||||
if (!Arrays.equals(mac, calculatedMac)) {
|
||||
LOG.warning("Received ACK with invalid MAC");
|
||||
throw new GeneralSecurityException();
|
||||
|
||||
@@ -53,6 +53,7 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.INTR
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.LOCAL_AUTHOR_ID;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_KEY;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_LENGTH;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_ID;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_TIME;
|
||||
@@ -66,6 +67,7 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCEE;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNATURE;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNING_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.STATE;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.STORAGE_ID;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TIME;
|
||||
@@ -74,7 +76,6 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
||||
import static org.briarproject.briar.introduction.IntroduceeManager.SIGNING_LABEL_RESPONSE;
|
||||
import static org.hamcrest.Matchers.array;
|
||||
import static org.hamcrest.Matchers.samePropertyValuesAs;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -266,7 +267,7 @@ public class IntroduceeManagerTest extends BriarTestCase {
|
||||
);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(cryptoComponent).verify(SIGNING_LABEL_RESPONSE, nonce,
|
||||
oneOf(cryptoComponent).verify(SIGNING_LABEL, nonce,
|
||||
introducee2.getAuthor().getPublicKey(), sig);
|
||||
will(returnValue(false));
|
||||
}});
|
||||
@@ -296,7 +297,7 @@ public class IntroduceeManagerTest extends BriarTestCase {
|
||||
state.put(SIGNATURE, sig);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(cryptoComponent).verify(SIGNING_LABEL_RESPONSE, nonce,
|
||||
oneOf(cryptoComponent).verify(SIGNING_LABEL, nonce,
|
||||
publicKeyBytes, sig);
|
||||
will(returnValue(true));
|
||||
}});
|
||||
@@ -330,7 +331,8 @@ public class IntroduceeManagerTest extends BriarTestCase {
|
||||
BdfList.of(publicKeyBytes, ePublicKeyBytes, tp, time));
|
||||
will(returnValue(signBytes));
|
||||
//noinspection unchecked
|
||||
oneOf(cryptoComponent).mac(with(samePropertyValuesAs(macKey)),
|
||||
oneOf(cryptoComponent).mac(with(MAC_LABEL),
|
||||
with(samePropertyValuesAs(macKey)),
|
||||
with(array(equal(signBytes))));
|
||||
will(returnValue(mac));
|
||||
}});
|
||||
@@ -343,14 +345,15 @@ public class IntroduceeManagerTest extends BriarTestCase {
|
||||
BdfList.of(publicKeyBytes, ePublicKeyBytes, tp, time));
|
||||
will(returnValue(signBytes));
|
||||
//noinspection unchecked
|
||||
oneOf(cryptoComponent).mac(with(samePropertyValuesAs(macKey)),
|
||||
oneOf(cryptoComponent).mac(with(MAC_LABEL),
|
||||
with(samePropertyValuesAs(macKey)),
|
||||
with(array(equal(signBytes))));
|
||||
will(returnValue(TestUtils.getRandomBytes(MAC_LENGTH)));
|
||||
}});
|
||||
try {
|
||||
introduceeManager.verifyMac(state);
|
||||
fail();
|
||||
} catch(GeneralSecurityException e) {
|
||||
} catch (GeneralSecurityException e) {
|
||||
// expected
|
||||
}
|
||||
context.assertIsSatisfied();
|
||||
|
||||
@@ -56,21 +56,25 @@ import javax.inject.Inject;
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||
import static org.briarproject.bramble.test.TestPluginConfigModule.TRANSPORT_ID;
|
||||
import static org.briarproject.briar.api.client.MessageQueueManager.QUEUE_STATE_KEY;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.ALICE_MAC_KEY_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.ALICE_NONCE_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.E_PUBLIC_KEY;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_KEY;
|
||||
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.NONCE;
|
||||
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.SHARED_SECRET_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNATURE;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNING_LABEL;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TIME;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TRANSPORT;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
||||
import static org.briarproject.briar.introduction.IntroduceeManager.SIGNING_LABEL_RESPONSE;
|
||||
import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -635,7 +639,7 @@ public class IntroductionIntegrationTest
|
||||
// adapt outgoing message queue to removed message
|
||||
Group g2 = introductionGroupFactory
|
||||
.createIntroductionGroup(contact2From0);
|
||||
decreaseOutgoingMessageCounter(ch, g2.getId(), 1);
|
||||
decreaseOutgoingMessageCounter(ch, g2.getId());
|
||||
|
||||
// allow visitor to modify response
|
||||
boolean earlyAbort = visitor.visit(response);
|
||||
@@ -746,34 +750,33 @@ public class IntroductionIntegrationTest
|
||||
// create keys
|
||||
KeyPair keyPair1 = crypto.generateSignatureKeyPair();
|
||||
KeyPair eKeyPair1 = crypto.generateAgreementKeyPair();
|
||||
byte[] ePublicKeyBytes1 = eKeyPair1.getPublic().getEncoded();
|
||||
KeyPair eKeyPair2 = crypto.generateAgreementKeyPair();
|
||||
byte[] ePublicKeyBytes2 = eKeyPair2.getPublic().getEncoded();
|
||||
|
||||
// Nonce 1
|
||||
SecretKey secretKey =
|
||||
crypto.deriveMasterSecret(ePublicKeyBytes2, eKeyPair1, true);
|
||||
byte[] nonce1 = crypto.deriveSignatureNonce(secretKey, true);
|
||||
SecretKey sharedSecret = crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
|
||||
eKeyPair2.getPublic(), eKeyPair1, true);
|
||||
byte[] nonce1 = crypto.deriveKeyBindingNonce(ALICE_NONCE_LABEL,
|
||||
sharedSecret);
|
||||
|
||||
// Signature 1
|
||||
byte[] sig1 = crypto.sign(SIGNING_LABEL_RESPONSE, nonce1,
|
||||
byte[] sig1 = crypto.sign(SIGNING_LABEL, nonce1,
|
||||
keyPair1.getPrivate().getEncoded());
|
||||
|
||||
// MAC 1
|
||||
SecretKey macKey1 = crypto.deriveMacKey(secretKey, true);
|
||||
SecretKey macKey1 = crypto.deriveKey(ALICE_MAC_KEY_LABEL, sharedSecret);
|
||||
BdfDictionary tp1 = BdfDictionary.of(new BdfEntry("fake", "fake"));
|
||||
long time1 = clock.currentTimeMillis();
|
||||
BdfList toMacList = BdfList.of(keyPair1.getPublic().getEncoded(),
|
||||
ePublicKeyBytes1, tp1, time1);
|
||||
eKeyPair1.getPublic().getEncoded(), tp1, time1);
|
||||
byte[] toMac = clientHelper.toByteArray(toMacList);
|
||||
byte[] mac1 = crypto.mac(macKey1, toMac);
|
||||
byte[] mac1 = crypto.mac(MAC_LABEL, macKey1, toMac);
|
||||
|
||||
// create only relevant part of state for introducee2
|
||||
BdfDictionary state = new BdfDictionary();
|
||||
state.put(PUBLIC_KEY, keyPair1.getPublic().getEncoded());
|
||||
state.put(TRANSPORT, tp1);
|
||||
state.put(TIME, time1);
|
||||
state.put(E_PUBLIC_KEY, ePublicKeyBytes1);
|
||||
state.put(E_PUBLIC_KEY, eKeyPair1.getPublic().getEncoded());
|
||||
state.put(MAC, mac1);
|
||||
state.put(MAC_KEY, macKey1.getBytes());
|
||||
state.put(NONCE, nonce1);
|
||||
@@ -786,16 +789,16 @@ public class IntroductionIntegrationTest
|
||||
// replace ephemeral key pair and recalculate matching keys and nonce
|
||||
KeyPair eKeyPair1f = crypto.generateAgreementKeyPair();
|
||||
byte[] ePublicKeyBytes1f = eKeyPair1f.getPublic().getEncoded();
|
||||
secretKey =
|
||||
crypto.deriveMasterSecret(ePublicKeyBytes2, eKeyPair1f, true);
|
||||
nonce1 = crypto.deriveSignatureNonce(secretKey, true);
|
||||
sharedSecret = crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
|
||||
eKeyPair2.getPublic(), eKeyPair1f, true);
|
||||
nonce1 = crypto.deriveKeyBindingNonce(ALICE_NONCE_LABEL, sharedSecret);
|
||||
|
||||
// recalculate MAC
|
||||
macKey1 = crypto.deriveMacKey(secretKey, true);
|
||||
macKey1 = crypto.deriveKey(ALICE_MAC_KEY_LABEL, sharedSecret);
|
||||
toMacList = BdfList.of(keyPair1.getPublic().getEncoded(),
|
||||
ePublicKeyBytes1f, tp1, time1);
|
||||
toMac = clientHelper.toByteArray(toMacList);
|
||||
mac1 = crypto.mac(macKey1, toMac);
|
||||
mac1 = crypto.mac(MAC_LABEL, macKey1, toMac);
|
||||
|
||||
// update state with faked information
|
||||
state.put(E_PUBLIC_KEY, ePublicKeyBytes1f);
|
||||
@@ -970,12 +973,12 @@ public class IntroductionIntegrationTest
|
||||
|
||||
}
|
||||
|
||||
private void decreaseOutgoingMessageCounter(ClientHelper ch, GroupId g,
|
||||
int num) throws FormatException, DbException {
|
||||
private void decreaseOutgoingMessageCounter(ClientHelper ch, GroupId g)
|
||||
throws FormatException, DbException {
|
||||
BdfDictionary gD = ch.getGroupMetadataAsDictionary(g);
|
||||
LOG.warning(gD.toString());
|
||||
BdfDictionary queue = gD.getDictionary(QUEUE_STATE_KEY);
|
||||
queue.put("nextOut", queue.getLong("nextOut") - num);
|
||||
queue.put("nextOut", queue.getLong("nextOut") - 1);
|
||||
gD.put(QUEUE_STATE_KEY, queue);
|
||||
ch.mergeGroupMetadata(g, gD);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user