diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java index fd2c0ffc9781a063588767f43d7fe74d526a1361..5fef176712f94c093c3922f4a1d888d808167987 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java @@ -1,8 +1,5 @@ package org.briarproject.bramble.api.crypto; -import org.briarproject.bramble.api.plugin.TransportId; -import org.briarproject.bramble.api.transport.TransportKeys; - import java.security.GeneralSecurityException; import java.security.SecureRandom; @@ -89,33 +86,6 @@ public interface CryptoComponent { PublicKey theirPublicKey, KeyPair ourKeyPair, boolean alice, boolean aliceRecord); - /** - * Derives initial transport keys for the given transport in the given - * rotation period from the given master secret. - * <p/> - * Used by the transport security protocol. - * - * @param alice whether the keys are for use by Alice or Bob. - */ - TransportKeys deriveTransportKeys(TransportId t, SecretKey master, - long rotationPeriod, boolean alice); - - /** - * Rotates the given transport keys to the given rotation period. If the - * keys are for a future rotation period they are not rotated. - * <p/> - * Used by the transport security protocol. - */ - TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod); - - /** - * Encodes the pseudo-random tag that is used to recognise a stream. - * <p/> - * Used by the transport security protocol. - */ - void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion, - long streamNumber); - /** * Signs the given byte[] with the given ECDSA private key. * diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java new file mode 100644 index 0000000000000000000000000000000000000000..e8be1484d6d0134a5a934a535a092cbb52f9ad3c --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java @@ -0,0 +1,34 @@ +package org.briarproject.bramble.api.crypto; + +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.transport.TransportKeys; + +public interface TransportCrypto { + + /** + * Derives initial transport keys for the given transport in the given + * rotation period from the given master secret. + * <p/> + * Used by the transport security protocol. + * + * @param alice whether the keys are for use by Alice or Bob. + */ + TransportKeys deriveTransportKeys(TransportId t, SecretKey master, + long rotationPeriod, boolean alice); + + /** + * Rotates the given transport keys to the given rotation period. If the + * keys are for a future rotation period they are not rotated. + * <p/> + * Used by the transport security protocol. + */ + TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod); + + /** + * Encodes the pseudo-random tag that is used to recognise a stream. + * <p/> + * Used by the transport security protocol. + */ + void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion, + long streamNumber); +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java index 0b1a7f23516c40806765e0a4fc3b574ff19f4f02..4a04c28a195f7460d5fa2cb34d66a2d08d3eea62 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java @@ -10,11 +10,7 @@ import org.briarproject.bramble.api.crypto.KeyParser; import org.briarproject.bramble.api.crypto.PrivateKey; import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.crypto.SecretKey; -import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.system.SecureRandomProvider; -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.util.ByteUtils; import org.briarproject.bramble.util.StringUtils; import org.spongycastle.crypto.AsymmetricCipherKeyPair; @@ -44,13 +40,8 @@ import javax.inject.Inject; import static java.util.logging.Level.INFO; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH; -import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; import static org.briarproject.bramble.crypto.EllipticCurveConstants.PARAMETERS; -import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES; -import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES; -import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED; -import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED; class CryptoComponentImpl implements CryptoComponent { @@ -75,15 +66,6 @@ class CryptoComponentImpl implements CryptoComponent { private static final String CONFIRMATION_MAC_LABEL = "org.briarproject.bramble.keyagreement/CONFIRMATION_MAC"; - // KDF labels for tag key derivation - private static final String A_TAG = "ALICE_TAG_KEY"; - private static final String B_TAG = "BOB_TAG_KEY"; - // KDF labels for header key derivation - private static final String A_HEADER = "ALICE_HEADER_KEY"; - private static final String B_HEADER = "BOB_HEADER_KEY"; - // KDF label for key rotation - private static final String ROTATE = "ROTATE"; - private final SecureRandom secureRandom; private final ECKeyPairGenerator agreementKeyPairGenerator; private final ECKeyPairGenerator signatureKeyPairGenerator; @@ -309,104 +291,6 @@ class CryptoComponentImpl implements CryptoComponent { } } - @Override - public TransportKeys deriveTransportKeys(TransportId t, - SecretKey master, long rotationPeriod, boolean alice) { - // Keys for the previous period are derived from the master secret - SecretKey inTagPrev = deriveTagKey(master, t, !alice); - SecretKey inHeaderPrev = deriveHeaderKey(master, t, !alice); - SecretKey outTagPrev = deriveTagKey(master, t, alice); - SecretKey outHeaderPrev = deriveHeaderKey(master, t, alice); - // Derive the keys for the current and next periods - SecretKey inTagCurr = rotateKey(inTagPrev, rotationPeriod); - SecretKey inHeaderCurr = rotateKey(inHeaderPrev, rotationPeriod); - SecretKey inTagNext = rotateKey(inTagCurr, rotationPeriod + 1); - SecretKey inHeaderNext = rotateKey(inHeaderCurr, rotationPeriod + 1); - SecretKey outTagCurr = rotateKey(outTagPrev, rotationPeriod); - SecretKey outHeaderCurr = rotateKey(outHeaderPrev, rotationPeriod); - // Initialise the reordering windows and stream counters - IncomingKeys inPrev = new IncomingKeys(inTagPrev, inHeaderPrev, - rotationPeriod - 1); - IncomingKeys inCurr = new IncomingKeys(inTagCurr, inHeaderCurr, - rotationPeriod); - IncomingKeys inNext = new IncomingKeys(inTagNext, inHeaderNext, - rotationPeriod + 1); - OutgoingKeys outCurr = new OutgoingKeys(outTagCurr, outHeaderCurr, - rotationPeriod); - // Collect and return the keys - return new TransportKeys(t, inPrev, inCurr, inNext, outCurr); - } - - @Override - public TransportKeys rotateTransportKeys(TransportKeys k, - long rotationPeriod) { - if (k.getRotationPeriod() >= rotationPeriod) return k; - IncomingKeys inPrev = k.getPreviousIncomingKeys(); - IncomingKeys inCurr = k.getCurrentIncomingKeys(); - IncomingKeys inNext = k.getNextIncomingKeys(); - OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); - long startPeriod = outCurr.getRotationPeriod(); - // Rotate the keys - for (long p = startPeriod + 1; p <= rotationPeriod; 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); - } - // Collect and return the keys - return new TransportKeys(k.getTransportId(), inPrev, inCurr, inNext, - outCurr); - } - - private SecretKey rotateKey(SecretKey k, long rotationPeriod) { - byte[] period = new byte[INT_64_BYTES]; - ByteUtils.writeUint64(rotationPeriod, period, 0); - return deriveKey(ROTATE, k, period); - } - - private SecretKey deriveTagKey(SecretKey master, TransportId t, - boolean alice) { - byte[] id = StringUtils.toUtf8(t.getString()); - return deriveKey(alice ? A_TAG : B_TAG, master, id); - } - - private SecretKey deriveHeaderKey(SecretKey master, TransportId t, - boolean alice) { - byte[] id = StringUtils.toUtf8(t.getString()); - return deriveKey(alice ? A_HEADER : B_HEADER, master, id); - } - - @Override - public void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion, - long streamNumber) { - if (tag.length < TAG_LENGTH) throw new IllegalArgumentException(); - if (protocolVersion < 0 || protocolVersion > MAX_16_BIT_UNSIGNED) - throw new IllegalArgumentException(); - if (streamNumber < 0 || streamNumber > MAX_32_BIT_UNSIGNED) - throw new IllegalArgumentException(); - // Initialise the PRF - Digest prf = new Blake2sDigest(tagKey.getBytes()); - // The output of the PRF must be long enough to use as a tag - int macLength = prf.getDigestSize(); - if (macLength < TAG_LENGTH) throw new IllegalStateException(); - // The input is the protocol version as a 16-bit integer, followed by - // the stream number as a 64-bit integer - byte[] protocolVersionBytes = new byte[INT_16_BYTES]; - ByteUtils.writeUint16(protocolVersion, protocolVersionBytes, 0); - prf.update(protocolVersionBytes, 0, protocolVersionBytes.length); - byte[] streamNumberBytes = new byte[INT_64_BYTES]; - ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0); - prf.update(streamNumberBytes, 0, streamNumberBytes.length); - byte[] mac = new byte[macLength]; - prf.doFinal(mac, 0); - // The output is the first TAG_LENGTH bytes of the MAC - System.arraycopy(mac, 0, tag, 0, TAG_LENGTH); - } - @Override public byte[] sign(String label, byte[] toSign, byte[] privateKey) throws GeneralSecurityException { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoModule.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoModule.java index 37c37abf3ee2ad5d7fa3b22edbb323f91b6f2629..99889104594bf89ee4550b02730cced465ef51b9 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoModule.java @@ -6,6 +6,7 @@ import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.api.crypto.StreamDecrypterFactory; import org.briarproject.bramble.api.crypto.StreamEncrypterFactory; +import org.briarproject.bramble.api.crypto.TransportCrypto; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.system.SecureRandomProvider; @@ -74,6 +75,12 @@ public class CryptoModule { return new PasswordStrengthEstimatorImpl(); } + @Provides + TransportCrypto provideTransportCrypto( + TransportCryptoImpl transportCrypto) { + return transportCrypto; + } + @Provides StreamDecrypterFactory provideStreamDecrypterFactory( Provider<AuthenticatedCipher> cipherProvider) { @@ -81,9 +88,11 @@ public class CryptoModule { } @Provides - StreamEncrypterFactory provideStreamEncrypterFactory(CryptoComponent crypto, + StreamEncrypterFactory provideStreamEncrypterFactory( + CryptoComponent crypto, TransportCrypto transportCrypto, Provider<AuthenticatedCipher> cipherProvider) { - return new StreamEncrypterFactoryImpl(crypto, cipherProvider); + return new StreamEncrypterFactoryImpl(crypto, transportCrypto, + cipherProvider); } @Provides diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamEncrypterFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamEncrypterFactoryImpl.java index 0d9b4a0fc2bf65d2732d649575ed63bdbcd4d764..984d5e826271191676224b872ce5e95037ff12d0 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamEncrypterFactoryImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamEncrypterFactoryImpl.java @@ -4,6 +4,7 @@ import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.StreamEncrypter; import org.briarproject.bramble.api.crypto.StreamEncrypterFactory; +import org.briarproject.bramble.api.crypto.TransportCrypto; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.transport.StreamContext; @@ -22,12 +23,15 @@ import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENG class StreamEncrypterFactoryImpl implements StreamEncrypterFactory { private final CryptoComponent crypto; + private final TransportCrypto transportCrypto; private final Provider<AuthenticatedCipher> cipherProvider; @Inject StreamEncrypterFactoryImpl(CryptoComponent crypto, + TransportCrypto transportCrypto, Provider<AuthenticatedCipher> cipherProvider) { this.crypto = crypto; + this.transportCrypto = transportCrypto; this.cipherProvider = cipherProvider; } @@ -37,7 +41,8 @@ class StreamEncrypterFactoryImpl implements StreamEncrypterFactory { AuthenticatedCipher cipher = cipherProvider.get(); long streamNumber = ctx.getStreamNumber(); byte[] tag = new byte[TAG_LENGTH]; - crypto.encodeTag(tag, ctx.getTagKey(), PROTOCOL_VERSION, streamNumber); + transportCrypto.encodeTag(tag, ctx.getTagKey(), PROTOCOL_VERSION, + streamNumber); byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH]; crypto.getSecureRandom().nextBytes(streamHeaderNonce); SecretKey frameKey = crypto.generateSecretKey(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..52b51723332d345cc8fd8f947205adc4814ea921 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java @@ -0,0 +1,137 @@ +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.IncomingKeys; +import org.briarproject.bramble.api.transport.OutgoingKeys; +import org.briarproject.bramble.api.transport.TransportKeys; +import org.briarproject.bramble.util.ByteUtils; +import org.briarproject.bramble.util.StringUtils; +import org.spongycastle.crypto.Digest; + +import javax.inject.Inject; + +import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; +import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES; +import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES; +import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED; +import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED; + +class TransportCryptoImpl implements TransportCrypto { + + // KDF labels for tag key derivation + private static final String A_TAG = "ALICE_TAG_KEY"; + private static final String B_TAG = "BOB_TAG_KEY"; + // KDF labels for header key derivation + private static final String A_HEADER = "ALICE_HEADER_KEY"; + private static final String B_HEADER = "BOB_HEADER_KEY"; + // KDF label for key rotation + private static final String ROTATE = "ROTATE"; + + private final CryptoComponent crypto; + + @Inject + TransportCryptoImpl(CryptoComponent crypto) { + this.crypto = crypto; + } + + @Override + public TransportKeys deriveTransportKeys(TransportId t, + SecretKey master, long rotationPeriod, boolean alice) { + // Keys for the previous period are derived from the master secret + SecretKey inTagPrev = deriveTagKey(master, t, !alice); + SecretKey inHeaderPrev = deriveHeaderKey(master, t, !alice); + SecretKey outTagPrev = deriveTagKey(master, t, alice); + SecretKey outHeaderPrev = deriveHeaderKey(master, t, alice); + // Derive the keys for the current and next periods + SecretKey inTagCurr = rotateKey(inTagPrev, rotationPeriod); + SecretKey inHeaderCurr = rotateKey(inHeaderPrev, rotationPeriod); + SecretKey inTagNext = rotateKey(inTagCurr, rotationPeriod + 1); + SecretKey inHeaderNext = rotateKey(inHeaderCurr, rotationPeriod + 1); + SecretKey outTagCurr = rotateKey(outTagPrev, rotationPeriod); + SecretKey outHeaderCurr = rotateKey(outHeaderPrev, rotationPeriod); + // Initialise the reordering windows and stream counters + IncomingKeys inPrev = new IncomingKeys(inTagPrev, inHeaderPrev, + rotationPeriod - 1); + IncomingKeys inCurr = new IncomingKeys(inTagCurr, inHeaderCurr, + rotationPeriod); + IncomingKeys inNext = new IncomingKeys(inTagNext, inHeaderNext, + rotationPeriod + 1); + OutgoingKeys outCurr = new OutgoingKeys(outTagCurr, outHeaderCurr, + rotationPeriod); + // Collect and return the keys + return new TransportKeys(t, inPrev, inCurr, inNext, outCurr); + } + + @Override + public TransportKeys rotateTransportKeys(TransportKeys k, + long rotationPeriod) { + if (k.getRotationPeriod() >= rotationPeriod) return k; + IncomingKeys inPrev = k.getPreviousIncomingKeys(); + IncomingKeys inCurr = k.getCurrentIncomingKeys(); + IncomingKeys inNext = k.getNextIncomingKeys(); + OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); + long startPeriod = outCurr.getRotationPeriod(); + // Rotate the keys + for (long p = startPeriod + 1; p <= rotationPeriod; 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); + } + // Collect and return the keys + return new TransportKeys(k.getTransportId(), inPrev, inCurr, inNext, + outCurr); + } + + private SecretKey rotateKey(SecretKey k, long rotationPeriod) { + byte[] period = new byte[INT_64_BYTES]; + ByteUtils.writeUint64(rotationPeriod, period, 0); + return crypto.deriveKey(ROTATE, k, period); + } + + private SecretKey deriveTagKey(SecretKey master, TransportId t, + boolean alice) { + byte[] id = StringUtils.toUtf8(t.getString()); + return crypto.deriveKey(alice ? A_TAG : B_TAG, master, id); + } + + private SecretKey deriveHeaderKey(SecretKey master, TransportId t, + boolean alice) { + byte[] id = StringUtils.toUtf8(t.getString()); + return crypto.deriveKey(alice ? A_HEADER : B_HEADER, master, id); + } + + @Override + public void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion, + long streamNumber) { + if (tag.length < TAG_LENGTH) throw new IllegalArgumentException(); + if (protocolVersion < 0 || protocolVersion > MAX_16_BIT_UNSIGNED) + throw new IllegalArgumentException(); + if (streamNumber < 0 || streamNumber > MAX_32_BIT_UNSIGNED) + throw new IllegalArgumentException(); + // Initialise the PRF + Digest prf = new Blake2sDigest(tagKey.getBytes()); + // The output of the PRF must be long enough to use as a tag + int macLength = prf.getDigestSize(); + if (macLength < TAG_LENGTH) throw new IllegalStateException(); + // The input is the protocol version as a 16-bit integer, followed by + // the stream number as a 64-bit integer + byte[] protocolVersionBytes = new byte[INT_16_BYTES]; + ByteUtils.writeUint16(protocolVersion, protocolVersionBytes, 0); + prf.update(protocolVersionBytes, 0, protocolVersionBytes.length); + byte[] streamNumberBytes = new byte[INT_64_BYTES]; + ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0); + prf.update(streamNumberBytes, 0, streamNumberBytes.length); + byte[] mac = new byte[macLength]; + prf.doFinal(mac, 0); + // The output is the first TAG_LENGTH bytes of the MAC + System.arraycopy(mac, 0, tag, 0, TAG_LENGTH); + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerFactoryImpl.java index d212a027b98f78304f31e6e2e3b6d9b544fca8b0..3a04f121a656837de2f02789f277d1ea7c65a095 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerFactoryImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerFactoryImpl.java @@ -1,6 +1,6 @@ package org.briarproject.bramble.transport; -import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.crypto.TransportCrypto; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; @@ -20,17 +20,18 @@ class TransportKeyManagerFactoryImpl implements TransportKeyManagerFactory { private final DatabaseComponent db; - private final CryptoComponent crypto; + private final TransportCrypto transportCrypto; private final Executor dbExecutor; private final ScheduledExecutorService scheduler; private final Clock clock; @Inject - TransportKeyManagerFactoryImpl(DatabaseComponent db, CryptoComponent crypto, + TransportKeyManagerFactoryImpl(DatabaseComponent db, + TransportCrypto transportCrypto, @DatabaseExecutor Executor dbExecutor, @Scheduler ScheduledExecutorService scheduler, Clock clock) { this.db = db; - this.crypto = crypto; + this.transportCrypto = transportCrypto; this.dbExecutor = dbExecutor; this.scheduler = scheduler; this.clock = clock; @@ -39,8 +40,8 @@ class TransportKeyManagerFactoryImpl implements @Override public TransportKeyManager createTransportKeyManager( TransportId transportId, long maxLatency) { - return new TransportKeyManagerImpl(db, crypto, dbExecutor, scheduler, - clock, transportId, maxLatency); + return new TransportKeyManagerImpl(db, transportCrypto, dbExecutor, + scheduler, clock, transportId, maxLatency); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java index 95e49f55346b6fc13ce6cf04b668bc5d12a41818..60b48427ff18f07703a147f827ae39639c6f629e 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java @@ -2,8 +2,8 @@ package org.briarproject.bramble.transport; import org.briarproject.bramble.api.Bytes; import org.briarproject.bramble.api.contact.ContactId; -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.db.DatabaseComponent; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; @@ -41,7 +41,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { Logger.getLogger(TransportKeyManagerImpl.class.getName()); private final DatabaseComponent db; - private final CryptoComponent crypto; + private final TransportCrypto transportCrypto; private final Executor dbExecutor; private final ScheduledExecutorService scheduler; private final Clock clock; @@ -54,11 +54,12 @@ class TransportKeyManagerImpl implements TransportKeyManager { private final Map<ContactId, MutableOutgoingKeys> outContexts; private final Map<ContactId, MutableTransportKeys> keys; - TransportKeyManagerImpl(DatabaseComponent db, CryptoComponent crypto, - Executor dbExecutor, @Scheduler ScheduledExecutorService scheduler, - Clock clock, TransportId transportId, long maxLatency) { + TransportKeyManagerImpl(DatabaseComponent db, + TransportCrypto transportCrypto, Executor dbExecutor, + @Scheduler ScheduledExecutorService scheduler, Clock clock, + TransportId transportId, long maxLatency) { this.db = db; - this.crypto = crypto; + this.transportCrypto = transportCrypto; this.dbExecutor = dbExecutor; this.scheduler = scheduler; this.clock = clock; @@ -99,7 +100,8 @@ class TransportKeyManagerImpl implements TransportKeyManager { for (Entry<ContactId, TransportKeys> e : keys.entrySet()) { ContactId c = e.getKey(); TransportKeys k = e.getValue(); - TransportKeys k1 = crypto.rotateTransportKeys(k, rotationPeriod); + TransportKeys k1 = + transportCrypto.rotateTransportKeys(k, rotationPeriod); if (k1.getRotationPeriod() > k.getRotationPeriod()) rotationResult.rotated.put(c, k1); rotationResult.current.put(c, k1); @@ -127,7 +129,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { for (long streamNumber : inKeys.getWindow().getUnseen()) { TagContext tagCtx = new TagContext(c, inKeys, streamNumber); byte[] tag = new byte[TAG_LENGTH]; - crypto.encodeTag(tag, inKeys.getTagKey(), PROTOCOL_VERSION, + transportCrypto.encodeTag(tag, inKeys.getTagKey(), PROTOCOL_VERSION, streamNumber); inContexts.put(new Bytes(tag), tagCtx); } @@ -162,11 +164,11 @@ class TransportKeyManagerImpl implements TransportKeyManager { // Work out what rotation period the timestamp belongs to long rotationPeriod = timestamp / rotationPeriodLength; // Derive the transport keys - TransportKeys k = crypto.deriveTransportKeys(transportId, master, - rotationPeriod, alice); + TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + master, rotationPeriod, alice); // Rotate the keys to the current rotation period if necessary rotationPeriod = clock.currentTimeMillis() / rotationPeriodLength; - k = crypto.rotateTransportKeys(k, rotationPeriod); + k = transportCrypto.rotateTransportKeys(k, rotationPeriod); // Initialise mutable state for the contact addKeys(c, new MutableTransportKeys(k)); // Write the keys back to the DB @@ -234,8 +236,8 @@ class TransportKeyManagerImpl implements TransportKeyManager { // Add tags for any stream numbers added to the window for (long streamNumber : change.getAdded()) { byte[] addTag = new byte[TAG_LENGTH]; - crypto.encodeTag(addTag, inKeys.getTagKey(), PROTOCOL_VERSION, - streamNumber); + transportCrypto.encodeTag(addTag, inKeys.getTagKey(), + PROTOCOL_VERSION, streamNumber); inContexts.put(new Bytes(addTag), new TagContext( tagCtx.contactId, inKeys, streamNumber)); } @@ -243,7 +245,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { for (long streamNumber : change.getRemoved()) { if (streamNumber == tagCtx.streamNumber) continue; byte[] removeTag = new byte[TAG_LENGTH]; - crypto.encodeTag(removeTag, inKeys.getTagKey(), + transportCrypto.encodeTag(removeTag, inKeys.getTagKey(), PROTOCOL_VERSION, streamNumber); inContexts.remove(new Bytes(removeTag)); } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTest.java index 7a3e67c4c2f5d09a5773585a2122d740e5c24f1d..805816e9233064e35064335069014e438d38670d 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTest.java @@ -3,11 +3,11 @@ package org.briarproject.bramble.crypto; import org.briarproject.bramble.api.Bytes; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.crypto.TransportCrypto; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.TestSecureRandomProvider; -import org.briarproject.bramble.test.TestUtils; import org.junit.Test; import java.util.ArrayList; @@ -16,35 +16,34 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class KeyDerivationTest extends BrambleTestCase { + private final CryptoComponent crypto = + new CryptoComponentImpl(new TestSecureRandomProvider()); + private final TransportCrypto transportCrypto = + new TransportCryptoImpl(crypto); private final TransportId transportId = new TransportId("id"); - private final CryptoComponent crypto; - private final SecretKey master; - - public KeyDerivationTest() { - crypto = new CryptoComponentImpl(new TestSecureRandomProvider()); - master = TestUtils.getSecretKey(); - } + private final SecretKey master = getSecretKey(); @Test public void testKeysAreDistinct() { - TransportKeys k = crypto.deriveTransportKeys(transportId, master, - 123, true); + TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + master, 123, true); assertAllDifferent(k); } @Test public void testCurrentKeysMatchCurrentKeysOfContact() { // Start in rotation period 123 - TransportKeys kA = crypto.deriveTransportKeys(transportId, master, - 123, true); - TransportKeys kB = crypto.deriveTransportKeys(transportId, master, - 123, false); + TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, + master, 123, true); + TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, + master, 123, false); // Alice's incoming keys should equal Bob's outgoing keys assertArrayEquals(kA.getCurrentIncomingKeys().getTagKey().getBytes(), kB.getCurrentOutgoingKeys().getTagKey().getBytes()); @@ -56,8 +55,8 @@ public class KeyDerivationTest extends BrambleTestCase { assertArrayEquals(kA.getCurrentOutgoingKeys().getHeaderKey().getBytes(), kB.getCurrentIncomingKeys().getHeaderKey().getBytes()); // Rotate into the future - kA = crypto.rotateTransportKeys(kA, 456); - kB = crypto.rotateTransportKeys(kB, 456); + kA = transportCrypto.rotateTransportKeys(kA, 456); + kB = transportCrypto.rotateTransportKeys(kB, 456); // Alice's incoming keys should equal Bob's outgoing keys assertArrayEquals(kA.getCurrentIncomingKeys().getTagKey().getBytes(), kB.getCurrentOutgoingKeys().getTagKey().getBytes()); @@ -73,22 +72,23 @@ public class KeyDerivationTest extends BrambleTestCase { @Test public void testPreviousKeysMatchPreviousKeysOfContact() { // Start in rotation period 123 - TransportKeys kA = crypto.deriveTransportKeys(transportId, master, - 123, true); - TransportKeys kB = crypto.deriveTransportKeys(transportId, master, - 123, false); + TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, + master, 123, true); + TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, + master, 123, false); // Compare Alice's previous keys in period 456 with Bob's current keys // in period 455 - kA = crypto.rotateTransportKeys(kA, 456); - kB = crypto.rotateTransportKeys(kB, 455); + kA = transportCrypto.rotateTransportKeys(kA, 456); + kB = transportCrypto.rotateTransportKeys(kB, 455); // Alice's previous incoming keys should equal Bob's outgoing keys assertArrayEquals(kA.getPreviousIncomingKeys().getTagKey().getBytes(), kB.getCurrentOutgoingKeys().getTagKey().getBytes()); - assertArrayEquals(kA.getPreviousIncomingKeys().getHeaderKey().getBytes(), + assertArrayEquals( + kA.getPreviousIncomingKeys().getHeaderKey().getBytes(), kB.getCurrentOutgoingKeys().getHeaderKey().getBytes()); // Compare Alice's current keys in period 456 with Bob's previous keys // in period 457 - kB = crypto.rotateTransportKeys(kB, 457); + kB = transportCrypto.rotateTransportKeys(kB, 457); // Alice's outgoing keys should equal Bob's previous incoming keys assertArrayEquals(kA.getCurrentOutgoingKeys().getTagKey().getBytes(), kB.getPreviousIncomingKeys().getTagKey().getBytes()); @@ -99,14 +99,14 @@ public class KeyDerivationTest extends BrambleTestCase { @Test public void testNextKeysMatchNextKeysOfContact() { // Start in rotation period 123 - TransportKeys kA = crypto.deriveTransportKeys(transportId, master, - 123, true); - TransportKeys kB = crypto.deriveTransportKeys(transportId, master, - 123, false); + TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, + master, 123, true); + TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, + master, 123, false); // Compare Alice's current keys in period 456 with Bob's next keys in // period 455 - kA = crypto.rotateTransportKeys(kA, 456); - kB = crypto.rotateTransportKeys(kB, 455); + kA = transportCrypto.rotateTransportKeys(kA, 456); + kB = transportCrypto.rotateTransportKeys(kB, 455); // Alice's outgoing keys should equal Bob's next incoming keys assertArrayEquals(kA.getCurrentOutgoingKeys().getTagKey().getBytes(), kB.getNextIncomingKeys().getTagKey().getBytes()); @@ -114,7 +114,7 @@ public class KeyDerivationTest extends BrambleTestCase { kB.getNextIncomingKeys().getHeaderKey().getBytes()); // Compare Alice's next keys in period 456 with Bob's current keys // in period 457 - kB = crypto.rotateTransportKeys(kB, 457); + kB = transportCrypto.rotateTransportKeys(kB, 457); // Alice's next incoming keys should equal Bob's outgoing keys assertArrayEquals(kA.getNextIncomingKeys().getTagKey().getBytes(), kB.getCurrentOutgoingKeys().getTagKey().getBytes()); @@ -124,12 +124,12 @@ public class KeyDerivationTest extends BrambleTestCase { @Test public void testMasterKeyAffectsOutput() { - SecretKey master1 = TestUtils.getSecretKey(); + SecretKey master1 = getSecretKey(); assertFalse(Arrays.equals(master.getBytes(), master1.getBytes())); - TransportKeys k = crypto.deriveTransportKeys(transportId, master, - 123, true); - TransportKeys k1 = crypto.deriveTransportKeys(transportId, master1, - 123, true); + TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + master, 123, true); + TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId, + master1, 123, true); assertAllDifferent(k, k1); } @@ -137,10 +137,10 @@ public class KeyDerivationTest extends BrambleTestCase { public void testTransportIdAffectsOutput() { TransportId transportId1 = new TransportId("id1"); assertFalse(transportId.getString().equals(transportId1.getString())); - TransportKeys k = crypto.deriveTransportKeys(transportId, master, - 123, true); - TransportKeys k1 = crypto.deriveTransportKeys(transportId1, master, - 123, true); + TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + master, 123, true); + TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId1, + master, 123, true); assertAllDifferent(k, k1); } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/TagEncodingTest.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/TagEncodingTest.java index cfbc6d37529510c2ce37260eaa53c8a05ee4493d..b6cce5ae242432a2bf9ccb9409d20bd494df5d9e 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/crypto/TagEncodingTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/TagEncodingTest.java @@ -3,9 +3,8 @@ package org.briarproject.bramble.crypto; import org.briarproject.bramble.api.Bytes; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.SecretKey; -import org.briarproject.bramble.test.BrambleTestCase; -import org.briarproject.bramble.test.TestSecureRandomProvider; -import org.briarproject.bramble.test.TestUtils; +import org.briarproject.bramble.api.crypto.TransportCrypto; +import org.briarproject.bramble.test.BrambleMockTestCase; import org.junit.Test; import java.util.HashSet; @@ -14,25 +13,25 @@ import java.util.Set; import static junit.framework.TestCase.assertTrue; import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION; import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; -public class TagEncodingTest extends BrambleTestCase { +public class TagEncodingTest extends BrambleMockTestCase { - private final CryptoComponent crypto; - private final SecretKey tagKey; - private final long streamNumber = 1234567890; + private final CryptoComponent crypto = context.mock(CryptoComponent.class); - public TagEncodingTest() { - crypto = new CryptoComponentImpl(new TestSecureRandomProvider()); - tagKey = TestUtils.getSecretKey(); - } + private final TransportCrypto transportCrypto = + new TransportCryptoImpl(crypto); + private final SecretKey tagKey = getSecretKey(); + private final long streamNumber = 1234567890; @Test public void testKeyAffectsTag() throws Exception { Set<Bytes> set = new HashSet<>(); for (int i = 0; i < 100; i++) { byte[] tag = new byte[TAG_LENGTH]; - SecretKey tagKey = TestUtils.getSecretKey(); - crypto.encodeTag(tag, tagKey, PROTOCOL_VERSION, streamNumber); + SecretKey tagKey = getSecretKey(); + transportCrypto.encodeTag(tag, tagKey, PROTOCOL_VERSION, + streamNumber); assertTrue(set.add(new Bytes(tag))); } } @@ -42,7 +41,8 @@ public class TagEncodingTest extends BrambleTestCase { Set<Bytes> set = new HashSet<>(); for (int i = 0; i < 100; i++) { byte[] tag = new byte[TAG_LENGTH]; - crypto.encodeTag(tag, tagKey, PROTOCOL_VERSION + i, streamNumber); + transportCrypto.encodeTag(tag, tagKey, PROTOCOL_VERSION + i, + streamNumber); assertTrue(set.add(new Bytes(tag))); } } @@ -52,7 +52,8 @@ public class TagEncodingTest extends BrambleTestCase { Set<Bytes> set = new HashSet<>(); for (int i = 0; i < 100; i++) { byte[] tag = new byte[TAG_LENGTH]; - crypto.encodeTag(tag, tagKey, PROTOCOL_VERSION, streamNumber + i); + transportCrypto.encodeTag(tag, tagKey, PROTOCOL_VERSION, + streamNumber + i); assertTrue(set.add(new Bytes(tag))); } } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java index bc5c86a8d5e1ec844885ddcc6ff760039f9c2a9c..7bb53e8435c05d56a0eec01b4eb944c4ab6a1cff 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java @@ -1,8 +1,8 @@ package org.briarproject.bramble.sync; import org.briarproject.bramble.api.contact.ContactId; -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.sync.Ack; import org.briarproject.bramble.api.sync.ClientId; @@ -57,7 +57,7 @@ public class SyncIntegrationTest extends BrambleTestCase { @Inject RecordWriterFactory recordWriterFactory; @Inject - CryptoComponent crypto; + TransportCrypto transportCrypto; private final ContactId contactId; private final TransportId transportId; @@ -117,7 +117,8 @@ public class SyncIntegrationTest extends BrambleTestCase { private void read(byte[] connectionData) throws Exception { // Calculate the expected tag byte[] expectedTag = new byte[TAG_LENGTH]; - crypto.encodeTag(expectedTag, tagKey, PROTOCOL_VERSION, streamNumber); + transportCrypto.encodeTag(expectedTag, tagKey, PROTOCOL_VERSION, + streamNumber); // Read the tag InputStream in = new ByteArrayInputStream(connectionData); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java index 0cdfaeb561228cfd7d22c991a7dae780ba5becb4..4dc1f980240d9d91daa57860c5da1ea40d47b93d 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java @@ -1,8 +1,8 @@ package org.briarproject.bramble.transport; import org.briarproject.bramble.api.contact.ContactId; -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.db.DatabaseComponent; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.plugin.TransportId; @@ -11,12 +11,11 @@ import org.briarproject.bramble.api.transport.IncomingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.StreamContext; import org.briarproject.bramble.api.transport.TransportKeys; -import org.briarproject.bramble.test.BrambleTestCase; +import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.RunAction; import org.briarproject.bramble.test.TestUtils; import org.hamcrest.Description; import org.jmock.Expectations; -import org.jmock.Mockery; import org.jmock.api.Action; import org.jmock.api.Invocation; import org.junit.Test; @@ -41,7 +40,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -public class TransportKeyManagerImplTest extends BrambleTestCase { +public class TransportKeyManagerImplTest extends BrambleMockTestCase { + + private final DatabaseComponent db = context.mock(DatabaseComponent.class); + private final TransportCrypto transportCrypto = + context.mock(TransportCrypto.class); + private final Executor dbExecutor = context.mock(Executor.class); + private final ScheduledExecutorService scheduler = + context.mock(ScheduledExecutorService.class); + private final Clock clock = context.mock(Clock.class); private final TransportId transportId = new TransportId("id"); private final long maxLatency = 30 * 1000; // 30 seconds @@ -55,14 +62,6 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { @Test public void testKeysAreRotatedAtStartup() throws Exception { - Mockery context = new Mockery(); - DatabaseComponent db = context.mock(DatabaseComponent.class); - CryptoComponent crypto = context.mock(CryptoComponent.class); - Executor dbExecutor = context.mock(Executor.class); - ScheduledExecutorService scheduler = - context.mock(ScheduledExecutorService.class); - Clock clock = context.mock(Clock.class); - Map<ContactId, TransportKeys> loaded = new LinkedHashMap<>(); TransportKeys shouldRotate = createTransportKeys(900, 0); TransportKeys shouldNotRotate = createTransportKeys(1000, 0); @@ -79,14 +78,15 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { oneOf(db).getTransportKeys(txn, transportId); will(returnValue(loaded)); // Rotate the transport keys - oneOf(crypto).rotateTransportKeys(shouldRotate, 1000); + oneOf(transportCrypto).rotateTransportKeys(shouldRotate, 1000); will(returnValue(rotated)); - oneOf(crypto).rotateTransportKeys(shouldNotRotate, 1000); + oneOf(transportCrypto).rotateTransportKeys(shouldNotRotate, 1000); will(returnValue(shouldNotRotate)); // Encode the tags (3 sets per contact) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { - exactly(6).of(crypto).encodeTag(with(any(byte[].class)), - with(tagKey), with(PROTOCOL_VERSION), with(i)); + exactly(6).of(transportCrypto).encodeTag( + with(any(byte[].class)), with(tagKey), + with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Save the keys that were rotated @@ -97,161 +97,124 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { with(rotationPeriodLength - 1), with(MILLISECONDS)); }}); - TransportKeyManager - transportKeyManager = new TransportKeyManagerImpl(db, - crypto, dbExecutor, scheduler, clock, transportId, maxLatency); + TransportKeyManager transportKeyManager = new TransportKeyManagerImpl( + db, transportCrypto, dbExecutor, scheduler, clock, transportId, + maxLatency); transportKeyManager.start(txn); - - context.assertIsSatisfied(); } @Test public void testKeysAreRotatedWhenAddingContact() throws Exception { - Mockery context = new Mockery(); - DatabaseComponent db = context.mock(DatabaseComponent.class); - CryptoComponent crypto = context.mock(CryptoComponent.class); - Executor dbExecutor = context.mock(Executor.class); - ScheduledExecutorService scheduler = - context.mock(ScheduledExecutorService.class); - Clock clock = context.mock(Clock.class); - - boolean alice = true; + boolean alice = random.nextBoolean(); TransportKeys transportKeys = createTransportKeys(999, 0); TransportKeys rotated = createTransportKeys(1000, 0); Transaction txn = new Transaction(null, false); context.checking(new Expectations() {{ - oneOf(crypto).deriveTransportKeys(transportId, masterKey, 999, - alice); + oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, + 999, alice); will(returnValue(transportKeys)); // Get the current time (1 ms after start of rotation period 1000) oneOf(clock).currentTimeMillis(); will(returnValue(rotationPeriodLength * 1000 + 1)); // Rotate the transport keys - oneOf(crypto).rotateTransportKeys(transportKeys, 1000); + oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); will(returnValue(rotated)); // Encode the tags (3 sets) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { - exactly(3).of(crypto).encodeTag(with(any(byte[].class)), - with(tagKey), with(PROTOCOL_VERSION), with(i)); + exactly(3).of(transportCrypto).encodeTag( + with(any(byte[].class)), with(tagKey), + with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Save the keys oneOf(db).addTransportKeys(txn, contactId, rotated); }}); - TransportKeyManager - transportKeyManager = new TransportKeyManagerImpl(db, - crypto, dbExecutor, scheduler, clock, transportId, maxLatency); + TransportKeyManager transportKeyManager = new TransportKeyManagerImpl( + db, transportCrypto, dbExecutor, scheduler, clock, transportId, + maxLatency); // The timestamp is 1 ms before the start of rotation period 1000 long timestamp = rotationPeriodLength * 1000 - 1; transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice); - - context.assertIsSatisfied(); } @Test public void testOutgoingStreamContextIsNullIfContactIsNotFound() throws Exception { - Mockery context = new Mockery(); - DatabaseComponent db = context.mock(DatabaseComponent.class); - CryptoComponent crypto = context.mock(CryptoComponent.class); - Executor dbExecutor = context.mock(Executor.class); - ScheduledExecutorService scheduler = - context.mock(ScheduledExecutorService.class); - Clock clock = context.mock(Clock.class); - Transaction txn = new Transaction(null, false); - TransportKeyManager - transportKeyManager = new TransportKeyManagerImpl(db, - crypto, dbExecutor, scheduler, clock, transportId, maxLatency); + TransportKeyManager transportKeyManager = new TransportKeyManagerImpl( + db, transportCrypto, dbExecutor, scheduler, clock, transportId, + maxLatency); assertNull(transportKeyManager.getStreamContext(txn, contactId)); - - context.assertIsSatisfied(); } @Test public void testOutgoingStreamContextIsNullIfStreamCounterIsExhausted() throws Exception { - Mockery context = new Mockery(); - DatabaseComponent db = context.mock(DatabaseComponent.class); - CryptoComponent crypto = context.mock(CryptoComponent.class); - Executor dbExecutor = context.mock(Executor.class); - ScheduledExecutorService scheduler = - context.mock(ScheduledExecutorService.class); - Clock clock = context.mock(Clock.class); - - boolean alice = true; + boolean alice = random.nextBoolean(); // The stream counter has been exhausted TransportKeys transportKeys = createTransportKeys(1000, MAX_32_BIT_UNSIGNED + 1); Transaction txn = new Transaction(null, false); context.checking(new Expectations() {{ - oneOf(crypto).deriveTransportKeys(transportId, masterKey, 1000, - alice); + oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, + 1000, alice); will(returnValue(transportKeys)); // Get the current time (the start of rotation period 1000) oneOf(clock).currentTimeMillis(); will(returnValue(rotationPeriodLength * 1000)); // Encode the tags (3 sets) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { - exactly(3).of(crypto).encodeTag(with(any(byte[].class)), - with(tagKey), with(PROTOCOL_VERSION), with(i)); + exactly(3).of(transportCrypto).encodeTag( + with(any(byte[].class)), with(tagKey), + with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Rotate the transport keys (the keys are unaffected) - oneOf(crypto).rotateTransportKeys(transportKeys, 1000); + oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); will(returnValue(transportKeys)); // Save the keys oneOf(db).addTransportKeys(txn, contactId, transportKeys); }}); - TransportKeyManager - transportKeyManager = new TransportKeyManagerImpl(db, - crypto, dbExecutor, scheduler, clock, transportId, maxLatency); + TransportKeyManager transportKeyManager = new TransportKeyManagerImpl( + db, transportCrypto, dbExecutor, scheduler, clock, transportId, + maxLatency); // The timestamp is at the start of rotation period 1000 long timestamp = rotationPeriodLength * 1000; transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice); assertNull(transportKeyManager.getStreamContext(txn, contactId)); - - context.assertIsSatisfied(); } @Test public void testOutgoingStreamCounterIsIncremented() throws Exception { - Mockery context = new Mockery(); - DatabaseComponent db = context.mock(DatabaseComponent.class); - CryptoComponent crypto = context.mock(CryptoComponent.class); - Executor dbExecutor = context.mock(Executor.class); - ScheduledExecutorService scheduler = - context.mock(ScheduledExecutorService.class); - Clock clock = context.mock(Clock.class); - - boolean alice = true; + boolean alice = random.nextBoolean(); // The stream counter can be used one more time before being exhausted TransportKeys transportKeys = createTransportKeys(1000, MAX_32_BIT_UNSIGNED); Transaction txn = new Transaction(null, false); context.checking(new Expectations() {{ - oneOf(crypto).deriveTransportKeys(transportId, masterKey, 1000, - alice); + oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, + 1000, alice); will(returnValue(transportKeys)); // Get the current time (the start of rotation period 1000) oneOf(clock).currentTimeMillis(); will(returnValue(rotationPeriodLength * 1000)); // Encode the tags (3 sets) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { - exactly(3).of(crypto).encodeTag(with(any(byte[].class)), - with(tagKey), with(PROTOCOL_VERSION), with(i)); + exactly(3).of(transportCrypto).encodeTag( + with(any(byte[].class)), with(tagKey), + with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Rotate the transport keys (the keys are unaffected) - oneOf(crypto).rotateTransportKeys(transportKeys, 1000); + oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); will(returnValue(transportKeys)); // Save the keys oneOf(db).addTransportKeys(txn, contactId, transportKeys); @@ -259,9 +222,9 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { oneOf(db).incrementStreamCounter(txn, contactId, transportId, 1000); }}); - TransportKeyManager - transportKeyManager = new TransportKeyManagerImpl(db, - crypto, dbExecutor, scheduler, clock, transportId, maxLatency); + TransportKeyManager transportKeyManager = new TransportKeyManagerImpl( + db, transportCrypto, dbExecutor, scheduler, clock, transportId, + maxLatency); // The timestamp is at the start of rotation period 1000 long timestamp = rotationPeriodLength * 1000; transportKeyManager.addContact(txn, contactId, masterKey, timestamp, @@ -277,94 +240,76 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { assertEquals(MAX_32_BIT_UNSIGNED, ctx.getStreamNumber()); // The second request should return null, the counter is exhausted assertNull(transportKeyManager.getStreamContext(txn, contactId)); - - context.assertIsSatisfied(); } @Test public void testIncomingStreamContextIsNullIfTagIsNotFound() throws Exception { - Mockery context = new Mockery(); - DatabaseComponent db = context.mock(DatabaseComponent.class); - CryptoComponent crypto = context.mock(CryptoComponent.class); - Executor dbExecutor = context.mock(Executor.class); - ScheduledExecutorService scheduler = - context.mock(ScheduledExecutorService.class); - Clock clock = context.mock(Clock.class); - - boolean alice = true; + boolean alice = random.nextBoolean(); TransportKeys transportKeys = createTransportKeys(1000, 0); Transaction txn = new Transaction(null, false); context.checking(new Expectations() {{ - oneOf(crypto).deriveTransportKeys(transportId, masterKey, 1000, - alice); + oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, + 1000, alice); will(returnValue(transportKeys)); // Get the current time (the start of rotation period 1000) oneOf(clock).currentTimeMillis(); will(returnValue(rotationPeriodLength * 1000)); // Encode the tags (3 sets) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { - exactly(3).of(crypto).encodeTag(with(any(byte[].class)), - with(tagKey), with(PROTOCOL_VERSION), with(i)); + exactly(3).of(transportCrypto).encodeTag( + with(any(byte[].class)), with(tagKey), + with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Rotate the transport keys (the keys are unaffected) - oneOf(crypto).rotateTransportKeys(transportKeys, 1000); + oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); will(returnValue(transportKeys)); // Save the keys oneOf(db).addTransportKeys(txn, contactId, transportKeys); }}); - TransportKeyManager - transportKeyManager = new TransportKeyManagerImpl(db, - crypto, dbExecutor, scheduler, clock, transportId, maxLatency); + TransportKeyManager transportKeyManager = new TransportKeyManagerImpl( + db, transportCrypto, dbExecutor, scheduler, clock, transportId, + maxLatency); // The timestamp is at the start of rotation period 1000 long timestamp = rotationPeriodLength * 1000; transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice); assertNull(transportKeyManager.getStreamContext(txn, new byte[TAG_LENGTH])); - - context.assertIsSatisfied(); } @Test public void testTagIsNotRecognisedTwice() throws Exception { - Mockery context = new Mockery(); - DatabaseComponent db = context.mock(DatabaseComponent.class); - CryptoComponent crypto = context.mock(CryptoComponent.class); - Executor dbExecutor = context.mock(Executor.class); - ScheduledExecutorService scheduler = - context.mock(ScheduledExecutorService.class); - Clock clock = context.mock(Clock.class); - - boolean alice = true; + boolean alice = random.nextBoolean(); TransportKeys transportKeys = createTransportKeys(1000, 0); // Keep a copy of the tags List<byte[]> tags = new ArrayList<>(); Transaction txn = new Transaction(null, false); context.checking(new Expectations() {{ - oneOf(crypto).deriveTransportKeys(transportId, masterKey, 1000, - alice); + oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, + 1000, alice); will(returnValue(transportKeys)); // Get the current time (the start of rotation period 1000) oneOf(clock).currentTimeMillis(); will(returnValue(rotationPeriodLength * 1000)); // Encode the tags (3 sets) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { - exactly(3).of(crypto).encodeTag(with(any(byte[].class)), - with(tagKey), with(PROTOCOL_VERSION), with(i)); + exactly(3).of(transportCrypto).encodeTag( + with(any(byte[].class)), with(tagKey), + with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction(tags)); } // Rotate the transport keys (the keys are unaffected) - oneOf(crypto).rotateTransportKeys(transportKeys, 1000); + oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); will(returnValue(transportKeys)); // Save the keys oneOf(db).addTransportKeys(txn, contactId, transportKeys); // Encode a new tag after sliding the window - oneOf(crypto).encodeTag(with(any(byte[].class)), + oneOf(transportCrypto).encodeTag(with(any(byte[].class)), with(tagKey), with(PROTOCOL_VERSION), with((long) REORDERING_WINDOW_SIZE)); will(new EncodeTagAction(tags)); @@ -373,9 +318,9 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { 1, new byte[REORDERING_WINDOW_SIZE / 8]); }}); - TransportKeyManager - transportKeyManager = new TransportKeyManagerImpl(db, - crypto, dbExecutor, scheduler, clock, transportId, maxLatency); + TransportKeyManager transportKeyManager = new TransportKeyManagerImpl( + db, transportCrypto, dbExecutor, scheduler, clock, transportId, + maxLatency); // The timestamp is at the start of rotation period 1000 long timestamp = rotationPeriodLength * 1000; transportKeyManager.addContact(txn, contactId, masterKey, timestamp, @@ -395,20 +340,10 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { assertEquals(REORDERING_WINDOW_SIZE * 3 + 1, tags.size()); // The second request should return null, the tag has already been used assertNull(transportKeyManager.getStreamContext(txn, tag)); - - context.assertIsSatisfied(); } @Test public void testKeysAreRotatedToCurrentPeriod() throws Exception { - Mockery context = new Mockery(); - DatabaseComponent db = context.mock(DatabaseComponent.class); - CryptoComponent crypto = context.mock(CryptoComponent.class); - Executor dbExecutor = context.mock(Executor.class); - ScheduledExecutorService scheduler = - context.mock(ScheduledExecutorService.class); - Clock clock = context.mock(Clock.class); - TransportKeys transportKeys = createTransportKeys(1000, 0); Map<ContactId, TransportKeys> loaded = Collections.singletonMap(contactId, transportKeys); @@ -424,12 +359,13 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { oneOf(db).getTransportKeys(txn, transportId); will(returnValue(loaded)); // Rotate the transport keys (the keys are unaffected) - oneOf(crypto).rotateTransportKeys(transportKeys, 1000); + oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); will(returnValue(transportKeys)); // Encode the tags (3 sets) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { - exactly(3).of(crypto).encodeTag(with(any(byte[].class)), - with(tagKey), with(PROTOCOL_VERSION), with(i)); + exactly(3).of(transportCrypto).encodeTag( + with(any(byte[].class)), with(tagKey), + with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Schedule key rotation at the start of the next rotation period @@ -445,13 +381,14 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(rotationPeriodLength * 1001)); // Rotate the transport keys - oneOf(crypto).rotateTransportKeys(with(any(TransportKeys.class)), - with(1001L)); + oneOf(transportCrypto).rotateTransportKeys( + with(any(TransportKeys.class)), with(1001L)); will(returnValue(rotated)); // Encode the tags (3 sets) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { - exactly(3).of(crypto).encodeTag(with(any(byte[].class)), - with(tagKey), with(PROTOCOL_VERSION), with(i)); + exactly(3).of(transportCrypto).encodeTag( + with(any(byte[].class)), with(tagKey), + with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Save the keys that were rotated @@ -465,12 +402,10 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { oneOf(db).endTransaction(txn1); }}); - TransportKeyManager - transportKeyManager = new TransportKeyManagerImpl(db, - crypto, dbExecutor, scheduler, clock, transportId, maxLatency); + TransportKeyManager transportKeyManager = new TransportKeyManagerImpl( + db, transportCrypto, dbExecutor, scheduler, clock, transportId, + maxLatency); transportKeyManager.start(txn); - - context.assertIsSatisfied(); } private TransportKeys createTransportKeys(long rotationPeriod,