From 7dc4dc566f4078ac10b0cc591369cb4637c3b2a8 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 1 May 2019 09:43:10 +0100 Subject: [PATCH] Merge handshake and transport keys. --- .../bramble/api/crypto/TransportCrypto.java | 25 +- .../bramble/api/db/DatabaseComponent.java | 79 +-- .../api/transport/AbstractTransportKeys.java | 57 -- .../api/transport/HandshakeKeySet.java | 70 --- .../bramble/api/transport/HandshakeKeys.java | 36 -- .../bramble/api/transport/IncomingKeys.java | 4 +- .../bramble/api/transport/KeyManager.java | 4 +- .../{HandshakeKeySetId.java => KeySetId.java} | 12 +- .../bramble/api/transport/OutgoingKeys.java | 4 +- .../api/transport/TransportKeySet.java | 24 +- .../api/transport/TransportKeySetId.java | 38 -- .../bramble/api/transport/TransportKeys.java | 96 +++- .../bramble/crypto/TransportCryptoImpl.java | 68 +-- .../org/briarproject/bramble/db/Database.java | 73 +-- .../bramble/db/DatabaseComponentImpl.java | 111 +--- .../briarproject/bramble/db/JdbcDatabase.java | 496 ++++-------------- .../bramble/db/Migration43_44.java | 58 ++ .../bramble/transport/KeyManagerImpl.java | 12 +- .../bramble/transport/MutableKeySet.java | 8 +- .../transport/TransportKeyManager.java | 9 +- .../transport/TransportKeyManagerImpl.java | 34 +- .../crypto/HandshakeKeyDerivationTest.java | 167 ------ .../crypto/KeyDerivationTestUtils.java | 45 -- .../crypto/TransportKeyDerivationTest.java | 257 +++++++-- .../bramble/db/DatabaseComponentImplTest.java | 80 ++- .../bramble/db/JdbcDatabaseTest.java | 171 +++--- .../bramble/transport/KeyManagerImplTest.java | 8 +- .../TransportKeyManagerImplTest.java | 41 +- .../IntroduceeProtocolEngine.java | 4 +- .../briar/introduction/IntroduceeSession.java | 11 +- .../introduction/SessionEncoderImpl.java | 7 +- .../briar/introduction/SessionParserImpl.java | 10 +- .../SessionEncoderParserIntegrationTest.java | 11 +- 33 files changed, 788 insertions(+), 1342 deletions(-) delete mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/transport/AbstractTransportKeys.java delete mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySet.java delete mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeys.java rename bramble-api/src/main/java/org/briarproject/bramble/api/transport/{HandshakeKeySetId.java => KeySetId.java} (56%) delete mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySetId.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/db/Migration43_44.java delete mode 100644 bramble-core/src/test/java/org/briarproject/bramble/crypto/HandshakeKeyDerivationTest.java delete mode 100644 bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTestUtils.java 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 a77f46157..6db16f7d5 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 @@ -1,7 +1,6 @@ package org.briarproject.bramble.api.crypto; import org.briarproject.bramble.api.plugin.TransportId; -import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.TransportKeys; /** @@ -11,35 +10,29 @@ import org.briarproject.bramble.api.transport.TransportKeys; public interface TransportCrypto { /** - * Derives initial transport keys for the given transport in the given - * time period from the given root key. + * Derives initial rotation mode transport keys for the given transport in + * the given time period from the given root key. * - * @param alice whether the keys are for use by Alice or Bob. - * @param active whether the keys are usable for outgoing streams. + * @param alice Whether the keys are for use by Alice or Bob + * @param active Whether the keys are usable for outgoing streams */ - TransportKeys deriveTransportKeys(TransportId t, SecretKey rootKey, + TransportKeys deriveRotationKeys(TransportId t, SecretKey rootKey, long timePeriod, boolean alice, boolean active); - /** - * Rotates the given transport keys to the given time period. If the keys - * are for the given period or any later period they are not rotated. - */ - TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod); - /** * Derives handshake keys for the given transport in the given time period * from the given root key. * - * @param alice whether the keys are for use by Alice or Bob. + * @param alice Whether the keys are for use by Alice or Bob */ - HandshakeKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey, + TransportKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey, long timePeriod, boolean alice); /** - * Updates the given handshake keys to the given time period. If the keys + * Updates the given transport keys to the given time period. If the keys * are for the given period or any later period they are not updated. */ - HandshakeKeys updateHandshakeKeys(HandshakeKeys k, long timePeriod); + TransportKeys updateTransportKeys(TransportKeys k, long timePeriod); /** * Encodes the pseudo-random tag that is used to recognise a stream. diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java index 3cbe58c87..2a899e403 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java @@ -22,11 +22,8 @@ import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.validation.MessageState; -import org.briarproject.bramble.api.transport.HandshakeKeySet; -import org.briarproject.bramble.api.transport.HandshakeKeySetId; -import org.briarproject.bramble.api.transport.HandshakeKeys; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.TransportKeySet; -import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import java.util.Collection; @@ -113,20 +110,6 @@ public interface DatabaseComponent { */ void addGroup(Transaction txn, Group g) throws DbException; - /** - * Stores the given handshake keys for the given contact and returns a - * key set ID. - */ - HandshakeKeySetId addHandshakeKeys(Transaction txn, ContactId c, - HandshakeKeys k) throws DbException; - - /** - * Stores the given handshake keys for the given pending contact and - * returns a key set ID. - */ - HandshakeKeySetId addHandshakeKeys(Transaction txn, PendingContactId p, - HandshakeKeys k) throws DbException; - /** * Stores an identity. */ @@ -154,7 +137,14 @@ public interface DatabaseComponent { * Stores the given transport keys for the given contact and returns a * key set ID. */ - TransportKeySetId addTransportKeys(Transaction txn, ContactId c, + KeySetId addTransportKeys(Transaction txn, ContactId c, TransportKeys k) + throws DbException; + + /** + * Stores the given transport keys for the given pending contact and + * returns a key set ID. + */ + KeySetId addTransportKeys(Transaction txn, PendingContactId p, TransportKeys k) throws DbException; /** @@ -308,14 +298,6 @@ public interface DatabaseComponent { Visibility getGroupVisibility(Transaction txn, ContactId c, GroupId g) throws DbException; - /** - * Returns all handshake keys for the given transport. - *

- * Read-only. - */ - Collection getHandshakeKeys(Transaction txn, TransportId t) - throws DbException; - /** * Returns the identity for the local pseudonym with the given ID. *

@@ -487,17 +469,11 @@ public interface DatabaseComponent { Collection getTransportKeys(Transaction txn, TransportId t) throws DbException; - /** - * Increments the outgoing stream counter for the given handshake keys. - */ - void incrementStreamCounter(Transaction txn, TransportId t, - HandshakeKeySetId k) throws DbException; - /** * Increments the outgoing stream counter for the given transport keys. */ - void incrementStreamCounter(Transaction txn, TransportId t, - TransportKeySetId k) throws DbException; + void incrementStreamCounter(Transaction txn, TransportId t, KeySetId k) + throws DbException; /** * Merges the given metadata with the existing metadata for the given @@ -552,12 +528,6 @@ public interface DatabaseComponent { */ void removeGroup(Transaction txn, Group g) throws DbException; - /** - * Removes the given handshake keys from the database. - */ - void removeHandshakeKeys(Transaction txn, TransportId t, - HandshakeKeySetId k) throws DbException; - /** * Removes an identity (and all associated state) from the database. */ @@ -582,8 +552,8 @@ public interface DatabaseComponent { /** * Removes the given transport keys from the database. */ - void removeTransportKeys(Transaction txn, TransportId t, - TransportKeySetId k) throws DbException; + void removeTransportKeys(Transaction txn, TransportId t, KeySetId k) + throws DbException; /** * Marks the given contact as verified. @@ -626,31 +596,16 @@ public interface DatabaseComponent { byte[] privateKey) throws DbException; /** - * Sets the reordering window for the given transport key set in the given + * Sets the reordering window for the given transport keys in the given * time period. */ - void setReorderingWindow(Transaction txn, TransportKeySetId k, - TransportId t, long timePeriod, long base, byte[] bitmap) - throws DbException; - - /** - * Sets the reordering window for the given handshake key set in the given - * time period. - */ - void setReorderingWindow(Transaction txn, HandshakeKeySetId k, - TransportId t, long timePeriod, long base, byte[] bitmap) - throws DbException; + void setReorderingWindow(Transaction txn, KeySetId k, TransportId t, + long timePeriod, long base, byte[] bitmap) throws DbException; /** * Marks the given transport keys as usable for outgoing streams. */ - void setTransportKeysActive(Transaction txn, TransportId t, - TransportKeySetId k) throws DbException; - - /** - * Stores the given handshake keys, deleting any keys they have replaced. - */ - void updateHandshakeKeys(Transaction txn, Collection keys) + void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k) throws DbException; /** diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/AbstractTransportKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/AbstractTransportKeys.java deleted file mode 100644 index d054983d2..000000000 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/AbstractTransportKeys.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.briarproject.bramble.api.transport; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.plugin.TransportId; - -import javax.annotation.concurrent.Immutable; - -/** - * Abstract superclass for {@link TransportKeys} and {@link HandshakeKeys}. - */ -@Immutable -@NotNullByDefault -public abstract class AbstractTransportKeys { - - private final TransportId transportId; - private final IncomingKeys inPrev, inCurr, inNext; - private final OutgoingKeys outCurr; - - AbstractTransportKeys(TransportId transportId, IncomingKeys inPrev, - IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) { - if (inPrev.getTimePeriod() != outCurr.getTimePeriod() - 1) - throw new IllegalArgumentException(); - if (inCurr.getTimePeriod() != outCurr.getTimePeriod()) - throw new IllegalArgumentException(); - if (inNext.getTimePeriod() != outCurr.getTimePeriod() + 1) - throw new IllegalArgumentException(); - this.transportId = transportId; - this.inPrev = inPrev; - this.inCurr = inCurr; - this.inNext = inNext; - this.outCurr = outCurr; - } - - public TransportId getTransportId() { - return transportId; - } - - public IncomingKeys getPreviousIncomingKeys() { - return inPrev; - } - - public IncomingKeys getCurrentIncomingKeys() { - return inCurr; - } - - public IncomingKeys getNextIncomingKeys() { - return inNext; - } - - public OutgoingKeys getCurrentOutgoingKeys() { - return outCurr; - } - - public long getTimePeriod() { - return outCurr.getTimePeriod(); - } -} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySet.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySet.java deleted file mode 100644 index cb40da1da..000000000 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySet.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.briarproject.bramble.api.transport; - -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.contact.PendingContactId; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; - -/** - * A set of keys for handshaking with a given contact or pending contact over a - * given transport. Unlike a {@link TransportKeySet} these keys do not provide - * forward secrecy. - */ -@Immutable -@NotNullByDefault -public class HandshakeKeySet { - - private final HandshakeKeySetId keySetId; - @Nullable - private final ContactId contactId; - @Nullable - private final PendingContactId pendingContactId; - private final HandshakeKeys keys; - - public HandshakeKeySet(HandshakeKeySetId keySetId, ContactId contactId, - HandshakeKeys keys) { - this.keySetId = keySetId; - this.contactId = contactId; - this.keys = keys; - pendingContactId = null; - } - - public HandshakeKeySet(HandshakeKeySetId keySetId, - PendingContactId pendingContactId, HandshakeKeys keys) { - this.keySetId = keySetId; - this.pendingContactId = pendingContactId; - this.keys = keys; - contactId = null; - } - - public HandshakeKeySetId getKeySetId() { - return keySetId; - } - - @Nullable - public ContactId getContactId() { - return contactId; - } - - @Nullable - public PendingContactId getPendingContactId() { - return pendingContactId; - } - - public HandshakeKeys getKeys() { - return keys; - } - - @Override - public int hashCode() { - return keySetId.hashCode(); - } - - @Override - public boolean equals(Object o) { - return o instanceof HandshakeKeySet && - keySetId.equals(((HandshakeKeySet) o).keySetId); - } -} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeys.java deleted file mode 100644 index 4a27e9adc..000000000 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeys.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.briarproject.bramble.api.transport; - -import org.briarproject.bramble.api.crypto.SecretKey; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.plugin.TransportId; - -import javax.annotation.concurrent.Immutable; - -/** - * Keys for handshaking with a given contact or pending contact over a given - * transport. Unlike {@link TransportKeys} these keys do not provide forward - * secrecy. - */ -@Immutable -@NotNullByDefault -public class HandshakeKeys extends AbstractTransportKeys { - - private final SecretKey rootKey; - private final boolean alice; - - public HandshakeKeys(TransportId transportId, IncomingKeys inPrev, - IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr, - SecretKey rootKey, boolean alice) { - super(transportId, inPrev, inCurr, inNext, outCurr); - this.rootKey = rootKey; - this.alice = alice; - } - - public SecretKey getRootKey() { - return rootKey; - } - - public boolean isAlice() { - return alice; - } -} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/IncomingKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/IncomingKeys.java index 46a17887e..465dec55a 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/IncomingKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/IncomingKeys.java @@ -8,8 +8,8 @@ import javax.annotation.concurrent.Immutable; import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE; /** - * Contains transport keys for receiving streams from a given contact over a - * given transport in a given time period. + * Contains transport keys for receiving streams from a given contact or + * pending contact over a given transport in a given time period. */ @Immutable @NotNullByDefault 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 e5c1ac541..827c94fb7 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 @@ -27,14 +27,14 @@ public interface KeyManager { * @param alice true if the local party is Alice * @param active whether the derived keys can be used for outgoing streams */ - Map addContact(Transaction txn, ContactId c, + Map addContact(Transaction txn, ContactId c, SecretKey rootKey, long timestamp, boolean alice, boolean active) throws DbException; /** * Marks the given transport keys as usable for outgoing streams. */ - void activateKeys(Transaction txn, Map keys) + void activateKeys(Transaction txn, Map keys) throws DbException; /** diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySetId.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeySetId.java similarity index 56% rename from bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySetId.java rename to bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeySetId.java index f54c3bb7a..fb6a929df 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySetId.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeySetId.java @@ -5,17 +5,16 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import javax.annotation.concurrent.Immutable; /** - * Type-safe wrapper for an integer that uniquely identifies a - * {@link HandshakeKeySet set of handshake keys} within the scope of the local - * device. + * Type-safe wrapper for an integer that uniquely identifies a set of + * {@link TransportKeySet transport keys} within the scope of the local device. */ @Immutable @NotNullByDefault -public class HandshakeKeySetId { +public class KeySetId { private final int id; - public HandshakeKeySetId(int id) { + public KeySetId(int id) { this.id = id; } @@ -30,7 +29,6 @@ public class HandshakeKeySetId { @Override public boolean equals(Object o) { - return o instanceof HandshakeKeySetId && - id == ((HandshakeKeySetId) o).id; + return o instanceof KeySetId && id == ((KeySetId) o).id; } } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/OutgoingKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/OutgoingKeys.java index 5e06e9b40..9fa6245d0 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/OutgoingKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/OutgoingKeys.java @@ -6,8 +6,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import javax.annotation.concurrent.Immutable; /** - * Contains transport keys for sending streams to a given contact over a given - * transport in a given time period. + * Contains transport keys for sending streams to a given contact or pending + * contact over a given transport in a given time period. */ @Immutable @NotNullByDefault diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java index 4b3831bc3..dc6e5c08d 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java @@ -1,37 +1,49 @@ package org.briarproject.bramble.api.transport; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; /** - * A set of keys for communicating with a given contact over a given transport. - * Unlike a {@link HandshakeKeySet} these keys provide forward secrecy. + * A set of keys for communicating with a given contact or pending contact + * over a given transport. */ @Immutable @NotNullByDefault public class TransportKeySet { - private final TransportKeySetId keySetId; + private final KeySetId keySetId; + @Nullable private final ContactId contactId; + @Nullable + private final PendingContactId pendingContactId; private final TransportKeys keys; - public TransportKeySet(TransportKeySetId keySetId, ContactId contactId, - TransportKeys keys) { + public TransportKeySet(KeySetId keySetId, @Nullable ContactId contactId, + @Nullable PendingContactId pendingContactId, TransportKeys keys) { this.keySetId = keySetId; this.contactId = contactId; + this.pendingContactId = pendingContactId; this.keys = keys; } - public TransportKeySetId getKeySetId() { + public KeySetId getKeySetId() { return keySetId; } + @Nullable public ContactId getContactId() { return contactId; } + @Nullable + public PendingContactId getPendingContactId() { + return pendingContactId; + } + public TransportKeys getKeys() { return keys; } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySetId.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySetId.java deleted file mode 100644 index c4b1ae088..000000000 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySetId.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.briarproject.bramble.api.transport; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; - -import javax.annotation.concurrent.Immutable; - -/** - * Type-safe wrapper for an integer that uniquely identifies a - * {@link TransportKeySet set of transport keys} within the scope of the local - * device. - *

- * Key sets created on a given device must have increasing identifiers. - */ -@Immutable -@NotNullByDefault -public class TransportKeySetId { - - private final int id; - - public TransportKeySetId(int id) { - this.id = id; - } - - public int getInt() { - return id; - } - - @Override - public int hashCode() { - return id; - } - - @Override - public boolean equals(Object o) { - return o instanceof TransportKeySetId && - id == ((TransportKeySetId) o).id; - } -} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java index 39a27d45b..200f05bd1 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java @@ -1,20 +1,108 @@ package org.briarproject.bramble.api.transport; +import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; /** - * Keys for communicating with a given contact over a given transport. Unlike - * {@link HandshakeKeys} these keys provide forward secrecy. + * Keys for communicating with a given contact or pending contact over a given + * transport. */ @Immutable @NotNullByDefault -public class TransportKeys extends AbstractTransportKeys { +public class TransportKeys { + private final TransportId transportId; + private final IncomingKeys inPrev, inCurr, inNext; + private final OutgoingKeys outCurr; + @Nullable + private final SecretKey rootKey; + private final boolean alice; + + /** + * Constructor for rotation mode. + */ public TransportKeys(TransportId transportId, IncomingKeys inPrev, IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) { - super(transportId, inPrev, inCurr, inNext, outCurr); + this(transportId, inPrev, inCurr, inNext, outCurr, null, false); + } + + /** + * Constructor for handshake mode. + */ + public TransportKeys(TransportId transportId, IncomingKeys inPrev, + IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr, + @Nullable SecretKey rootKey, boolean alice) { + if (inPrev.getTimePeriod() != outCurr.getTimePeriod() - 1) + throw new IllegalArgumentException(); + if (inCurr.getTimePeriod() != outCurr.getTimePeriod()) + throw new IllegalArgumentException(); + if (inNext.getTimePeriod() != outCurr.getTimePeriod() + 1) + throw new IllegalArgumentException(); + this.transportId = transportId; + this.inPrev = inPrev; + this.inCurr = inCurr; + this.inNext = inNext; + this.outCurr = outCurr; + this.rootKey = rootKey; + this.alice = alice; + } + + public TransportId getTransportId() { + return transportId; + } + + public IncomingKeys getPreviousIncomingKeys() { + return inPrev; + } + + public IncomingKeys getCurrentIncomingKeys() { + return inCurr; + } + + public IncomingKeys getNextIncomingKeys() { + return inNext; + } + + public OutgoingKeys getCurrentOutgoingKeys() { + return outCurr; + } + + public long getTimePeriod() { + return outCurr.getTimePeriod(); + } + + /** + * Returns true if these keys are for use in handshake mode or false if + * they're for use in rotation mode. + */ + public boolean isHandshakeMode() { + return rootKey != null; + } + + /** + * If these keys are for use in handshake mode, returns the root key. + * + * @throws UnsupportedOperationException If these keys are for use in + * rotation mode + */ + public SecretKey getRootKey() { + if (rootKey == null) throw new UnsupportedOperationException(); + return rootKey; + } + + /** + * If these keys are for use in handshake mode, returns true if the local + * party is Alice. + * + * @throws UnsupportedOperationException If these keys are for use in + * rotation mode + */ + public boolean isAlice() { + if (rootKey == null) throw new UnsupportedOperationException(); + return alice; } } 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 5ee6b87ee..fab0c8fcd 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 @@ -4,7 +4,6 @@ import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.TransportCrypto; import org.briarproject.bramble.api.plugin.TransportId; -import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.IncomingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.TransportKeys; @@ -42,7 +41,7 @@ class TransportCryptoImpl implements TransportCrypto { } @Override - public TransportKeys deriveTransportKeys(TransportId t, + public TransportKeys deriveRotationKeys(TransportId t, SecretKey rootKey, long timePeriod, boolean weAreAlice, boolean active) { // Keys for the previous period are derived from the root key @@ -70,31 +69,6 @@ class TransportCryptoImpl implements TransportCrypto { return new TransportKeys(t, inPrev, inCurr, inNext, outCurr); } - @Override - public TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod) { - if (k.getTimePeriod() >= timePeriod) return k; - IncomingKeys inPrev = k.getPreviousIncomingKeys(); - IncomingKeys inCurr = k.getCurrentIncomingKeys(); - IncomingKeys inNext = k.getNextIncomingKeys(); - OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); - long startPeriod = outCurr.getTimePeriod(); - boolean active = outCurr.isActive(); - // Rotate the keys - for (long p = startPeriod + 1; p <= timePeriod; p++) { - inPrev = inCurr; - inCurr = inNext; - SecretKey inNextTag = rotateKey(inNext.getTagKey(), p + 1); - SecretKey inNextHeader = rotateKey(inNext.getHeaderKey(), p + 1); - inNext = new IncomingKeys(inNextTag, inNextHeader, p + 1); - SecretKey outCurrTag = rotateKey(outCurr.getTagKey(), p); - SecretKey outCurrHeader = rotateKey(outCurr.getHeaderKey(), p); - outCurr = new OutgoingKeys(outCurrTag, outCurrHeader, p, active); - } - // Collect and return the keys - return new TransportKeys(k.getTransportId(), inPrev, inCurr, inNext, - outCurr); - } - private SecretKey rotateKey(SecretKey k, long timePeriod) { byte[] period = new byte[INT_64_BYTES]; writeUint64(timePeriod, period, 0); @@ -117,7 +91,7 @@ class TransportCryptoImpl implements TransportCrypto { } @Override - public HandshakeKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey, + public TransportKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey, long timePeriod, boolean weAreAlice) { if (timePeriod < 1) throw new IllegalArgumentException(); IncomingKeys inPrev = deriveIncomingHandshakeKeys(t, rootKey, @@ -128,7 +102,7 @@ class TransportCryptoImpl implements TransportCrypto { weAreAlice, timePeriod + 1); OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, weAreAlice, timePeriod); - return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, rootKey, + return new TransportKeys(t, inPrev, inCurr, inNext, outCurr, rootKey, weAreAlice); } @@ -171,7 +145,13 @@ class TransportCryptoImpl implements TransportCrypto { } @Override - public HandshakeKeys updateHandshakeKeys(HandshakeKeys k, long timePeriod) { + public TransportKeys updateTransportKeys(TransportKeys k, long timePeriod) { + if (k.isHandshakeMode()) return updateHandshakeKeys(k, timePeriod); + else return updateRotationKeys(k, timePeriod); + } + + private TransportKeys updateHandshakeKeys(TransportKeys k, + long timePeriod) { long elapsed = timePeriod - k.getTimePeriod(); TransportId t = k.getTransportId(); SecretKey rootKey = k.getRootKey(); @@ -188,7 +168,7 @@ class TransportCryptoImpl implements TransportCrypto { weAreAlice, timePeriod + 1); OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, weAreAlice, timePeriod); - return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, + return new TransportKeys(t, inPrev, inCurr, inNext, outCurr, rootKey, weAreAlice); } else if (elapsed == 2) { // The keys are two periods old - shift by two periods, keeping @@ -200,7 +180,7 @@ class TransportCryptoImpl implements TransportCrypto { weAreAlice, timePeriod + 1); OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, weAreAlice, timePeriod); - return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, + return new TransportKeys(t, inPrev, inCurr, inNext, outCurr, rootKey, weAreAlice); } else { // The keys are more than two periods old - derive fresh keys @@ -208,6 +188,30 @@ class TransportCryptoImpl implements TransportCrypto { } } + private TransportKeys updateRotationKeys(TransportKeys k, long timePeriod) { + if (k.getTimePeriod() >= timePeriod) return k; + IncomingKeys inPrev = k.getPreviousIncomingKeys(); + IncomingKeys inCurr = k.getCurrentIncomingKeys(); + IncomingKeys inNext = k.getNextIncomingKeys(); + OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); + long startPeriod = outCurr.getTimePeriod(); + boolean active = outCurr.isActive(); + // Rotate the keys + for (long p = startPeriod + 1; p <= timePeriod; p++) { + inPrev = inCurr; + inCurr = inNext; + SecretKey inNextTag = rotateKey(inNext.getTagKey(), p + 1); + SecretKey inNextHeader = rotateKey(inNext.getHeaderKey(), p + 1); + inNext = new IncomingKeys(inNextTag, inNextHeader, p + 1); + SecretKey outCurrTag = rotateKey(outCurr.getTagKey(), p); + SecretKey outCurrHeader = rotateKey(outCurr.getHeaderKey(), p); + outCurr = new OutgoingKeys(outCurrTag, outCurrHeader, p, active); + } + // Collect and return the keys + return new TransportKeys(k.getTransportId(), inPrev, inCurr, inNext, + outCurr); + } + @Override public void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion, long streamNumber) { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java index 01e1eec15..3de03987c 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java @@ -27,11 +27,8 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.validation.MessageState; -import org.briarproject.bramble.api.transport.HandshakeKeySet; -import org.briarproject.bramble.api.transport.HandshakeKeySetId; -import org.briarproject.bramble.api.transport.HandshakeKeys; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.TransportKeySet; -import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import java.util.Collection; @@ -105,20 +102,6 @@ interface Database { void addGroupVisibility(T txn, ContactId c, GroupId g, boolean shared) throws DbException; - /** - * Stores the given handshake keys for the given contact and returns a - * key set ID. - */ - HandshakeKeySetId addHandshakeKeys(T txn, ContactId c, HandshakeKeys k) - throws DbException; - - /** - * Stores the given handshake keys for the given pending contact and - * returns a key set ID. - */ - HandshakeKeySetId addHandshakeKeys(T txn, PendingContactId p, - HandshakeKeys k) throws DbException; - /** * Stores an identity. */ @@ -160,7 +143,14 @@ interface Database { * Stores the given transport keys for the given contact and returns a * key set ID. */ - TransportKeySetId addTransportKeys(T txn, ContactId c, TransportKeys k) + KeySetId addTransportKeys(T txn, ContactId c, TransportKeys k) + throws DbException; + + /** + * Stores the given transport keys for the given pending contact and + * returns a key set ID. + */ + KeySetId addTransportKeys(T txn, PendingContactId p, TransportKeys k) throws DbException; /** @@ -315,14 +305,6 @@ interface Database { Map getGroupVisibility(T txn, GroupId g) throws DbException; - /** - * Returns all handshake keys for the given transport. - *

- * Read-only. - */ - Collection getHandshakeKeys(T txn, TransportId t) - throws DbException; - /** * Returns the identity for local pseudonym with the given ID. *

@@ -545,16 +527,10 @@ interface Database { Collection getTransportKeys(T txn, TransportId t) throws DbException; - /** - * Increments the outgoing stream counter for the given handshake keys. - */ - void incrementStreamCounter(T txn, TransportId t, HandshakeKeySetId k) - throws DbException; - /** * Increments the outgoing stream counter for the given transport keys. */ - void incrementStreamCounter(T txn, TransportId t, TransportKeySetId k) + void incrementStreamCounter(T txn, TransportId t, KeySetId k) throws DbException; /** @@ -623,12 +599,6 @@ interface Database { void removeGroupVisibility(T txn, ContactId c, GroupId g) throws DbException; - /** - * Removes the given handshake keys from the database. - */ - void removeHandshakeKeys(T txn, TransportId t, HandshakeKeySetId k) - throws DbException; - /** * Removes an identity (and all associated state) from the database. */ @@ -659,8 +629,7 @@ interface Database { /** * Removes the given transport keys from the database. */ - void removeTransportKeys(T txn, TransportId t, TransportKeySetId k) - throws DbException; + void removeTransportKeys(T txn, TransportId t, KeySetId k) throws DbException; /** * Resets the transmission count and expiry time of the given message with @@ -710,23 +679,16 @@ interface Database { PendingContactState state) throws DbException; /** - * Sets the reordering window for the given transport key set in the given + * Sets the reordering window for the given transport keys in the given * time period. */ - void setReorderingWindow(T txn, TransportKeySetId k, TransportId t, - long timePeriod, long base, byte[] bitmap) throws DbException; - - /** - * Sets the reordering window for the given handshake key set in the given - * time period. - */ - void setReorderingWindow(T txn, HandshakeKeySetId k, TransportId t, + void setReorderingWindow(T txn, KeySetId k, TransportId t, long timePeriod, long base, byte[] bitmap) throws DbException; /** * Marks the given transport keys as usable for outgoing streams. */ - void setTransportKeysActive(T txn, TransportId t, TransportKeySetId k) + void setTransportKeysActive(T txn, TransportId t, KeySetId k) throws DbException; /** @@ -738,12 +700,7 @@ interface Database { throws DbException; /** - * Updates the given handshake keys. - */ - void updateHandshakeKeys(T txn, HandshakeKeySet ks) throws DbException; - - /** - * Updates the given transport keys following key rotation. + * Stores the given transport keys, deleting any keys they have replaced. */ void updateTransportKeys(T txn, TransportKeySet ks) throws DbException; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java index bebdea3d8..0185f2e68 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java @@ -62,11 +62,8 @@ import org.briarproject.bramble.api.sync.event.MessageToRequestEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesSentEvent; import org.briarproject.bramble.api.sync.validation.MessageState; -import org.briarproject.bramble.api.transport.HandshakeKeySet; -import org.briarproject.bramble.api.transport.HandshakeKeySetId; -import org.briarproject.bramble.api.transport.HandshakeKeys; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.TransportKeySet; -import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import java.util.ArrayList; @@ -258,30 +255,6 @@ class DatabaseComponentImpl implements DatabaseComponent { } } - @Override - public HandshakeKeySetId addHandshakeKeys(Transaction transaction, - ContactId c, HandshakeKeys k) throws DbException { - if (transaction.isReadOnly()) throw new IllegalArgumentException(); - T txn = unbox(transaction); - if (!db.containsContact(txn, c)) - throw new NoSuchContactException(); - if (!db.containsTransport(txn, k.getTransportId())) - throw new NoSuchTransportException(); - return db.addHandshakeKeys(txn, c, k); - } - - @Override - public HandshakeKeySetId addHandshakeKeys(Transaction transaction, - PendingContactId p, HandshakeKeys k) throws DbException { - if (transaction.isReadOnly()) throw new IllegalArgumentException(); - T txn = unbox(transaction); - if (!db.containsPendingContact(txn, p)) - throw new NoSuchPendingContactException(); - if (!db.containsTransport(txn, k.getTransportId())) - throw new NoSuchTransportException(); - return db.addHandshakeKeys(txn, p, k); - } - @Override public void addIdentity(Transaction transaction, Identity i) throws DbException { @@ -330,8 +303,8 @@ class DatabaseComponentImpl implements DatabaseComponent { } @Override - public TransportKeySetId addTransportKeys(Transaction transaction, - ContactId c, TransportKeys k) throws DbException { + public KeySetId addTransportKeys(Transaction transaction, ContactId c, + TransportKeys k) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) @@ -341,6 +314,18 @@ class DatabaseComponentImpl implements DatabaseComponent { return db.addTransportKeys(txn, c, k); } + @Override + public KeySetId addTransportKeys(Transaction transaction, + PendingContactId p, TransportKeys k) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); + T txn = unbox(transaction); + if (!db.containsPendingContact(txn, p)) + throw new NoSuchPendingContactException(); + if (!db.containsTransport(txn, k.getTransportId())) + throw new NoSuchTransportException(); + return db.addTransportKeys(txn, p, k); + } + @Override public boolean containsContact(Transaction transaction, AuthorId remote, AuthorId local) throws DbException { @@ -544,15 +529,6 @@ class DatabaseComponentImpl implements DatabaseComponent { return db.getGroupVisibility(txn, c, g); } - @Override - public Collection getHandshakeKeys(Transaction transaction, - TransportId t) throws DbException { - T txn = unbox(transaction); - if (!db.containsTransport(txn, t)) - throw new NoSuchTransportException(); - return db.getHandshakeKeys(txn, t); - } - @Override public Identity getIdentity(Transaction transaction, AuthorId a) throws DbException { @@ -735,17 +711,7 @@ class DatabaseComponentImpl implements DatabaseComponent { @Override public void incrementStreamCounter(Transaction transaction, TransportId t, - HandshakeKeySetId k) throws DbException { - if (transaction.isReadOnly()) throw new IllegalArgumentException(); - T txn = unbox(transaction); - if (!db.containsTransport(txn, t)) - throw new NoSuchTransportException(); - db.incrementStreamCounter(txn, t, k); - } - - @Override - public void incrementStreamCounter(Transaction transaction, TransportId t, - TransportKeySetId k) throws DbException { + KeySetId k) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsTransport(txn, t)) @@ -894,16 +860,6 @@ class DatabaseComponentImpl implements DatabaseComponent { transaction.attach(new GroupVisibilityUpdatedEvent(affected)); } - @Override - public void removeHandshakeKeys(Transaction transaction, - TransportId t, HandshakeKeySetId k) throws DbException { - if (transaction.isReadOnly()) throw new IllegalArgumentException(); - T txn = unbox(transaction); - if (!db.containsTransport(txn, t)) - throw new NoSuchTransportException(); - db.removeHandshakeKeys(txn, t, k); - } - @Override public void removeIdentity(Transaction transaction, AuthorId a) throws DbException { @@ -947,8 +903,8 @@ class DatabaseComponentImpl implements DatabaseComponent { } @Override - public void removeTransportKeys(Transaction transaction, - TransportId t, TransportKeySetId k) throws DbException { + public void removeTransportKeys(Transaction transaction, TransportId t, + KeySetId k) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsTransport(txn, t)) @@ -1046,20 +1002,9 @@ class DatabaseComponentImpl implements DatabaseComponent { } @Override - public void setReorderingWindow(Transaction transaction, - TransportKeySetId k, TransportId t, long timePeriod, long base, - byte[] bitmap) throws DbException { - if (transaction.isReadOnly()) throw new IllegalArgumentException(); - T txn = unbox(transaction); - if (!db.containsTransport(txn, t)) - throw new NoSuchTransportException(); - db.setReorderingWindow(txn, k, t, timePeriod, base, bitmap); - } - - @Override - public void setReorderingWindow(Transaction transaction, - HandshakeKeySetId k, TransportId t, long timePeriod, long base, - byte[] bitmap) throws DbException { + public void setReorderingWindow(Transaction transaction, KeySetId k, + TransportId t, long timePeriod, long base, byte[] bitmap) + throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsTransport(txn, t)) @@ -1069,7 +1014,7 @@ class DatabaseComponentImpl implements DatabaseComponent { @Override public void setTransportKeysActive(Transaction transaction, TransportId t, - TransportKeySetId k) throws DbException { + KeySetId k) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsTransport(txn, t)) @@ -1077,18 +1022,6 @@ class DatabaseComponentImpl implements DatabaseComponent { db.setTransportKeysActive(txn, t, k); } - @Override - public void updateHandshakeKeys(Transaction transaction, - Collection keys) throws DbException { - if (transaction.isReadOnly()) throw new IllegalArgumentException(); - T txn = unbox(transaction); - for (HandshakeKeySet ks : keys) { - TransportId t = ks.getKeys().getTransportId(); - if (db.containsTransport(txn, t)) - db.updateHandshakeKeys(txn, ks); - } - } - @Override public void updateTransportKeys(Transaction transaction, Collection keys) throws DbException { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index 36cb1ef4f..bf6f71b0f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -30,13 +30,10 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.system.Clock; -import org.briarproject.bramble.api.transport.HandshakeKeySet; -import org.briarproject.bramble.api.transport.HandshakeKeySetId; -import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.IncomingKeys; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.TransportKeySet; -import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import java.sql.Connection; @@ -62,11 +59,13 @@ import java.util.logging.Logger; import javax.annotation.Nullable; import static java.sql.Types.BINARY; +import static java.sql.Types.BOOLEAN; import static java.sql.Types.INTEGER; import static java.sql.Types.VARCHAR; import static java.util.Arrays.asList; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.db.Metadata.REMOVE; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; @@ -93,7 +92,7 @@ import static org.briarproject.bramble.util.LogUtils.now; abstract class JdbcDatabase implements Database { // Package access for testing - static final int CODE_SCHEMA_VERSION = 43; + static final int CODE_SCHEMA_VERSION = 44; // Time period offsets for incoming transport keys private static final int OFFSET_PREV = -1; @@ -254,16 +253,28 @@ abstract class JdbcDatabase implements Database { + " maxLatency INT NOT NULL," + " PRIMARY KEY (transportId))"; + private static final String CREATE_PENDING_CONTACTS = + "CREATE TABLE pendingContacts" + + " (pendingContactId _HASH NOT NULL," + + " publicKey _BINARY NOT NULL," + + " alias _STRING NOT NULL," + + " state INT NOT NULL," + + " timestamp BIGINT NOT NULL," + + " PRIMARY KEY (pendingContactId))"; + private static final String CREATE_OUTGOING_KEYS = "CREATE TABLE outgoingKeys" + " (transportId _STRING NOT NULL," + " keySetId _COUNTER," + " timePeriod BIGINT NOT NULL," - + " contactId INT NOT NULL," + + " contactId INT," // Null if contact is pending + + " pendingContactId _HASH," // Null if not pending + " tagKey _SECRET NOT NULL," + " headerKey _SECRET NOT NULL," + " stream BIGINT NOT NULL," + " active BOOLEAN NOT NULL," + + " rootKey _SECRET," // Null for rotation keys + + " alice BOOLEAN," // Null for rotation keys + " PRIMARY KEY (transportId, keySetId)," + " FOREIGN KEY (transportId)" + " REFERENCES transports (transportId)" @@ -271,6 +282,9 @@ abstract class JdbcDatabase implements Database { + " UNIQUE (keySetId)," + " FOREIGN KEY (contactId)" + " REFERENCES contacts (contactId)" + + " ON DELETE CASCADE," + + " FOREIGN KEY (pendingContactId)" + + " REFERENCES pendingContacts (pendingContactId)" + " ON DELETE CASCADE)"; private static final String CREATE_INCOMING_KEYS = @@ -291,57 +305,6 @@ abstract class JdbcDatabase implements Database { + " REFERENCES outgoingKeys (keySetId)" + " ON DELETE CASCADE)"; - private static final String CREATE_PENDING_CONTACTS = - "CREATE TABLE pendingContacts" - + " (pendingContactId _HASH NOT NULL," - + " publicKey _BINARY NOT NULL," - + " alias _STRING NOT NULL," - + " state INT NOT NULL," - + " timestamp BIGINT NOT NULL," - + " PRIMARY KEY (pendingContactId))"; - - private static final String CREATE_OUTGOING_HANDSHAKE_KEYS = - "CREATE TABLE outgoingHandshakeKeys" - + " (transportId _STRING NOT NULL," - + " keySetId _COUNTER," - + " timePeriod BIGINT NOT NULL," - + " contactId INT," // Null if contact is pending - + " pendingContactId _HASH," // Null if not pending - + " rootKey _SECRET NOT NULL," - + " alice BOOLEAN NOT NULL," - + " tagKey _SECRET NOT NULL," - + " headerKey _SECRET NOT NULL," - + " stream BIGINT NOT NULL," - + " PRIMARY KEY (transportId, keySetId)," - + " FOREIGN KEY (transportId)" - + " REFERENCES transports (transportId)" - + " ON DELETE CASCADE," - + " UNIQUE (keySetId)," - + " FOREIGN KEY (contactId)" - + " REFERENCES contacts (contactId)" - + " ON DELETE CASCADE," - + " FOREIGN KEY (pendingContactId)" - + " REFERENCES pendingContacts (pendingContactId)" - + " ON DELETE CASCADE)"; - - private static final String CREATE_INCOMING_HANDSHAKE_KEYS = - "CREATE TABLE incomingHandshakeKeys" - + " (transportId _STRING NOT NULL," - + " keySetId INT NOT NULL," - + " timePeriod BIGINT NOT NULL," - + " tagKey _SECRET NOT NULL," - + " headerKey _SECRET NOT NULL," - + " base BIGINT NOT NULL," - + " bitmap _BINARY NOT NULL," - + " periodOffset INT NOT NULL," - + " PRIMARY KEY (transportId, keySetId, periodOffset)," - + " FOREIGN KEY (transportId)" - + " REFERENCES transports (transportId)" - + " ON DELETE CASCADE," - + " FOREIGN KEY (keySetId)" - + " REFERENCES outgoingHandshakeKeys (keySetId)" - + " ON DELETE CASCADE)"; - private static final String INDEX_CONTACTS_BY_AUTHOR_ID = "CREATE INDEX IF NOT EXISTS contactsByAuthorId" + " ON contacts (authorId)"; @@ -367,7 +330,7 @@ abstract class JdbcDatabase implements Database { + " ON statuses (contactId, timestamp)"; private static final Logger LOG = - Logger.getLogger(JdbcDatabase.class.getName()); + getLogger(JdbcDatabase.class.getName()); // Different database libraries use different names for certain types private final MessageFactory messageFactory; @@ -487,7 +450,8 @@ abstract class JdbcDatabase implements Database { new Migration39_40(), new Migration40_41(dbTypes), new Migration41_42(dbTypes), - new Migration42_43(dbTypes) + new Migration42_43(dbTypes), + new Migration43_44(dbTypes) ); } @@ -535,13 +499,9 @@ abstract class JdbcDatabase implements Database { s.executeUpdate(dbTypes.replaceTypes(CREATE_OFFERS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_STATUSES)); s.executeUpdate(dbTypes.replaceTypes(CREATE_TRANSPORTS)); + s.executeUpdate(dbTypes.replaceTypes(CREATE_PENDING_CONTACTS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_OUTGOING_KEYS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_INCOMING_KEYS)); - s.executeUpdate(dbTypes.replaceTypes(CREATE_PENDING_CONTACTS)); - s.executeUpdate(dbTypes.replaceTypes( - CREATE_OUTGOING_HANDSHAKE_KEYS)); - s.executeUpdate(dbTypes.replaceTypes( - CREATE_INCOMING_HANDSHAKE_KEYS)); s.close(); } catch (SQLException e) { tryToClose(s, LOG, WARNING); @@ -777,103 +737,6 @@ abstract class JdbcDatabase implements Database { } } - @Override - public HandshakeKeySetId addHandshakeKeys(Connection txn, ContactId c, - HandshakeKeys k) throws DbException { - return addHandshakeKeys(txn, c, null, k); - } - - @Override - public HandshakeKeySetId addHandshakeKeys(Connection txn, - PendingContactId p, HandshakeKeys k) throws DbException { - return addHandshakeKeys(txn, null, p, k); - } - - private HandshakeKeySetId addHandshakeKeys(Connection txn, - @Nullable ContactId c, @Nullable PendingContactId p, - HandshakeKeys k) throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - // Store the outgoing keys - String sql = "INSERT INTO outgoingHandshakeKeys (contactId," - + " pendingContactId, transportId, rootKey, alice," - + " timePeriod, tagKey, headerKey, stream)" - + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; - ps = txn.prepareStatement(sql); - if (c == null) ps.setNull(1, INTEGER); - else ps.setInt(1, c.getInt()); - if (p == null) ps.setNull(2, BINARY); - else ps.setBytes(2, p.getBytes()); - ps.setString(3, k.getTransportId().getString()); - ps.setBytes(4, k.getRootKey().getBytes()); - ps.setBoolean(5, k.isAlice()); - OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); - ps.setLong(6, outCurr.getTimePeriod()); - ps.setBytes(7, outCurr.getTagKey().getBytes()); - ps.setBytes(8, outCurr.getHeaderKey().getBytes()); - ps.setLong(9, outCurr.getStreamCounter()); - int affected = ps.executeUpdate(); - if (affected != 1) throw new DbStateException(); - ps.close(); - // Get the new (highest) key set ID - sql = "SELECT keySetId FROM outgoingHandshakeKeys" - + " ORDER BY keySetId DESC LIMIT 1"; - ps = txn.prepareStatement(sql); - rs = ps.executeQuery(); - if (!rs.next()) throw new DbStateException(); - HandshakeKeySetId keySetId = new HandshakeKeySetId(rs.getInt(1)); - if (rs.next()) throw new DbStateException(); - rs.close(); - ps.close(); - // Store the incoming keys - sql = "INSERT INTO incomingHandshakeKeys (keySetId, transportId," - + " timePeriod, tagKey, headerKey, base, bitmap," - + " periodOffset)" - + " VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; - ps = txn.prepareStatement(sql); - ps.setInt(1, keySetId.getInt()); - ps.setString(2, k.getTransportId().getString()); - // Previous time period - IncomingKeys inPrev = k.getPreviousIncomingKeys(); - ps.setLong(3, inPrev.getTimePeriod()); - ps.setBytes(4, inPrev.getTagKey().getBytes()); - ps.setBytes(5, inPrev.getHeaderKey().getBytes()); - ps.setLong(6, inPrev.getWindowBase()); - ps.setBytes(7, inPrev.getWindowBitmap()); - ps.setInt(8, OFFSET_PREV); - ps.addBatch(); - // Current time period - IncomingKeys inCurr = k.getCurrentIncomingKeys(); - ps.setLong(3, inCurr.getTimePeriod()); - ps.setBytes(4, inCurr.getTagKey().getBytes()); - ps.setBytes(5, inCurr.getHeaderKey().getBytes()); - ps.setLong(6, inCurr.getWindowBase()); - ps.setBytes(7, inCurr.getWindowBitmap()); - ps.setInt(8, OFFSET_CURR); - ps.addBatch(); - // Next time period - IncomingKeys inNext = k.getNextIncomingKeys(); - ps.setLong(3, inNext.getTimePeriod()); - ps.setBytes(4, inNext.getTagKey().getBytes()); - ps.setBytes(5, inNext.getHeaderKey().getBytes()); - ps.setLong(6, inNext.getWindowBase()); - ps.setBytes(7, inNext.getWindowBitmap()); - ps.setInt(8, OFFSET_NEXT); - ps.addBatch(); - int[] batchAffected = ps.executeBatch(); - if (batchAffected.length != 3) throw new DbStateException(); - for (int rows : batchAffected) - if (rows != 1) throw new DbStateException(); - ps.close(); - return keySetId; - } catch (SQLException e) { - tryToClose(rs, LOG, WARNING); - tryToClose(ps, LOG, WARNING); - throw new DbException(e); - } - } - @Override public void addIdentity(Connection txn, Identity i) throws DbException { PreparedStatement ps = null; @@ -1101,24 +964,47 @@ abstract class JdbcDatabase implements Database { } @Override - public TransportKeySetId addTransportKeys(Connection txn, ContactId c, + public KeySetId addTransportKeys(Connection txn, ContactId c, + TransportKeys k) throws DbException { + return addTransportKeys(txn, c, null, k); + } + + @Override + public KeySetId addTransportKeys(Connection txn, + PendingContactId p, TransportKeys k) throws DbException { + return addTransportKeys(txn, null, p, k); + } + + private KeySetId addTransportKeys(Connection txn, + @Nullable ContactId c, @Nullable PendingContactId p, TransportKeys k) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { // Store the outgoing keys - String sql = "INSERT INTO outgoingKeys (contactId, transportId," - + " timePeriod, tagKey, headerKey, stream, active)" - + " VALUES (?, ?, ?, ?, ?, ?, ?)"; + String sql = "INSERT INTO outgoingKeys (transportId, timePeriod," + + " contactId, pendingContactId, tagKey, headerKey," + + " stream, active, rootKey, alice)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; ps = txn.prepareStatement(sql); - ps.setInt(1, c.getInt()); - ps.setString(2, k.getTransportId().getString()); + ps.setString(1, k.getTransportId().getString()); + ps.setLong(2, k.getTimePeriod()); + if (c == null) ps.setNull(3, INTEGER); + else ps.setInt(3, c.getInt()); + if (p == null) ps.setNull(4, BINARY); + else ps.setBytes(4, p.getBytes()); OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); - ps.setLong(3, outCurr.getTimePeriod()); - ps.setBytes(4, outCurr.getTagKey().getBytes()); - ps.setBytes(5, outCurr.getHeaderKey().getBytes()); - ps.setLong(6, outCurr.getStreamCounter()); - ps.setBoolean(7, outCurr.isActive()); + ps.setBytes(5, outCurr.getTagKey().getBytes()); + ps.setBytes(6, outCurr.getHeaderKey().getBytes()); + ps.setLong(7, outCurr.getStreamCounter()); + ps.setBoolean(8, outCurr.isActive()); + if (k.isHandshakeMode()) { + ps.setBytes(9, k.getRootKey().getBytes()); + ps.setBoolean(10, k.isAlice()); + } else { + ps.setNull(9, BINARY); + ps.setNull(10, BOOLEAN); + } int affected = ps.executeUpdate(); if (affected != 1) throw new DbStateException(); ps.close(); @@ -1128,18 +1014,18 @@ abstract class JdbcDatabase implements Database { ps = txn.prepareStatement(sql); rs = ps.executeQuery(); if (!rs.next()) throw new DbStateException(); - TransportKeySetId keySetId = new TransportKeySetId(rs.getInt(1)); + KeySetId keySetId = new KeySetId(rs.getInt(1)); if (rs.next()) throw new DbStateException(); rs.close(); ps.close(); // Store the incoming keys - sql = "INSERT INTO incomingKeys (keySetId, transportId," + sql = "INSERT INTO incomingKeys (transportId, keySetId," + " timePeriod, tagKey, headerKey, base, bitmap," + " periodOffset)" + " VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; ps = txn.prepareStatement(sql); - ps.setInt(1, keySetId.getInt()); - ps.setString(2, k.getTransportId().getString()); + ps.setString(1, k.getTransportId().getString()); + ps.setInt(2, keySetId.getInt()); // Previous time period IncomingKeys inPrev = k.getPreviousIncomingKeys(); ps.setLong(3, inPrev.getTimePeriod()); @@ -1661,86 +1547,6 @@ abstract class JdbcDatabase implements Database { } } - @Override - public Collection getHandshakeKeys(Connection txn, - TransportId t) throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - // Retrieve the incoming keys - String sql = "SELECT timePeriod, tagKey, headerKey, base, bitmap" - + " FROM incomingHandshakeKeys" - + " WHERE transportId = ?" - + " ORDER BY keySetId, periodOffset"; - ps = txn.prepareStatement(sql); - ps.setString(1, t.getString()); - rs = ps.executeQuery(); - List inKeys = new ArrayList<>(); - while (rs.next()) { - long timePeriod = rs.getLong(1); - SecretKey tagKey = new SecretKey(rs.getBytes(2)); - SecretKey headerKey = new SecretKey(rs.getBytes(3)); - long windowBase = rs.getLong(4); - byte[] windowBitmap = rs.getBytes(5); - inKeys.add(new IncomingKeys(tagKey, headerKey, timePeriod, - windowBase, windowBitmap)); - } - rs.close(); - ps.close(); - // Retrieve the outgoing keys in the same order - sql = "SELECT keySetId, contactId, pendingContactId, timePeriod," - + " tagKey, headerKey, rootKey, alice, stream" - + " FROM outgoingHandshakeKeys" - + " WHERE transportId = ?" - + " ORDER BY keySetId"; - ps = txn.prepareStatement(sql); - ps.setString(1, t.getString()); - rs = ps.executeQuery(); - Collection keys = new ArrayList<>(); - for (int i = 0; rs.next(); i++) { - // There should be three times as many incoming keys - if (inKeys.size() < (i + 1) * 3) throw new DbStateException(); - HandshakeKeySetId keySetId = - new HandshakeKeySetId(rs.getInt(1)); - ContactId contactId = null; - int cId = rs.getInt(2); - if (!rs.wasNull()) contactId = new ContactId(cId); - PendingContactId pendingContactId = null; - byte[] pId = rs.getBytes(3); - if (!rs.wasNull()) pendingContactId = new PendingContactId(pId); - long timePeriod = rs.getLong(4); - SecretKey tagKey = new SecretKey(rs.getBytes(5)); - SecretKey headerKey = new SecretKey(rs.getBytes(6)); - SecretKey rootKey = new SecretKey(rs.getBytes(7)); - boolean alice = rs.getBoolean(8); - long streamCounter = rs.getLong(9); - OutgoingKeys outCurr = new OutgoingKeys(tagKey, headerKey, - timePeriod, streamCounter, true); - IncomingKeys inPrev = inKeys.get(i * 3); - IncomingKeys inCurr = inKeys.get(i * 3 + 1); - IncomingKeys inNext = inKeys.get(i * 3 + 2); - HandshakeKeys handshakeKeys = new HandshakeKeys(t, inPrev, - inCurr, inNext, outCurr, rootKey, alice); - if (contactId == null) { - if (pendingContactId == null) throw new DbStateException(); - keys.add(new HandshakeKeySet(keySetId, pendingContactId, - handshakeKeys)); - } else { - if (pendingContactId != null) throw new DbStateException(); - keys.add(new HandshakeKeySet(keySetId, contactId, - handshakeKeys)); - } - } - rs.close(); - ps.close(); - return keys; - } catch (SQLException e) { - tryToClose(rs, LOG, WARNING); - tryToClose(ps, LOG, WARNING); - throw new DbException(e); - } - } - @Override public Identity getIdentity(Connection txn, AuthorId a) throws DbException { PreparedStatement ps = null; @@ -2502,8 +2308,8 @@ abstract class JdbcDatabase implements Database { rs.close(); ps.close(); // Retrieve the outgoing keys in the same order - sql = "SELECT keySetId, contactId, timePeriod," - + " tagKey, headerKey, stream, active" + sql = "SELECT keySetId, timePeriod, contactId, pendingContactId," + + " tagKey, headerKey, stream, active, rootKey, alice" + " FROM outgoingKeys" + " WHERE transportId = ?" + " ORDER BY keySetId"; @@ -2514,23 +2320,34 @@ abstract class JdbcDatabase implements Database { for (int i = 0; rs.next(); i++) { // There should be three times as many incoming keys if (inKeys.size() < (i + 1) * 3) throw new DbStateException(); - TransportKeySetId keySetId = - new TransportKeySetId(rs.getInt(1)); - ContactId contactId = new ContactId(rs.getInt(2)); - long timePeriod = rs.getLong(3); - SecretKey tagKey = new SecretKey(rs.getBytes(4)); - SecretKey headerKey = new SecretKey(rs.getBytes(5)); - long streamCounter = rs.getLong(6); - boolean active = rs.getBoolean(7); + KeySetId keySetId = new KeySetId(rs.getInt(1)); + long timePeriod = rs.getLong(2); + int cId = rs.getInt(3); + ContactId contactId = rs.wasNull() ? null : new ContactId(cId); + byte[] pId = rs.getBytes(4); + PendingContactId pendingContactId = pId == null ? + null : new PendingContactId(pId); + SecretKey tagKey = new SecretKey(rs.getBytes(5)); + SecretKey headerKey = new SecretKey(rs.getBytes(6)); + long streamCounter = rs.getLong(7); + boolean active = rs.getBoolean(8); + byte[] rootKey = rs.getBytes(9); + boolean alice = rs.getBoolean(10); OutgoingKeys outCurr = new OutgoingKeys(tagKey, headerKey, timePeriod, streamCounter, active); IncomingKeys inPrev = inKeys.get(i * 3); IncomingKeys inCurr = inKeys.get(i * 3 + 1); IncomingKeys inNext = inKeys.get(i * 3 + 2); - TransportKeys transportKeys = new TransportKeys(t, inPrev, - inCurr, inNext, outCurr); + TransportKeys transportKeys; + if (rootKey == null) { + transportKeys = new TransportKeys(t, inPrev, inCurr, + inNext, outCurr); + } else { + transportKeys = new TransportKeys(t, inPrev, inCurr, + inNext, outCurr, new SecretKey(rootKey), alice); + } keys.add(new TransportKeySet(keySetId, contactId, - transportKeys)); + pendingContactId, transportKeys)); } rs.close(); ps.close(); @@ -2544,26 +2361,7 @@ abstract class JdbcDatabase implements Database { @Override public void incrementStreamCounter(Connection txn, TransportId t, - HandshakeKeySetId k) throws DbException { - PreparedStatement ps = null; - try { - String sql = "UPDATE outgoingHandshakeKeys SET stream = stream + 1" - + " WHERE transportId = ? AND keySetId = ?"; - ps = txn.prepareStatement(sql); - ps.setString(1, t.getString()); - ps.setInt(2, k.getInt()); - int affected = ps.executeUpdate(); - if (affected != 1) throw new DbStateException(); - ps.close(); - } catch (SQLException e) { - tryToClose(ps, LOG, WARNING); - throw new DbException(e); - } - } - - @Override - public void incrementStreamCounter(Connection txn, TransportId t, - TransportKeySetId k) throws DbException { + KeySetId k) throws DbException { PreparedStatement ps = null; try { String sql = "UPDATE outgoingKeys SET stream = stream + 1" @@ -2941,27 +2739,6 @@ abstract class JdbcDatabase implements Database { } } - @Override - public void removeHandshakeKeys(Connection txn, TransportId t, - HandshakeKeySetId k) throws DbException { - PreparedStatement ps = null; - try { - // Delete any existing outgoing keys - this will also remove any - // incoming keys with the same key set ID - String sql = "DELETE FROM outgoingHandshakeKeys" - + " WHERE transportId = ? AND keySetId = ?"; - ps = txn.prepareStatement(sql); - ps.setString(1, t.getString()); - ps.setInt(2, k.getInt()); - int affected = ps.executeUpdate(); - if (affected < 0) throw new DbStateException(); - ps.close(); - } catch (SQLException e) { - tryToClose(ps, LOG, WARNING); - throw new DbException(e); - } - } - @Override public void removeIdentity(Connection txn, AuthorId a) throws DbException { PreparedStatement ps = null; @@ -3074,8 +2851,8 @@ abstract class JdbcDatabase implements Database { } @Override - public void removeTransportKeys(Connection txn, TransportId t, - TransportKeySetId k) throws DbException { + public void removeTransportKeys(Connection txn, TransportId t, KeySetId k) + throws DbException { PreparedStatement ps = null; try { // Delete any existing outgoing keys - this will also remove any @@ -3300,7 +3077,7 @@ abstract class JdbcDatabase implements Database { } @Override - public void setReorderingWindow(Connection txn, TransportKeySetId k, + public void setReorderingWindow(Connection txn, KeySetId k, TransportId t, long timePeriod, long base, byte[] bitmap) throws DbException { PreparedStatement ps = null; @@ -3323,33 +3100,9 @@ abstract class JdbcDatabase implements Database { } } - @Override - public void setReorderingWindow(Connection txn, HandshakeKeySetId k, - TransportId t, long timePeriod, long base, byte[] bitmap) - throws DbException { - PreparedStatement ps = null; - try { - String sql = "UPDATE incomingHandshakeKeys SET base = ?, bitmap = ?" - + " WHERE transportId = ? AND keySetId = ?" - + " AND timePeriod = ?"; - ps = txn.prepareStatement(sql); - ps.setLong(1, base); - ps.setBytes(2, bitmap); - ps.setString(3, t.getString()); - ps.setInt(4, k.getInt()); - ps.setLong(5, timePeriod); - int affected = ps.executeUpdate(); - if (affected < 0 || affected > 1) throw new DbStateException(); - ps.close(); - } catch (SQLException e) { - tryToClose(ps, LOG, WARNING); - throw new DbException(e); - } - } - @Override public void setTransportKeysActive(Connection txn, TransportId t, - TransportKeySetId k) throws DbException { + KeySetId k) throws DbException { PreparedStatement ps = null; try { String sql = "UPDATE outgoingKeys SET active = true" @@ -3469,71 +3222,4 @@ abstract class JdbcDatabase implements Database { throw new DbException(e); } } - - @Override - public void updateHandshakeKeys(Connection txn, HandshakeKeySet ks) - throws DbException { - PreparedStatement ps = null; - try { - // Update the outgoing keys - String sql = "UPDATE outgoingHandshakeKeys SET timePeriod = ?," - + " tagKey = ?, headerKey = ?, stream = ?" - + " WHERE transportId = ? AND keySetId = ?"; - ps = txn.prepareStatement(sql); - HandshakeKeys k = ks.getKeys(); - OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); - ps.setLong(1, outCurr.getTimePeriod()); - ps.setBytes(2, outCurr.getTagKey().getBytes()); - ps.setBytes(3, outCurr.getHeaderKey().getBytes()); - ps.setLong(4, outCurr.getStreamCounter()); - ps.setString(5, k.getTransportId().getString()); - ps.setInt(6, ks.getKeySetId().getInt()); - int affected = ps.executeUpdate(); - if (affected < 0 || affected > 1) throw new DbStateException(); - ps.close(); - // Update the incoming keys - sql = "UPDATE incomingHandshakeKeys SET timePeriod = ?," - + " tagKey = ?, headerKey = ?, base = ?, bitmap = ?" - + " WHERE transportId = ? AND keySetId = ?" - + " AND periodOffset = ?"; - ps = txn.prepareStatement(sql); - ps.setString(6, k.getTransportId().getString()); - ps.setInt(7, ks.getKeySetId().getInt()); - // Previous time period - IncomingKeys inPrev = k.getPreviousIncomingKeys(); - ps.setLong(1, inPrev.getTimePeriod()); - ps.setBytes(2, inPrev.getTagKey().getBytes()); - ps.setBytes(3, inPrev.getHeaderKey().getBytes()); - ps.setLong(4, inPrev.getWindowBase()); - ps.setBytes(5, inPrev.getWindowBitmap()); - ps.setInt(8, OFFSET_PREV); - ps.addBatch(); - // Current time period - IncomingKeys inCurr = k.getCurrentIncomingKeys(); - ps.setLong(1, inCurr.getTimePeriod()); - ps.setBytes(2, inCurr.getTagKey().getBytes()); - ps.setBytes(3, inCurr.getHeaderKey().getBytes()); - ps.setLong(4, inCurr.getWindowBase()); - ps.setBytes(5, inCurr.getWindowBitmap()); - ps.setInt(8, OFFSET_CURR); - ps.addBatch(); - // Next time period - IncomingKeys inNext = k.getNextIncomingKeys(); - ps.setLong(1, inNext.getTimePeriod()); - ps.setBytes(2, inNext.getTagKey().getBytes()); - ps.setBytes(3, inNext.getHeaderKey().getBytes()); - ps.setLong(4, inNext.getWindowBase()); - ps.setBytes(5, inNext.getWindowBitmap()); - ps.setInt(8, OFFSET_NEXT); - ps.addBatch(); - int[] batchAffected = ps.executeBatch(); - if (batchAffected.length != 3) throw new DbStateException(); - for (int rows : batchAffected) - if (rows < 0 || rows > 1) throw new DbStateException(); - ps.close(); - } catch (SQLException e) { - tryToClose(ps, LOG, WARNING); - throw new DbException(e); - } - } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Migration43_44.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration43_44.java new file mode 100644 index 000000000..530cbe0e9 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration43_44.java @@ -0,0 +1,58 @@ +package org.briarproject.bramble.db; + +import org.briarproject.bramble.api.db.DbException; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.logging.Logger; + +import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.db.JdbcUtils.tryToClose; + +class Migration43_44 implements Migration { + + private static final Logger LOG = getLogger(Migration43_44.class.getName()); + + private final DatabaseTypes dbTypes; + + Migration43_44(DatabaseTypes dbTypes) { + this.dbTypes = dbTypes; + } + + @Override + public int getStartVersion() { + return 43; + } + + @Override + public int getEndVersion() { + return 44; + } + + @Override + public void migrate(Connection txn) throws DbException { + Statement s = null; + try { + s = txn.createStatement(); + s.execute("DROP TABLE outgoingHandshakeKeys"); + s.execute("DROP TABLE incomingHandshakeKeys"); + s.execute("ALTER TABLE outgoingKeys" + + " ALTER COLUMN contactId DROP NOT NULL"); + s.execute(dbTypes.replaceTypes("ALTER TABLE outgoingKeys" + + " ADD COLUMN pendingContactId _HASH")); + s.execute("ALTER TABLE outgoingKeys" + + " ADD FOREIGN KEY (pendingContactId)" + + " REFERENCES pendingContacts (pendingContactId)" + + " ON DELETE CASCADE"); + s.execute(dbTypes.replaceTypes("ALTER TABLE outgoingKeys" + + " ADD COLUMN rootKey _SECRET")); + s.execute("ALTER TABLE outgoingKeys" + + " ADD COLUMN alice BOOLEAN"); + } catch (SQLException e) { + tryToClose(s, LOG, WARNING); + throw new DbException(e); + } + } +} 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 4ad9fe7d5..18d1b63ff 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 @@ -17,8 +17,8 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; import org.briarproject.bramble.api.transport.KeyManager; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.StreamContext; -import org.briarproject.bramble.api.transport.TransportKeySetId; import java.util.HashMap; import java.util.Map; @@ -88,10 +88,10 @@ class KeyManagerImpl implements KeyManager, Service, EventListener { } @Override - public Map addContact(Transaction txn, + public Map addContact(Transaction txn, ContactId c, SecretKey rootKey, long timestamp, boolean alice, boolean active) throws DbException { - Map ids = new HashMap<>(); + Map ids = new HashMap<>(); for (Entry e : managers.entrySet()) { TransportId t = e.getKey(); TransportKeyManager m = e.getValue(); @@ -101,9 +101,9 @@ class KeyManagerImpl implements KeyManager, Service, EventListener { } @Override - public void activateKeys(Transaction txn, Map keys) throws DbException { - for (Entry e : keys.entrySet()) { + public void activateKeys(Transaction txn, Map keys) + throws DbException { + for (Entry e : keys.entrySet()) { TransportId t = e.getKey(); TransportKeyManager m = managers.get(t); if (m == null) { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableKeySet.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableKeySet.java index 5c24b2220..63ce3134f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableKeySet.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableKeySet.java @@ -1,22 +1,22 @@ package org.briarproject.bramble.transport; import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.transport.TransportKeySetId; +import org.briarproject.bramble.api.transport.KeySetId; class MutableKeySet { - private final TransportKeySetId keySetId; + private final KeySetId keySetId; private final ContactId contactId; private final MutableTransportKeys transportKeys; - MutableKeySet(TransportKeySetId keySetId, ContactId contactId, + MutableKeySet(KeySetId keySetId, ContactId contactId, MutableTransportKeys transportKeys) { this.keySetId = keySetId; this.contactId = contactId; this.transportKeys = transportKeys; } - TransportKeySetId getKeySetId() { + KeySetId getKeySetId() { return keySetId; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java index 2d08ec4c1..fa3f54e11 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java @@ -5,8 +5,8 @@ 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.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.StreamContext; -import org.briarproject.bramble.api.transport.TransportKeySetId; import javax.annotation.Nullable; @@ -15,11 +15,10 @@ interface TransportKeyManager { void start(Transaction txn) throws DbException; - TransportKeySetId addContact(Transaction txn, ContactId c, - SecretKey rootKey, long timestamp, boolean alice, boolean active) - throws DbException; + KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey, + long timestamp, boolean alice, boolean active) throws DbException; - void activateKeys(Transaction txn, TransportKeySetId k) throws DbException; + void activateKeys(Transaction txn, KeySetId k) throws DbException; void removeContact(ContactId c); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java index e93aab417..30731936e 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java @@ -11,9 +11,9 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Scheduler; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.StreamContext; import org.briarproject.bramble.api.transport.TransportKeySet; -import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.transport.ReorderingWindow.Change; @@ -56,7 +56,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { private final ReentrantLock lock = new ReentrantLock(); // The following are locking: lock - private final Map keys = new HashMap<>(); + private final Map keys = new HashMap<>(); private final Map inContexts = new HashMap<>(); private final Map outContexts = new HashMap<>(); @@ -102,10 +102,10 @@ class TransportKeyManagerImpl implements TransportKeyManager { long timePeriod = now / timePeriodLength; for (TransportKeySet ks : keys) { TransportKeys k = ks.getKeys(); - TransportKeys k1 = transportCrypto.rotateTransportKeys(k, + TransportKeys k1 = transportCrypto.updateTransportKeys(k, timePeriod); TransportKeySet ks1 = new TransportKeySet(ks.getKeySetId(), - ks.getContactId(), k1); + ks.getContactId(), null, k1); if (k1.getTimePeriod() > k.getTimePeriod()) rotationResult.rotated.add(ks1); rotationResult.current.add(ks1); @@ -116,13 +116,14 @@ class TransportKeyManagerImpl implements TransportKeyManager { // Locking: lock private void addKeys(Collection keys) { for (TransportKeySet ks : keys) { + // TODO: Keys may be for a pending contact addKeys(ks.getKeySetId(), ks.getContactId(), new MutableTransportKeys(ks.getKeys())); } } // Locking: lock - private void addKeys(TransportKeySetId keySetId, ContactId contactId, + private void addKeys(KeySetId keySetId, ContactId contactId, MutableTransportKeys m) { MutableKeySet ks = new MutableKeySet(keySetId, contactId, m); keys.put(keySetId, ks); @@ -133,7 +134,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { } // Locking: lock - private void encodeTags(TransportKeySetId keySetId, ContactId contactId, + private void encodeTags(KeySetId keySetId, ContactId contactId, MutableIncomingKeys inKeys) { for (long streamNumber : inKeys.getWindow().getUnseen()) { TagContext tagCtx = @@ -173,21 +174,20 @@ class TransportKeyManagerImpl implements TransportKeyManager { } @Override - public TransportKeySetId addContact(Transaction txn, ContactId c, - SecretKey rootKey, long timestamp, boolean alice, boolean active) - throws DbException { + public KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey, + long timestamp, boolean alice, boolean active) throws DbException { lock.lock(); try { // Work out what time period the timestamp belongs to long timePeriod = timestamp / timePeriodLength; // Derive the transport keys - TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + TransportKeys k = transportCrypto.deriveRotationKeys(transportId, rootKey, timePeriod, alice, active); // Rotate the keys to the current time period if necessary timePeriod = clock.currentTimeMillis() / timePeriodLength; - k = transportCrypto.rotateTransportKeys(k, timePeriod); + k = transportCrypto.updateTransportKeys(k, timePeriod); // Write the keys back to the DB - TransportKeySetId keySetId = db.addTransportKeys(txn, c, k); + KeySetId keySetId = db.addTransportKeys(txn, c, k); // Initialise mutable state for the contact addKeys(keySetId, c, new MutableTransportKeys(k)); return keySetId; @@ -197,8 +197,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { } @Override - public void activateKeys(Transaction txn, TransportKeySetId k) - throws DbException { + public void activateKeys(Transaction txn, KeySetId k) throws DbException { lock.lock(); try { MutableKeySet ks = keys.get(k); @@ -331,7 +330,8 @@ class TransportKeyManagerImpl implements TransportKeyManager { Collection snapshot = new ArrayList<>(keys.size()); for (MutableKeySet ks : keys.values()) { snapshot.add(new TransportKeySet(ks.getKeySetId(), - ks.getContactId(), ks.getTransportKeys().snapshot())); + ks.getContactId(), null, + ks.getTransportKeys().snapshot())); } RotationResult rotationResult = rotateKeys(snapshot, now); // Rebuild the mutable state for all contacts @@ -351,12 +351,12 @@ class TransportKeyManagerImpl implements TransportKeyManager { private static class TagContext { - private final TransportKeySetId keySetId; + private final KeySetId keySetId; private final ContactId contactId; private final MutableIncomingKeys inKeys; private final long streamNumber; - private TagContext(TransportKeySetId keySetId, ContactId contactId, + private TagContext(KeySetId keySetId, ContactId contactId, MutableIncomingKeys inKeys, long streamNumber) { this.keySetId = keySetId; this.contactId = contactId; diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/HandshakeKeyDerivationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/HandshakeKeyDerivationTest.java deleted file mode 100644 index e741b9f08..000000000 --- a/bramble-core/src/test/java/org/briarproject/bramble/crypto/HandshakeKeyDerivationTest.java +++ /dev/null @@ -1,167 +0,0 @@ -package org.briarproject.bramble.crypto; - -import org.briarproject.bramble.api.crypto.CryptoComponent; -import org.briarproject.bramble.api.crypto.SecretKey; -import org.briarproject.bramble.api.crypto.TransportCrypto; -import org.briarproject.bramble.api.plugin.TransportId; -import org.briarproject.bramble.api.transport.HandshakeKeys; -import org.briarproject.bramble.test.BrambleTestCase; -import org.briarproject.bramble.test.TestSecureRandomProvider; -import org.junit.Test; - -import java.util.Arrays; - -import static org.briarproject.bramble.crypto.KeyDerivationTestUtils.assertAllDifferent; -import static org.briarproject.bramble.crypto.KeyDerivationTestUtils.assertMatches; -import static org.briarproject.bramble.test.TestUtils.getSecretKey; -import static org.briarproject.bramble.test.TestUtils.getTransportId; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertSame; - -public class HandshakeKeyDerivationTest extends BrambleTestCase { - - private final CryptoComponent crypto = - new CryptoComponentImpl(new TestSecureRandomProvider(), null); - private final TransportCrypto transportCrypto = - new TransportCryptoImpl(crypto); - private final TransportId transportId = getTransportId(); - private final SecretKey rootKey = getSecretKey(); - - @Test - public void testKeysAreDistinct() { - HandshakeKeys kA = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, true); - HandshakeKeys kB = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, false); - assertAllDifferent(kA); - assertAllDifferent(kB); - } - - @Test - public void testKeysAreNotUpdatedToPreviousPeriod() { - HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, true); - HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 122); - assertSame(k, k1); - } - - @Test - public void testKeysAreNotUpdatedToCurrentPeriod() { - HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, true); - HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 123); - assertSame(k, k1); - } - - @Test - public void testKeysAreUpdatedByOnePeriod() { - HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, true); - HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 124); - assertSame(k.getCurrentIncomingKeys(), k1.getPreviousIncomingKeys()); - assertSame(k.getNextIncomingKeys(), k1.getCurrentIncomingKeys()); - } - - @Test - public void testKeysAreUpdatedByTwoPeriods() { - HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, true); - HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 125); - assertSame(k.getNextIncomingKeys(), k1.getPreviousIncomingKeys()); - } - - @Test - public void testKeysAreUpdatedByThreePeriods() { - HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, true); - HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 126); - assertAllDifferent(k, k1); - } - - @Test - public void testCurrentKeysMatchContact() { - // Start in time period 123 - HandshakeKeys kA = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, true); - HandshakeKeys kB = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, false); - // Alice's incoming keys should equal Bob's outgoing keys - assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); - // Bob's incoming keys should equal Alice's outgoing keys - assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys()); - // Update into the future - kA = transportCrypto.updateHandshakeKeys(kA, 456); - kB = transportCrypto.updateHandshakeKeys(kB, 456); - // Alice's incoming keys should equal Bob's outgoing keys - assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); - // Bob's incoming keys should equal Alice's outgoing keys - assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys()); - } - - @Test - public void testPreviousKeysMatchContact() { - // Start in time period 123 - HandshakeKeys kA = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, true); - HandshakeKeys kB = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, false); - // Compare Alice's previous keys in period 456 with Bob's current keys - // in period 455 - kA = transportCrypto.updateHandshakeKeys(kA, 456); - kB = transportCrypto.updateHandshakeKeys(kB, 455); - // Alice's previous incoming keys should equal Bob's current - // outgoing keys - assertMatches(kA.getPreviousIncomingKeys(), - kB.getCurrentOutgoingKeys()); - // Compare Alice's current keys in period 456 with Bob's previous keys - // in period 457 - kB = transportCrypto.updateHandshakeKeys(kB, 457); - // Bob's previous incoming keys should equal Alice's current - // outgoing keys - assertMatches(kB.getPreviousIncomingKeys(), - kA.getCurrentOutgoingKeys()); - } - - @Test - public void testNextKeysMatchContact() { - // Start in time period 123 - HandshakeKeys kA = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, true); - HandshakeKeys kB = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, false); - // Compare Alice's current keys in period 456 with Bob's next keys in - // period 455 - kA = transportCrypto.updateHandshakeKeys(kA, 456); - kB = transportCrypto.updateHandshakeKeys(kB, 455); - // Bob's next incoming keys should equal Alice's current outgoing keys - assertMatches(kB.getNextIncomingKeys(), kA.getCurrentOutgoingKeys()); - // Compare Alice's next keys in period 456 with Bob's current keys - // in period 457 - kB = transportCrypto.updateHandshakeKeys(kB, 457); - // Alice's next incoming keys should equal Bob's current outgoing keys - assertMatches(kA.getNextIncomingKeys(), kB.getCurrentOutgoingKeys()); - } - - @Test - public void testRootKeyAffectsOutput() { - SecretKey rootKey1 = getSecretKey(); - assertFalse(Arrays.equals(rootKey.getBytes(), rootKey1.getBytes())); - HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, true); - HandshakeKeys k1 = transportCrypto.deriveHandshakeKeys(transportId, - rootKey1, 123, true); - assertAllDifferent(k, k1); - } - - @Test - public void testTransportIdAffectsOutput() { - TransportId transportId1 = getTransportId(); - assertNotEquals(transportId.getString(), transportId1.getString()); - HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, - rootKey, 123, true); - HandshakeKeys k1 = transportCrypto.deriveHandshakeKeys(transportId1, - rootKey, 123, true); - assertAllDifferent(k, k1); - } -} \ No newline at end of file diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTestUtils.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTestUtils.java deleted file mode 100644 index 878dc5488..000000000 --- a/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTestUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.briarproject.bramble.crypto; - -import org.briarproject.bramble.api.Bytes; -import org.briarproject.bramble.api.crypto.SecretKey; -import org.briarproject.bramble.api.transport.AbstractTransportKeys; -import org.briarproject.bramble.api.transport.IncomingKeys; -import org.briarproject.bramble.api.transport.OutgoingKeys; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertTrue; - -class KeyDerivationTestUtils { - - static void assertAllDifferent(AbstractTransportKeys... transportKeys) { - List secretKeys = new ArrayList<>(); - for (AbstractTransportKeys k : transportKeys) { - secretKeys.add(k.getPreviousIncomingKeys().getTagKey()); - secretKeys.add(k.getPreviousIncomingKeys().getHeaderKey()); - secretKeys.add(k.getCurrentIncomingKeys().getTagKey()); - secretKeys.add(k.getCurrentIncomingKeys().getHeaderKey()); - secretKeys.add(k.getNextIncomingKeys().getTagKey()); - secretKeys.add(k.getNextIncomingKeys().getHeaderKey()); - secretKeys.add(k.getCurrentOutgoingKeys().getTagKey()); - secretKeys.add(k.getCurrentOutgoingKeys().getHeaderKey()); - } - assertAllDifferent(secretKeys); - } - - static void assertAllDifferent(List keys) { - Set set = new HashSet<>(); - for (SecretKey k : keys) assertTrue(set.add(new Bytes(k.getBytes()))); - } - - static void assertMatches(IncomingKeys in, OutgoingKeys out) { - assertArrayEquals(in.getTagKey().getBytes(), - out.getTagKey().getBytes()); - assertArrayEquals(in.getHeaderKey().getBytes(), - out.getHeaderKey().getBytes()); - } -} diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/TransportKeyDerivationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/TransportKeyDerivationTest.java index bfa031e73..e83e4052a 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/crypto/TransportKeyDerivationTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/TransportKeyDerivationTest.java @@ -1,23 +1,30 @@ package org.briarproject.bramble.crypto; +import org.briarproject.bramble.api.Bytes; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.TransportCrypto; import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.transport.IncomingKeys; +import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.TestSecureRandomProvider; import org.junit.Test; +import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; -import static org.briarproject.bramble.crypto.KeyDerivationTestUtils.assertAllDifferent; -import static org.briarproject.bramble.crypto.KeyDerivationTestUtils.assertMatches; import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getTransportId; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; public class TransportKeyDerivationTest extends BrambleTestCase { @@ -29,70 +36,70 @@ public class TransportKeyDerivationTest extends BrambleTestCase { private final SecretKey rootKey = getSecretKey(); @Test - public void testKeysAreDistinct() { - TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, + public void testRotationKeysAreDistinct() { + TransportKeys kA = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, true, true); - TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, + TransportKeys kB = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, false, true); assertAllDifferent(kA); assertAllDifferent(kB); } @Test - public void testKeysAreNotRotatedToPreviousPeriod() { - TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + public void testRotationKeysAreNotRotatedToPreviousPeriod() { + TransportKeys k = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, true, true); - TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 122); + TransportKeys k1 = transportCrypto.updateTransportKeys(k, 122); assertSame(k, k1); } @Test - public void testKeysAreNotRotatedToCurrentPeriod() { - TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + public void testRotationKeysAreNotRotatedToCurrentPeriod() { + TransportKeys k = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, true, true); - TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 123); + TransportKeys k1 = transportCrypto.updateTransportKeys(k, 123); assertSame(k, k1); } @Test - public void testKeysAreRotatedByOnePeriod() { - TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + public void testRotationKeysAreRotatedByOnePeriod() { + TransportKeys k = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, true, true); - TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 124); + TransportKeys k1 = transportCrypto.updateTransportKeys(k, 124); assertSame(k.getCurrentIncomingKeys(), k1.getPreviousIncomingKeys()); assertSame(k.getNextIncomingKeys(), k1.getCurrentIncomingKeys()); } @Test - public void testKeysAreRotatedByTwoPeriods() { - TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + public void testRotationKeysAreRotatedByTwoPeriods() { + TransportKeys k = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, true, true); - TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 125); + TransportKeys k1 = transportCrypto.updateTransportKeys(k, 125); assertSame(k.getNextIncomingKeys(), k1.getPreviousIncomingKeys()); } @Test - public void testKeysAreRotatedByThreePeriods() { - TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + public void testRotationKeysAreRotatedByThreePeriods() { + TransportKeys k = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, true, true); - TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 126); + TransportKeys k1 = transportCrypto.updateTransportKeys(k, 126); assertAllDifferent(k, k1); } @Test - public void testCurrentKeysMatchContact() { + public void testCurrentRotationKeysMatchContact() { // Start in time period 123 - TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, + TransportKeys kA = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, true, true); - TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, + TransportKeys kB = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, false, true); // Alice's incoming keys should equal Bob's outgoing keys assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); // Bob's incoming keys should equal Alice's outgoing keys assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys()); // Rotate into the future - kA = transportCrypto.rotateTransportKeys(kA, 456); - kB = transportCrypto.rotateTransportKeys(kB, 456); + kA = transportCrypto.updateTransportKeys(kA, 456); + kB = transportCrypto.updateTransportKeys(kB, 456); // Alice's incoming keys should equal Bob's outgoing keys assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); // Bob's incoming keys should equal Alice's outgoing keys @@ -100,23 +107,23 @@ public class TransportKeyDerivationTest extends BrambleTestCase { } @Test - public void testPreviousKeysMatchContact() { + public void testPreviousRotationKeysMatchContact() { // Start in time period 123 - TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, + TransportKeys kA = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, true, true); - TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, + TransportKeys kB = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, false, true); // Compare Alice's previous keys in period 456 with Bob's current keys // in period 455 - kA = transportCrypto.rotateTransportKeys(kA, 456); - kB = transportCrypto.rotateTransportKeys(kB, 455); + kA = transportCrypto.updateTransportKeys(kA, 456); + kB = transportCrypto.updateTransportKeys(kB, 455); // Alice's previous incoming keys should equal Bob's current // outgoing keys assertMatches(kA.getPreviousIncomingKeys(), kB.getCurrentOutgoingKeys()); // Compare Alice's current keys in period 456 with Bob's previous keys // in period 457 - kB = transportCrypto.rotateTransportKeys(kB, 457); + kB = transportCrypto.updateTransportKeys(kB, 457); // Bob's previous incoming keys should equal Alice's current // outgoing keys assertMatches(kB.getPreviousIncomingKeys(), @@ -124,44 +131,208 @@ public class TransportKeyDerivationTest extends BrambleTestCase { } @Test - public void testNextKeysMatchContact() { + public void testNextRotationKeysMatchContact() { // Start in time period 123 - TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, + TransportKeys kA = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, true, true); - TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, + TransportKeys kB = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, false, true); // Compare Alice's current keys in period 456 with Bob's next keys in // period 455 - kA = transportCrypto.rotateTransportKeys(kA, 456); - kB = transportCrypto.rotateTransportKeys(kB, 455); + kA = transportCrypto.updateTransportKeys(kA, 456); + kB = transportCrypto.updateTransportKeys(kB, 455); // Bob's next incoming keys should equal Alice's current outgoing keys assertMatches(kB.getNextIncomingKeys(), kA.getCurrentOutgoingKeys()); // Compare Alice's next keys in period 456 with Bob's current keys // in period 457 - kB = transportCrypto.rotateTransportKeys(kB, 457); + kB = transportCrypto.updateTransportKeys(kB, 457); // Alice's next incoming keys should equal Bob's current outgoing keys assertMatches(kA.getNextIncomingKeys(), kB.getCurrentOutgoingKeys()); } @Test - public void testRootKeyAffectsOutput() { + public void testRootKeyAffectsRotationKeyDerivation() { SecretKey rootKey1 = getSecretKey(); assertFalse(Arrays.equals(rootKey.getBytes(), rootKey1.getBytes())); - TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + TransportKeys k = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, true, true); - TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId, + TransportKeys k1 = transportCrypto.deriveRotationKeys(transportId, rootKey1, 123, true, true); assertAllDifferent(k, k1); } @Test - public void testTransportIdAffectsOutput() { + public void testTransportIdAffectsRotationKeyDerivation() { TransportId transportId1 = getTransportId(); assertNotEquals(transportId.getString(), transportId1.getString()); - TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + TransportKeys k = transportCrypto.deriveRotationKeys(transportId, rootKey, 123, true, true); - TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId1, + TransportKeys k1 = transportCrypto.deriveRotationKeys(transportId1, rootKey, 123, true, true); assertAllDifferent(k, k1); } + + @Test + public void testHandshakeKeysAreDistinct() { + TransportKeys kA = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + TransportKeys kB = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, false); + assertAllDifferent(kA); + assertAllDifferent(kB); + } + + @Test + public void testHandshakeKeysAreNotUpdatedToPreviousPeriod() { + TransportKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + TransportKeys k1 = transportCrypto.updateTransportKeys(k, 122); + assertSame(k, k1); + } + + @Test + public void testHandshakeKeysAreNotUpdatedToCurrentPeriod() { + TransportKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + TransportKeys k1 = transportCrypto.updateTransportKeys(k, 123); + assertSame(k, k1); + } + + @Test + public void testHandshakeKeysAreUpdatedByOnePeriod() { + TransportKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + TransportKeys k1 = transportCrypto.updateTransportKeys(k, 124); + assertSame(k.getCurrentIncomingKeys(), k1.getPreviousIncomingKeys()); + assertSame(k.getNextIncomingKeys(), k1.getCurrentIncomingKeys()); + } + + @Test + public void testHandshakeKeysAreUpdatedByTwoPeriods() { + TransportKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + TransportKeys k1 = transportCrypto.updateTransportKeys(k, 125); + assertSame(k.getNextIncomingKeys(), k1.getPreviousIncomingKeys()); + } + + @Test + public void testHandshakeKeysAreUpdatedByThreePeriods() { + TransportKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + TransportKeys k1 = transportCrypto.updateTransportKeys(k, 126); + assertAllDifferent(k, k1); + } + + @Test + public void testCurrentHandshakeKeysMatchContact() { + // Start in time period 123 + TransportKeys kA = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + TransportKeys kB = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, false); + // Alice's incoming keys should equal Bob's outgoing keys + assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); + // Bob's incoming keys should equal Alice's outgoing keys + assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys()); + // Update into the future + kA = transportCrypto.updateTransportKeys(kA, 456); + kB = transportCrypto.updateTransportKeys(kB, 456); + // Alice's incoming keys should equal Bob's outgoing keys + assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); + // Bob's incoming keys should equal Alice's outgoing keys + assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys()); + } + + @Test + public void testPreviousHandshakeKeysMatchContact() { + // Start in time period 123 + TransportKeys kA = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + TransportKeys kB = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, false); + // Compare Alice's previous keys in period 456 with Bob's current keys + // in period 455 + kA = transportCrypto.updateTransportKeys(kA, 456); + kB = transportCrypto.updateTransportKeys(kB, 455); + // Alice's previous incoming keys should equal Bob's current + // outgoing keys + assertMatches(kA.getPreviousIncomingKeys(), + kB.getCurrentOutgoingKeys()); + // Compare Alice's current keys in period 456 with Bob's previous keys + // in period 457 + kB = transportCrypto.updateTransportKeys(kB, 457); + // Bob's previous incoming keys should equal Alice's current + // outgoing keys + assertMatches(kB.getPreviousIncomingKeys(), + kA.getCurrentOutgoingKeys()); + } + + @Test + public void testNextHandshakeKeysMatchContact() { + // Start in time period 123 + TransportKeys kA = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + TransportKeys kB = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, false); + // Compare Alice's current keys in period 456 with Bob's next keys in + // period 455 + kA = transportCrypto.updateTransportKeys(kA, 456); + kB = transportCrypto.updateTransportKeys(kB, 455); + // Bob's next incoming keys should equal Alice's current outgoing keys + assertMatches(kB.getNextIncomingKeys(), kA.getCurrentOutgoingKeys()); + // Compare Alice's next keys in period 456 with Bob's current keys + // in period 457 + kB = transportCrypto.updateTransportKeys(kB, 457); + // Alice's next incoming keys should equal Bob's current outgoing keys + assertMatches(kA.getNextIncomingKeys(), kB.getCurrentOutgoingKeys()); + } + + @Test + public void testRootKeyAffectsHandshakeKeyDerivation() { + SecretKey rootKey1 = getSecretKey(); + assertFalse(Arrays.equals(rootKey.getBytes(), rootKey1.getBytes())); + TransportKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + TransportKeys k1 = transportCrypto.deriveHandshakeKeys(transportId, + rootKey1, 123, true); + assertAllDifferent(k, k1); + } + + @Test + public void testTransportIdAffectsHandshakeKeyDerivation() { + TransportId transportId1 = getTransportId(); + assertNotEquals(transportId.getString(), transportId1.getString()); + TransportKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + TransportKeys k1 = transportCrypto.deriveHandshakeKeys(transportId1, + rootKey, 123, true); + assertAllDifferent(k, k1); + } + + private void assertAllDifferent(TransportKeys... transportKeys) { + List secretKeys = new ArrayList<>(); + for (TransportKeys k : transportKeys) { + secretKeys.add(k.getPreviousIncomingKeys().getTagKey()); + secretKeys.add(k.getPreviousIncomingKeys().getHeaderKey()); + secretKeys.add(k.getCurrentIncomingKeys().getTagKey()); + secretKeys.add(k.getCurrentIncomingKeys().getHeaderKey()); + secretKeys.add(k.getNextIncomingKeys().getTagKey()); + secretKeys.add(k.getNextIncomingKeys().getHeaderKey()); + secretKeys.add(k.getCurrentOutgoingKeys().getTagKey()); + secretKeys.add(k.getCurrentOutgoingKeys().getHeaderKey()); + } + assertAllDifferent(secretKeys); + } + + private void assertAllDifferent(List keys) { + Set set = new HashSet<>(); + for (SecretKey k : keys) assertTrue(set.add(new Bytes(k.getBytes()))); + } + + private void assertMatches(IncomingKeys in, OutgoingKeys out) { + assertArrayEquals(in.getTagKey().getBytes(), + out.getTagKey().getBytes()); + assertArrayEquals(in.getHeaderKey().getBytes(), + out.getHeaderKey().getBytes()); + } } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java index 4968bf81e..e353a4921 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java @@ -46,11 +46,10 @@ import org.briarproject.bramble.api.sync.event.MessageToAckEvent; import org.briarproject.bramble.api.sync.event.MessageToRequestEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesSentEvent; -import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.IncomingKeys; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.TransportKeySet; -import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.CaptureArgumentAction; @@ -117,7 +116,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { private final int maxLatency; private final ContactId contactId; private final Contact contact; - private final TransportKeySetId keySetId; + private final KeySetId keySetId; private final PendingContactId pendingContactId; public DatabaseComponentImplTest() { @@ -139,7 +138,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { contact = getContact(author, localAuthor.getId(), true); contactId = contact.getId(); alias = contact.getAlias(); - keySetId = new TransportKeySetId(345); + keySetId = new KeySetId(345); pendingContactId = new PendingContactId(getRandomId()); } @@ -284,24 +283,15 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { throws Exception { context.checking(new Expectations() {{ // Check whether the contact is in the DB (which it's not) - exactly(17).of(database).startTransaction(); + exactly(16).of(database).startTransaction(); will(returnValue(txn)); - exactly(17).of(database).containsContact(txn, contactId); + exactly(16).of(database).containsContact(txn, contactId); will(returnValue(false)); - exactly(17).of(database).abortTransaction(txn); + exactly(16).of(database).abortTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, eventBus, eventExecutor, shutdownManager); - try { - db.transaction(false, transaction -> - db.addHandshakeKeys(transaction, contactId, - createHandshakeKeys())); - fail(); - } catch (NoSuchContactException expected) { - // Expected - } - try { db.transaction(false, transaction -> db.addTransportKeys(transaction, contactId, @@ -497,8 +487,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { exactly(8).of(database).containsGroup(txn, groupId); will(returnValue(false)); exactly(8).of(database).abortTransaction(txn); - // This is needed for getMessageStatus() and setGroupVisibility() - exactly(2).of(database).containsContact(txn, contactId); + // Allow other checks to pass + allowing(database).containsContact(txn, contactId); will(returnValue(true)); }}); DatabaseComponent db = createDatabaseComponent(database, eventBus, @@ -581,8 +571,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { exactly(11).of(database).containsMessage(txn, messageId); will(returnValue(false)); exactly(11).of(database).abortTransaction(txn); - // This is needed for getMessageStatus() to proceed - exactly(1).of(database).containsContact(txn, contactId); + // Allow other checks to pass + allowing(database).containsContact(txn, contactId); will(returnValue(true)); }}); DatabaseComponent db = createDatabaseComponent(database, eventBus, @@ -682,15 +672,38 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { throws Exception { context.checking(new Expectations() {{ // Check whether the transport is in the DB (which it's not) - exactly(5).of(database).startTransaction(); + exactly(8).of(database).startTransaction(); will(returnValue(txn)); - exactly(5).of(database).containsTransport(txn, transportId); + exactly(8).of(database).containsTransport(txn, transportId); will(returnValue(false)); - exactly(5).of(database).abortTransaction(txn); + exactly(8).of(database).abortTransaction(txn); + // Allow other checks to pass + allowing(database).containsContact(txn, contactId); + will(returnValue(true)); + allowing(database).containsPendingContact(txn, pendingContactId); + will(returnValue(true)); }}); DatabaseComponent db = createDatabaseComponent(database, eventBus, eventExecutor, shutdownManager); + try { + db.transaction(false, transaction -> + db.addTransportKeys(transaction, contactId, + createHandshakeKeys())); + fail(); + } catch (NoSuchTransportException expected) { + // Expected + } + + try { + db.transaction(false, transaction -> + db.addTransportKeys(transaction, pendingContactId, + createHandshakeKeys())); + fail(); + } catch (NoSuchTransportException expected) { + // Expected + } + try { db.transaction(false, transaction -> db.getTransportKeys(transaction, transportId)); @@ -710,7 +723,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { try { db.transaction(false, transaction -> - db.removeTransport(transaction, transportId)); + db.removeTransportKeys(transaction, transportId, keySetId)); fail(); } catch (NoSuchTransportException expected) { // Expected @@ -718,7 +731,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { try { db.transaction(false, transaction -> - db.removeTransportKeys(transaction, transportId, keySetId)); + db.removeTransport(transaction, transportId)); fail(); } catch (NoSuchTransportException expected) { // Expected @@ -732,6 +745,15 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { } catch (NoSuchTransportException expected) { // Expected } + + try { + db.transaction(false, transaction -> + db.setTransportKeysActive(transaction, transportId, + keySetId)); + fail(); + } catch (NoSuchTransportException expected) { + // Expected + } } @Test @@ -751,7 +773,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { try { db.transaction(false, transaction -> - db.addHandshakeKeys(transaction, pendingContactId, + db.addTransportKeys(transaction, pendingContactId, createHandshakeKeys())); fail(); } catch (NoSuchPendingContactException expected) { @@ -1167,7 +1189,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { public void testTransportKeys() throws Exception { TransportKeys transportKeys = createTransportKeys(); TransportKeySet ks = - new TransportKeySet(keySetId, contactId, transportKeys); + new TransportKeySet(keySetId, contactId, null, transportKeys); Collection keys = singletonList(ks); context.checking(new Expectations() {{ @@ -1295,7 +1317,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { }); } - private HandshakeKeys createHandshakeKeys() { + private TransportKeys createHandshakeKeys() { SecretKey inPrevTagKey = getSecretKey(); SecretKey inPrevHeaderKey = getSecretKey(); IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey, @@ -1312,7 +1334,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { SecretKey outCurrHeaderKey = getSecretKey(); OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey, 2, 456, true); - return new HandshakeKeys(transportId, inPrev, inCurr, inNext, outCurr, + return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr, getSecretKey(), true); } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java index 9093baa07..471539769 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java @@ -22,13 +22,10 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.system.Clock; -import org.briarproject.bramble.api.transport.HandshakeKeySet; -import org.briarproject.bramble.api.transport.HandshakeKeySetId; -import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.IncomingKeys; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.TransportKeySet; -import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.system.SystemClock; import org.briarproject.bramble.test.BrambleTestCase; @@ -112,8 +109,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { private final MessageId messageId; private final TransportId transportId; private final ContactId contactId; - private final TransportKeySetId keySetId, keySetId1; - private final HandshakeKeySetId handshakeKeySetId, handshakeKeySetId1; + private final KeySetId keySetId, keySetId1; private final PendingContact pendingContact; private final Random random = new Random(); @@ -129,10 +125,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { messageId = message.getId(); transportId = getTransportId(); contactId = new ContactId(1); - keySetId = new TransportKeySetId(1); - keySetId1 = new TransportKeySetId(2); - handshakeKeySetId = new HandshakeKeySetId(1); - handshakeKeySetId1 = new HandshakeKeySetId(2); + keySetId = new KeySetId(1); + keySetId1 = new KeySetId(2); pendingContact = getPendingContact(); } @@ -706,9 +700,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { TransportKeys rotated1 = createTransportKeys(timePeriod1 + 1, active); db.updateTransportKeys(txn, new TransportKeySet(keySetId, contactId, - rotated)); + null, rotated)); db.updateTransportKeys(txn, new TransportKeySet(keySetId1, contactId, - rotated1)); + null, rotated1)); // Retrieve the transport keys again allKeys = db.getTransportKeys(txn, transportId); @@ -743,6 +737,14 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { actual.getNextIncomingKeys()); assertKeysEquals(expected.getCurrentOutgoingKeys(), actual.getCurrentOutgoingKeys()); + if (expected.isHandshakeMode()) { + assertTrue(actual.isHandshakeMode()); + assertArrayEquals(expected.getRootKey().getBytes(), + actual.getRootKey().getBytes()); + assertEquals(expected.isAlice(), actual.isAlice()); + } else { + assertFalse(actual.isHandshakeMode()); + } } private void assertKeysEquals(IncomingKeys expected, IncomingKeys actual) { @@ -771,154 +773,135 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { boolean alice = random.nextBoolean(); SecretKey rootKey = getSecretKey(); SecretKey rootKey1 = getSecretKey(); - HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); - HandshakeKeys keys1 = createHandshakeKeys(timePeriod1, rootKey1, alice); + TransportKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); + TransportKeys keys1 = createHandshakeKeys(timePeriod1, rootKey1, alice); Database db = open(false); Connection txn = db.startTransaction(); // Initially there should be no handshake keys in the database - assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId)); + assertEquals(emptyList(), db.getTransportKeys(txn, transportId)); // Add the contact, the transport and the handshake keys db.addIdentity(txn, identity); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), true)); db.addTransport(txn, transportId, 123); - assertEquals(handshakeKeySetId, - db.addHandshakeKeys(txn, contactId, keys)); - assertEquals(handshakeKeySetId1, - db.addHandshakeKeys(txn, contactId, keys1)); + assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys)); + assertEquals(keySetId1, db.addTransportKeys(txn, contactId, keys1)); // Retrieve the handshake keys - Collection allKeys = - db.getHandshakeKeys(txn, transportId); + Collection allKeys = + db.getTransportKeys(txn, transportId); assertEquals(2, allKeys.size()); - for (HandshakeKeySet ks : allKeys) { + for (TransportKeySet ks : allKeys) { assertEquals(contactId, ks.getContactId()); assertNull(ks.getPendingContactId()); - if (ks.getKeySetId().equals(handshakeKeySetId)) { + if (ks.getKeySetId().equals(keySetId)) { assertKeysEquals(keys, ks.getKeys()); } else { - assertEquals(handshakeKeySetId1, ks.getKeySetId()); + assertEquals(keySetId1, ks.getKeySetId()); assertKeysEquals(keys1, ks.getKeys()); } } // Update the handshake keys - HandshakeKeys updated = + TransportKeys updated = createHandshakeKeys(timePeriod + 1, rootKey, alice); - HandshakeKeys updated1 = + TransportKeys updated1 = createHandshakeKeys(timePeriod1 + 1, rootKey1, alice); - db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId, - contactId, updated)); - db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId1, - contactId, updated1)); + db.updateTransportKeys(txn, new TransportKeySet(keySetId, contactId, + null, updated)); + db.updateTransportKeys(txn, new TransportKeySet(keySetId1, contactId, + null, updated1)); // Retrieve the handshake keys again - allKeys = db.getHandshakeKeys(txn, transportId); + allKeys = db.getTransportKeys(txn, transportId); assertEquals(2, allKeys.size()); - for (HandshakeKeySet ks : allKeys) { + for (TransportKeySet ks : allKeys) { assertEquals(contactId, ks.getContactId()); assertNull(ks.getPendingContactId()); - if (ks.getKeySetId().equals(handshakeKeySetId)) { + if (ks.getKeySetId().equals(keySetId)) { assertKeysEquals(updated, ks.getKeys()); } else { - assertEquals(handshakeKeySetId1, ks.getKeySetId()); + assertEquals(keySetId1, ks.getKeySetId()); assertKeysEquals(updated1, ks.getKeys()); } } // Removing the contact should remove the handshake keys db.removeContact(txn, contactId); - assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId)); + assertEquals(emptyList(), db.getTransportKeys(txn, transportId)); db.commitTransaction(txn); db.close(); } - private void assertKeysEquals(HandshakeKeys expected, - HandshakeKeys actual) { - assertEquals(expected.getTransportId(), actual.getTransportId()); - assertEquals(expected.getTimePeriod(), actual.getTimePeriod()); - assertArrayEquals(expected.getRootKey().getBytes(), - actual.getRootKey().getBytes()); - assertEquals(expected.isAlice(), actual.isAlice()); - assertKeysEquals(expected.getPreviousIncomingKeys(), - actual.getPreviousIncomingKeys()); - assertKeysEquals(expected.getCurrentIncomingKeys(), - actual.getCurrentIncomingKeys()); - assertKeysEquals(expected.getNextIncomingKeys(), - actual.getNextIncomingKeys()); - assertKeysEquals(expected.getCurrentOutgoingKeys(), - actual.getCurrentOutgoingKeys()); - } - @Test public void testHandshakeKeysForPendingContact() throws Exception { long timePeriod = 123, timePeriod1 = 234; boolean alice = random.nextBoolean(); SecretKey rootKey = getSecretKey(); SecretKey rootKey1 = getSecretKey(); - HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); - HandshakeKeys keys1 = createHandshakeKeys(timePeriod1, rootKey1, alice); + TransportKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); + TransportKeys keys1 = createHandshakeKeys(timePeriod1, rootKey1, alice); Database db = open(false); Connection txn = db.startTransaction(); // Initially there should be no handshake keys in the database - assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId)); + assertEquals(emptyList(), db.getTransportKeys(txn, transportId)); // Add the pending contact, the transport and the handshake keys db.addPendingContact(txn, pendingContact); db.addTransport(txn, transportId, 123); - assertEquals(handshakeKeySetId, db.addHandshakeKeys(txn, - pendingContact.getId(), keys)); - assertEquals(handshakeKeySetId1, db.addHandshakeKeys(txn, - pendingContact.getId(), keys1)); + assertEquals(keySetId, + db.addTransportKeys(txn, pendingContact.getId(), keys)); + assertEquals(keySetId1, + db.addTransportKeys(txn, pendingContact.getId(), keys1)); // Retrieve the handshake keys - Collection allKeys = - db.getHandshakeKeys(txn, transportId); + Collection allKeys = + db.getTransportKeys(txn, transportId); assertEquals(2, allKeys.size()); - for (HandshakeKeySet ks : allKeys) { + for (TransportKeySet ks : allKeys) { assertNull(ks.getContactId()); assertEquals(pendingContact.getId(), ks.getPendingContactId()); - if (ks.getKeySetId().equals(handshakeKeySetId)) { + if (ks.getKeySetId().equals(keySetId)) { assertKeysEquals(keys, ks.getKeys()); } else { - assertEquals(handshakeKeySetId1, ks.getKeySetId()); + assertEquals(keySetId1, ks.getKeySetId()); assertKeysEquals(keys1, ks.getKeys()); } } // Update the handshake keys - HandshakeKeys updated = + TransportKeys updated = createHandshakeKeys(timePeriod + 1, rootKey, alice); - HandshakeKeys updated1 = + TransportKeys updated1 = createHandshakeKeys(timePeriod1 + 1, rootKey1, alice); - db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId, + db.updateTransportKeys(txn, new TransportKeySet(keySetId, null, pendingContact.getId(), updated)); - db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId1, + db.updateTransportKeys(txn, new TransportKeySet(keySetId1, null, pendingContact.getId(), updated1)); // Retrieve the handshake keys again - allKeys = db.getHandshakeKeys(txn, transportId); + allKeys = db.getTransportKeys(txn, transportId); assertEquals(2, allKeys.size()); - for (HandshakeKeySet ks : allKeys) { + for (TransportKeySet ks : allKeys) { assertNull(ks.getContactId()); assertEquals(pendingContact.getId(), ks.getPendingContactId()); - if (ks.getKeySetId().equals(handshakeKeySetId)) { + if (ks.getKeySetId().equals(keySetId)) { assertKeysEquals(updated, ks.getKeys()); } else { - assertEquals(handshakeKeySetId1, ks.getKeySetId()); + assertEquals(keySetId1, ks.getKeySetId()); assertKeysEquals(updated1, ks.getKeys()); } } // Removing the pending contact should remove the handshake keys db.removePendingContact(txn, pendingContact.getId()); - assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId)); + assertEquals(emptyList(), db.getTransportKeys(txn, transportId)); db.commitTransaction(txn); db.close(); @@ -971,7 +954,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { long timePeriod = 123; SecretKey rootKey = getSecretKey(); boolean alice = random.nextBoolean(); - HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); + TransportKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter(); Database db = open(false); @@ -982,20 +965,20 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), true)); db.addTransport(txn, transportId, 123); - assertEquals(handshakeKeySetId, - db.addHandshakeKeys(txn, contactId, keys)); + assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys)); // Increment the stream counter twice and retrieve the handshake keys - db.incrementStreamCounter(txn, transportId, handshakeKeySetId); - db.incrementStreamCounter(txn, transportId, handshakeKeySetId); - Collection newKeys = - db.getHandshakeKeys(txn, transportId); + db.incrementStreamCounter(txn, transportId, keySetId); + db.incrementStreamCounter(txn, transportId, keySetId); + Collection newKeys = + db.getTransportKeys(txn, transportId); assertEquals(1, newKeys.size()); - HandshakeKeySet ks = newKeys.iterator().next(); - assertEquals(handshakeKeySetId, ks.getKeySetId()); + TransportKeySet ks = newKeys.iterator().next(); + assertEquals(keySetId, ks.getKeySetId()); assertEquals(contactId, ks.getContactId()); - HandshakeKeys k = ks.getKeys(); + TransportKeys k = ks.getKeys(); assertEquals(transportId, k.getTransportId()); + assertNotNull(k.getRootKey()); assertArrayEquals(rootKey.getBytes(), k.getRootKey().getBytes()); assertEquals(alice, k.isAlice()); OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); @@ -1064,7 +1047,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { long timePeriod = 123; SecretKey rootKey = getSecretKey(); boolean alice = random.nextBoolean(); - HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); + TransportKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); long base = keys.getCurrentIncomingKeys().getWindowBase(); byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap(); @@ -1076,21 +1059,21 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), true)); db.addTransport(txn, transportId, 123); - assertEquals(handshakeKeySetId, - db.addHandshakeKeys(txn, contactId, keys)); + assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys)); // Update the reordering window and retrieve the handshake keys random.nextBytes(bitmap); - db.setReorderingWindow(txn, handshakeKeySetId, transportId, timePeriod, + db.setReorderingWindow(txn, keySetId, transportId, timePeriod, base + 1, bitmap); - Collection newKeys = - db.getHandshakeKeys(txn, transportId); + Collection newKeys = + db.getTransportKeys(txn, transportId); assertEquals(1, newKeys.size()); - HandshakeKeySet ks = newKeys.iterator().next(); - assertEquals(handshakeKeySetId, ks.getKeySetId()); + TransportKeySet ks = newKeys.iterator().next(); + assertEquals(keySetId, ks.getKeySetId()); assertEquals(contactId, ks.getContactId()); - HandshakeKeys k = ks.getKeys(); + TransportKeys k = ks.getKeys(); assertEquals(transportId, k.getTransportId()); + assertNotNull(k.getRootKey()); assertArrayEquals(rootKey.getBytes(), k.getRootKey().getBytes()); assertEquals(alice, k.isAlice()); IncomingKeys inCurr = k.getCurrentIncomingKeys(); @@ -2302,7 +2285,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr); } - private HandshakeKeys createHandshakeKeys(long timePeriod, + private TransportKeys createHandshakeKeys(long timePeriod, SecretKey rootKey, boolean alice) { SecretKey inPrevTagKey = getSecretKey(); SecretKey inPrevHeaderKey = getSecretKey(); @@ -2320,7 +2303,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { SecretKey outCurrHeaderKey = getSecretKey(); OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey, timePeriod, 456, true); - return new HandshakeKeys(transportId, inPrev, inCurr, inNext, outCurr, + return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr, rootKey, alice); } 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 8e78d5e56..4ffec6764 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 @@ -8,8 +8,8 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.plugin.PluginConfig; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.StreamContext; -import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.DbExpectations; import org.jmock.Expectations; @@ -43,7 +43,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase { private final DeterministicExecutor executor = new DeterministicExecutor(); private final Transaction txn = new Transaction(null, false); private final ContactId contactId = getContactId(); - private final TransportKeySetId keySetId = new TransportKeySetId(345); + private final KeySetId keySetId = new KeySetId(345); private final TransportId transportId = getTransportId(); private final TransportId unknownTransportId = getTransportId(); private final StreamContext streamContext = new StreamContext(contactId, @@ -95,8 +95,8 @@ public class KeyManagerImplTest extends BrambleMockTestCase { will(returnValue(keySetId)); }}); - Map ids = keyManager.addContact(txn, - contactId, secretKey, timestamp, alice, active); + Map ids = keyManager.addContact(txn, contactId, + secretKey, timestamp, alice, active); assertEquals(singletonMap(transportId, keySetId), ids); } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java index 5acae322e..9688ff89c 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java @@ -8,10 +8,10 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.IncomingKeys; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.StreamContext; import org.briarproject.bramble.api.transport.TransportKeySet; -import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.DbExpectations; @@ -61,8 +61,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { private final long timePeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE; private final ContactId contactId = getContactId(); private final ContactId contactId1 = getContactId(); - private final TransportKeySetId keySetId = new TransportKeySetId(345); - private final TransportKeySetId keySetId1 = new TransportKeySetId(456); + private final KeySetId keySetId = new KeySetId(345); + private final KeySetId keySetId1 = new KeySetId(456); private final SecretKey tagKey = getSecretKey(); private final SecretKey headerKey = getSecretKey(); private final SecretKey rootKey = getSecretKey(); @@ -73,8 +73,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { TransportKeys shouldRotate = createTransportKeys(900, 0, true); TransportKeys shouldNotRotate = createTransportKeys(1000, 0, true); Collection loaded = asList( - new TransportKeySet(keySetId, contactId, shouldRotate), - new TransportKeySet(keySetId1, contactId1, shouldNotRotate) + new TransportKeySet(keySetId, contactId, null, shouldRotate), + new TransportKeySet(keySetId1, contactId1, null, + shouldNotRotate) ); TransportKeys rotated = createTransportKeys(1000, 0, true); Transaction txn = new Transaction(null, false); @@ -87,9 +88,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { oneOf(db).getTransportKeys(txn, transportId); will(returnValue(loaded)); // Rotate the transport keys - oneOf(transportCrypto).rotateTransportKeys(shouldRotate, 1000); + oneOf(transportCrypto).updateTransportKeys(shouldRotate, 1000); will(returnValue(rotated)); - oneOf(transportCrypto).rotateTransportKeys(shouldNotRotate, 1000); + oneOf(transportCrypto).updateTransportKeys(shouldNotRotate, 1000); will(returnValue(shouldNotRotate)); // Encode the tags (3 sets per contact) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { @@ -100,7 +101,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { } // Save the keys that were rotated oneOf(db).updateTransportKeys(txn, singletonList( - new TransportKeySet(keySetId, contactId, rotated))); + new TransportKeySet(keySetId, contactId, null, rotated))); // Schedule key rotation at the start of the next time period oneOf(scheduler).schedule(with(any(Runnable.class)), with(timePeriodLength - 1), with(MILLISECONDS)); @@ -121,14 +122,14 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { Transaction txn = new Transaction(null, false); context.checking(new Expectations() {{ - oneOf(transportCrypto).deriveTransportKeys(transportId, rootKey, + oneOf(transportCrypto).deriveRotationKeys(transportId, rootKey, 999, alice, true); will(returnValue(transportKeys)); // Get the current time (1 ms after start of time period 1000) oneOf(clock).currentTimeMillis(); will(returnValue(timePeriodLength * 1000 + 1)); // Rotate the transport keys - oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); + oneOf(transportCrypto).updateTransportKeys(transportKeys, 1000); will(returnValue(rotated)); // Encode the tags (3 sets) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { @@ -257,7 +258,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { List tags = new ArrayList<>(); context.checking(new Expectations() {{ - oneOf(transportCrypto).deriveTransportKeys(transportId, rootKey, + oneOf(transportCrypto).deriveRotationKeys(transportId, rootKey, 1000, alice, true); will(returnValue(transportKeys)); // Get the current time (the start of time period 1000) @@ -271,7 +272,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { will(new EncodeTagAction(tags)); } // Rotate the transport keys (the keys are unaffected) - oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); + oneOf(transportCrypto).updateTransportKeys(transportKeys, 1000); will(returnValue(transportKeys)); // Save the keys oneOf(db).addTransportKeys(txn, contactId, transportKeys); @@ -315,7 +316,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { public void testKeysAreRotatedToCurrentPeriod() throws Exception { TransportKeys transportKeys = createTransportKeys(1000, 0, true); Collection loaded = singletonList( - new TransportKeySet(keySetId, contactId, transportKeys)); + new TransportKeySet(keySetId, contactId, null, transportKeys)); TransportKeys rotated = createTransportKeys(1001, 0, true); Transaction txn = new Transaction(null, false); Transaction txn1 = new Transaction(null, false); @@ -328,7 +329,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { oneOf(db).getTransportKeys(txn, transportId); will(returnValue(loaded)); // Rotate the transport keys (the keys are unaffected) - oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); + oneOf(transportCrypto).updateTransportKeys(transportKeys, 1000); will(returnValue(transportKeys)); // Encode the tags (3 sets) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { @@ -349,7 +350,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(timePeriodLength * 1001)); // Rotate the transport keys - oneOf(transportCrypto).rotateTransportKeys( + oneOf(transportCrypto).updateTransportKeys( with(any(TransportKeys.class)), with(1001L)); will(returnValue(rotated)); // Encode the tags (3 sets) @@ -361,7 +362,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { } // Save the keys that were rotated oneOf(db).updateTransportKeys(txn1, singletonList( - new TransportKeySet(keySetId, contactId, rotated))); + new TransportKeySet(keySetId, contactId, null, rotated))); // Schedule key rotation at the start of the next time period oneOf(scheduler).schedule(with(any(Runnable.class)), with(timePeriodLength), with(MILLISECONDS)); @@ -422,7 +423,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { List tags = new ArrayList<>(); context.checking(new Expectations() {{ - oneOf(transportCrypto).deriveTransportKeys(transportId, rootKey, + oneOf(transportCrypto).deriveRotationKeys(transportId, rootKey, 1000, alice, false); will(returnValue(transportKeys)); // Get the current time (the start of time period 1000) @@ -436,7 +437,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { will(new EncodeTagAction(tags)); } // Rotate the transport keys (the keys are unaffected) - oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); + oneOf(transportCrypto).updateTransportKeys(transportKeys, 1000); will(returnValue(transportKeys)); // Save the keys oneOf(db).addTransportKeys(txn, contactId, transportKeys); @@ -489,7 +490,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { private void expectAddContactNoRotation(boolean alice, boolean active, TransportKeys transportKeys, Transaction txn) throws Exception { context.checking(new Expectations() {{ - oneOf(transportCrypto).deriveTransportKeys(transportId, rootKey, + oneOf(transportCrypto).deriveRotationKeys(transportId, rootKey, 1000, alice, active); will(returnValue(transportKeys)); // Get the current time (the start of time period 1000) @@ -503,7 +504,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { will(new EncodeTagAction()); } // Rotate the transport keys (the keys are unaffected) - oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); + oneOf(transportCrypto).updateTransportKeys(transportKeys, 1000); will(returnValue(transportKeys)); // Save the keys oneOf(db).addTransportKeys(txn, contactId, transportKeys); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java index d7ef81893..49ed450e8 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java @@ -23,7 +23,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.KeyManager; -import org.briarproject.bramble.api.transport.TransportKeySetId; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.SessionId; @@ -430,7 +430,7 @@ class IntroduceeProtocolEngine s.getRemote().acceptTimestamp); if (timestamp == -1) throw new AssertionError(); - Map keys = null; + Map keys = null; try { contactManager.addContact(txn, s.getRemote().author, localAuthor.getId(), false); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java index 5a6967a90..d5c85e323 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java @@ -8,7 +8,7 @@ import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.transport.TransportKeySetId; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.introduction.Role; @@ -33,12 +33,12 @@ class IntroduceeSession extends Session @Nullable private final byte[] masterKey; @Nullable - private final Map transportKeys; + private final Map transportKeys; IntroduceeSession(SessionId sessionId, IntroduceeState state, long requestTimestamp, GroupId contactGroupId, Author introducer, Local local, Remote remote, @Nullable byte[] masterKey, - @Nullable Map transportKeys) { + @Nullable Map transportKeys) { super(sessionId, state, requestTimestamp); this.contactGroupId = contactGroupId; this.introducer = introducer; @@ -113,8 +113,7 @@ class IntroduceeSession extends Session } static IntroduceeSession awaitActivate(IntroduceeSession s, AuthMessage m, - Message sent, - @Nullable Map transportKeys) { + Message sent, @Nullable Map transportKeys) { Local local = new Local(s.local, sent.getId(), sent.getTimestamp()); Remote remote = new Remote(s.remote, m.getMessageId()); return new IntroduceeSession(s.getSessionId(), AWAIT_ACTIVATE, @@ -181,7 +180,7 @@ class IntroduceeSession extends Session } @Nullable - Map getTransportKeys() { + Map getTransportKeys() { return transportKeys; } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoderImpl.java index 434608503..8f9819cf8 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoderImpl.java @@ -6,13 +6,14 @@ import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; -import org.briarproject.bramble.api.transport.TransportKeySetId; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.briar.introduction.IntroduceeSession.Common; import org.briarproject.briar.introduction.IntroduceeSession.Local; import org.briarproject.briar.introduction.IntroduceeSession.Remote; import org.briarproject.briar.introduction.IntroducerSession.Introducee; import java.util.Map; +import java.util.Map.Entry; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; @@ -143,10 +144,10 @@ class SessionEncoderImpl implements SessionEncoder { @Nullable private BdfDictionary encodeTransportKeys( - @Nullable Map keys) { + @Nullable Map keys) { if (keys == null) return null; BdfDictionary d = new BdfDictionary(); - for (Map.Entry e : keys.entrySet()) { + for (Entry e : keys.entrySet()) { d.put(e.getKey().getString(), e.getValue().getInt()); } return d; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java index 471d8efa2..bd7f51770 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java @@ -10,7 +10,7 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.transport.TransportKeySetId; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.introduction.Role; import org.briarproject.briar.introduction.IntroduceeSession.Local; @@ -110,7 +110,7 @@ class SessionParserImpl implements SessionParser { Local local = parseLocal(d.getDictionary(SESSION_KEY_LOCAL)); Remote remote = parseRemote(d.getDictionary(SESSION_KEY_REMOTE)); byte[] masterKey = d.getOptionalRaw(SESSION_KEY_MASTER_KEY); - Map transportKeys = parseTransportKeys( + Map transportKeys = parseTransportKeys( d.getOptionalDictionary(SESSION_KEY_TRANSPORT_KEYS)); return new IntroduceeSession(sessionId, state, requestTimestamp, introducerGroupId, introducer, local, remote, @@ -184,13 +184,13 @@ class SessionParserImpl implements SessionParser { } @Nullable - private Map parseTransportKeys( + private Map parseTransportKeys( @Nullable BdfDictionary d) throws FormatException { if (d == null) return null; - Map map = new HashMap<>(d.size()); + Map map = new HashMap<>(d.size()); for (String key : d.keySet()) { map.put(new TransportId(key), - new TransportKeySetId(d.getLong(key).intValue())); + new KeySetId(d.getLong(key).intValue())); } return map; } diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java index df29af3d7..9ddb00632 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java @@ -10,7 +10,7 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.transport.TransportKeySetId; +import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.introduction.IntroducerSession.Introducee; @@ -75,8 +75,7 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase { getTransportPropertiesMap(3); private final Map remoteTransportProperties = getTransportPropertiesMap(3); - private final Map transportKeys = - new HashMap<>(); + private final Map transportKeys = new HashMap<>(); private final byte[] localMacKey = getRandomBytes(SecretKey.LENGTH); private final byte[] remoteMacKey = getRandomBytes(SecretKey.LENGTH); @@ -89,9 +88,9 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase { sessionParser = new SessionParserImpl(clientHelper); author1 = getRealAuthor(authorFactory); author2 = getRealAuthor(authorFactory); - transportKeys.put(getTransportId(), new TransportKeySetId(1)); - transportKeys.put(getTransportId(), new TransportKeySetId(2)); - transportKeys.put(getTransportId(), new TransportKeySetId(3)); + transportKeys.put(getTransportId(), new KeySetId(1)); + transportKeys.put(getTransportId(), new KeySetId(2)); + transportKeys.put(getTransportId(), new KeySetId(3)); } @Test