Merge handshake and transport keys.

This commit is contained in:
akwizgran
2019-05-01 09:43:10 +01:00
parent 658c63d94e
commit 7dc4dc566f
33 changed files with 788 additions and 1342 deletions

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.api.crypto; package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.transport.HandshakeKeys;
import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.api.transport.TransportKeys;
/** /**
@@ -11,35 +10,29 @@ import org.briarproject.bramble.api.transport.TransportKeys;
public interface TransportCrypto { public interface TransportCrypto {
/** /**
* Derives initial transport keys for the given transport in the given * Derives initial rotation mode transport keys for the given transport in
* time period from the given root key. * 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
* @param active whether the keys are usable for outgoing streams. * @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); 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 * Derives handshake keys for the given transport in the given time period
* from the given root key. * 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); 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. * 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. * Encodes the pseudo-random tag that is used to recognise a stream.

View File

@@ -22,11 +22,8 @@ import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.HandshakeKeySet; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
import org.briarproject.bramble.api.transport.HandshakeKeys;
import org.briarproject.bramble.api.transport.TransportKeySet; 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.api.transport.TransportKeys;
import java.util.Collection; import java.util.Collection;
@@ -113,20 +110,6 @@ public interface DatabaseComponent {
*/ */
void addGroup(Transaction txn, Group g) throws DbException; 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. * Stores an identity.
*/ */
@@ -154,7 +137,14 @@ public interface DatabaseComponent {
* Stores the given transport keys for the given contact and returns a * Stores the given transport keys for the given contact and returns a
* key set ID. * 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; TransportKeys k) throws DbException;
/** /**
@@ -308,14 +298,6 @@ public interface DatabaseComponent {
Visibility getGroupVisibility(Transaction txn, ContactId c, GroupId g) Visibility getGroupVisibility(Transaction txn, ContactId c, GroupId g)
throws DbException; throws DbException;
/**
* Returns all handshake keys for the given transport.
* <p/>
* Read-only.
*/
Collection<HandshakeKeySet> getHandshakeKeys(Transaction txn, TransportId t)
throws DbException;
/** /**
* Returns the identity for the local pseudonym with the given ID. * Returns the identity for the local pseudonym with the given ID.
* <p/> * <p/>
@@ -487,17 +469,11 @@ public interface DatabaseComponent {
Collection<TransportKeySet> getTransportKeys(Transaction txn, TransportId t) Collection<TransportKeySet> getTransportKeys(Transaction txn, TransportId t)
throws DbException; 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. * Increments the outgoing stream counter for the given transport keys.
*/ */
void incrementStreamCounter(Transaction txn, TransportId t, void incrementStreamCounter(Transaction txn, TransportId t, KeySetId k)
TransportKeySetId k) throws DbException; throws DbException;
/** /**
* Merges the given metadata with the existing metadata for the given * 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; 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. * 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. * Removes the given transport keys from the database.
*/ */
void removeTransportKeys(Transaction txn, TransportId t, void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
TransportKeySetId k) throws DbException; throws DbException;
/** /**
* Marks the given contact as verified. * Marks the given contact as verified.
@@ -626,31 +596,16 @@ public interface DatabaseComponent {
byte[] privateKey) throws DbException; 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. * time period.
*/ */
void setReorderingWindow(Transaction txn, TransportKeySetId k, void setReorderingWindow(Transaction txn, KeySetId k, TransportId t,
TransportId t, long timePeriod, long base, byte[] bitmap) long timePeriod, long base, byte[] bitmap) throws DbException;
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;
/** /**
* Marks the given transport keys as usable for outgoing streams. * Marks the given transport keys as usable for outgoing streams.
*/ */
void setTransportKeysActive(Transaction txn, TransportId t, void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k)
TransportKeySetId k) throws DbException;
/**
* Stores the given handshake keys, deleting any keys they have replaced.
*/
void updateHandshakeKeys(Transaction txn, Collection<HandshakeKeySet> keys)
throws DbException; throws DbException;
/** /**

View File

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

View File

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

View File

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

View File

@@ -8,8 +8,8 @@ import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE; import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
/** /**
* Contains transport keys for receiving streams from a given contact over a * Contains transport keys for receiving streams from a given contact or
* given transport in a given time period. * pending contact over a given transport in a given time period.
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault

View File

@@ -27,14 +27,14 @@ public interface KeyManager {
* @param alice true if the local party is Alice * @param alice true if the local party is Alice
* @param active whether the derived keys can be used for outgoing streams * @param active whether the derived keys can be used for outgoing streams
*/ */
Map<TransportId, TransportKeySetId> addContact(Transaction txn, ContactId c, Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
SecretKey rootKey, long timestamp, boolean alice, boolean active) SecretKey rootKey, long timestamp, boolean alice, boolean active)
throws DbException; throws DbException;
/** /**
* Marks the given transport keys as usable for outgoing streams. * Marks the given transport keys as usable for outgoing streams.
*/ */
void activateKeys(Transaction txn, Map<TransportId, TransportKeySetId> keys) void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
throws DbException; throws DbException;
/** /**

View File

@@ -5,17 +5,16 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
/** /**
* Type-safe wrapper for an integer that uniquely identifies a * Type-safe wrapper for an integer that uniquely identifies a set of
* {@link HandshakeKeySet set of handshake keys} within the scope of the local * {@link TransportKeySet transport keys} within the scope of the local device.
* device.
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class HandshakeKeySetId { public class KeySetId {
private final int id; private final int id;
public HandshakeKeySetId(int id) { public KeySetId(int id) {
this.id = id; this.id = id;
} }
@@ -30,7 +29,6 @@ public class HandshakeKeySetId {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof HandshakeKeySetId && return o instanceof KeySetId && id == ((KeySetId) o).id;
id == ((HandshakeKeySetId) o).id;
} }
} }

View File

@@ -6,8 +6,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
/** /**
* Contains transport keys for sending streams to a given contact over a given * Contains transport keys for sending streams to a given contact or pending
* transport in a given time period. * contact over a given transport in a given time period.
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault

View File

@@ -1,37 +1,49 @@
package org.briarproject.bramble.api.transport; package org.briarproject.bramble.api.transport;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
/** /**
* A set of keys for communicating with a given contact over a given transport. * A set of keys for communicating with a given contact or pending contact
* Unlike a {@link HandshakeKeySet} these keys provide forward secrecy. * over a given transport.
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class TransportKeySet { public class TransportKeySet {
private final TransportKeySetId keySetId; private final KeySetId keySetId;
@Nullable
private final ContactId contactId; private final ContactId contactId;
@Nullable
private final PendingContactId pendingContactId;
private final TransportKeys keys; private final TransportKeys keys;
public TransportKeySet(TransportKeySetId keySetId, ContactId contactId, public TransportKeySet(KeySetId keySetId, @Nullable ContactId contactId,
TransportKeys keys) { @Nullable PendingContactId pendingContactId, TransportKeys keys) {
this.keySetId = keySetId; this.keySetId = keySetId;
this.contactId = contactId; this.contactId = contactId;
this.pendingContactId = pendingContactId;
this.keys = keys; this.keys = keys;
} }
public TransportKeySetId getKeySetId() { public KeySetId getKeySetId() {
return keySetId; return keySetId;
} }
@Nullable
public ContactId getContactId() { public ContactId getContactId() {
return contactId; return contactId;
} }
@Nullable
public PendingContactId getPendingContactId() {
return pendingContactId;
}
public TransportKeys getKeys() { public TransportKeys getKeys() {
return keys; return keys;
} }

View File

@@ -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.
* <p/>
* 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;
}
}

View File

@@ -1,20 +1,108 @@
package org.briarproject.bramble.api.transport; 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.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
/** /**
* Keys for communicating with a given contact over a given transport. Unlike * Keys for communicating with a given contact or pending contact over a given
* {@link HandshakeKeys} these keys provide forward secrecy. * transport.
*/ */
@Immutable @Immutable
@NotNullByDefault @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, public TransportKeys(TransportId transportId, IncomingKeys inPrev,
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) { 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;
} }
} }

View File

@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.crypto.TransportCrypto; import org.briarproject.bramble.api.crypto.TransportCrypto;
import org.briarproject.bramble.api.plugin.TransportId; 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.IncomingKeys;
import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys;
import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.api.transport.TransportKeys;
@@ -42,7 +41,7 @@ class TransportCryptoImpl implements TransportCrypto {
} }
@Override @Override
public TransportKeys deriveTransportKeys(TransportId t, public TransportKeys deriveRotationKeys(TransportId t,
SecretKey rootKey, long timePeriod, boolean weAreAlice, SecretKey rootKey, long timePeriod, boolean weAreAlice,
boolean active) { boolean active) {
// Keys for the previous period are derived from the root key // 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); 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) { private SecretKey rotateKey(SecretKey k, long timePeriod) {
byte[] period = new byte[INT_64_BYTES]; byte[] period = new byte[INT_64_BYTES];
writeUint64(timePeriod, period, 0); writeUint64(timePeriod, period, 0);
@@ -117,7 +91,7 @@ class TransportCryptoImpl implements TransportCrypto {
} }
@Override @Override
public HandshakeKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey, public TransportKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey,
long timePeriod, boolean weAreAlice) { long timePeriod, boolean weAreAlice) {
if (timePeriod < 1) throw new IllegalArgumentException(); if (timePeriod < 1) throw new IllegalArgumentException();
IncomingKeys inPrev = deriveIncomingHandshakeKeys(t, rootKey, IncomingKeys inPrev = deriveIncomingHandshakeKeys(t, rootKey,
@@ -128,7 +102,7 @@ class TransportCryptoImpl implements TransportCrypto {
weAreAlice, timePeriod + 1); weAreAlice, timePeriod + 1);
OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey,
weAreAlice, timePeriod); weAreAlice, timePeriod);
return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, rootKey, return new TransportKeys(t, inPrev, inCurr, inNext, outCurr, rootKey,
weAreAlice); weAreAlice);
} }
@@ -171,7 +145,13 @@ class TransportCryptoImpl implements TransportCrypto {
} }
@Override @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(); long elapsed = timePeriod - k.getTimePeriod();
TransportId t = k.getTransportId(); TransportId t = k.getTransportId();
SecretKey rootKey = k.getRootKey(); SecretKey rootKey = k.getRootKey();
@@ -188,7 +168,7 @@ class TransportCryptoImpl implements TransportCrypto {
weAreAlice, timePeriod + 1); weAreAlice, timePeriod + 1);
OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey,
weAreAlice, timePeriod); weAreAlice, timePeriod);
return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, return new TransportKeys(t, inPrev, inCurr, inNext, outCurr,
rootKey, weAreAlice); rootKey, weAreAlice);
} else if (elapsed == 2) { } else if (elapsed == 2) {
// The keys are two periods old - shift by two periods, keeping // The keys are two periods old - shift by two periods, keeping
@@ -200,7 +180,7 @@ class TransportCryptoImpl implements TransportCrypto {
weAreAlice, timePeriod + 1); weAreAlice, timePeriod + 1);
OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey,
weAreAlice, timePeriod); weAreAlice, timePeriod);
return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, return new TransportKeys(t, inPrev, inCurr, inNext, outCurr,
rootKey, weAreAlice); rootKey, weAreAlice);
} else { } else {
// The keys are more than two periods old - derive fresh keys // 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 @Override
public void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion, public void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion,
long streamNumber) { long streamNumber) {

View File

@@ -27,11 +27,8 @@ import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.HandshakeKeySet; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
import org.briarproject.bramble.api.transport.HandshakeKeys;
import org.briarproject.bramble.api.transport.TransportKeySet; 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.api.transport.TransportKeys;
import java.util.Collection; import java.util.Collection;
@@ -105,20 +102,6 @@ interface Database<T> {
void addGroupVisibility(T txn, ContactId c, GroupId g, boolean shared) void addGroupVisibility(T txn, ContactId c, GroupId g, boolean shared)
throws DbException; 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. * Stores an identity.
*/ */
@@ -160,7 +143,14 @@ interface Database<T> {
* Stores the given transport keys for the given contact and returns a * Stores the given transport keys for the given contact and returns a
* key set ID. * 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; throws DbException;
/** /**
@@ -315,14 +305,6 @@ interface Database<T> {
Map<ContactId, Boolean> getGroupVisibility(T txn, GroupId g) Map<ContactId, Boolean> getGroupVisibility(T txn, GroupId g)
throws DbException; throws DbException;
/**
* Returns all handshake keys for the given transport.
* <p/>
* Read-only.
*/
Collection<HandshakeKeySet> getHandshakeKeys(T txn, TransportId t)
throws DbException;
/** /**
* Returns the identity for local pseudonym with the given ID. * Returns the identity for local pseudonym with the given ID.
* <p/> * <p/>
@@ -545,16 +527,10 @@ interface Database<T> {
Collection<TransportKeySet> getTransportKeys(T txn, TransportId t) Collection<TransportKeySet> getTransportKeys(T txn, TransportId t)
throws DbException; 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. * 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; throws DbException;
/** /**
@@ -623,12 +599,6 @@ interface Database<T> {
void removeGroupVisibility(T txn, ContactId c, GroupId g) void removeGroupVisibility(T txn, ContactId c, GroupId g)
throws DbException; 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. * Removes an identity (and all associated state) from the database.
*/ */
@@ -659,8 +629,7 @@ interface Database<T> {
/** /**
* Removes the given transport keys from the database. * Removes the given transport keys from the database.
*/ */
void removeTransportKeys(T txn, TransportId t, TransportKeySetId k) void removeTransportKeys(T txn, TransportId t, KeySetId k) throws DbException;
throws DbException;
/** /**
* Resets the transmission count and expiry time of the given message with * Resets the transmission count and expiry time of the given message with
@@ -710,23 +679,16 @@ interface Database<T> {
PendingContactState state) throws DbException; 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. * time period.
*/ */
void setReorderingWindow(T txn, TransportKeySetId k, TransportId t, void setReorderingWindow(T txn, KeySetId 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,
long timePeriod, long base, byte[] bitmap) throws DbException; long timePeriod, long base, byte[] bitmap) throws DbException;
/** /**
* Marks the given transport keys as usable for outgoing streams. * 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; throws DbException;
/** /**
@@ -738,12 +700,7 @@ interface Database<T> {
throws DbException; throws DbException;
/** /**
* Updates the given handshake keys. * Stores the given transport keys, deleting any keys they have replaced.
*/
void updateHandshakeKeys(T txn, HandshakeKeySet ks) throws DbException;
/**
* Updates the given transport keys following key rotation.
*/ */
void updateTransportKeys(T txn, TransportKeySet ks) throws DbException; void updateTransportKeys(T txn, TransportKeySet ks) throws DbException;
} }

View File

@@ -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.MessagesAckedEvent;
import org.briarproject.bramble.api.sync.event.MessagesSentEvent; import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.HandshakeKeySet; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
import org.briarproject.bramble.api.transport.HandshakeKeys;
import org.briarproject.bramble.api.transport.TransportKeySet; 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.api.transport.TransportKeys;
import java.util.ArrayList; import java.util.ArrayList;
@@ -258,30 +255,6 @@ class DatabaseComponentImpl<T> 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 @Override
public void addIdentity(Transaction transaction, Identity i) public void addIdentity(Transaction transaction, Identity i)
throws DbException { throws DbException {
@@ -330,8 +303,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
@Override @Override
public TransportKeySetId addTransportKeys(Transaction transaction, public KeySetId addTransportKeys(Transaction transaction, ContactId c,
ContactId c, TransportKeys k) throws DbException { TransportKeys k) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException(); if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsContact(txn, c)) if (!db.containsContact(txn, c))
@@ -341,6 +314,18 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.addTransportKeys(txn, c, k); 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 @Override
public boolean containsContact(Transaction transaction, AuthorId remote, public boolean containsContact(Transaction transaction, AuthorId remote,
AuthorId local) throws DbException { AuthorId local) throws DbException {
@@ -544,15 +529,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.getGroupVisibility(txn, c, g); return db.getGroupVisibility(txn, c, g);
} }
@Override
public Collection<HandshakeKeySet> 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 @Override
public Identity getIdentity(Transaction transaction, AuthorId a) public Identity getIdentity(Transaction transaction, AuthorId a)
throws DbException { throws DbException {
@@ -735,17 +711,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Override @Override
public void incrementStreamCounter(Transaction transaction, TransportId t, public void incrementStreamCounter(Transaction transaction, TransportId t,
HandshakeKeySetId k) throws DbException { KeySetId 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 {
if (transaction.isReadOnly()) throw new IllegalArgumentException(); if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsTransport(txn, t)) if (!db.containsTransport(txn, t))
@@ -894,16 +860,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
transaction.attach(new GroupVisibilityUpdatedEvent(affected)); 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 @Override
public void removeIdentity(Transaction transaction, AuthorId a) public void removeIdentity(Transaction transaction, AuthorId a)
throws DbException { throws DbException {
@@ -947,8 +903,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
@Override @Override
public void removeTransportKeys(Transaction transaction, public void removeTransportKeys(Transaction transaction, TransportId t,
TransportId t, TransportKeySetId k) throws DbException { KeySetId k) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException(); if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsTransport(txn, t)) if (!db.containsTransport(txn, t))
@@ -1046,20 +1002,9 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
@Override @Override
public void setReorderingWindow(Transaction transaction, public void setReorderingWindow(Transaction transaction, KeySetId k,
TransportKeySetId k, TransportId t, long timePeriod, long base, TransportId t, long timePeriod, long base, byte[] bitmap)
byte[] bitmap) throws DbException { 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 {
if (transaction.isReadOnly()) throw new IllegalArgumentException(); if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsTransport(txn, t)) if (!db.containsTransport(txn, t))
@@ -1069,7 +1014,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Override @Override
public void setTransportKeysActive(Transaction transaction, TransportId t, public void setTransportKeysActive(Transaction transaction, TransportId t,
TransportKeySetId k) throws DbException { KeySetId k) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException(); if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsTransport(txn, t)) if (!db.containsTransport(txn, t))
@@ -1077,18 +1022,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
db.setTransportKeysActive(txn, t, k); db.setTransportKeysActive(txn, t, k);
} }
@Override
public void updateHandshakeKeys(Transaction transaction,
Collection<HandshakeKeySet> 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 @Override
public void updateTransportKeys(Transaction transaction, public void updateTransportKeys(Transaction transaction,
Collection<TransportKeySet> keys) throws DbException { Collection<TransportKeySet> keys) throws DbException {

View File

@@ -30,13 +30,10 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.system.Clock; 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.IncomingKeys;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys;
import org.briarproject.bramble.api.transport.TransportKeySet; 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.api.transport.TransportKeys;
import java.sql.Connection; import java.sql.Connection;
@@ -62,11 +59,13 @@ import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static java.sql.Types.BINARY; import static java.sql.Types.BINARY;
import static java.sql.Types.BOOLEAN;
import static java.sql.Types.INTEGER; import static java.sql.Types.INTEGER;
import static java.sql.Types.VARCHAR; import static java.sql.Types.VARCHAR;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; 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.db.Metadata.REMOVE;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; 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<Connection> { abstract class JdbcDatabase implements Database<Connection> {
// Package access for testing // 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 // Time period offsets for incoming transport keys
private static final int OFFSET_PREV = -1; private static final int OFFSET_PREV = -1;
@@ -254,16 +253,28 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " maxLatency INT NOT NULL," + " maxLatency INT NOT NULL,"
+ " PRIMARY KEY (transportId))"; + " 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 = private static final String CREATE_OUTGOING_KEYS =
"CREATE TABLE outgoingKeys" "CREATE TABLE outgoingKeys"
+ " (transportId _STRING NOT NULL," + " (transportId _STRING NOT NULL,"
+ " keySetId _COUNTER," + " keySetId _COUNTER,"
+ " timePeriod BIGINT NOT NULL," + " 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," + " tagKey _SECRET NOT NULL,"
+ " headerKey _SECRET NOT NULL," + " headerKey _SECRET NOT NULL,"
+ " stream BIGINT NOT NULL," + " stream BIGINT NOT NULL,"
+ " active BOOLEAN NOT NULL," + " active BOOLEAN NOT NULL,"
+ " rootKey _SECRET," // Null for rotation keys
+ " alice BOOLEAN," // Null for rotation keys
+ " PRIMARY KEY (transportId, keySetId)," + " PRIMARY KEY (transportId, keySetId),"
+ " FOREIGN KEY (transportId)" + " FOREIGN KEY (transportId)"
+ " REFERENCES transports (transportId)" + " REFERENCES transports (transportId)"
@@ -271,6 +282,9 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " UNIQUE (keySetId)," + " UNIQUE (keySetId),"
+ " FOREIGN KEY (contactId)" + " FOREIGN KEY (contactId)"
+ " REFERENCES contacts (contactId)" + " REFERENCES contacts (contactId)"
+ " ON DELETE CASCADE,"
+ " FOREIGN KEY (pendingContactId)"
+ " REFERENCES pendingContacts (pendingContactId)"
+ " ON DELETE CASCADE)"; + " ON DELETE CASCADE)";
private static final String CREATE_INCOMING_KEYS = private static final String CREATE_INCOMING_KEYS =
@@ -291,57 +305,6 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " REFERENCES outgoingKeys (keySetId)" + " REFERENCES outgoingKeys (keySetId)"
+ " ON DELETE CASCADE)"; + " 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 = private static final String INDEX_CONTACTS_BY_AUTHOR_ID =
"CREATE INDEX IF NOT EXISTS contactsByAuthorId" "CREATE INDEX IF NOT EXISTS contactsByAuthorId"
+ " ON contacts (authorId)"; + " ON contacts (authorId)";
@@ -367,7 +330,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " ON statuses (contactId, timestamp)"; + " ON statuses (contactId, timestamp)";
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(JdbcDatabase.class.getName()); getLogger(JdbcDatabase.class.getName());
// Different database libraries use different names for certain types // Different database libraries use different names for certain types
private final MessageFactory messageFactory; private final MessageFactory messageFactory;
@@ -487,7 +450,8 @@ abstract class JdbcDatabase implements Database<Connection> {
new Migration39_40(), new Migration39_40(),
new Migration40_41(dbTypes), new Migration40_41(dbTypes),
new Migration41_42(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<Connection> {
s.executeUpdate(dbTypes.replaceTypes(CREATE_OFFERS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_OFFERS));
s.executeUpdate(dbTypes.replaceTypes(CREATE_STATUSES)); s.executeUpdate(dbTypes.replaceTypes(CREATE_STATUSES));
s.executeUpdate(dbTypes.replaceTypes(CREATE_TRANSPORTS)); 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_OUTGOING_KEYS));
s.executeUpdate(dbTypes.replaceTypes(CREATE_INCOMING_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(); s.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s, LOG, WARNING);
@@ -777,103 +737,6 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
@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 @Override
public void addIdentity(Connection txn, Identity i) throws DbException { public void addIdentity(Connection txn, Identity i) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
@@ -1101,24 +964,47 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
@Override @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 { TransportKeys k) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
// Store the outgoing keys // Store the outgoing keys
String sql = "INSERT INTO outgoingKeys (contactId, transportId," String sql = "INSERT INTO outgoingKeys (transportId, timePeriod,"
+ " timePeriod, tagKey, headerKey, stream, active)" + " contactId, pendingContactId, tagKey, headerKey,"
+ " VALUES (?, ?, ?, ?, ?, ?, ?)"; + " stream, active, rootKey, alice)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt()); ps.setString(1, k.getTransportId().getString());
ps.setString(2, 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(); OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
ps.setLong(3, outCurr.getTimePeriod()); ps.setBytes(5, outCurr.getTagKey().getBytes());
ps.setBytes(4, outCurr.getTagKey().getBytes()); ps.setBytes(6, outCurr.getHeaderKey().getBytes());
ps.setBytes(5, outCurr.getHeaderKey().getBytes()); ps.setLong(7, outCurr.getStreamCounter());
ps.setLong(6, outCurr.getStreamCounter()); ps.setBoolean(8, outCurr.isActive());
ps.setBoolean(7, 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(); int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException(); if (affected != 1) throw new DbStateException();
ps.close(); ps.close();
@@ -1128,18 +1014,18 @@ abstract class JdbcDatabase implements Database<Connection> {
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
rs = ps.executeQuery(); rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException(); 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(); if (rs.next()) throw new DbStateException();
rs.close(); rs.close();
ps.close(); ps.close();
// Store the incoming keys // Store the incoming keys
sql = "INSERT INTO incomingKeys (keySetId, transportId," sql = "INSERT INTO incomingKeys (transportId, keySetId,"
+ " timePeriod, tagKey, headerKey, base, bitmap," + " timePeriod, tagKey, headerKey, base, bitmap,"
+ " periodOffset)" + " periodOffset)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + " VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setInt(1, keySetId.getInt()); ps.setString(1, k.getTransportId().getString());
ps.setString(2, k.getTransportId().getString()); ps.setInt(2, keySetId.getInt());
// Previous time period // Previous time period
IncomingKeys inPrev = k.getPreviousIncomingKeys(); IncomingKeys inPrev = k.getPreviousIncomingKeys();
ps.setLong(3, inPrev.getTimePeriod()); ps.setLong(3, inPrev.getTimePeriod());
@@ -1661,86 +1547,6 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
@Override
public Collection<HandshakeKeySet> 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<IncomingKeys> 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<HandshakeKeySet> 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 @Override
public Identity getIdentity(Connection txn, AuthorId a) throws DbException { public Identity getIdentity(Connection txn, AuthorId a) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
@@ -2502,8 +2308,8 @@ abstract class JdbcDatabase implements Database<Connection> {
rs.close(); rs.close();
ps.close(); ps.close();
// Retrieve the outgoing keys in the same order // Retrieve the outgoing keys in the same order
sql = "SELECT keySetId, contactId, timePeriod," sql = "SELECT keySetId, timePeriod, contactId, pendingContactId,"
+ " tagKey, headerKey, stream, active" + " tagKey, headerKey, stream, active, rootKey, alice"
+ " FROM outgoingKeys" + " FROM outgoingKeys"
+ " WHERE transportId = ?" + " WHERE transportId = ?"
+ " ORDER BY keySetId"; + " ORDER BY keySetId";
@@ -2514,23 +2320,34 @@ abstract class JdbcDatabase implements Database<Connection> {
for (int i = 0; rs.next(); i++) { for (int i = 0; rs.next(); i++) {
// There should be three times as many incoming keys // There should be three times as many incoming keys
if (inKeys.size() < (i + 1) * 3) throw new DbStateException(); if (inKeys.size() < (i + 1) * 3) throw new DbStateException();
TransportKeySetId keySetId = KeySetId keySetId = new KeySetId(rs.getInt(1));
new TransportKeySetId(rs.getInt(1)); long timePeriod = rs.getLong(2);
ContactId contactId = new ContactId(rs.getInt(2)); int cId = rs.getInt(3);
long timePeriod = rs.getLong(3); ContactId contactId = rs.wasNull() ? null : new ContactId(cId);
SecretKey tagKey = new SecretKey(rs.getBytes(4)); byte[] pId = rs.getBytes(4);
SecretKey headerKey = new SecretKey(rs.getBytes(5)); PendingContactId pendingContactId = pId == null ?
long streamCounter = rs.getLong(6); null : new PendingContactId(pId);
boolean active = rs.getBoolean(7); 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, OutgoingKeys outCurr = new OutgoingKeys(tagKey, headerKey,
timePeriod, streamCounter, active); timePeriod, streamCounter, active);
IncomingKeys inPrev = inKeys.get(i * 3); IncomingKeys inPrev = inKeys.get(i * 3);
IncomingKeys inCurr = inKeys.get(i * 3 + 1); IncomingKeys inCurr = inKeys.get(i * 3 + 1);
IncomingKeys inNext = inKeys.get(i * 3 + 2); IncomingKeys inNext = inKeys.get(i * 3 + 2);
TransportKeys transportKeys = new TransportKeys(t, inPrev, TransportKeys transportKeys;
inCurr, inNext, outCurr); 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, keys.add(new TransportKeySet(keySetId, contactId,
transportKeys)); pendingContactId, transportKeys));
} }
rs.close(); rs.close();
ps.close(); ps.close();
@@ -2544,26 +2361,7 @@ abstract class JdbcDatabase implements Database<Connection> {
@Override @Override
public void incrementStreamCounter(Connection txn, TransportId t, public void incrementStreamCounter(Connection txn, TransportId t,
HandshakeKeySetId k) throws DbException { KeySetId 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 {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
String sql = "UPDATE outgoingKeys SET stream = stream + 1" String sql = "UPDATE outgoingKeys SET stream = stream + 1"
@@ -2941,27 +2739,6 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
@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 @Override
public void removeIdentity(Connection txn, AuthorId a) throws DbException { public void removeIdentity(Connection txn, AuthorId a) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
@@ -3074,8 +2851,8 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
@Override @Override
public void removeTransportKeys(Connection txn, TransportId t, public void removeTransportKeys(Connection txn, TransportId t, KeySetId k)
TransportKeySetId k) throws DbException { throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
// Delete any existing outgoing keys - this will also remove any // Delete any existing outgoing keys - this will also remove any
@@ -3300,7 +3077,7 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
@Override @Override
public void setReorderingWindow(Connection txn, TransportKeySetId k, public void setReorderingWindow(Connection txn, KeySetId k,
TransportId t, long timePeriod, long base, byte[] bitmap) TransportId t, long timePeriod, long base, byte[] bitmap)
throws DbException { throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
@@ -3323,33 +3100,9 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
@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 @Override
public void setTransportKeysActive(Connection txn, TransportId t, public void setTransportKeysActive(Connection txn, TransportId t,
TransportKeySetId k) throws DbException { KeySetId k) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
String sql = "UPDATE outgoingKeys SET active = true" String sql = "UPDATE outgoingKeys SET active = true"
@@ -3469,71 +3222,4 @@ abstract class JdbcDatabase implements Database<Connection> {
throw new DbException(e); 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);
}
}
} }

View File

@@ -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<Connection> {
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);
}
}
}

View File

@@ -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.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
import org.briarproject.bramble.api.transport.KeyManager; 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.StreamContext;
import org.briarproject.bramble.api.transport.TransportKeySetId;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -88,10 +88,10 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
} }
@Override @Override
public Map<TransportId, TransportKeySetId> addContact(Transaction txn, public Map<TransportId, KeySetId> addContact(Transaction txn,
ContactId c, SecretKey rootKey, long timestamp, boolean alice, ContactId c, SecretKey rootKey, long timestamp, boolean alice,
boolean active) throws DbException { boolean active) throws DbException {
Map<TransportId, TransportKeySetId> ids = new HashMap<>(); Map<TransportId, KeySetId> ids = new HashMap<>();
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) { for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
TransportId t = e.getKey(); TransportId t = e.getKey();
TransportKeyManager m = e.getValue(); TransportKeyManager m = e.getValue();
@@ -101,9 +101,9 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
} }
@Override @Override
public void activateKeys(Transaction txn, Map<TransportId, public void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
TransportKeySetId> keys) throws DbException { throws DbException {
for (Entry<TransportId, TransportKeySetId> e : keys.entrySet()) { for (Entry<TransportId, KeySetId> e : keys.entrySet()) {
TransportId t = e.getKey(); TransportId t = e.getKey();
TransportKeyManager m = managers.get(t); TransportKeyManager m = managers.get(t);
if (m == null) { if (m == null) {

View File

@@ -1,22 +1,22 @@
package org.briarproject.bramble.transport; package org.briarproject.bramble.transport;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.KeySetId;
class MutableKeySet { class MutableKeySet {
private final TransportKeySetId keySetId; private final KeySetId keySetId;
private final ContactId contactId; private final ContactId contactId;
private final MutableTransportKeys transportKeys; private final MutableTransportKeys transportKeys;
MutableKeySet(TransportKeySetId keySetId, ContactId contactId, MutableKeySet(KeySetId keySetId, ContactId contactId,
MutableTransportKeys transportKeys) { MutableTransportKeys transportKeys) {
this.keySetId = keySetId; this.keySetId = keySetId;
this.contactId = contactId; this.contactId = contactId;
this.transportKeys = transportKeys; this.transportKeys = transportKeys;
} }
TransportKeySetId getKeySetId() { KeySetId getKeySetId() {
return keySetId; return keySetId;
} }

View File

@@ -5,8 +5,8 @@ import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; 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.StreamContext;
import org.briarproject.bramble.api.transport.TransportKeySetId;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -15,11 +15,10 @@ interface TransportKeyManager {
void start(Transaction txn) throws DbException; void start(Transaction txn) throws DbException;
TransportKeySetId addContact(Transaction txn, ContactId c, KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey,
SecretKey rootKey, long timestamp, boolean alice, boolean active) long timestamp, boolean alice, boolean active) throws DbException;
throws DbException;
void activateKeys(Transaction txn, TransportKeySetId k) throws DbException; void activateKeys(Transaction txn, KeySetId k) throws DbException;
void removeContact(ContactId c); void removeContact(ContactId c);

View File

@@ -11,9 +11,9 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.Scheduler; 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.StreamContext;
import org.briarproject.bramble.api.transport.TransportKeySet; 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.api.transport.TransportKeys;
import org.briarproject.bramble.transport.ReorderingWindow.Change; import org.briarproject.bramble.transport.ReorderingWindow.Change;
@@ -56,7 +56,7 @@ class TransportKeyManagerImpl implements TransportKeyManager {
private final ReentrantLock lock = new ReentrantLock(); private final ReentrantLock lock = new ReentrantLock();
// The following are locking: lock // The following are locking: lock
private final Map<TransportKeySetId, MutableKeySet> keys = new HashMap<>(); private final Map<KeySetId, MutableKeySet> keys = new HashMap<>();
private final Map<Bytes, TagContext> inContexts = new HashMap<>(); private final Map<Bytes, TagContext> inContexts = new HashMap<>();
private final Map<ContactId, MutableKeySet> outContexts = new HashMap<>(); private final Map<ContactId, MutableKeySet> outContexts = new HashMap<>();
@@ -102,10 +102,10 @@ class TransportKeyManagerImpl implements TransportKeyManager {
long timePeriod = now / timePeriodLength; long timePeriod = now / timePeriodLength;
for (TransportKeySet ks : keys) { for (TransportKeySet ks : keys) {
TransportKeys k = ks.getKeys(); TransportKeys k = ks.getKeys();
TransportKeys k1 = transportCrypto.rotateTransportKeys(k, TransportKeys k1 = transportCrypto.updateTransportKeys(k,
timePeriod); timePeriod);
TransportKeySet ks1 = new TransportKeySet(ks.getKeySetId(), TransportKeySet ks1 = new TransportKeySet(ks.getKeySetId(),
ks.getContactId(), k1); ks.getContactId(), null, k1);
if (k1.getTimePeriod() > k.getTimePeriod()) if (k1.getTimePeriod() > k.getTimePeriod())
rotationResult.rotated.add(ks1); rotationResult.rotated.add(ks1);
rotationResult.current.add(ks1); rotationResult.current.add(ks1);
@@ -116,13 +116,14 @@ class TransportKeyManagerImpl implements TransportKeyManager {
// Locking: lock // Locking: lock
private void addKeys(Collection<TransportKeySet> keys) { private void addKeys(Collection<TransportKeySet> keys) {
for (TransportKeySet ks : keys) { for (TransportKeySet ks : keys) {
// TODO: Keys may be for a pending contact
addKeys(ks.getKeySetId(), ks.getContactId(), addKeys(ks.getKeySetId(), ks.getContactId(),
new MutableTransportKeys(ks.getKeys())); new MutableTransportKeys(ks.getKeys()));
} }
} }
// Locking: lock // Locking: lock
private void addKeys(TransportKeySetId keySetId, ContactId contactId, private void addKeys(KeySetId keySetId, ContactId contactId,
MutableTransportKeys m) { MutableTransportKeys m) {
MutableKeySet ks = new MutableKeySet(keySetId, contactId, m); MutableKeySet ks = new MutableKeySet(keySetId, contactId, m);
keys.put(keySetId, ks); keys.put(keySetId, ks);
@@ -133,7 +134,7 @@ class TransportKeyManagerImpl implements TransportKeyManager {
} }
// Locking: lock // Locking: lock
private void encodeTags(TransportKeySetId keySetId, ContactId contactId, private void encodeTags(KeySetId keySetId, ContactId contactId,
MutableIncomingKeys inKeys) { MutableIncomingKeys inKeys) {
for (long streamNumber : inKeys.getWindow().getUnseen()) { for (long streamNumber : inKeys.getWindow().getUnseen()) {
TagContext tagCtx = TagContext tagCtx =
@@ -173,21 +174,20 @@ class TransportKeyManagerImpl implements TransportKeyManager {
} }
@Override @Override
public TransportKeySetId addContact(Transaction txn, ContactId c, public KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey,
SecretKey rootKey, long timestamp, boolean alice, boolean active) long timestamp, boolean alice, boolean active) throws DbException {
throws DbException {
lock.lock(); lock.lock();
try { try {
// Work out what time period the timestamp belongs to // Work out what time period the timestamp belongs to
long timePeriod = timestamp / timePeriodLength; long timePeriod = timestamp / timePeriodLength;
// Derive the transport keys // Derive the transport keys
TransportKeys k = transportCrypto.deriveTransportKeys(transportId, TransportKeys k = transportCrypto.deriveRotationKeys(transportId,
rootKey, timePeriod, alice, active); rootKey, timePeriod, alice, active);
// Rotate the keys to the current time period if necessary // Rotate the keys to the current time period if necessary
timePeriod = clock.currentTimeMillis() / timePeriodLength; timePeriod = clock.currentTimeMillis() / timePeriodLength;
k = transportCrypto.rotateTransportKeys(k, timePeriod); k = transportCrypto.updateTransportKeys(k, timePeriod);
// Write the keys back to the DB // 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 // Initialise mutable state for the contact
addKeys(keySetId, c, new MutableTransportKeys(k)); addKeys(keySetId, c, new MutableTransportKeys(k));
return keySetId; return keySetId;
@@ -197,8 +197,7 @@ class TransportKeyManagerImpl implements TransportKeyManager {
} }
@Override @Override
public void activateKeys(Transaction txn, TransportKeySetId k) public void activateKeys(Transaction txn, KeySetId k) throws DbException {
throws DbException {
lock.lock(); lock.lock();
try { try {
MutableKeySet ks = keys.get(k); MutableKeySet ks = keys.get(k);
@@ -331,7 +330,8 @@ class TransportKeyManagerImpl implements TransportKeyManager {
Collection<TransportKeySet> snapshot = new ArrayList<>(keys.size()); Collection<TransportKeySet> snapshot = new ArrayList<>(keys.size());
for (MutableKeySet ks : keys.values()) { for (MutableKeySet ks : keys.values()) {
snapshot.add(new TransportKeySet(ks.getKeySetId(), snapshot.add(new TransportKeySet(ks.getKeySetId(),
ks.getContactId(), ks.getTransportKeys().snapshot())); ks.getContactId(), null,
ks.getTransportKeys().snapshot()));
} }
RotationResult rotationResult = rotateKeys(snapshot, now); RotationResult rotationResult = rotateKeys(snapshot, now);
// Rebuild the mutable state for all contacts // Rebuild the mutable state for all contacts
@@ -351,12 +351,12 @@ class TransportKeyManagerImpl implements TransportKeyManager {
private static class TagContext { private static class TagContext {
private final TransportKeySetId keySetId; private final KeySetId keySetId;
private final ContactId contactId; private final ContactId contactId;
private final MutableIncomingKeys inKeys; private final MutableIncomingKeys inKeys;
private final long streamNumber; private final long streamNumber;
private TagContext(TransportKeySetId keySetId, ContactId contactId, private TagContext(KeySetId keySetId, ContactId contactId,
MutableIncomingKeys inKeys, long streamNumber) { MutableIncomingKeys inKeys, long streamNumber) {
this.keySetId = keySetId; this.keySetId = keySetId;
this.contactId = contactId; this.contactId = contactId;

View File

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

View File

@@ -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<SecretKey> 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<SecretKey> keys) {
Set<Bytes> 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());
}
}

View File

@@ -1,23 +1,30 @@
package org.briarproject.bramble.crypto; package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.crypto.TransportCrypto; import org.briarproject.bramble.api.crypto.TransportCrypto;
import org.briarproject.bramble.api.plugin.TransportId; 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.api.transport.TransportKeys;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.TestSecureRandomProvider; import org.briarproject.bramble.test.TestSecureRandomProvider;
import org.junit.Test; import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays; 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.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTransportId; 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.assertFalse;
import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
public class TransportKeyDerivationTest extends BrambleTestCase { public class TransportKeyDerivationTest extends BrambleTestCase {
@@ -29,70 +36,70 @@ public class TransportKeyDerivationTest extends BrambleTestCase {
private final SecretKey rootKey = getSecretKey(); private final SecretKey rootKey = getSecretKey();
@Test @Test
public void testKeysAreDistinct() { public void testRotationKeysAreDistinct() {
TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, TransportKeys kA = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, true, true); rootKey, 123, true, true);
TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, TransportKeys kB = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, false, true); rootKey, 123, false, true);
assertAllDifferent(kA); assertAllDifferent(kA);
assertAllDifferent(kB); assertAllDifferent(kB);
} }
@Test @Test
public void testKeysAreNotRotatedToPreviousPeriod() { public void testRotationKeysAreNotRotatedToPreviousPeriod() {
TransportKeys k = transportCrypto.deriveTransportKeys(transportId, TransportKeys k = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, true, true); rootKey, 123, true, true);
TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 122); TransportKeys k1 = transportCrypto.updateTransportKeys(k, 122);
assertSame(k, k1); assertSame(k, k1);
} }
@Test @Test
public void testKeysAreNotRotatedToCurrentPeriod() { public void testRotationKeysAreNotRotatedToCurrentPeriod() {
TransportKeys k = transportCrypto.deriveTransportKeys(transportId, TransportKeys k = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, true, true); rootKey, 123, true, true);
TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 123); TransportKeys k1 = transportCrypto.updateTransportKeys(k, 123);
assertSame(k, k1); assertSame(k, k1);
} }
@Test @Test
public void testKeysAreRotatedByOnePeriod() { public void testRotationKeysAreRotatedByOnePeriod() {
TransportKeys k = transportCrypto.deriveTransportKeys(transportId, TransportKeys k = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, true, true); rootKey, 123, true, true);
TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 124); TransportKeys k1 = transportCrypto.updateTransportKeys(k, 124);
assertSame(k.getCurrentIncomingKeys(), k1.getPreviousIncomingKeys()); assertSame(k.getCurrentIncomingKeys(), k1.getPreviousIncomingKeys());
assertSame(k.getNextIncomingKeys(), k1.getCurrentIncomingKeys()); assertSame(k.getNextIncomingKeys(), k1.getCurrentIncomingKeys());
} }
@Test @Test
public void testKeysAreRotatedByTwoPeriods() { public void testRotationKeysAreRotatedByTwoPeriods() {
TransportKeys k = transportCrypto.deriveTransportKeys(transportId, TransportKeys k = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, true, true); rootKey, 123, true, true);
TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 125); TransportKeys k1 = transportCrypto.updateTransportKeys(k, 125);
assertSame(k.getNextIncomingKeys(), k1.getPreviousIncomingKeys()); assertSame(k.getNextIncomingKeys(), k1.getPreviousIncomingKeys());
} }
@Test @Test
public void testKeysAreRotatedByThreePeriods() { public void testRotationKeysAreRotatedByThreePeriods() {
TransportKeys k = transportCrypto.deriveTransportKeys(transportId, TransportKeys k = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, true, true); rootKey, 123, true, true);
TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 126); TransportKeys k1 = transportCrypto.updateTransportKeys(k, 126);
assertAllDifferent(k, k1); assertAllDifferent(k, k1);
} }
@Test @Test
public void testCurrentKeysMatchContact() { public void testCurrentRotationKeysMatchContact() {
// Start in time period 123 // Start in time period 123
TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, TransportKeys kA = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, true, true); rootKey, 123, true, true);
TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, TransportKeys kB = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, false, true); rootKey, 123, false, true);
// Alice's incoming keys should equal Bob's outgoing keys // Alice's incoming keys should equal Bob's outgoing keys
assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys());
// Bob's incoming keys should equal Alice's outgoing keys // Bob's incoming keys should equal Alice's outgoing keys
assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys()); assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys());
// Rotate into the future // Rotate into the future
kA = transportCrypto.rotateTransportKeys(kA, 456); kA = transportCrypto.updateTransportKeys(kA, 456);
kB = transportCrypto.rotateTransportKeys(kB, 456); kB = transportCrypto.updateTransportKeys(kB, 456);
// Alice's incoming keys should equal Bob's outgoing keys // Alice's incoming keys should equal Bob's outgoing keys
assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys());
// Bob's incoming keys should equal Alice's outgoing keys // Bob's incoming keys should equal Alice's outgoing keys
@@ -100,23 +107,23 @@ public class TransportKeyDerivationTest extends BrambleTestCase {
} }
@Test @Test
public void testPreviousKeysMatchContact() { public void testPreviousRotationKeysMatchContact() {
// Start in time period 123 // Start in time period 123
TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, TransportKeys kA = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, true, true); rootKey, 123, true, true);
TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, TransportKeys kB = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, false, true); rootKey, 123, false, true);
// Compare Alice's previous keys in period 456 with Bob's current keys // Compare Alice's previous keys in period 456 with Bob's current keys
// in period 455 // in period 455
kA = transportCrypto.rotateTransportKeys(kA, 456); kA = transportCrypto.updateTransportKeys(kA, 456);
kB = transportCrypto.rotateTransportKeys(kB, 455); kB = transportCrypto.updateTransportKeys(kB, 455);
// Alice's previous incoming keys should equal Bob's current // Alice's previous incoming keys should equal Bob's current
// outgoing keys // outgoing keys
assertMatches(kA.getPreviousIncomingKeys(), assertMatches(kA.getPreviousIncomingKeys(),
kB.getCurrentOutgoingKeys()); kB.getCurrentOutgoingKeys());
// Compare Alice's current keys in period 456 with Bob's previous keys // Compare Alice's current keys in period 456 with Bob's previous keys
// in period 457 // in period 457
kB = transportCrypto.rotateTransportKeys(kB, 457); kB = transportCrypto.updateTransportKeys(kB, 457);
// Bob's previous incoming keys should equal Alice's current // Bob's previous incoming keys should equal Alice's current
// outgoing keys // outgoing keys
assertMatches(kB.getPreviousIncomingKeys(), assertMatches(kB.getPreviousIncomingKeys(),
@@ -124,44 +131,208 @@ public class TransportKeyDerivationTest extends BrambleTestCase {
} }
@Test @Test
public void testNextKeysMatchContact() { public void testNextRotationKeysMatchContact() {
// Start in time period 123 // Start in time period 123
TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, TransportKeys kA = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, true, true); rootKey, 123, true, true);
TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, TransportKeys kB = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, false, true); rootKey, 123, false, true);
// Compare Alice's current keys in period 456 with Bob's next keys in // Compare Alice's current keys in period 456 with Bob's next keys in
// period 455 // period 455
kA = transportCrypto.rotateTransportKeys(kA, 456); kA = transportCrypto.updateTransportKeys(kA, 456);
kB = transportCrypto.rotateTransportKeys(kB, 455); kB = transportCrypto.updateTransportKeys(kB, 455);
// Bob's next incoming keys should equal Alice's current outgoing keys // Bob's next incoming keys should equal Alice's current outgoing keys
assertMatches(kB.getNextIncomingKeys(), kA.getCurrentOutgoingKeys()); assertMatches(kB.getNextIncomingKeys(), kA.getCurrentOutgoingKeys());
// Compare Alice's next keys in period 456 with Bob's current keys // Compare Alice's next keys in period 456 with Bob's current keys
// in period 457 // 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 // Alice's next incoming keys should equal Bob's current outgoing keys
assertMatches(kA.getNextIncomingKeys(), kB.getCurrentOutgoingKeys()); assertMatches(kA.getNextIncomingKeys(), kB.getCurrentOutgoingKeys());
} }
@Test @Test
public void testRootKeyAffectsOutput() { public void testRootKeyAffectsRotationKeyDerivation() {
SecretKey rootKey1 = getSecretKey(); SecretKey rootKey1 = getSecretKey();
assertFalse(Arrays.equals(rootKey.getBytes(), rootKey1.getBytes())); assertFalse(Arrays.equals(rootKey.getBytes(), rootKey1.getBytes()));
TransportKeys k = transportCrypto.deriveTransportKeys(transportId, TransportKeys k = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, true, true); rootKey, 123, true, true);
TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId, TransportKeys k1 = transportCrypto.deriveRotationKeys(transportId,
rootKey1, 123, true, true); rootKey1, 123, true, true);
assertAllDifferent(k, k1); assertAllDifferent(k, k1);
} }
@Test @Test
public void testTransportIdAffectsOutput() { public void testTransportIdAffectsRotationKeyDerivation() {
TransportId transportId1 = getTransportId(); TransportId transportId1 = getTransportId();
assertNotEquals(transportId.getString(), transportId1.getString()); assertNotEquals(transportId.getString(), transportId1.getString());
TransportKeys k = transportCrypto.deriveTransportKeys(transportId, TransportKeys k = transportCrypto.deriveRotationKeys(transportId,
rootKey, 123, true, true); rootKey, 123, true, true);
TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId1, TransportKeys k1 = transportCrypto.deriveRotationKeys(transportId1,
rootKey, 123, true, true); rootKey, 123, true, true);
assertAllDifferent(k, k1); 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<SecretKey> 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<SecretKey> keys) {
Set<Bytes> 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());
}
} }

View File

@@ -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.MessageToRequestEvent;
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
import org.briarproject.bramble.api.sync.event.MessagesSentEvent; 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.IncomingKeys;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys;
import org.briarproject.bramble.api.transport.TransportKeySet; 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.api.transport.TransportKeys;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.CaptureArgumentAction; import org.briarproject.bramble.test.CaptureArgumentAction;
@@ -117,7 +116,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
private final int maxLatency; private final int maxLatency;
private final ContactId contactId; private final ContactId contactId;
private final Contact contact; private final Contact contact;
private final TransportKeySetId keySetId; private final KeySetId keySetId;
private final PendingContactId pendingContactId; private final PendingContactId pendingContactId;
public DatabaseComponentImplTest() { public DatabaseComponentImplTest() {
@@ -139,7 +138,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
contact = getContact(author, localAuthor.getId(), true); contact = getContact(author, localAuthor.getId(), true);
contactId = contact.getId(); contactId = contact.getId();
alias = contact.getAlias(); alias = contact.getAlias();
keySetId = new TransportKeySetId(345); keySetId = new KeySetId(345);
pendingContactId = new PendingContactId(getRandomId()); pendingContactId = new PendingContactId(getRandomId());
} }
@@ -284,24 +283,15 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
throws Exception { throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
// Check whether the contact is in the DB (which it's not) // 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)); will(returnValue(txn));
exactly(17).of(database).containsContact(txn, contactId); exactly(16).of(database).containsContact(txn, contactId);
will(returnValue(false)); will(returnValue(false));
exactly(17).of(database).abortTransaction(txn); exactly(16).of(database).abortTransaction(txn);
}}); }});
DatabaseComponent db = createDatabaseComponent(database, eventBus, DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager); eventExecutor, shutdownManager);
try {
db.transaction(false, transaction ->
db.addHandshakeKeys(transaction, contactId,
createHandshakeKeys()));
fail();
} catch (NoSuchContactException expected) {
// Expected
}
try { try {
db.transaction(false, transaction -> db.transaction(false, transaction ->
db.addTransportKeys(transaction, contactId, db.addTransportKeys(transaction, contactId,
@@ -497,8 +487,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
exactly(8).of(database).containsGroup(txn, groupId); exactly(8).of(database).containsGroup(txn, groupId);
will(returnValue(false)); will(returnValue(false));
exactly(8).of(database).abortTransaction(txn); exactly(8).of(database).abortTransaction(txn);
// This is needed for getMessageStatus() and setGroupVisibility() // Allow other checks to pass
exactly(2).of(database).containsContact(txn, contactId); allowing(database).containsContact(txn, contactId);
will(returnValue(true)); will(returnValue(true));
}}); }});
DatabaseComponent db = createDatabaseComponent(database, eventBus, DatabaseComponent db = createDatabaseComponent(database, eventBus,
@@ -581,8 +571,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
exactly(11).of(database).containsMessage(txn, messageId); exactly(11).of(database).containsMessage(txn, messageId);
will(returnValue(false)); will(returnValue(false));
exactly(11).of(database).abortTransaction(txn); exactly(11).of(database).abortTransaction(txn);
// This is needed for getMessageStatus() to proceed // Allow other checks to pass
exactly(1).of(database).containsContact(txn, contactId); allowing(database).containsContact(txn, contactId);
will(returnValue(true)); will(returnValue(true));
}}); }});
DatabaseComponent db = createDatabaseComponent(database, eventBus, DatabaseComponent db = createDatabaseComponent(database, eventBus,
@@ -682,15 +672,38 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
throws Exception { throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
// Check whether the transport is in the DB (which it's not) // 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)); will(returnValue(txn));
exactly(5).of(database).containsTransport(txn, transportId); exactly(8).of(database).containsTransport(txn, transportId);
will(returnValue(false)); 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, DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager); 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 { try {
db.transaction(false, transaction -> db.transaction(false, transaction ->
db.getTransportKeys(transaction, transportId)); db.getTransportKeys(transaction, transportId));
@@ -710,7 +723,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
try { try {
db.transaction(false, transaction -> db.transaction(false, transaction ->
db.removeTransport(transaction, transportId)); db.removeTransportKeys(transaction, transportId, keySetId));
fail(); fail();
} catch (NoSuchTransportException expected) { } catch (NoSuchTransportException expected) {
// Expected // Expected
@@ -718,7 +731,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
try { try {
db.transaction(false, transaction -> db.transaction(false, transaction ->
db.removeTransportKeys(transaction, transportId, keySetId)); db.removeTransport(transaction, transportId));
fail(); fail();
} catch (NoSuchTransportException expected) { } catch (NoSuchTransportException expected) {
// Expected // Expected
@@ -732,6 +745,15 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} catch (NoSuchTransportException expected) { } catch (NoSuchTransportException expected) {
// Expected // Expected
} }
try {
db.transaction(false, transaction ->
db.setTransportKeysActive(transaction, transportId,
keySetId));
fail();
} catch (NoSuchTransportException expected) {
// Expected
}
} }
@Test @Test
@@ -751,7 +773,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
try { try {
db.transaction(false, transaction -> db.transaction(false, transaction ->
db.addHandshakeKeys(transaction, pendingContactId, db.addTransportKeys(transaction, pendingContactId,
createHandshakeKeys())); createHandshakeKeys()));
fail(); fail();
} catch (NoSuchPendingContactException expected) { } catch (NoSuchPendingContactException expected) {
@@ -1167,7 +1189,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
public void testTransportKeys() throws Exception { public void testTransportKeys() throws Exception {
TransportKeys transportKeys = createTransportKeys(); TransportKeys transportKeys = createTransportKeys();
TransportKeySet ks = TransportKeySet ks =
new TransportKeySet(keySetId, contactId, transportKeys); new TransportKeySet(keySetId, contactId, null, transportKeys);
Collection<TransportKeySet> keys = singletonList(ks); Collection<TransportKeySet> keys = singletonList(ks);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
@@ -1295,7 +1317,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
}); });
} }
private HandshakeKeys createHandshakeKeys() { private TransportKeys createHandshakeKeys() {
SecretKey inPrevTagKey = getSecretKey(); SecretKey inPrevTagKey = getSecretKey();
SecretKey inPrevHeaderKey = getSecretKey(); SecretKey inPrevHeaderKey = getSecretKey();
IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey, IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey,
@@ -1312,7 +1334,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
SecretKey outCurrHeaderKey = getSecretKey(); SecretKey outCurrHeaderKey = getSecretKey();
OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey, OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey,
2, 456, true); 2, 456, true);
return new HandshakeKeys(transportId, inPrev, inCurr, inNext, outCurr, return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr,
getSecretKey(), true); getSecretKey(), true);
} }

View File

@@ -22,13 +22,10 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.system.Clock; 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.IncomingKeys;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys;
import org.briarproject.bramble.api.transport.TransportKeySet; 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.api.transport.TransportKeys;
import org.briarproject.bramble.system.SystemClock; import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
@@ -112,8 +109,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
private final MessageId messageId; private final MessageId messageId;
private final TransportId transportId; private final TransportId transportId;
private final ContactId contactId; private final ContactId contactId;
private final TransportKeySetId keySetId, keySetId1; private final KeySetId keySetId, keySetId1;
private final HandshakeKeySetId handshakeKeySetId, handshakeKeySetId1;
private final PendingContact pendingContact; private final PendingContact pendingContact;
private final Random random = new Random(); private final Random random = new Random();
@@ -129,10 +125,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
messageId = message.getId(); messageId = message.getId();
transportId = getTransportId(); transportId = getTransportId();
contactId = new ContactId(1); contactId = new ContactId(1);
keySetId = new TransportKeySetId(1); keySetId = new KeySetId(1);
keySetId1 = new TransportKeySetId(2); keySetId1 = new KeySetId(2);
handshakeKeySetId = new HandshakeKeySetId(1);
handshakeKeySetId1 = new HandshakeKeySetId(2);
pendingContact = getPendingContact(); pendingContact = getPendingContact();
} }
@@ -706,9 +700,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
TransportKeys rotated1 = TransportKeys rotated1 =
createTransportKeys(timePeriod1 + 1, active); createTransportKeys(timePeriod1 + 1, active);
db.updateTransportKeys(txn, new TransportKeySet(keySetId, contactId, db.updateTransportKeys(txn, new TransportKeySet(keySetId, contactId,
rotated)); null, rotated));
db.updateTransportKeys(txn, new TransportKeySet(keySetId1, contactId, db.updateTransportKeys(txn, new TransportKeySet(keySetId1, contactId,
rotated1)); null, rotated1));
// Retrieve the transport keys again // Retrieve the transport keys again
allKeys = db.getTransportKeys(txn, transportId); allKeys = db.getTransportKeys(txn, transportId);
@@ -743,6 +737,14 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
actual.getNextIncomingKeys()); actual.getNextIncomingKeys());
assertKeysEquals(expected.getCurrentOutgoingKeys(), assertKeysEquals(expected.getCurrentOutgoingKeys(),
actual.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) { private void assertKeysEquals(IncomingKeys expected, IncomingKeys actual) {
@@ -771,154 +773,135 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
boolean alice = random.nextBoolean(); boolean alice = random.nextBoolean();
SecretKey rootKey = getSecretKey(); SecretKey rootKey = getSecretKey();
SecretKey rootKey1 = getSecretKey(); SecretKey rootKey1 = getSecretKey();
HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); TransportKeys keys = createHandshakeKeys(timePeriod, rootKey, alice);
HandshakeKeys keys1 = createHandshakeKeys(timePeriod1, rootKey1, alice); TransportKeys keys1 = createHandshakeKeys(timePeriod1, rootKey1, alice);
Database<Connection> db = open(false); Database<Connection> db = open(false);
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Initially there should be no handshake keys in the database // 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 // Add the contact, the transport and the handshake keys
db.addIdentity(txn, identity); db.addIdentity(txn, identity);
assertEquals(contactId, assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true)); db.addContact(txn, author, localAuthor.getId(), true));
db.addTransport(txn, transportId, 123); db.addTransport(txn, transportId, 123);
assertEquals(handshakeKeySetId, assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
db.addHandshakeKeys(txn, contactId, keys)); assertEquals(keySetId1, db.addTransportKeys(txn, contactId, keys1));
assertEquals(handshakeKeySetId1,
db.addHandshakeKeys(txn, contactId, keys1));
// Retrieve the handshake keys // Retrieve the handshake keys
Collection<HandshakeKeySet> allKeys = Collection<TransportKeySet> allKeys =
db.getHandshakeKeys(txn, transportId); db.getTransportKeys(txn, transportId);
assertEquals(2, allKeys.size()); assertEquals(2, allKeys.size());
for (HandshakeKeySet ks : allKeys) { for (TransportKeySet ks : allKeys) {
assertEquals(contactId, ks.getContactId()); assertEquals(contactId, ks.getContactId());
assertNull(ks.getPendingContactId()); assertNull(ks.getPendingContactId());
if (ks.getKeySetId().equals(handshakeKeySetId)) { if (ks.getKeySetId().equals(keySetId)) {
assertKeysEquals(keys, ks.getKeys()); assertKeysEquals(keys, ks.getKeys());
} else { } else {
assertEquals(handshakeKeySetId1, ks.getKeySetId()); assertEquals(keySetId1, ks.getKeySetId());
assertKeysEquals(keys1, ks.getKeys()); assertKeysEquals(keys1, ks.getKeys());
} }
} }
// Update the handshake keys // Update the handshake keys
HandshakeKeys updated = TransportKeys updated =
createHandshakeKeys(timePeriod + 1, rootKey, alice); createHandshakeKeys(timePeriod + 1, rootKey, alice);
HandshakeKeys updated1 = TransportKeys updated1 =
createHandshakeKeys(timePeriod1 + 1, rootKey1, alice); createHandshakeKeys(timePeriod1 + 1, rootKey1, alice);
db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId, db.updateTransportKeys(txn, new TransportKeySet(keySetId, contactId,
contactId, updated)); null, updated));
db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId1, db.updateTransportKeys(txn, new TransportKeySet(keySetId1, contactId,
contactId, updated1)); null, updated1));
// Retrieve the handshake keys again // Retrieve the handshake keys again
allKeys = db.getHandshakeKeys(txn, transportId); allKeys = db.getTransportKeys(txn, transportId);
assertEquals(2, allKeys.size()); assertEquals(2, allKeys.size());
for (HandshakeKeySet ks : allKeys) { for (TransportKeySet ks : allKeys) {
assertEquals(contactId, ks.getContactId()); assertEquals(contactId, ks.getContactId());
assertNull(ks.getPendingContactId()); assertNull(ks.getPendingContactId());
if (ks.getKeySetId().equals(handshakeKeySetId)) { if (ks.getKeySetId().equals(keySetId)) {
assertKeysEquals(updated, ks.getKeys()); assertKeysEquals(updated, ks.getKeys());
} else { } else {
assertEquals(handshakeKeySetId1, ks.getKeySetId()); assertEquals(keySetId1, ks.getKeySetId());
assertKeysEquals(updated1, ks.getKeys()); assertKeysEquals(updated1, ks.getKeys());
} }
} }
// Removing the contact should remove the handshake keys // Removing the contact should remove the handshake keys
db.removeContact(txn, contactId); db.removeContact(txn, contactId);
assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId)); assertEquals(emptyList(), db.getTransportKeys(txn, transportId));
db.commitTransaction(txn); db.commitTransaction(txn);
db.close(); 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 @Test
public void testHandshakeKeysForPendingContact() throws Exception { public void testHandshakeKeysForPendingContact() throws Exception {
long timePeriod = 123, timePeriod1 = 234; long timePeriod = 123, timePeriod1 = 234;
boolean alice = random.nextBoolean(); boolean alice = random.nextBoolean();
SecretKey rootKey = getSecretKey(); SecretKey rootKey = getSecretKey();
SecretKey rootKey1 = getSecretKey(); SecretKey rootKey1 = getSecretKey();
HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); TransportKeys keys = createHandshakeKeys(timePeriod, rootKey, alice);
HandshakeKeys keys1 = createHandshakeKeys(timePeriod1, rootKey1, alice); TransportKeys keys1 = createHandshakeKeys(timePeriod1, rootKey1, alice);
Database<Connection> db = open(false); Database<Connection> db = open(false);
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Initially there should be no handshake keys in the database // 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 // Add the pending contact, the transport and the handshake keys
db.addPendingContact(txn, pendingContact); db.addPendingContact(txn, pendingContact);
db.addTransport(txn, transportId, 123); db.addTransport(txn, transportId, 123);
assertEquals(handshakeKeySetId, db.addHandshakeKeys(txn, assertEquals(keySetId,
pendingContact.getId(), keys)); db.addTransportKeys(txn, pendingContact.getId(), keys));
assertEquals(handshakeKeySetId1, db.addHandshakeKeys(txn, assertEquals(keySetId1,
pendingContact.getId(), keys1)); db.addTransportKeys(txn, pendingContact.getId(), keys1));
// Retrieve the handshake keys // Retrieve the handshake keys
Collection<HandshakeKeySet> allKeys = Collection<TransportKeySet> allKeys =
db.getHandshakeKeys(txn, transportId); db.getTransportKeys(txn, transportId);
assertEquals(2, allKeys.size()); assertEquals(2, allKeys.size());
for (HandshakeKeySet ks : allKeys) { for (TransportKeySet ks : allKeys) {
assertNull(ks.getContactId()); assertNull(ks.getContactId());
assertEquals(pendingContact.getId(), ks.getPendingContactId()); assertEquals(pendingContact.getId(), ks.getPendingContactId());
if (ks.getKeySetId().equals(handshakeKeySetId)) { if (ks.getKeySetId().equals(keySetId)) {
assertKeysEquals(keys, ks.getKeys()); assertKeysEquals(keys, ks.getKeys());
} else { } else {
assertEquals(handshakeKeySetId1, ks.getKeySetId()); assertEquals(keySetId1, ks.getKeySetId());
assertKeysEquals(keys1, ks.getKeys()); assertKeysEquals(keys1, ks.getKeys());
} }
} }
// Update the handshake keys // Update the handshake keys
HandshakeKeys updated = TransportKeys updated =
createHandshakeKeys(timePeriod + 1, rootKey, alice); createHandshakeKeys(timePeriod + 1, rootKey, alice);
HandshakeKeys updated1 = TransportKeys updated1 =
createHandshakeKeys(timePeriod1 + 1, rootKey1, alice); createHandshakeKeys(timePeriod1 + 1, rootKey1, alice);
db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId, db.updateTransportKeys(txn, new TransportKeySet(keySetId, null,
pendingContact.getId(), updated)); pendingContact.getId(), updated));
db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId1, db.updateTransportKeys(txn, new TransportKeySet(keySetId1, null,
pendingContact.getId(), updated1)); pendingContact.getId(), updated1));
// Retrieve the handshake keys again // Retrieve the handshake keys again
allKeys = db.getHandshakeKeys(txn, transportId); allKeys = db.getTransportKeys(txn, transportId);
assertEquals(2, allKeys.size()); assertEquals(2, allKeys.size());
for (HandshakeKeySet ks : allKeys) { for (TransportKeySet ks : allKeys) {
assertNull(ks.getContactId()); assertNull(ks.getContactId());
assertEquals(pendingContact.getId(), ks.getPendingContactId()); assertEquals(pendingContact.getId(), ks.getPendingContactId());
if (ks.getKeySetId().equals(handshakeKeySetId)) { if (ks.getKeySetId().equals(keySetId)) {
assertKeysEquals(updated, ks.getKeys()); assertKeysEquals(updated, ks.getKeys());
} else { } else {
assertEquals(handshakeKeySetId1, ks.getKeySetId()); assertEquals(keySetId1, ks.getKeySetId());
assertKeysEquals(updated1, ks.getKeys()); assertKeysEquals(updated1, ks.getKeys());
} }
} }
// Removing the pending contact should remove the handshake keys // Removing the pending contact should remove the handshake keys
db.removePendingContact(txn, pendingContact.getId()); db.removePendingContact(txn, pendingContact.getId());
assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId)); assertEquals(emptyList(), db.getTransportKeys(txn, transportId));
db.commitTransaction(txn); db.commitTransaction(txn);
db.close(); db.close();
@@ -971,7 +954,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
long timePeriod = 123; long timePeriod = 123;
SecretKey rootKey = getSecretKey(); SecretKey rootKey = getSecretKey();
boolean alice = random.nextBoolean(); boolean alice = random.nextBoolean();
HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); TransportKeys keys = createHandshakeKeys(timePeriod, rootKey, alice);
long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter(); long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter();
Database<Connection> db = open(false); Database<Connection> db = open(false);
@@ -982,20 +965,20 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertEquals(contactId, assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true)); db.addContact(txn, author, localAuthor.getId(), true));
db.addTransport(txn, transportId, 123); db.addTransport(txn, transportId, 123);
assertEquals(handshakeKeySetId, assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
db.addHandshakeKeys(txn, contactId, keys));
// Increment the stream counter twice and retrieve the handshake keys // Increment the stream counter twice and retrieve the handshake keys
db.incrementStreamCounter(txn, transportId, handshakeKeySetId); db.incrementStreamCounter(txn, transportId, keySetId);
db.incrementStreamCounter(txn, transportId, handshakeKeySetId); db.incrementStreamCounter(txn, transportId, keySetId);
Collection<HandshakeKeySet> newKeys = Collection<TransportKeySet> newKeys =
db.getHandshakeKeys(txn, transportId); db.getTransportKeys(txn, transportId);
assertEquals(1, newKeys.size()); assertEquals(1, newKeys.size());
HandshakeKeySet ks = newKeys.iterator().next(); TransportKeySet ks = newKeys.iterator().next();
assertEquals(handshakeKeySetId, ks.getKeySetId()); assertEquals(keySetId, ks.getKeySetId());
assertEquals(contactId, ks.getContactId()); assertEquals(contactId, ks.getContactId());
HandshakeKeys k = ks.getKeys(); TransportKeys k = ks.getKeys();
assertEquals(transportId, k.getTransportId()); assertEquals(transportId, k.getTransportId());
assertNotNull(k.getRootKey());
assertArrayEquals(rootKey.getBytes(), k.getRootKey().getBytes()); assertArrayEquals(rootKey.getBytes(), k.getRootKey().getBytes());
assertEquals(alice, k.isAlice()); assertEquals(alice, k.isAlice());
OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
@@ -1064,7 +1047,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
long timePeriod = 123; long timePeriod = 123;
SecretKey rootKey = getSecretKey(); SecretKey rootKey = getSecretKey();
boolean alice = random.nextBoolean(); boolean alice = random.nextBoolean();
HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); TransportKeys keys = createHandshakeKeys(timePeriod, rootKey, alice);
long base = keys.getCurrentIncomingKeys().getWindowBase(); long base = keys.getCurrentIncomingKeys().getWindowBase();
byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap(); byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap();
@@ -1076,21 +1059,21 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertEquals(contactId, assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true)); db.addContact(txn, author, localAuthor.getId(), true));
db.addTransport(txn, transportId, 123); db.addTransport(txn, transportId, 123);
assertEquals(handshakeKeySetId, assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
db.addHandshakeKeys(txn, contactId, keys));
// Update the reordering window and retrieve the handshake keys // Update the reordering window and retrieve the handshake keys
random.nextBytes(bitmap); random.nextBytes(bitmap);
db.setReorderingWindow(txn, handshakeKeySetId, transportId, timePeriod, db.setReorderingWindow(txn, keySetId, transportId, timePeriod,
base + 1, bitmap); base + 1, bitmap);
Collection<HandshakeKeySet> newKeys = Collection<TransportKeySet> newKeys =
db.getHandshakeKeys(txn, transportId); db.getTransportKeys(txn, transportId);
assertEquals(1, newKeys.size()); assertEquals(1, newKeys.size());
HandshakeKeySet ks = newKeys.iterator().next(); TransportKeySet ks = newKeys.iterator().next();
assertEquals(handshakeKeySetId, ks.getKeySetId()); assertEquals(keySetId, ks.getKeySetId());
assertEquals(contactId, ks.getContactId()); assertEquals(contactId, ks.getContactId());
HandshakeKeys k = ks.getKeys(); TransportKeys k = ks.getKeys();
assertEquals(transportId, k.getTransportId()); assertEquals(transportId, k.getTransportId());
assertNotNull(k.getRootKey());
assertArrayEquals(rootKey.getBytes(), k.getRootKey().getBytes()); assertArrayEquals(rootKey.getBytes(), k.getRootKey().getBytes());
assertEquals(alice, k.isAlice()); assertEquals(alice, k.isAlice());
IncomingKeys inCurr = k.getCurrentIncomingKeys(); IncomingKeys inCurr = k.getCurrentIncomingKeys();
@@ -2302,7 +2285,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr); return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr);
} }
private HandshakeKeys createHandshakeKeys(long timePeriod, private TransportKeys createHandshakeKeys(long timePeriod,
SecretKey rootKey, boolean alice) { SecretKey rootKey, boolean alice) {
SecretKey inPrevTagKey = getSecretKey(); SecretKey inPrevTagKey = getSecretKey();
SecretKey inPrevHeaderKey = getSecretKey(); SecretKey inPrevHeaderKey = getSecretKey();
@@ -2320,7 +2303,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
SecretKey outCurrHeaderKey = getSecretKey(); SecretKey outCurrHeaderKey = getSecretKey();
OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey, OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey,
timePeriod, 456, true); timePeriod, 456, true);
return new HandshakeKeys(transportId, inPrev, inCurr, inNext, outCurr, return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr,
rootKey, alice); rootKey, alice);
} }

View File

@@ -8,8 +8,8 @@ import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.plugin.PluginConfig; import org.briarproject.bramble.api.plugin.PluginConfig;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; 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.StreamContext;
import org.briarproject.bramble.api.transport.TransportKeySetId;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations; import org.briarproject.bramble.test.DbExpectations;
import org.jmock.Expectations; import org.jmock.Expectations;
@@ -43,7 +43,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
private final DeterministicExecutor executor = new DeterministicExecutor(); private final DeterministicExecutor executor = new DeterministicExecutor();
private final Transaction txn = new Transaction(null, false); private final Transaction txn = new Transaction(null, false);
private final ContactId contactId = getContactId(); 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 transportId = getTransportId();
private final TransportId unknownTransportId = getTransportId(); private final TransportId unknownTransportId = getTransportId();
private final StreamContext streamContext = new StreamContext(contactId, private final StreamContext streamContext = new StreamContext(contactId,
@@ -95,8 +95,8 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
will(returnValue(keySetId)); will(returnValue(keySetId));
}}); }});
Map<TransportId, TransportKeySetId> ids = keyManager.addContact(txn, Map<TransportId, KeySetId> ids = keyManager.addContact(txn, contactId,
contactId, secretKey, timestamp, alice, active); secretKey, timestamp, alice, active);
assertEquals(singletonMap(transportId, keySetId), ids); assertEquals(singletonMap(transportId, keySetId), ids);
} }

View File

@@ -8,10 +8,10 @@ import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.IncomingKeys; 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.OutgoingKeys;
import org.briarproject.bramble.api.transport.StreamContext; import org.briarproject.bramble.api.transport.StreamContext;
import org.briarproject.bramble.api.transport.TransportKeySet; 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.api.transport.TransportKeys;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations; 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 long timePeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE;
private final ContactId contactId = getContactId(); private final ContactId contactId = getContactId();
private final ContactId contactId1 = getContactId(); private final ContactId contactId1 = getContactId();
private final TransportKeySetId keySetId = new TransportKeySetId(345); private final KeySetId keySetId = new KeySetId(345);
private final TransportKeySetId keySetId1 = new TransportKeySetId(456); private final KeySetId keySetId1 = new KeySetId(456);
private final SecretKey tagKey = getSecretKey(); private final SecretKey tagKey = getSecretKey();
private final SecretKey headerKey = getSecretKey(); private final SecretKey headerKey = getSecretKey();
private final SecretKey rootKey = getSecretKey(); private final SecretKey rootKey = getSecretKey();
@@ -73,8 +73,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
TransportKeys shouldRotate = createTransportKeys(900, 0, true); TransportKeys shouldRotate = createTransportKeys(900, 0, true);
TransportKeys shouldNotRotate = createTransportKeys(1000, 0, true); TransportKeys shouldNotRotate = createTransportKeys(1000, 0, true);
Collection<TransportKeySet> loaded = asList( Collection<TransportKeySet> loaded = asList(
new TransportKeySet(keySetId, contactId, shouldRotate), new TransportKeySet(keySetId, contactId, null, shouldRotate),
new TransportKeySet(keySetId1, contactId1, shouldNotRotate) new TransportKeySet(keySetId1, contactId1, null,
shouldNotRotate)
); );
TransportKeys rotated = createTransportKeys(1000, 0, true); TransportKeys rotated = createTransportKeys(1000, 0, true);
Transaction txn = new Transaction(null, false); Transaction txn = new Transaction(null, false);
@@ -87,9 +88,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
oneOf(db).getTransportKeys(txn, transportId); oneOf(db).getTransportKeys(txn, transportId);
will(returnValue(loaded)); will(returnValue(loaded));
// Rotate the transport keys // Rotate the transport keys
oneOf(transportCrypto).rotateTransportKeys(shouldRotate, 1000); oneOf(transportCrypto).updateTransportKeys(shouldRotate, 1000);
will(returnValue(rotated)); will(returnValue(rotated));
oneOf(transportCrypto).rotateTransportKeys(shouldNotRotate, 1000); oneOf(transportCrypto).updateTransportKeys(shouldNotRotate, 1000);
will(returnValue(shouldNotRotate)); will(returnValue(shouldNotRotate));
// Encode the tags (3 sets per contact) // Encode the tags (3 sets per contact)
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
@@ -100,7 +101,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
} }
// Save the keys that were rotated // Save the keys that were rotated
oneOf(db).updateTransportKeys(txn, singletonList( 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 // Schedule key rotation at the start of the next time period
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with(timePeriodLength - 1), with(MILLISECONDS)); with(timePeriodLength - 1), with(MILLISECONDS));
@@ -121,14 +122,14 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
Transaction txn = new Transaction(null, false); Transaction txn = new Transaction(null, false);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(transportCrypto).deriveTransportKeys(transportId, rootKey, oneOf(transportCrypto).deriveRotationKeys(transportId, rootKey,
999, alice, true); 999, alice, true);
will(returnValue(transportKeys)); will(returnValue(transportKeys));
// Get the current time (1 ms after start of time period 1000) // Get the current time (1 ms after start of time period 1000)
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timePeriodLength * 1000 + 1)); will(returnValue(timePeriodLength * 1000 + 1));
// Rotate the transport keys // Rotate the transport keys
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); oneOf(transportCrypto).updateTransportKeys(transportKeys, 1000);
will(returnValue(rotated)); will(returnValue(rotated));
// Encode the tags (3 sets) // Encode the tags (3 sets)
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
@@ -257,7 +258,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
List<byte[]> tags = new ArrayList<>(); List<byte[]> tags = new ArrayList<>();
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(transportCrypto).deriveTransportKeys(transportId, rootKey, oneOf(transportCrypto).deriveRotationKeys(transportId, rootKey,
1000, alice, true); 1000, alice, true);
will(returnValue(transportKeys)); will(returnValue(transportKeys));
// Get the current time (the start of time period 1000) // Get the current time (the start of time period 1000)
@@ -271,7 +272,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
will(new EncodeTagAction(tags)); will(new EncodeTagAction(tags));
} }
// Rotate the transport keys (the keys are unaffected) // Rotate the transport keys (the keys are unaffected)
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); oneOf(transportCrypto).updateTransportKeys(transportKeys, 1000);
will(returnValue(transportKeys)); will(returnValue(transportKeys));
// Save the keys // Save the keys
oneOf(db).addTransportKeys(txn, contactId, transportKeys); oneOf(db).addTransportKeys(txn, contactId, transportKeys);
@@ -315,7 +316,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
public void testKeysAreRotatedToCurrentPeriod() throws Exception { public void testKeysAreRotatedToCurrentPeriod() throws Exception {
TransportKeys transportKeys = createTransportKeys(1000, 0, true); TransportKeys transportKeys = createTransportKeys(1000, 0, true);
Collection<TransportKeySet> loaded = singletonList( Collection<TransportKeySet> loaded = singletonList(
new TransportKeySet(keySetId, contactId, transportKeys)); new TransportKeySet(keySetId, contactId, null, transportKeys));
TransportKeys rotated = createTransportKeys(1001, 0, true); TransportKeys rotated = createTransportKeys(1001, 0, true);
Transaction txn = new Transaction(null, false); Transaction txn = new Transaction(null, false);
Transaction txn1 = new Transaction(null, false); Transaction txn1 = new Transaction(null, false);
@@ -328,7 +329,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
oneOf(db).getTransportKeys(txn, transportId); oneOf(db).getTransportKeys(txn, transportId);
will(returnValue(loaded)); will(returnValue(loaded));
// Rotate the transport keys (the keys are unaffected) // Rotate the transport keys (the keys are unaffected)
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); oneOf(transportCrypto).updateTransportKeys(transportKeys, 1000);
will(returnValue(transportKeys)); will(returnValue(transportKeys));
// Encode the tags (3 sets) // Encode the tags (3 sets)
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
@@ -349,7 +350,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timePeriodLength * 1001)); will(returnValue(timePeriodLength * 1001));
// Rotate the transport keys // Rotate the transport keys
oneOf(transportCrypto).rotateTransportKeys( oneOf(transportCrypto).updateTransportKeys(
with(any(TransportKeys.class)), with(1001L)); with(any(TransportKeys.class)), with(1001L));
will(returnValue(rotated)); will(returnValue(rotated));
// Encode the tags (3 sets) // Encode the tags (3 sets)
@@ -361,7 +362,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
} }
// Save the keys that were rotated // Save the keys that were rotated
oneOf(db).updateTransportKeys(txn1, singletonList( 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 // Schedule key rotation at the start of the next time period
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with(timePeriodLength), with(MILLISECONDS)); with(timePeriodLength), with(MILLISECONDS));
@@ -422,7 +423,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
List<byte[]> tags = new ArrayList<>(); List<byte[]> tags = new ArrayList<>();
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(transportCrypto).deriveTransportKeys(transportId, rootKey, oneOf(transportCrypto).deriveRotationKeys(transportId, rootKey,
1000, alice, false); 1000, alice, false);
will(returnValue(transportKeys)); will(returnValue(transportKeys));
// Get the current time (the start of time period 1000) // Get the current time (the start of time period 1000)
@@ -436,7 +437,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
will(new EncodeTagAction(tags)); will(new EncodeTagAction(tags));
} }
// Rotate the transport keys (the keys are unaffected) // Rotate the transport keys (the keys are unaffected)
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); oneOf(transportCrypto).updateTransportKeys(transportKeys, 1000);
will(returnValue(transportKeys)); will(returnValue(transportKeys));
// Save the keys // Save the keys
oneOf(db).addTransportKeys(txn, contactId, transportKeys); oneOf(db).addTransportKeys(txn, contactId, transportKeys);
@@ -489,7 +490,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
private void expectAddContactNoRotation(boolean alice, boolean active, private void expectAddContactNoRotation(boolean alice, boolean active,
TransportKeys transportKeys, Transaction txn) throws Exception { TransportKeys transportKeys, Transaction txn) throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(transportCrypto).deriveTransportKeys(transportId, rootKey, oneOf(transportCrypto).deriveRotationKeys(transportId, rootKey,
1000, alice, active); 1000, alice, active);
will(returnValue(transportKeys)); will(returnValue(transportKeys));
// Get the current time (the start of time period 1000) // Get the current time (the start of time period 1000)
@@ -503,7 +504,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
will(new EncodeTagAction()); will(new EncodeTagAction());
} }
// Rotate the transport keys (the keys are unaffected) // Rotate the transport keys (the keys are unaffected)
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); oneOf(transportCrypto).updateTransportKeys(transportKeys, 1000);
will(returnValue(transportKeys)); will(returnValue(transportKeys));
// Save the keys // Save the keys
oneOf(db).addTransportKeys(txn, contactId, transportKeys); oneOf(db).addTransportKeys(txn, contactId, transportKeys);

View File

@@ -23,7 +23,7 @@ import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.KeyManager; 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.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
@@ -430,7 +430,7 @@ class IntroduceeProtocolEngine
s.getRemote().acceptTimestamp); s.getRemote().acceptTimestamp);
if (timestamp == -1) throw new AssertionError(); if (timestamp == -1) throw new AssertionError();
Map<TransportId, TransportKeySetId> keys = null; Map<TransportId, KeySetId> keys = null;
try { try {
contactManager.addContact(txn, s.getRemote().author, contactManager.addContact(txn, s.getRemote().author,
localAuthor.getId(), false); localAuthor.getId(), false);

View File

@@ -8,7 +8,7 @@ import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId; 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.client.SessionId;
import org.briarproject.briar.api.introduction.Role; import org.briarproject.briar.api.introduction.Role;
@@ -33,12 +33,12 @@ class IntroduceeSession extends Session<IntroduceeState>
@Nullable @Nullable
private final byte[] masterKey; private final byte[] masterKey;
@Nullable @Nullable
private final Map<TransportId, TransportKeySetId> transportKeys; private final Map<TransportId, KeySetId> transportKeys;
IntroduceeSession(SessionId sessionId, IntroduceeState state, IntroduceeSession(SessionId sessionId, IntroduceeState state,
long requestTimestamp, GroupId contactGroupId, Author introducer, long requestTimestamp, GroupId contactGroupId, Author introducer,
Local local, Remote remote, @Nullable byte[] masterKey, Local local, Remote remote, @Nullable byte[] masterKey,
@Nullable Map<TransportId, TransportKeySetId> transportKeys) { @Nullable Map<TransportId, KeySetId> transportKeys) {
super(sessionId, state, requestTimestamp); super(sessionId, state, requestTimestamp);
this.contactGroupId = contactGroupId; this.contactGroupId = contactGroupId;
this.introducer = introducer; this.introducer = introducer;
@@ -113,8 +113,7 @@ class IntroduceeSession extends Session<IntroduceeState>
} }
static IntroduceeSession awaitActivate(IntroduceeSession s, AuthMessage m, static IntroduceeSession awaitActivate(IntroduceeSession s, AuthMessage m,
Message sent, Message sent, @Nullable Map<TransportId, KeySetId> transportKeys) {
@Nullable Map<TransportId, TransportKeySetId> transportKeys) {
Local local = new Local(s.local, sent.getId(), sent.getTimestamp()); Local local = new Local(s.local, sent.getId(), sent.getTimestamp());
Remote remote = new Remote(s.remote, m.getMessageId()); Remote remote = new Remote(s.remote, m.getMessageId());
return new IntroduceeSession(s.getSessionId(), AWAIT_ACTIVATE, return new IntroduceeSession(s.getSessionId(), AWAIT_ACTIVATE,
@@ -181,7 +180,7 @@ class IntroduceeSession extends Session<IntroduceeState>
} }
@Nullable @Nullable
Map<TransportId, TransportKeySetId> getTransportKeys() { Map<TransportId, KeySetId> getTransportKeys() {
return transportKeys; return transportKeys;
} }

View File

@@ -6,13 +6,14 @@ import org.briarproject.bramble.api.data.BdfEntry;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId; 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.Common;
import org.briarproject.briar.introduction.IntroduceeSession.Local; import org.briarproject.briar.introduction.IntroduceeSession.Local;
import org.briarproject.briar.introduction.IntroduceeSession.Remote; import org.briarproject.briar.introduction.IntroduceeSession.Remote;
import org.briarproject.briar.introduction.IntroducerSession.Introducee; import org.briarproject.briar.introduction.IntroducerSession.Introducee;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@@ -143,10 +144,10 @@ class SessionEncoderImpl implements SessionEncoder {
@Nullable @Nullable
private BdfDictionary encodeTransportKeys( private BdfDictionary encodeTransportKeys(
@Nullable Map<TransportId, TransportKeySetId> keys) { @Nullable Map<TransportId, KeySetId> keys) {
if (keys == null) return null; if (keys == null) return null;
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
for (Map.Entry<TransportId, TransportKeySetId> e : keys.entrySet()) { for (Entry<TransportId, KeySetId> e : keys.entrySet()) {
d.put(e.getKey().getString(), e.getValue().getInt()); d.put(e.getKey().getString(), e.getValue().getInt());
} }
return d; return d;

View File

@@ -10,7 +10,7 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; 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.client.SessionId;
import org.briarproject.briar.api.introduction.Role; import org.briarproject.briar.api.introduction.Role;
import org.briarproject.briar.introduction.IntroduceeSession.Local; import org.briarproject.briar.introduction.IntroduceeSession.Local;
@@ -110,7 +110,7 @@ class SessionParserImpl implements SessionParser {
Local local = parseLocal(d.getDictionary(SESSION_KEY_LOCAL)); Local local = parseLocal(d.getDictionary(SESSION_KEY_LOCAL));
Remote remote = parseRemote(d.getDictionary(SESSION_KEY_REMOTE)); Remote remote = parseRemote(d.getDictionary(SESSION_KEY_REMOTE));
byte[] masterKey = d.getOptionalRaw(SESSION_KEY_MASTER_KEY); byte[] masterKey = d.getOptionalRaw(SESSION_KEY_MASTER_KEY);
Map<TransportId, TransportKeySetId> transportKeys = parseTransportKeys( Map<TransportId, KeySetId> transportKeys = parseTransportKeys(
d.getOptionalDictionary(SESSION_KEY_TRANSPORT_KEYS)); d.getOptionalDictionary(SESSION_KEY_TRANSPORT_KEYS));
return new IntroduceeSession(sessionId, state, requestTimestamp, return new IntroduceeSession(sessionId, state, requestTimestamp,
introducerGroupId, introducer, local, remote, introducerGroupId, introducer, local, remote,
@@ -184,13 +184,13 @@ class SessionParserImpl implements SessionParser {
} }
@Nullable @Nullable
private Map<TransportId, TransportKeySetId> parseTransportKeys( private Map<TransportId, KeySetId> parseTransportKeys(
@Nullable BdfDictionary d) throws FormatException { @Nullable BdfDictionary d) throws FormatException {
if (d == null) return null; if (d == null) return null;
Map<TransportId, TransportKeySetId> map = new HashMap<>(d.size()); Map<TransportId, KeySetId> map = new HashMap<>(d.size());
for (String key : d.keySet()) { for (String key : d.keySet()) {
map.put(new TransportId(key), map.put(new TransportId(key),
new TransportKeySetId(d.getLong(key).intValue())); new KeySetId(d.getLong(key).intValue()));
} }
return map; return map;
} }

View File

@@ -10,7 +10,7 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; 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.bramble.test.BrambleTestCase;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.introduction.IntroducerSession.Introducee; import org.briarproject.briar.introduction.IntroducerSession.Introducee;
@@ -75,8 +75,7 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
getTransportPropertiesMap(3); getTransportPropertiesMap(3);
private final Map<TransportId, TransportProperties> private final Map<TransportId, TransportProperties>
remoteTransportProperties = getTransportPropertiesMap(3); remoteTransportProperties = getTransportPropertiesMap(3);
private final Map<TransportId, TransportKeySetId> transportKeys = private final Map<TransportId, KeySetId> transportKeys = new HashMap<>();
new HashMap<>();
private final byte[] localMacKey = getRandomBytes(SecretKey.LENGTH); private final byte[] localMacKey = getRandomBytes(SecretKey.LENGTH);
private final byte[] remoteMacKey = getRandomBytes(SecretKey.LENGTH); private final byte[] remoteMacKey = getRandomBytes(SecretKey.LENGTH);
@@ -89,9 +88,9 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
sessionParser = new SessionParserImpl(clientHelper); sessionParser = new SessionParserImpl(clientHelper);
author1 = getRealAuthor(authorFactory); author1 = getRealAuthor(authorFactory);
author2 = getRealAuthor(authorFactory); author2 = getRealAuthor(authorFactory);
transportKeys.put(getTransportId(), new TransportKeySetId(1)); transportKeys.put(getTransportId(), new KeySetId(1));
transportKeys.put(getTransportId(), new TransportKeySetId(2)); transportKeys.put(getTransportId(), new KeySetId(2));
transportKeys.put(getTransportId(), new TransportKeySetId(3)); transportKeys.put(getTransportId(), new KeySetId(3));
} }
@Test @Test