Derive handshake root key when adding a pending contact.

This commit is contained in:
akwizgran
2019-05-30 15:48:26 +01:00
parent 9b4f60088f
commit 810d45d6b9
6 changed files with 79 additions and 19 deletions

View File

@@ -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
*/

View File

@@ -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 {
* <p/>
* {@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<TransportId, KeySetId> 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.

View File

@@ -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<ContactHook> 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;
}

View File

@@ -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);

View File

@@ -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<TransportId, TransportKeyManager> 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<TransportId, KeySetId> 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<TransportId, KeySetId> ids = new HashMap<>();
for (Entry<TransportId, TransportKeyManager> 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;
}

View File

@@ -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<TransportId, KeySetId> ids = keyManager.addPendingContact(txn,
pendingContactId, secretKey, alice);
pendingContact, ourKeyPair);
assertEquals(singletonMap(transportId, keySetId), ids);
}