Factor out transport crypto from CryptoComponent.

This commit is contained in:
akwizgran
2017-11-27 16:24:58 +00:00
parent 9f7021acd3
commit 1843aea2a7
12 changed files with 356 additions and 377 deletions

View File

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

View File

@@ -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 CryptoComponent crypto = context.mock(CryptoComponent.class);
private final TransportCrypto transportCrypto =
new TransportCryptoImpl(crypto);
private final SecretKey tagKey = getSecretKey();
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<>();
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)));
}
}

View File

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

View File

@@ -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,