mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-22 23:59:54 +01:00
IntroductionCrypto: Create dedicated class to handle introduction related crypto
This commit is contained in:
@@ -10,4 +10,20 @@ public interface IntroductionConstants {
|
|||||||
*/
|
*/
|
||||||
int MAX_REQUEST_MESSAGE_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
|
int MAX_REQUEST_MESSAGE_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
|
||||||
|
|
||||||
|
String LABEL_SESSION_ID = "org.briarproject.briar.introduction/SESSION_ID";
|
||||||
|
|
||||||
|
String LABEL_MASTER_KEY = "org.briarproject.briar.introduction/MASTER_KEY";
|
||||||
|
|
||||||
|
String LABEL_ALICE_MAC_KEY =
|
||||||
|
"org.briarproject.briar.introduction/ALICE_MAC_KEY";
|
||||||
|
|
||||||
|
String LABEL_BOB_MAC_KEY =
|
||||||
|
"org.briarproject.briar.introduction/BOB_MAC_KEY";
|
||||||
|
|
||||||
|
String LABEL_AUTH_MAC = "org.briarproject.briar.introduction/AUTH_MAC";
|
||||||
|
|
||||||
|
String LABEL_AUTH_SIGN = "org.briarproject.briar.introduction/AUTH_SIGN";
|
||||||
|
|
||||||
|
String LABEL_AUTH_NONCE = "org.briarproject.briar.introduction/AUTH_NONCE";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package org.briarproject.briar.introduction2;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
|
import org.briarproject.briar.api.client.SessionId;
|
||||||
|
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
|
||||||
|
interface IntroductionCrypto {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link SessionId} based on the introducer
|
||||||
|
* and the two introducees.
|
||||||
|
*
|
||||||
|
* Note: The roles of Alice and Bob can be switched.
|
||||||
|
*/
|
||||||
|
SessionId getSessionId(Author introducer, Author alice, Author bob);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the first author is indeed alice
|
||||||
|
*/
|
||||||
|
boolean isAlice(AuthorId alice, AuthorId bob);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an agreement key pair.
|
||||||
|
*/
|
||||||
|
KeyPair generateKeyPair();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives a session master key for Alice or Bob.
|
||||||
|
*
|
||||||
|
* @param alice true if the session owner is Alice
|
||||||
|
* @return The secret master key
|
||||||
|
*/
|
||||||
|
SecretKey deriveMasterKey(IntroduceeSession s, boolean alice)
|
||||||
|
throws GeneralSecurityException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives a MAC key from the session's master key for Alice or Bob.
|
||||||
|
*
|
||||||
|
* @param masterKey The key returned by {@link #deriveMasterKey(IntroduceeSession, boolean)}
|
||||||
|
* @param alice true for Alice's MAC key, false for Bob's
|
||||||
|
* @return The MAC key
|
||||||
|
*/
|
||||||
|
SecretKey deriveMacKey(SecretKey masterKey, boolean alice);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a MAC that covers both introducee's ephemeral public keys and
|
||||||
|
* transport properties.
|
||||||
|
*/
|
||||||
|
byte[] mac(SecretKey macKey, IntroduceeSession s, AuthorId localAuthorId,
|
||||||
|
boolean alice) throws FormatException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies a received MAC
|
||||||
|
*
|
||||||
|
* @param mac The MAC to verify
|
||||||
|
* as returned by {@link #deriveMasterKey(IntroduceeSession, boolean)}
|
||||||
|
* @throws GeneralSecurityException if the verification fails
|
||||||
|
*/
|
||||||
|
void verifyMac(byte[] mac, IntroduceeSession s, AuthorId localAuthorId)
|
||||||
|
throws GeneralSecurityException, FormatException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signs a nonce derived from the macKey
|
||||||
|
* with the local introducee's identity private key.
|
||||||
|
*
|
||||||
|
* @param macKey The corresponding MAC key for the signer's role
|
||||||
|
* @param privateKey The identity private key
|
||||||
|
* (from {@link LocalAuthor#getPrivateKey()})
|
||||||
|
* @return The signature as a byte array
|
||||||
|
*/
|
||||||
|
byte[] sign(SecretKey macKey, byte[] privateKey)
|
||||||
|
throws GeneralSecurityException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the signature on a corresponding MAC key.
|
||||||
|
*
|
||||||
|
* @throws GeneralSecurityException if the signature is invalid
|
||||||
|
*/
|
||||||
|
void verifySignature(byte[] signature, IntroduceeSession s,
|
||||||
|
AuthorId localAuthorId) throws GeneralSecurityException;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
package org.briarproject.briar.introduction2;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Bytes;
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
|
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.PrivateKey;
|
||||||
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
import org.briarproject.briar.api.client.SessionId;
|
||||||
|
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_ALICE_MAC_KEY;
|
||||||
|
import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_AUTH_MAC;
|
||||||
|
import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_AUTH_NONCE;
|
||||||
|
import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_AUTH_SIGN;
|
||||||
|
import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_BOB_MAC_KEY;
|
||||||
|
import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_MASTER_KEY;
|
||||||
|
import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_SESSION_ID;
|
||||||
|
import static org.briarproject.briar.api.introduction2.IntroductionManager.CLIENT_VERSION;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
class IntroductionCryptoImpl implements IntroductionCrypto {
|
||||||
|
|
||||||
|
private final CryptoComponent crypto;
|
||||||
|
private final ClientHelper clientHelper;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
IntroductionCryptoImpl(
|
||||||
|
CryptoComponent crypto,
|
||||||
|
ClientHelper clientHelper) {
|
||||||
|
this.crypto = crypto;
|
||||||
|
this.clientHelper = clientHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SessionId getSessionId(Author introducer, Author alice,
|
||||||
|
Author bob) {
|
||||||
|
boolean isAlice = isAlice(alice.getId(), bob.getId());
|
||||||
|
byte[] hash = crypto.hash(
|
||||||
|
LABEL_SESSION_ID,
|
||||||
|
introducer.getId().getBytes(),
|
||||||
|
isAlice ? alice.getId().getBytes() : bob.getId().getBytes(),
|
||||||
|
isAlice ? bob.getId().getBytes() : alice.getId().getBytes()
|
||||||
|
);
|
||||||
|
return new SessionId(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyPair generateKeyPair() {
|
||||||
|
return crypto.generateAgreementKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAlice(AuthorId alice, AuthorId bob) {
|
||||||
|
byte[] a = alice.getBytes();
|
||||||
|
byte[] b = bob.getBytes();
|
||||||
|
return Bytes.COMPARATOR.compare(new Bytes(a), new Bytes(b)) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
public SecretKey deriveMasterKey(IntroduceeSession s, boolean alice)
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
return deriveMasterKey(s.getEphemeralPublicKey(),
|
||||||
|
s.getEphemeralPrivateKey(), s.getRemotePublicKey(), alice);
|
||||||
|
}
|
||||||
|
|
||||||
|
SecretKey deriveMasterKey(byte[] publicKey, byte[] privateKey,
|
||||||
|
byte[] remotePublicKey, boolean alice)
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
KeyParser kp = crypto.getAgreementKeyParser();
|
||||||
|
PublicKey remoteEphemeralPublicKey = kp.parsePublicKey(remotePublicKey);
|
||||||
|
PublicKey ephemeralPublicKey = kp.parsePublicKey(publicKey);
|
||||||
|
PrivateKey ephemeralPrivateKey = kp.parsePrivateKey(privateKey);
|
||||||
|
KeyPair keyPair = new KeyPair(ephemeralPublicKey, ephemeralPrivateKey);
|
||||||
|
return crypto.deriveSharedSecret(
|
||||||
|
LABEL_MASTER_KEY,
|
||||||
|
remoteEphemeralPublicKey,
|
||||||
|
keyPair,
|
||||||
|
new byte[] {CLIENT_VERSION},
|
||||||
|
alice ? publicKey : remotePublicKey,
|
||||||
|
alice ? remotePublicKey : publicKey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SecretKey deriveMacKey(SecretKey masterKey, boolean alice) {
|
||||||
|
return crypto.deriveKey(
|
||||||
|
alice ? LABEL_ALICE_MAC_KEY : LABEL_BOB_MAC_KEY,
|
||||||
|
masterKey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
public byte[] mac(SecretKey macKey, IntroduceeSession s,
|
||||||
|
AuthorId localAuthorId, boolean alice) throws FormatException {
|
||||||
|
return mac(macKey, s.getIntroducer().getId(), localAuthorId,
|
||||||
|
s.getRemoteAuthor().getId(), s.getAcceptTimestamp(),
|
||||||
|
s.getRemoteAcceptTimestamp(), s.getEphemeralPublicKey(),
|
||||||
|
s.getRemotePublicKey(), s.getTransportProperties(),
|
||||||
|
s.getRemoteTransportProperties(), alice);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] mac(SecretKey macKey, AuthorId introducerId,
|
||||||
|
AuthorId localAuthorId, AuthorId remoteAuthorId,
|
||||||
|
long acceptTimestamp, long remoteAcceptTimestamp,
|
||||||
|
byte[] ephemeralPublicKey, byte[] remoteEphemeralPublicKey,
|
||||||
|
Map<TransportId, TransportProperties> transportProperties,
|
||||||
|
Map<TransportId, TransportProperties> remoteTransportProperties,
|
||||||
|
boolean alice) throws FormatException {
|
||||||
|
BdfList localInfo = BdfList.of(
|
||||||
|
localAuthorId,
|
||||||
|
acceptTimestamp,
|
||||||
|
ephemeralPublicKey,
|
||||||
|
clientHelper.toDictionary(transportProperties)
|
||||||
|
);
|
||||||
|
BdfList remoteInfo = BdfList.of(
|
||||||
|
remoteAuthorId,
|
||||||
|
remoteAcceptTimestamp,
|
||||||
|
remoteEphemeralPublicKey,
|
||||||
|
clientHelper.toDictionary(remoteTransportProperties)
|
||||||
|
);
|
||||||
|
BdfList macList = BdfList.of(
|
||||||
|
introducerId,
|
||||||
|
alice ? localInfo : remoteInfo,
|
||||||
|
alice ? remoteInfo : localInfo
|
||||||
|
);
|
||||||
|
return crypto.mac(
|
||||||
|
LABEL_AUTH_MAC,
|
||||||
|
macKey,
|
||||||
|
clientHelper.toByteArray(macList)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
public void verifyMac(byte[] mac, IntroduceeSession s,
|
||||||
|
AuthorId localAuthorId)
|
||||||
|
throws GeneralSecurityException, FormatException {
|
||||||
|
boolean alice = isAlice(localAuthorId, s.getRemoteAuthor().getId());
|
||||||
|
verifyMac(mac, new SecretKey(s.getMasterKey()),
|
||||||
|
s.getIntroducer().getId(), localAuthorId,
|
||||||
|
s.getRemoteAuthor().getId(), s.getAcceptTimestamp(),
|
||||||
|
s.getRemoteAcceptTimestamp(), s.getEphemeralPublicKey(),
|
||||||
|
s.getRemotePublicKey(), s.getTransportProperties(),
|
||||||
|
s.getRemoteTransportProperties(), !alice);
|
||||||
|
}
|
||||||
|
|
||||||
|
void verifyMac(byte[] mac, SecretKey masterKey,
|
||||||
|
AuthorId introducerId, AuthorId localAuthorId,
|
||||||
|
AuthorId remoteAuthorId, long acceptTimestamp,
|
||||||
|
long remoteAcceptTimestamp, byte[] ephemeralPublicKey,
|
||||||
|
byte[] remoteEphemeralPublicKey,
|
||||||
|
Map<TransportId, TransportProperties> transportProperties,
|
||||||
|
Map<TransportId, TransportProperties> remoteTransportProperties,
|
||||||
|
boolean alice) throws GeneralSecurityException, FormatException {
|
||||||
|
SecretKey macKey = deriveMacKey(masterKey, alice);
|
||||||
|
byte[] calculatedMac =
|
||||||
|
mac(macKey, introducerId, localAuthorId, remoteAuthorId,
|
||||||
|
acceptTimestamp, remoteAcceptTimestamp,
|
||||||
|
ephemeralPublicKey, remoteEphemeralPublicKey,
|
||||||
|
transportProperties, remoteTransportProperties, !alice);
|
||||||
|
if (!Arrays.equals(mac, calculatedMac)) {
|
||||||
|
throw new GeneralSecurityException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] sign(SecretKey macKey, byte[] privateKey)
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
return crypto.sign(
|
||||||
|
LABEL_AUTH_SIGN,
|
||||||
|
getNonce(macKey),
|
||||||
|
privateKey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
public void verifySignature(byte[] signature, IntroduceeSession s,
|
||||||
|
AuthorId localAuthorId) throws GeneralSecurityException {
|
||||||
|
boolean alice = isAlice(s.getRemoteAuthor().getId(), localAuthorId);
|
||||||
|
SecretKey macKey = deriveMacKey(new SecretKey(s.getMasterKey()), alice);
|
||||||
|
verifySignature(macKey, s.getRemoteAuthor().getPublicKey(), signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
void verifySignature(SecretKey macKey, byte[] publicKey,
|
||||||
|
byte[] signature) throws GeneralSecurityException {
|
||||||
|
byte[] nonce = getNonce(macKey);
|
||||||
|
if (!crypto.verify(LABEL_AUTH_SIGN, nonce, publicKey, signature)) {
|
||||||
|
throw new GeneralSecurityException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getNonce(SecretKey macKey) {
|
||||||
|
return crypto.mac(LABEL_AUTH_NONCE, macKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
package org.briarproject.briar.introduction2;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
|
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.identity.Author;
|
||||||
|
import org.briarproject.bramble.api.identity.AuthorFactory;
|
||||||
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.briarproject.briar.api.client.SessionId;
|
||||||
|
import org.briarproject.briar.test.BriarIntegrationTestComponent;
|
||||||
|
import org.briarproject.briar.test.DaggerBriarIntegrationTestComponent;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getTransportPropertiesMap;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class IntroductionCryptoImplTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ClientHelper clientHelper;
|
||||||
|
@Inject
|
||||||
|
AuthorFactory authorFactory;
|
||||||
|
@Inject
|
||||||
|
CryptoComponent cryptoComponent;
|
||||||
|
|
||||||
|
private final IntroductionCryptoImpl crypto;
|
||||||
|
|
||||||
|
private final Author introducer;
|
||||||
|
private final LocalAuthor alice, bob;
|
||||||
|
private final long aliceAcceptTimestamp = 42L;
|
||||||
|
private final long bobAcceptTimestamp = 1337L;
|
||||||
|
private final SecretKey masterKey =
|
||||||
|
new SecretKey(getRandomBytes(SecretKey.LENGTH));
|
||||||
|
private final KeyPair aliceEphemeral, bobEphemeral;
|
||||||
|
private final Map<TransportId, TransportProperties> aliceTransport =
|
||||||
|
getTransportPropertiesMap(3);
|
||||||
|
private final Map<TransportId, TransportProperties> bobTransport =
|
||||||
|
getTransportPropertiesMap(3);
|
||||||
|
|
||||||
|
public IntroductionCryptoImplTest() {
|
||||||
|
BriarIntegrationTestComponent component =
|
||||||
|
DaggerBriarIntegrationTestComponent.builder().build();
|
||||||
|
component.inject(this);
|
||||||
|
crypto = new IntroductionCryptoImpl(cryptoComponent, clientHelper);
|
||||||
|
|
||||||
|
// create actual deterministic authors for testing
|
||||||
|
introducer = authorFactory
|
||||||
|
.createAuthor("Introducer", new byte[] {0x1, 0x2, 0x3});
|
||||||
|
alice = authorFactory.createLocalAuthor("Alice",
|
||||||
|
fromHexString(
|
||||||
|
"A626F080C94771698F86B4B4094C4F560904B53398805AE02BA2343F1829187A"),
|
||||||
|
fromHexString(
|
||||||
|
"60F010187AF91ACA15141E8C811EC8E79C7CAA6461C21A852BB03066C89B0A70"));
|
||||||
|
bob = authorFactory.createLocalAuthor("Bob",
|
||||||
|
fromHexString(
|
||||||
|
"A0D0FED1CE4674D8B6441AD0A664E41BF60D489F35DA11F52AF923540848546F"),
|
||||||
|
fromHexString(
|
||||||
|
"20B25BE7E999F68FE07189449E91984FA79121DBFF28A651669A3CF512D6A758"));
|
||||||
|
aliceEphemeral = crypto.generateKeyPair();
|
||||||
|
bobEphemeral = crypto.generateKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSessionId() {
|
||||||
|
SessionId s1 = crypto.getSessionId(introducer, alice, bob);
|
||||||
|
SessionId s2 = crypto.getSessionId(introducer, bob, alice);
|
||||||
|
assertEquals(s1, s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAlice() {
|
||||||
|
assertTrue(crypto.isAlice(alice.getId(), bob.getId()));
|
||||||
|
assertFalse(crypto.isAlice(bob.getId(), alice.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeriveMasterKey() throws Exception {
|
||||||
|
SecretKey aliceMasterKey = crypto.deriveMasterKey(alice.getPublicKey(),
|
||||||
|
alice.getPrivateKey(), bob.getPublicKey(), true);
|
||||||
|
SecretKey bobMasterKey = crypto.deriveMasterKey(bob.getPublicKey(),
|
||||||
|
bob.getPrivateKey(), alice.getPublicKey(), false);
|
||||||
|
assertArrayEquals(aliceMasterKey.getBytes(), bobMasterKey.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAliceMac() throws Exception {
|
||||||
|
SecretKey aliceMacKey = crypto.deriveMacKey(masterKey, true);
|
||||||
|
byte[] aliceMac =
|
||||||
|
crypto.mac(aliceMacKey, introducer.getId(), alice.getId(),
|
||||||
|
bob.getId(), aliceAcceptTimestamp, bobAcceptTimestamp,
|
||||||
|
aliceEphemeral.getPublic().getEncoded(),
|
||||||
|
bobEphemeral.getPublic().getEncoded(), aliceTransport,
|
||||||
|
bobTransport, true);
|
||||||
|
|
||||||
|
crypto.verifyMac(aliceMac, masterKey, introducer.getId(), bob.getId(),
|
||||||
|
alice.getId(), bobAcceptTimestamp, aliceAcceptTimestamp,
|
||||||
|
bobEphemeral.getPublic().getEncoded(),
|
||||||
|
aliceEphemeral.getPublic().getEncoded(), bobTransport,
|
||||||
|
aliceTransport, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBobMac() throws Exception {
|
||||||
|
SecretKey bobMacKey = crypto.deriveMacKey(masterKey, false);
|
||||||
|
byte[] bobMac =
|
||||||
|
crypto.mac(bobMacKey, introducer.getId(), bob.getId(),
|
||||||
|
alice.getId(), bobAcceptTimestamp, aliceAcceptTimestamp,
|
||||||
|
bobEphemeral.getPublic().getEncoded(),
|
||||||
|
aliceEphemeral.getPublic().getEncoded(), bobTransport,
|
||||||
|
aliceTransport, false);
|
||||||
|
|
||||||
|
crypto.verifyMac(bobMac, masterKey, introducer.getId(), alice.getId(),
|
||||||
|
bob.getId(), aliceAcceptTimestamp, bobAcceptTimestamp,
|
||||||
|
aliceEphemeral.getPublic().getEncoded(),
|
||||||
|
bobEphemeral.getPublic().getEncoded(), aliceTransport,
|
||||||
|
bobTransport, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSign() throws Exception {
|
||||||
|
KeyPair keyPair = cryptoComponent.generateSignatureKeyPair();
|
||||||
|
SecretKey macKey = crypto.deriveMacKey(masterKey, true);
|
||||||
|
byte[] signature =
|
||||||
|
crypto.sign(macKey, keyPair.getPrivate().getEncoded());
|
||||||
|
crypto.verifySignature(macKey, keyPair.getPublic().getEncoded(),
|
||||||
|
signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package org.briarproject.briar.introduction2;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.UniqueId;
|
||||||
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
|
import org.briarproject.briar.api.client.SessionId;
|
||||||
|
import org.jmock.Expectations;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_SESSION_ID;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class IntroductionCryptoTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
|
private final CryptoComponent cryptoComponent =
|
||||||
|
context.mock(CryptoComponent.class);
|
||||||
|
private final ClientHelper clientHelper = context.mock(ClientHelper.class);
|
||||||
|
|
||||||
|
private final IntroductionCrypto crypto =
|
||||||
|
new IntroductionCryptoImpl(cryptoComponent, clientHelper);
|
||||||
|
|
||||||
|
private final Author introducer = getAuthor();
|
||||||
|
private final Author alice = getAuthor(), bob = getAuthor();
|
||||||
|
private final byte[] hash = getRandomBytes(UniqueId.LENGTH);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSessionId() {
|
||||||
|
boolean isAlice = crypto.isAlice(alice.getId(), bob.getId());
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(cryptoComponent).hash(
|
||||||
|
LABEL_SESSION_ID,
|
||||||
|
introducer.getId().getBytes(),
|
||||||
|
isAlice ? alice.getId().getBytes() : bob.getId().getBytes(),
|
||||||
|
isAlice ? bob.getId().getBytes() : alice.getId().getBytes()
|
||||||
|
);
|
||||||
|
will(returnValue(hash));
|
||||||
|
}});
|
||||||
|
SessionId sessionId = crypto.getSessionId(introducer, alice, bob);
|
||||||
|
assertEquals(new SessionId(hash), sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -37,6 +37,7 @@ import org.briarproject.briar.blog.BlogModule;
|
|||||||
import org.briarproject.briar.client.BriarClientModule;
|
import org.briarproject.briar.client.BriarClientModule;
|
||||||
import org.briarproject.briar.forum.ForumModule;
|
import org.briarproject.briar.forum.ForumModule;
|
||||||
import org.briarproject.briar.introduction.IntroductionModule;
|
import org.briarproject.briar.introduction.IntroductionModule;
|
||||||
|
import org.briarproject.briar.introduction2.IntroductionCryptoImplTest;
|
||||||
import org.briarproject.briar.introduction2.MessageEncoderParserIntegrationTest;
|
import org.briarproject.briar.introduction2.MessageEncoderParserIntegrationTest;
|
||||||
import org.briarproject.briar.introduction2.SessionEncoderParserIntegrationTest;
|
import org.briarproject.briar.introduction2.SessionEncoderParserIntegrationTest;
|
||||||
import org.briarproject.briar.messaging.MessagingModule;
|
import org.briarproject.briar.messaging.MessagingModule;
|
||||||
@@ -80,6 +81,7 @@ public interface BriarIntegrationTestComponent {
|
|||||||
|
|
||||||
void inject(MessageEncoderParserIntegrationTest init);
|
void inject(MessageEncoderParserIntegrationTest init);
|
||||||
void inject(SessionEncoderParserIntegrationTest init);
|
void inject(SessionEncoderParserIntegrationTest init);
|
||||||
|
void inject(IntroductionCryptoImplTest init);
|
||||||
|
|
||||||
void inject(BlogModule.EagerSingletons init);
|
void inject(BlogModule.EagerSingletons init);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user