diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java
index a58645792..7439c0ec8 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java
@@ -11,6 +11,12 @@ import java.security.GeneralSecurityException;
*/
public interface TransportCrypto {
+ /**
+ * Returns true if the local peer is Alice.
+ */
+ boolean isAlice(PublicKey theirHandshakePublicKey,
+ KeyPair ourHandshakeKeyPair);
+
/**
* Derives the static master key shared with a contact or pending contact.
*/
@@ -19,6 +25,7 @@ public interface TransportCrypto {
/**
* Derives the handshake mode root key from the static master key.
+ *
* @param pendingContact Whether the static master key is shared with a
* pending contact or a contact
*/
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java
index 75ae88d86..898a45e5f 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java
@@ -1,12 +1,15 @@
package org.briarproject.bramble.api.transport;
import org.briarproject.bramble.api.contact.ContactId;
+import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId;
+import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.plugin.TransportId;
+import java.security.GeneralSecurityException;
import java.util.Map;
import javax.annotation.Nullable;
@@ -53,12 +56,10 @@ public interface KeyManager {
*
* {@link StreamContext StreamContexts} for the pending contact can be
* created after this method has returned.
- *
- * @param alice True if the local party is Alice
*/
Map addPendingContact(Transaction txn,
- PendingContactId p, SecretKey rootKey, boolean alice)
- throws DbException;
+ PendingContact p, KeyPair ourKeyPair)
+ throws DbException, GeneralSecurityException;
/**
* Marks the given transport keys as usable for outgoing streams.
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java
index 7bea2930e..30c3b3c42 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java
@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.contact.PendingContactState;
+import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
@@ -21,6 +22,7 @@ import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.KeyManager;
+import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -51,6 +53,7 @@ class ContactManagerImpl implements ContactManager {
private final KeyManager keyManager;
private final IdentityManager identityManager;
private final PendingContactFactory pendingContactFactory;
+
private final List hooks;
@Inject
@@ -123,7 +126,15 @@ class ContactManagerImpl implements ContactManager {
throws DbException, FormatException {
PendingContact p =
pendingContactFactory.createPendingContact(link, alias);
- db.transaction(false, txn -> db.addPendingContact(txn, p));
+ db.transaction(false, txn -> {
+ db.addPendingContact(txn, p);
+ KeyPair ourKeyPair = identityManager.getHandshakeKeys(txn);
+ try {
+ keyManager.addPendingContact(txn, p, ourKeyPair);
+ } catch (GeneralSecurityException e) {
+ throw new AssertionError();
+ }
+ });
return p;
}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java
index aa8d4d665..2bf4c7b21 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java
@@ -48,6 +48,14 @@ class TransportCryptoImpl implements TransportCrypto {
this.crypto = crypto;
}
+ @Override
+ public boolean isAlice(PublicKey theirHandshakePublicKey,
+ KeyPair ourHandshakeKeyPair) {
+ byte[] theirPublic = theirHandshakePublicKey.getEncoded();
+ byte[] ourPublic = ourHandshakeKeyPair.getPublic().getEncoded();
+ return compare(ourPublic, theirPublic) < 0;
+ }
+
@Override
public SecretKey deriveStaticMasterKey(PublicKey theirHandshakePublicKey,
KeyPair ourHandshakeKeyPair) throws GeneralSecurityException {
@@ -55,8 +63,8 @@ class TransportCryptoImpl implements TransportCrypto {
byte[] ourPublic = ourHandshakeKeyPair.getPublic().getEncoded();
boolean alice = compare(ourPublic, theirPublic) < 0;
byte[][] inputs = {
- alice ? ourPublic : theirPublic,
- alice ? theirPublic : ourPublic
+ alice ? ourPublic : theirPublic,
+ alice ? theirPublic : ourPublic
};
return crypto.deriveSharedSecret(STATIC_MASTER_KEY_LABEL,
theirHandshakePublicKey, ourHandshakeKeyPair, inputs);
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java
index a508c2e83..a979e10b5 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java
@@ -1,9 +1,12 @@
package org.briarproject.bramble.transport;
import org.briarproject.bramble.api.contact.ContactId;
+import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
+import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.SecretKey;
+import org.briarproject.bramble.api.crypto.TransportCrypto;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
@@ -21,6 +24,7 @@ import org.briarproject.bramble.api.transport.KeyManager;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.StreamContext;
+import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@@ -46,17 +50,22 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
private final Executor dbExecutor;
private final PluginConfig pluginConfig;
private final TransportKeyManagerFactory transportKeyManagerFactory;
+ private final TransportCrypto transportCrypto;
+
private final ConcurrentHashMap managers;
private final AtomicBoolean used = new AtomicBoolean(false);
@Inject
- KeyManagerImpl(DatabaseComponent db, @DatabaseExecutor Executor dbExecutor,
+ KeyManagerImpl(DatabaseComponent db,
+ @DatabaseExecutor Executor dbExecutor,
PluginConfig pluginConfig,
- TransportKeyManagerFactory transportKeyManagerFactory) {
+ TransportKeyManagerFactory transportKeyManagerFactory,
+ TransportCrypto transportCrypto) {
this.db = db;
this.dbExecutor = dbExecutor;
this.pluginConfig = pluginConfig;
this.transportKeyManagerFactory = transportKeyManagerFactory;
+ this.transportCrypto = transportCrypto;
managers = new ConcurrentHashMap<>();
}
@@ -118,13 +127,18 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
@Override
public Map addPendingContact(Transaction txn,
- PendingContactId p, SecretKey rootKey, boolean alice)
- throws DbException {
+ PendingContact p, KeyPair ourKeyPair)
+ throws DbException, GeneralSecurityException {
+ SecretKey staticMasterKey = transportCrypto
+ .deriveStaticMasterKey(p.getPublicKey(), ourKeyPair);
+ SecretKey rootKey =
+ transportCrypto.deriveHandshakeRootKey(staticMasterKey, true);
+ boolean alice = transportCrypto.isAlice(p.getPublicKey(), ourKeyPair);
Map ids = new HashMap<>();
for (Entry e : managers.entrySet()) {
TransportId t = e.getKey();
TransportKeyManager m = e.getValue();
- ids.put(t, m.addPendingContact(txn, p, rootKey, alice));
+ ids.put(t, m.addPendingContact(txn, p.getId(), rootKey, alice));
}
return ids;
}
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/transport/KeyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/transport/KeyManagerImplTest.java
index 0220c358b..95c03a3fd 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/transport/KeyManagerImplTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/transport/KeyManagerImplTest.java
@@ -1,9 +1,12 @@
package org.briarproject.bramble.transport;
import org.briarproject.bramble.api.contact.ContactId;
+import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
+import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.SecretKey;
+import org.briarproject.bramble.api.crypto.TransportCrypto;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.plugin.PluginConfig;
@@ -25,9 +28,11 @@ import java.util.Random;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
+import static org.briarproject.bramble.test.TestUtils.getAgreementPrivateKey;
+import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey;
import static org.briarproject.bramble.test.TestUtils.getContactId;
+import static org.briarproject.bramble.test.TestUtils.getPendingContact;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
-import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTransportId;
import static org.junit.Assert.assertEquals;
@@ -41,12 +46,14 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
context.mock(TransportKeyManagerFactory.class);
private final TransportKeyManager transportKeyManager =
context.mock(TransportKeyManager.class);
+ private final TransportCrypto transportCrypto =
+ context.mock(TransportCrypto.class);
private final DeterministicExecutor executor = new DeterministicExecutor();
private final Transaction txn = new Transaction(null, false);
private final ContactId contactId = getContactId();
- private final PendingContactId pendingContactId =
- new PendingContactId(getRandomId());
+ private final PendingContact pendingContact = getPendingContact();
+ private final PendingContactId pendingContactId = pendingContact.getId();
private final KeySetId keySetId = new KeySetId(345);
private final TransportId transportId = getTransportId();
private final TransportId unknownTransportId = getTransportId();
@@ -60,7 +67,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
private final Random random = new Random();
private final KeyManagerImpl keyManager = new KeyManagerImpl(db, executor,
- pluginConfig, transportKeyManagerFactory);
+ pluginConfig, transportKeyManagerFactory, transportCrypto);
@Before
public void testStartService() throws Exception {
@@ -126,17 +133,29 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
@Test
public void testAddPendingContact() throws Exception {
- SecretKey secretKey = getSecretKey();
+ KeyPair ourKeyPair =
+ new KeyPair(getAgreementPublicKey(), getAgreementPrivateKey());
+ SecretKey staticMasterKey = getSecretKey();
+ SecretKey rootKey = getSecretKey();
boolean alice = random.nextBoolean();
context.checking(new Expectations() {{
+ oneOf(transportCrypto).deriveStaticMasterKey(
+ pendingContact.getPublicKey(), ourKeyPair);
+ will(returnValue(staticMasterKey));
+ oneOf(transportCrypto)
+ .deriveHandshakeRootKey(staticMasterKey, true);
+ will(returnValue(rootKey));
+ oneOf(transportCrypto).isAlice(pendingContact.getPublicKey(),
+ ourKeyPair);
+ will(returnValue(alice));
oneOf(transportKeyManager).addPendingContact(txn, pendingContactId,
- secretKey, alice);
+ rootKey, alice);
will(returnValue(keySetId));
}});
Map ids = keyManager.addPendingContact(txn,
- pendingContactId, secretKey, alice);
+ pendingContact, ourKeyPair);
assertEquals(singletonMap(transportId, keySetId), ids);
}