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 c6cd78c4cb8f36b0fc834cd6634b26d768351da3..3d610c8506d2195e68788f97574f061c05ddb6c1 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 @@ -137,7 +137,8 @@ public interface CryptoComponent { TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod); /** Encodes the pseudo-random tag that is used to recognise a stream. */ - void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber); + void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion, + long streamNumber); /** * Signs the given byte[] with the given PrivateKey. diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportConstants.java index 5bd47f0a0ac83a0e97069d78b9c8fb135b13246c..af9d09731dcb40aa8549797a7573037161f0d3c5 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportConstants.java @@ -4,6 +4,11 @@ import org.briarproject.bramble.api.crypto.SecretKey; public interface TransportConstants { + /** + * The current version of the transport protocol. + */ + int PROTOCOL_VERSION = 3; + /** * The length of the pseudo-random tag in bytes. */ @@ -15,20 +20,21 @@ public interface TransportConstants { int STREAM_HEADER_NONCE_LENGTH = 24; /** - * The length of the stream header initialisation vector (IV) in bytes. + * The length of the message authentication code (MAC) in bytes. */ - int STREAM_HEADER_IV_LENGTH = STREAM_HEADER_NONCE_LENGTH - 8; + int MAC_LENGTH = 16; /** - * The length of the message authentication code (MAC) in bytes. + * The length of the stream header plaintext in bytes. The stream header + * contains the protocol version, stream number and frame key. */ - int MAC_LENGTH = 16; + int STREAM_HEADER_PLAINTEXT_LENGTH = 2 + 8 + SecretKey.LENGTH; /** * The length of the stream header in bytes. */ - int STREAM_HEADER_LENGTH = STREAM_HEADER_IV_LENGTH + SecretKey.LENGTH - + MAC_LENGTH; + int STREAM_HEADER_LENGTH = STREAM_HEADER_NONCE_LENGTH + + STREAM_HEADER_PLAINTEXT_LENGTH + MAC_LENGTH; /** * The length of the frame nonce in bytes. 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 197ef79738c379d56185f09361997554746b708f..f0c26edd9ef9e59915e68cb71d5524dad7c5a1c0 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 @@ -45,8 +45,10 @@ import static org.briarproject.bramble.api.invitation.InvitationConstants.CODE_B 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 { @@ -412,8 +414,11 @@ class CryptoComponentImpl implements CryptoComponent { } @Override - public void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber) { + 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 @@ -421,10 +426,14 @@ class CryptoComponentImpl implements CryptoComponent { // 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 stream number as a 64-bit integer - byte[] input = new byte[INT_64_BYTES]; - ByteUtils.writeUint64(streamNumber, input, 0); - prf.update(input, 0, input.length); + // 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 diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamDecrypterImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamDecrypterImpl.java index 22c522d3d5c5cbd4a2525b70d0fdeab6bf207864..16edc2c740946e421f04e8d5d8059491fb70746b 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamDecrypterImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamDecrypterImpl.java @@ -20,9 +20,11 @@ import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NO import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH; -import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH; +import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION; import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH; +import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH; +import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES; @NotThreadSafe @@ -117,7 +119,7 @@ class StreamDecrypterImpl implements StreamDecrypter { private void readStreamHeader() throws IOException { byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH]; - byte[] streamHeaderPlaintext = new byte[SecretKey.LENGTH]; + byte[] streamHeaderPlaintext = new byte[STREAM_HEADER_PLAINTEXT_LENGTH]; // Read the stream header int offset = 0; while (offset < STREAM_HEADER_LENGTH) { @@ -126,21 +128,35 @@ class StreamDecrypterImpl implements StreamDecrypter { if (read == -1) throw new EOFException(); offset += read; } - // The nonce consists of the stream number followed by the IV + // Extract the nonce byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH]; - ByteUtils.writeUint64(streamNumber, streamHeaderNonce, 0); - System.arraycopy(streamHeaderCiphertext, 0, streamHeaderNonce, - INT_64_BYTES, STREAM_HEADER_IV_LENGTH); + System.arraycopy(streamHeaderCiphertext, 0, streamHeaderNonce, 0, + STREAM_HEADER_NONCE_LENGTH); // Decrypt and authenticate the stream header try { cipher.init(false, streamHeaderKey, streamHeaderNonce); int decrypted = cipher.process(streamHeaderCiphertext, - STREAM_HEADER_IV_LENGTH, SecretKey.LENGTH + MAC_LENGTH, + STREAM_HEADER_NONCE_LENGTH, + STREAM_HEADER_PLAINTEXT_LENGTH + MAC_LENGTH, streamHeaderPlaintext, 0); - if (decrypted != SecretKey.LENGTH) throw new RuntimeException(); + if (decrypted != STREAM_HEADER_PLAINTEXT_LENGTH) + throw new RuntimeException(); } catch (GeneralSecurityException e) { throw new FormatException(); } - frameKey = new SecretKey(streamHeaderPlaintext); + // Check the protocol version + int receivedProtocolVersion = + ByteUtils.readUint16(streamHeaderPlaintext, 0); + if (receivedProtocolVersion != PROTOCOL_VERSION) + throw new FormatException(); + // Check the stream number + long receivedStreamNumber = ByteUtils.readUint64(streamHeaderPlaintext, + INT_16_BYTES); + if (receivedStreamNumber != streamNumber) throw new FormatException(); + // Extract the frame key + byte[] frameKeyBytes = new byte[SecretKey.LENGTH]; + System.arraycopy(streamHeaderPlaintext, INT_16_BYTES + INT_64_BYTES, + frameKeyBytes, 0, SecretKey.LENGTH); + frameKey = new SecretKey(frameKeyBytes); } } \ No newline at end of file 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 4feff3ece868bbeb8fbc98614447b47bde4381fd..be7f553de2d4fc2284496069dada1d0dea657267 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 @@ -13,7 +13,8 @@ import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import javax.inject.Provider; -import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH; +import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION; +import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; @Immutable @@ -36,22 +37,22 @@ class StreamEncrypterFactoryImpl implements StreamEncrypterFactory { AuthenticatedCipher cipher = cipherProvider.get(); long streamNumber = ctx.getStreamNumber(); byte[] tag = new byte[TAG_LENGTH]; - crypto.encodeTag(tag, ctx.getTagKey(), streamNumber); - byte[] streamHeaderIv = new byte[STREAM_HEADER_IV_LENGTH]; - crypto.getSecureRandom().nextBytes(streamHeaderIv); + crypto.encodeTag(tag, ctx.getTagKey(), PROTOCOL_VERSION, streamNumber); + byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH]; + crypto.getSecureRandom().nextBytes(streamHeaderNonce); SecretKey frameKey = crypto.generateSecretKey(); return new StreamEncrypterImpl(out, cipher, streamNumber, tag, - streamHeaderIv, ctx.getHeaderKey(), frameKey); + streamHeaderNonce, ctx.getHeaderKey(), frameKey); } @Override public StreamEncrypter createInvitationStreamEncrypter(OutputStream out, SecretKey headerKey) { AuthenticatedCipher cipher = cipherProvider.get(); - byte[] streamHeaderIv = new byte[STREAM_HEADER_IV_LENGTH]; - crypto.getSecureRandom().nextBytes(streamHeaderIv); + byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH]; + crypto.getSecureRandom().nextBytes(streamHeaderNonce); SecretKey frameKey = crypto.generateSecretKey(); - return new StreamEncrypterImpl(out, cipher, 0, null, streamHeaderIv, + return new StreamEncrypterImpl(out, cipher, 0, null, streamHeaderNonce, headerKey, frameKey); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamEncrypterImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamEncrypterImpl.java index 59afd8531f6f3cdc011b2da46d5d6994dbb0bcd2..d64cc4aae85d34ac242c0a264b17d106b9393416 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamEncrypterImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamEncrypterImpl.java @@ -18,9 +18,11 @@ import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NO import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH; -import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH; +import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION; import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH; +import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH; +import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES; @NotThreadSafe @@ -33,7 +35,7 @@ class StreamEncrypterImpl implements StreamEncrypter { private final long streamNumber; @Nullable private final byte[] tag; - private final byte[] streamHeaderIv; + private final byte[] streamHeaderNonce; private final byte[] frameNonce, frameHeader; private final byte[] framePlaintext, frameCiphertext; @@ -41,13 +43,13 @@ class StreamEncrypterImpl implements StreamEncrypter { private boolean writeTag, writeStreamHeader; StreamEncrypterImpl(OutputStream out, AuthenticatedCipher cipher, - long streamNumber, @Nullable byte[] tag, byte[] streamHeaderIv, + long streamNumber, @Nullable byte[] tag, byte[] streamHeaderNonce, SecretKey streamHeaderKey, SecretKey frameKey) { this.out = out; this.cipher = cipher; this.streamNumber = streamNumber; this.tag = tag; - this.streamHeaderIv = streamHeaderIv; + this.streamHeaderNonce = streamHeaderNonce; this.streamHeaderKey = streamHeaderKey; this.frameKey = frameKey; frameNonce = new byte[FRAME_NONCE_LENGTH]; @@ -114,22 +116,23 @@ class StreamEncrypterImpl implements StreamEncrypter { } private void writeStreamHeader() throws IOException { - // The nonce consists of the stream number followed by the IV - byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH]; - ByteUtils.writeUint64(streamNumber, streamHeaderNonce, 0); - System.arraycopy(streamHeaderIv, 0, streamHeaderNonce, INT_64_BYTES, - STREAM_HEADER_IV_LENGTH); - byte[] streamHeaderPlaintext = frameKey.getBytes(); + // The header contains the protocol version, stream number and frame key + byte[] streamHeaderPlaintext = new byte[STREAM_HEADER_PLAINTEXT_LENGTH]; + ByteUtils.writeUint16(PROTOCOL_VERSION, streamHeaderPlaintext, 0); + ByteUtils.writeUint64(streamNumber, streamHeaderPlaintext, + INT_16_BYTES); + System.arraycopy(frameKey.getBytes(), 0, streamHeaderPlaintext, + INT_16_BYTES + INT_64_BYTES, SecretKey.LENGTH); byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH]; - System.arraycopy(streamHeaderIv, 0, streamHeaderCiphertext, 0, - STREAM_HEADER_IV_LENGTH); - // Encrypt and authenticate the frame key + System.arraycopy(this.streamHeaderNonce, 0, streamHeaderCiphertext, 0, + STREAM_HEADER_NONCE_LENGTH); + // Encrypt and authenticate the stream header key try { cipher.init(true, streamHeaderKey, streamHeaderNonce); int encrypted = cipher.process(streamHeaderPlaintext, 0, - SecretKey.LENGTH, streamHeaderCiphertext, - STREAM_HEADER_IV_LENGTH); - if (encrypted != SecretKey.LENGTH + MAC_LENGTH) + STREAM_HEADER_PLAINTEXT_LENGTH, streamHeaderCiphertext, + STREAM_HEADER_NONCE_LENGTH); + if (encrypted != STREAM_HEADER_PLAINTEXT_LENGTH + MAC_LENGTH) throw new RuntimeException(); } catch (GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); 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 9c1582425c8bf89b2d0cc5171322578ecc4133f4..86c50d5fcc275a24b993184d2bd5c5f540026649 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 @@ -29,6 +29,7 @@ import javax.annotation.concurrent.ThreadSafe; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.logging.Level.WARNING; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; +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.util.ByteUtils.MAX_32_BIT_UNSIGNED; @@ -126,7 +127,8 @@ 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(), streamNumber); + crypto.encodeTag(tag, inKeys.getTagKey(),PROTOCOL_VERSION, + streamNumber); inContexts.put(new Bytes(tag), tagCtx); } } @@ -242,7 +244,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(), streamNumber); + crypto.encodeTag(addTag, inKeys.getTagKey(), PROTOCOL_VERSION, + streamNumber); inContexts.put(new Bytes(addTag), new TagContext( tagCtx.contactId, inKeys, streamNumber)); } @@ -250,7 +253,8 @@ 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(), streamNumber); + crypto.encodeTag(removeTag, inKeys.getTagKey(), + PROTOCOL_VERSION, streamNumber); inContexts.remove(new Bytes(removeTag)); } // Write the window back to the DB diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/StreamDecrypterImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/StreamDecrypterImplTest.java index 0a6a5f4c0ede9658a15fb50b1bbdf82c3d79e039..e5ea2d31dfdecdb5a6db9739e04399710a961f76 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/crypto/StreamDecrypterImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/StreamDecrypterImplTest.java @@ -14,7 +14,8 @@ import static junit.framework.Assert.assertEquals; import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH; -import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH; +import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION; +import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH; import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES; import static org.junit.Assert.assertArrayEquals; @@ -22,7 +23,8 @@ public class StreamDecrypterImplTest extends BrambleTestCase { private final AuthenticatedCipher cipher; private final SecretKey streamHeaderKey, frameKey; - private final byte[] streamHeaderIv, payload; + private final byte[] streamHeaderNonce, protocolVersionBytes; + private final byte[] streamNumberBytes, payload; private final int payloadLength = 123, paddingLength = 234; private final long streamNumber = 1234; @@ -30,7 +32,12 @@ public class StreamDecrypterImplTest extends BrambleTestCase { cipher = new TestAuthenticatedCipher(); // Null cipher streamHeaderKey = TestUtils.getSecretKey(); frameKey = TestUtils.getSecretKey(); - streamHeaderIv = TestUtils.getRandomBytes(STREAM_HEADER_IV_LENGTH); + streamHeaderNonce = + TestUtils.getRandomBytes(STREAM_HEADER_NONCE_LENGTH); + protocolVersionBytes = new byte[2]; + ByteUtils.writeUint16(PROTOCOL_VERSION, protocolVersionBytes, 0); + streamNumberBytes = new byte[8]; + ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0); payload = TestUtils.getRandomBytes(payloadLength); } @@ -47,7 +54,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase { byte[] payload1 = TestUtils.getRandomBytes(payloadLength1); ByteArrayOutputStream out = new ByteArrayOutputStream(); - out.write(streamHeaderIv); + out.write(streamHeaderNonce); + out.write(protocolVersionBytes); + out.write(streamNumberBytes); out.write(frameKey.getBytes()); out.write(new byte[MAC_LENGTH]); out.write(frameHeader); @@ -76,6 +85,85 @@ public class StreamDecrypterImplTest extends BrambleTestCase { assertEquals(-1, s.readFrame(buffer)); } + @Test(expected = IOException.class) + public void testWrongProtocolVersionThrowsException() throws Exception { + byte[] wrongProtocolVersionBytes = new byte[2]; + ByteUtils.writeUint16(PROTOCOL_VERSION + 1, wrongProtocolVersionBytes, + 0); + + byte[] frameHeader = new byte[FRAME_HEADER_LENGTH]; + FrameEncoder.encodeHeader(frameHeader, false, payloadLength, + paddingLength); + + byte[] frameHeader1 = new byte[FRAME_HEADER_LENGTH]; + int payloadLength1 = 345, paddingLength1 = 456; + FrameEncoder.encodeHeader(frameHeader1, true, payloadLength1, + paddingLength1); + byte[] payload1 = TestUtils.getRandomBytes(payloadLength1); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(streamHeaderNonce); + out.write(wrongProtocolVersionBytes); + out.write(streamNumberBytes); + out.write(frameKey.getBytes()); + out.write(new byte[MAC_LENGTH]); + out.write(frameHeader); + out.write(payload); + out.write(new byte[paddingLength]); + out.write(new byte[MAC_LENGTH]); + out.write(frameHeader1); + out.write(payload1); + out.write(new byte[paddingLength1]); + out.write(new byte[MAC_LENGTH]); + + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + StreamDecrypterImpl s = new StreamDecrypterImpl(in, cipher, + streamNumber, streamHeaderKey); + + // Try to read the first frame + byte[] buffer = new byte[MAX_PAYLOAD_LENGTH]; + s.readFrame(buffer); + } + + @Test(expected = IOException.class) + public void testWrongStreamNumberThrowsException() throws Exception { + byte[] wrongStreamNumberBytes = new byte[8]; + ByteUtils.writeUint64(streamNumber + 1, wrongStreamNumberBytes, 0); + + byte[] frameHeader = new byte[FRAME_HEADER_LENGTH]; + FrameEncoder.encodeHeader(frameHeader, false, payloadLength, + paddingLength); + + byte[] frameHeader1 = new byte[FRAME_HEADER_LENGTH]; + int payloadLength1 = 345, paddingLength1 = 456; + FrameEncoder.encodeHeader(frameHeader1, true, payloadLength1, + paddingLength1); + byte[] payload1 = TestUtils.getRandomBytes(payloadLength1); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(streamHeaderNonce); + out.write(protocolVersionBytes); + out.write(wrongStreamNumberBytes); + out.write(frameKey.getBytes()); + out.write(new byte[MAC_LENGTH]); + out.write(frameHeader); + out.write(payload); + out.write(new byte[paddingLength]); + out.write(new byte[MAC_LENGTH]); + out.write(frameHeader1); + out.write(payload1); + out.write(new byte[paddingLength1]); + out.write(new byte[MAC_LENGTH]); + + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + StreamDecrypterImpl s = new StreamDecrypterImpl(in, cipher, + streamNumber, streamHeaderKey); + + // Try to read the first frame + byte[] buffer = new byte[MAX_PAYLOAD_LENGTH]; + s.readFrame(buffer); + } + @Test(expected = IOException.class) public void testTruncatedFrameThrowsException() throws Exception { byte[] frameHeader = new byte[FRAME_HEADER_LENGTH]; @@ -83,7 +171,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase { paddingLength); ByteArrayOutputStream out = new ByteArrayOutputStream(); - out.write(streamHeaderIv); + out.write(streamHeaderNonce); + out.write(protocolVersionBytes); + out.write(streamNumberBytes); out.write(frameKey.getBytes()); out.write(new byte[MAC_LENGTH]); out.write(frameHeader); @@ -111,7 +201,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase { byte[] payload = TestUtils.getRandomBytes(payloadLength); ByteArrayOutputStream out = new ByteArrayOutputStream(); - out.write(streamHeaderIv); + out.write(streamHeaderNonce); + out.write(protocolVersionBytes); + out.write(streamNumberBytes); out.write(frameKey.getBytes()); out.write(new byte[MAC_LENGTH]); out.write(frameHeader); @@ -138,7 +230,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase { padding[paddingLength - 1] = 1; ByteArrayOutputStream out = new ByteArrayOutputStream(); - out.write(streamHeaderIv); + out.write(streamHeaderNonce); + out.write(protocolVersionBytes); + out.write(streamNumberBytes); out.write(frameKey.getBytes()); out.write(new byte[MAC_LENGTH]); out.write(frameHeader); @@ -162,7 +256,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase { paddingLength); ByteArrayOutputStream out = new ByteArrayOutputStream(); - out.write(streamHeaderIv); + out.write(streamHeaderNonce); + out.write(protocolVersionBytes); + out.write(streamNumberBytes); out.write(frameKey.getBytes()); out.write(new byte[MAC_LENGTH]); out.write(frameHeader); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/StreamEncrypterImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/StreamEncrypterImplTest.java index c13749f684170dcc55593cb616fc23f5e9331938..c720805bd22c72278d2f2e8432d1cbdaa566edbe 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/crypto/StreamEncrypterImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/StreamEncrypterImplTest.java @@ -3,6 +3,7 @@ package org.briarproject.bramble.crypto; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.TestUtils; +import org.briarproject.bramble.util.ByteUtils; import org.junit.Test; import java.io.ByteArrayOutputStream; @@ -11,8 +12,9 @@ import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HE import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH; -import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH; +import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION; import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH; +import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -21,7 +23,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase { private final AuthenticatedCipher cipher; private final SecretKey streamHeaderKey, frameKey; - private final byte[] tag, streamHeaderIv, payload; + private final byte[] tag, streamHeaderNonce, protocolVersionBytes; + private final byte[] streamNumberBytes, payload; private final long streamNumber = 1234; private final int payloadLength = 123, paddingLength = 234; @@ -30,7 +33,12 @@ public class StreamEncrypterImplTest extends BrambleTestCase { streamHeaderKey = TestUtils.getSecretKey(); frameKey = TestUtils.getSecretKey(); tag = TestUtils.getRandomBytes(TAG_LENGTH); - streamHeaderIv = TestUtils.getRandomBytes(STREAM_HEADER_IV_LENGTH); + streamHeaderNonce = + TestUtils.getRandomBytes(STREAM_HEADER_NONCE_LENGTH); + protocolVersionBytes = new byte[2]; + ByteUtils.writeUint16(PROTOCOL_VERSION, protocolVersionBytes, 0); + streamNumberBytes = new byte[8]; + ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0); payload = TestUtils.getRandomBytes(payloadLength); } @@ -38,7 +46,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testRejectsNegativePayloadLength() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, tag, streamHeaderNonce, streamHeaderKey, + frameKey); s.writeFrame(payload, -1, 0, false); } @@ -47,7 +56,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testRejectsNegativePaddingLength() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, tag, streamHeaderNonce, streamHeaderKey, + frameKey); s.writeFrame(payload, 0, -1, false); } @@ -56,7 +66,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testRejectsMaxPayloadPlusPadding() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, tag, streamHeaderNonce, streamHeaderKey, + frameKey); byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH + 1]; s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH, 1, false); @@ -66,7 +77,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testAcceptsMaxPayloadIncludingPadding() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, tag, streamHeaderNonce, streamHeaderKey, + frameKey); byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH]; s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH - 1, 1, false); @@ -78,7 +90,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testAcceptsMaxPayloadWithoutPadding() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, tag, streamHeaderNonce, streamHeaderKey, + frameKey); byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH]; s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH, 0, false); @@ -90,14 +103,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testWriteUnpaddedNonFinalFrameWithTag() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, tag, streamHeaderNonce, streamHeaderKey, + frameKey); s.writeFrame(payload, payloadLength, 0, false); // Expect the tag, stream header, frame header, payload and MAC ByteArrayOutputStream expected = new ByteArrayOutputStream(); expected.write(tag); - expected.write(streamHeaderIv); + expected.write(streamHeaderNonce); + expected.write(protocolVersionBytes); + expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH]; @@ -113,14 +129,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testWriteUnpaddedFinalFrameWithTag() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, tag, streamHeaderNonce, streamHeaderKey, + frameKey); s.writeFrame(payload, payloadLength, 0, true); // Expect the tag, stream header, frame header, payload and MAC ByteArrayOutputStream expected = new ByteArrayOutputStream(); expected.write(tag); - expected.write(streamHeaderIv); + expected.write(streamHeaderNonce); + expected.write(protocolVersionBytes); + expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH]; @@ -136,13 +155,16 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testWriteUnpaddedNonFinalFrameWithoutTag() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, null, streamHeaderNonce, streamHeaderKey, + frameKey); s.writeFrame(payload, payloadLength, 0, false); // Expect the stream header, frame header, payload and MAC ByteArrayOutputStream expected = new ByteArrayOutputStream(); - expected.write(streamHeaderIv); + expected.write(streamHeaderNonce); + expected.write(protocolVersionBytes); + expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH]; @@ -158,13 +180,16 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testWriteUnpaddedFinalFrameWithoutTag() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, null, streamHeaderNonce, streamHeaderKey, + frameKey); s.writeFrame(payload, payloadLength, 0, true); // Expect the stream header, frame header, payload and MAC ByteArrayOutputStream expected = new ByteArrayOutputStream(); - expected.write(streamHeaderIv); + expected.write(streamHeaderNonce); + expected.write(protocolVersionBytes); + expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH]; @@ -180,14 +205,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testWritePaddedNonFinalFrameWithTag() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, tag, streamHeaderNonce, streamHeaderKey, + frameKey); s.writeFrame(payload, payloadLength, paddingLength, false); // Expect the tag, stream header, frame header, payload, padding and MAC ByteArrayOutputStream expected = new ByteArrayOutputStream(); expected.write(tag); - expected.write(streamHeaderIv); + expected.write(streamHeaderNonce); + expected.write(protocolVersionBytes); + expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH]; @@ -205,14 +233,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testWritePaddedFinalFrameWithTag() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, tag, streamHeaderNonce, streamHeaderKey, + frameKey); s.writeFrame(payload, payloadLength, paddingLength, true); // Expect the tag, stream header, frame header, payload, padding and MAC ByteArrayOutputStream expected = new ByteArrayOutputStream(); expected.write(tag); - expected.write(streamHeaderIv); + expected.write(streamHeaderNonce); + expected.write(protocolVersionBytes); + expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH]; @@ -230,13 +261,16 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testWritePaddedNonFinalFrameWithoutTag() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, null, streamHeaderNonce, streamHeaderKey, + frameKey); s.writeFrame(payload, payloadLength, paddingLength, false); // Expect the stream header, frame header, payload, padding and MAC ByteArrayOutputStream expected = new ByteArrayOutputStream(); - expected.write(streamHeaderIv); + expected.write(streamHeaderNonce); + expected.write(protocolVersionBytes); + expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH]; @@ -254,13 +288,16 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testWritePaddedFinalFrameWithoutTag() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, null, streamHeaderNonce, streamHeaderKey, + frameKey); s.writeFrame(payload, payloadLength, paddingLength, true); // Expect the stream header, frame header, payload, padding and MAC ByteArrayOutputStream expected = new ByteArrayOutputStream(); - expected.write(streamHeaderIv); + expected.write(streamHeaderNonce); + expected.write(protocolVersionBytes); + expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH]; @@ -278,7 +315,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testWriteTwoFramesWithTag() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, tag, streamHeaderNonce, streamHeaderKey, + frameKey); int payloadLength1 = 345, paddingLength1 = 456; byte[] payload1 = TestUtils.getRandomBytes(payloadLength1); @@ -289,7 +327,9 @@ public class StreamEncrypterImplTest extends BrambleTestCase { // MAC, second frame header, payload, padding, MAC ByteArrayOutputStream expected = new ByteArrayOutputStream(); expected.write(tag); - expected.write(streamHeaderIv); + expected.write(streamHeaderNonce); + expected.write(protocolVersionBytes); + expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH]; @@ -315,7 +355,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase { throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, tag, streamHeaderNonce, streamHeaderKey, + frameKey); // Flush the stream once s.flush(); @@ -323,7 +364,9 @@ public class StreamEncrypterImplTest extends BrambleTestCase { // Expect the tag and stream header ByteArrayOutputStream expected = new ByteArrayOutputStream(); expected.write(tag); - expected.write(streamHeaderIv); + expected.write(streamHeaderNonce); + expected.write(protocolVersionBytes); + expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); @@ -335,7 +378,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase { throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, tag, streamHeaderNonce, streamHeaderKey, + frameKey); // Flush the stream twice s.flush(); @@ -344,7 +388,9 @@ public class StreamEncrypterImplTest extends BrambleTestCase { // Expect the tag and stream header ByteArrayOutputStream expected = new ByteArrayOutputStream(); expected.write(tag); - expected.write(streamHeaderIv); + expected.write(streamHeaderNonce); + expected.write(protocolVersionBytes); + expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); @@ -355,14 +401,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase { public void testFlushDoesNotWriteTagIfNull() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, - streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey); + streamNumber, null, streamHeaderNonce, streamHeaderKey, + frameKey); // Flush the stream once s.flush(); // Expect the stream header ByteArrayOutputStream expected = new ByteArrayOutputStream(); - expected.write(streamHeaderIv); + expected.write(streamHeaderNonce); + expected.write(protocolVersionBytes); + expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); 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 new file mode 100644 index 0000000000000000000000000000000000000000..b10654e9f3d2c7b9d571b71d6634f9c0060dffe3 --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/TagEncodingTest.java @@ -0,0 +1,59 @@ +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.junit.Test; + +import java.util.HashSet; +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; + +public class TagEncodingTest extends BrambleTestCase { + + private final CryptoComponent crypto; + private final SecretKey tagKey; + private final long streamNumber = 1234567890; + + public TagEncodingTest() { + crypto = new CryptoComponentImpl(new TestSecureRandomProvider()); + tagKey = TestUtils.getSecretKey(); + } + + @Test + public void testKeyAffectsTag() throws Exception { + Set<Bytes> set = new HashSet<Bytes>(); + for (int i = 0; i < 100; i++) { + byte[] tag = new byte[TAG_LENGTH]; + SecretKey tagKey = TestUtils.getSecretKey(); + crypto.encodeTag(tag, tagKey, PROTOCOL_VERSION, streamNumber); + assertTrue(set.add(new Bytes(tag))); + } + } + + @Test + public void testProtocolVersionAffectsTag() throws Exception { + Set<Bytes> set = new HashSet<Bytes>(); + for (int i = 0; i < 100; i++) { + byte[] tag = new byte[TAG_LENGTH]; + crypto.encodeTag(tag, tagKey, PROTOCOL_VERSION + i, streamNumber); + assertTrue(set.add(new Bytes(tag))); + } + } + + @Test + public void testStreamNumberAffectsTag() throws Exception { + Set<Bytes> set = new HashSet<Bytes>(); + for (int i = 0; i < 100; i++) { + byte[] tag = new byte[TAG_LENGTH]; + crypto.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 533dfb2fab638178323b3dfe534b044a19daf663..c19d148b1eeccdb98157e3999c3353390efb8942 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 @@ -34,6 +34,7 @@ import java.util.Collection; import javax.inject.Inject; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH; +import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION; import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -115,7 +116,7 @@ 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, streamNumber); + crypto.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 5962afcf5269e1df0a41925b7de2586db0dedff3..b66f5c745493e42ccdaaa2fd491da2a80e1be1e6 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 @@ -33,6 +33,7 @@ import java.util.concurrent.ScheduledExecutorService; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; +import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION; import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE; import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED; @@ -86,7 +87,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { // 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(i)); + with(tagKey), with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Save the keys that were rotated @@ -133,7 +134,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { // 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(i)); + with(tagKey), with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Save the keys @@ -199,7 +200,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { // 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(i)); + with(tagKey), with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Rotate the transport keys (the keys are unaffected) @@ -247,7 +248,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { // 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(i)); + with(tagKey), with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Rotate the transport keys (the keys are unaffected) @@ -306,7 +307,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { // 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(i)); + with(tagKey), with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Rotate the transport keys (the keys are unaffected) @@ -355,7 +356,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { // 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(i)); + with(tagKey), with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction(tags)); } // Rotate the transport keys (the keys are unaffected) @@ -365,7 +366,8 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { oneOf(db).addTransportKeys(txn, contactId, transportKeys); // Encode a new tag after sliding the window oneOf(crypto).encodeTag(with(any(byte[].class)), - with(tagKey), with((long) REORDERING_WINDOW_SIZE)); + with(tagKey), with(PROTOCOL_VERSION), + with((long) REORDERING_WINDOW_SIZE)); will(new EncodeTagAction(tags)); // Save the reordering window (previous rotation period, base 1) oneOf(db).setReorderingWindow(txn, contactId, transportId, 999, @@ -428,7 +430,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { // 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(i)); + with(tagKey), with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Schedule key rotation at the start of the next rotation period @@ -450,7 +452,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase { // 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(i)); + with(tagKey), with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } // Save the keys that were rotated