Commit 9f7021ac authored by akwizgran's avatar akwizgran

Include namespaced labels in crypto operations.

parent ddea031c
......@@ -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.
*/
SecretKey deriveHeaderKey(SecretKey master, boolean alice);
/**
* Derives a message authentication code 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 deriveMacKey(SecretKey master, boolean alice);
SecretKey deriveKey(String label, SecretKey k, byte[]... inputs);
/**
* 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.
* 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
*/
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));
}
@Override
public SecretKey deriveMacKey(SecretKey master, boolean alice) {
return new SecretKey(macKdf(master, alice ? A_MAC : B_MAC));
public SecretKey deriveKey(String label, SecretKey k,
byte[]... inputs) {
return new SecretKey(macKdf(label, k, inputs));
}
@Override
public byte[] deriveSignatureNonce(SecretKey master,
boolean alice) {
return macKdf(master, alice ? A_SIG_NONCE : B_SIG_NONCE);
public byte[] deriveKeyBindingNonce(String label, SecretKey k) {
return macKdf(label, k);
}
@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 {