From b568405f59ea883f0cef60c4a40e2c66bb7fa523 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 9 Apr 2019 14:48:45 +0100 Subject: [PATCH 01/19] Create DB tables for static keys. --- .../bramble/api/crypto/TransportCrypto.java | 10 +- .../bramble/api/db/DatabaseComponent.java | 4 +- .../bramble/api/transport/IncomingKeys.java | 16 +- .../bramble/api/transport/OutgoingKeys.java | 16 +- .../bramble/api/transport/TransportKeys.java | 10 +- .../bramble/crypto/TransportCryptoImpl.java | 35 ++--- .../org/briarproject/bramble/db/Database.java | 4 +- .../bramble/db/DatabaseComponentImpl.java | 4 +- .../briarproject/bramble/db/JdbcDatabase.java | 147 +++++++++++------- .../bramble/db/Migration40_41.java | 2 +- .../bramble/db/Migration41_42.java | 89 +++++++++++ .../transport/MutableIncomingKeys.java | 10 +- .../transport/MutableOutgoingKeys.java | 10 +- .../transport/TransportKeyManagerImpl.java | 30 ++-- .../bramble/crypto/KeyDerivationTest.java | 6 +- .../bramble/db/JdbcDatabaseTest.java | 41 +++-- .../TransportKeyManagerImplTest.java | 86 +++++----- 17 files changed, 324 insertions(+), 196 deletions(-) create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java index 666abffc6..b51dc972a 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java @@ -11,19 +11,19 @@ public interface TransportCrypto { /** * Derives initial transport keys for the given transport in the given - * rotation period from the given master secret. + * time period from the given master secret. * * @param alice whether the keys are for use by Alice or Bob. * @param active whether the keys are usable for outgoing streams. */ TransportKeys deriveTransportKeys(TransportId t, SecretKey master, - long rotationPeriod, boolean alice, boolean active); + long timePeriod, boolean alice, boolean active); /** - * Rotates the given transport keys to the given rotation period. If the - * keys are for the given period or any later period they are not rotated. + * Rotates the given transport keys to the given time period. If the keys + * are for the given period or any later period they are not rotated. */ - TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod); + TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod); /** * Encodes the pseudo-random tag that is used to recognise a stream. diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java index 9ec8b5c7b..d44398747 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java @@ -554,10 +554,10 @@ public interface DatabaseComponent { /** * Sets the reordering window for the given key set and transport in the - * given rotation period. + * given time period. */ void setReorderingWindow(Transaction txn, KeySetId k, TransportId t, - long rotationPeriod, long base, byte[] bitmap) throws DbException; + long timePeriod, long base, byte[] bitmap) throws DbException; /** * Marks the given transport keys as usable for outgoing streams. diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/IncomingKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/IncomingKeys.java index 1b7942512..46a17887e 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/IncomingKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/IncomingKeys.java @@ -9,27 +9,27 @@ import static org.briarproject.bramble.api.transport.TransportConstants.REORDERI /** * Contains transport keys for receiving streams from a given contact over a - * given transport in a given rotation period. + * given transport in a given time period. */ @Immutable @NotNullByDefault public class IncomingKeys { private final SecretKey tagKey, headerKey; - private final long rotationPeriod, windowBase; + private final long timePeriod, windowBase; private final byte[] windowBitmap; public IncomingKeys(SecretKey tagKey, SecretKey headerKey, - long rotationPeriod) { - this(tagKey, headerKey, rotationPeriod, 0, + long timePeriod) { + this(tagKey, headerKey, timePeriod, 0, new byte[REORDERING_WINDOW_SIZE / 8]); } public IncomingKeys(SecretKey tagKey, SecretKey headerKey, - long rotationPeriod, long windowBase, byte[] windowBitmap) { + long timePeriod, long windowBase, byte[] windowBitmap) { this.tagKey = tagKey; this.headerKey = headerKey; - this.rotationPeriod = rotationPeriod; + this.timePeriod = timePeriod; this.windowBase = windowBase; this.windowBitmap = windowBitmap; } @@ -42,8 +42,8 @@ public class IncomingKeys { return headerKey; } - public long getRotationPeriod() { - return rotationPeriod; + public long getTimePeriod() { + return timePeriod; } public long getWindowBase() { diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/OutgoingKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/OutgoingKeys.java index 2cdbfadaf..5e06e9b40 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/OutgoingKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/OutgoingKeys.java @@ -7,26 +7,26 @@ import javax.annotation.concurrent.Immutable; /** * Contains transport keys for sending streams to a given contact over a given - * transport in a given rotation period. + * transport in a given time period. */ @Immutable @NotNullByDefault public class OutgoingKeys { private final SecretKey tagKey, headerKey; - private final long rotationPeriod, streamCounter; + private final long timePeriod, streamCounter; private final boolean active; public OutgoingKeys(SecretKey tagKey, SecretKey headerKey, - long rotationPeriod, boolean active) { - this(tagKey, headerKey, rotationPeriod, 0, active); + long timePeriod, boolean active) { + this(tagKey, headerKey, timePeriod, 0, active); } public OutgoingKeys(SecretKey tagKey, SecretKey headerKey, - long rotationPeriod, long streamCounter, boolean active) { + long timePeriod, long streamCounter, boolean active) { this.tagKey = tagKey; this.headerKey = headerKey; - this.rotationPeriod = rotationPeriod; + this.timePeriod = timePeriod; this.streamCounter = streamCounter; this.active = active; } @@ -39,8 +39,8 @@ public class OutgoingKeys { return headerKey; } - public long getRotationPeriod() { - return rotationPeriod; + public long getTimePeriod() { + return timePeriod; } public long getStreamCounter() { diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java index 58795445b..860916457 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java @@ -18,11 +18,11 @@ public class TransportKeys { public TransportKeys(TransportId transportId, IncomingKeys inPrev, IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) { - if (inPrev.getRotationPeriod() != outCurr.getRotationPeriod() - 1) + if (inPrev.getTimePeriod() != outCurr.getTimePeriod() - 1) throw new IllegalArgumentException(); - if (inCurr.getRotationPeriod() != outCurr.getRotationPeriod()) + if (inCurr.getTimePeriod() != outCurr.getTimePeriod()) throw new IllegalArgumentException(); - if (inNext.getRotationPeriod() != outCurr.getRotationPeriod() + 1) + if (inNext.getTimePeriod() != outCurr.getTimePeriod() + 1) throw new IllegalArgumentException(); this.transportId = transportId; this.inPrev = inPrev; @@ -51,7 +51,7 @@ public class TransportKeys { return outCurr; } - public long getRotationPeriod() { - return outCurr.getRotationPeriod(); + public long getTimePeriod() { + return outCurr.getTimePeriod(); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java index 2d4ffb7d3..003a2ab63 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java @@ -36,45 +36,44 @@ class TransportCryptoImpl implements TransportCrypto { @Override public TransportKeys deriveTransportKeys(TransportId t, - SecretKey master, long rotationPeriod, boolean alice, - boolean active) { + SecretKey master, long timePeriod, boolean alice, boolean active) { // 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); + SecretKey inTagCurr = rotateKey(inTagPrev, timePeriod); + SecretKey inHeaderCurr = rotateKey(inHeaderPrev, timePeriod); + SecretKey inTagNext = rotateKey(inTagCurr, timePeriod + 1); + SecretKey inHeaderNext = rotateKey(inHeaderCurr, timePeriod + 1); + SecretKey outTagCurr = rotateKey(outTagPrev, timePeriod); + SecretKey outHeaderCurr = rotateKey(outHeaderPrev, timePeriod); // Initialise the reordering windows and stream counters IncomingKeys inPrev = new IncomingKeys(inTagPrev, inHeaderPrev, - rotationPeriod - 1); + timePeriod - 1); IncomingKeys inCurr = new IncomingKeys(inTagCurr, inHeaderCurr, - rotationPeriod); + timePeriod); IncomingKeys inNext = new IncomingKeys(inTagNext, inHeaderNext, - rotationPeriod + 1); + timePeriod + 1); OutgoingKeys outCurr = new OutgoingKeys(outTagCurr, outHeaderCurr, - rotationPeriod, active); + timePeriod, active); // 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; + long timePeriod) { + if (k.getTimePeriod() >= timePeriod) return k; IncomingKeys inPrev = k.getPreviousIncomingKeys(); IncomingKeys inCurr = k.getCurrentIncomingKeys(); IncomingKeys inNext = k.getNextIncomingKeys(); OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); - long startPeriod = outCurr.getRotationPeriod(); + long startPeriod = outCurr.getTimePeriod(); boolean active = outCurr.isActive(); // Rotate the keys - for (long p = startPeriod + 1; p <= rotationPeriod; p++) { + for (long p = startPeriod + 1; p <= timePeriod; p++) { inPrev = inCurr; inCurr = inNext; SecretKey inNextTag = rotateKey(inNext.getTagKey(), p + 1); @@ -89,9 +88,9 @@ class TransportCryptoImpl implements TransportCrypto { outCurr); } - private SecretKey rotateKey(SecretKey k, long rotationPeriod) { + private SecretKey rotateKey(SecretKey k, long timePeriod) { byte[] period = new byte[INT_64_BYTES]; - ByteUtils.writeUint64(rotationPeriod, period, 0); + ByteUtils.writeUint64(timePeriod, period, 0); return crypto.deriveKey(ROTATE_LABEL, k, period); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java index 958da7907..8b57537d2 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java @@ -635,10 +635,10 @@ interface Database { /** * Sets the reordering window for the given key set and transport in the - * given rotation period. + * given time period. */ void setReorderingWindow(T txn, KeySetId k, TransportId t, - long rotationPeriod, long base, byte[] bitmap) throws DbException; + long timePeriod, long base, byte[] bitmap) throws DbException; /** * Marks the given transport keys as usable for outgoing streams. diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java index a60d26c57..ef5ec82f9 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java @@ -956,13 +956,13 @@ class DatabaseComponentImpl implements DatabaseComponent { @Override public void setReorderingWindow(Transaction transaction, KeySetId k, - TransportId t, long rotationPeriod, long base, byte[] bitmap) + TransportId t, long timePeriod, long base, byte[] bitmap) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsTransport(txn, t)) throw new NoSuchTransportException(); - db.setReorderingWindow(txn, k, t, rotationPeriod, base, bitmap); + db.setReorderingWindow(txn, k, t, timePeriod, base, bitmap); } @Override diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index 7da00445c..5d5605fc9 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -85,9 +85,9 @@ import static org.briarproject.bramble.util.LogUtils.now; abstract class JdbcDatabase implements Database { // Package access for testing - static final int CODE_SCHEMA_VERSION = 41; + static final int CODE_SCHEMA_VERSION = 42; - // Rotation period offsets for incoming transport keys + // Time period offsets for incoming transport keys private static final int OFFSET_PREV = -1; private static final int OFFSET_CURR = 0; private static final int OFFSET_NEXT = 1; @@ -248,7 +248,7 @@ abstract class JdbcDatabase implements Database { "CREATE TABLE outgoingKeys" + " (transportId _STRING NOT NULL," + " keySetId _COUNTER," - + " rotationPeriod BIGINT NOT NULL," + + " timePeriod BIGINT NOT NULL," + " contactId INT NOT NULL," + " tagKey _SECRET NOT NULL," + " headerKey _SECRET NOT NULL," @@ -267,8 +267,7 @@ abstract class JdbcDatabase implements Database { "CREATE TABLE incomingKeys" + " (transportId _STRING NOT NULL," + " keySetId INT NOT NULL," - + " rotationPeriod BIGINT NOT NULL," - + " contactId INT NOT NULL," + + " timePeriod BIGINT NOT NULL," + " tagKey _SECRET NOT NULL," + " headerKey _SECRET NOT NULL," + " base BIGINT NOT NULL," @@ -280,9 +279,49 @@ abstract class JdbcDatabase implements Database { + " ON DELETE CASCADE," + " FOREIGN KEY (keySetId)" + " REFERENCES outgoingKeys (keySetId)" + + " ON DELETE CASCADE)"; + + private static final String CREATE_PENDING_CONTACTS = + "CREATE TABLE pendingContacts" + + " (pendingContactId _HASH NOT NULL," + + " PRIMARY KEY (pendingContactId))"; + + private static final String CREATE_OUTGOING_STATIC_KEYS = + "CREATE TABLE outgoingStaticKeys" + + " (transportId _STRING NOT NULL," + + " staticKeySetId _COUNTER," + + " rootKey _SECRET NOT NULL," + + " timePeriod BIGINT NOT NULL," + + " stream BIGINT NOT NULL," + + " contactId INT," // Null if contact is pending + + " pendingContactId _HASH," // Null if not pending + + " PRIMARY KEY (transportId, staticKeySetId)," + + " FOREIGN KEY (transportId)" + + " REFERENCES transports (transportId)" + " ON DELETE CASCADE," + + " UNIQUE (staticKeySetId)," + " FOREIGN KEY (contactId)" + " REFERENCES contacts (contactId)" + + " ON DELETE CASCADE," + + " FOREIGN KEY (pendingContactId)" + + " REFERENCES pendingContacts (pendingContactId)" + + " ON DELETE CASCADE)"; + + private static final String CREATE_INCOMING_STATIC_KEYS = + "CREATE TABLE incomingStaticKeys" + + " (transportId _STRING NOT NULL," + + " staticKeySetId INT NOT NULL," + + " timePeriod BIGINT NOT NULL," + + " base BIGINT NOT NULL," + + " bitmap _BINARY NOT NULL," + + " periodOffset INT NOT NULL," + + " PRIMARY KEY (transportId, staticKeySetId," + + " periodOffset)," + + " FOREIGN KEY (transportId)" + + " REFERENCES transports (transportId)" + + " ON DELETE CASCADE," + + " FOREIGN KEY (staticKeySetId)" + + " REFERENCES outgoingStaticKeys (staticKeySetId)" + " ON DELETE CASCADE)"; private static final String INDEX_CONTACTS_BY_AUTHOR_ID = @@ -428,7 +467,8 @@ abstract class JdbcDatabase implements Database { return Arrays.asList( new Migration38_39(), new Migration39_40(), - new Migration40_41(dbTypes) + new Migration40_41(dbTypes), + new Migration41_42(dbTypes) ); } @@ -478,6 +518,9 @@ abstract class JdbcDatabase implements Database { s.executeUpdate(dbTypes.replaceTypes(CREATE_TRANSPORTS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_OUTGOING_KEYS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_INCOMING_KEYS)); + s.executeUpdate(dbTypes.replaceTypes(CREATE_PENDING_CONTACTS)); + s.executeUpdate(dbTypes.replaceTypes(CREATE_OUTGOING_STATIC_KEYS)); + s.executeUpdate(dbTypes.replaceTypes(CREATE_INCOMING_STATIC_KEYS)); s.close(); } catch (SQLException e) { tryToClose(s, LOG, WARNING); @@ -922,13 +965,13 @@ abstract class JdbcDatabase implements Database { try { // Store the outgoing keys String sql = "INSERT INTO outgoingKeys (contactId, transportId," - + " rotationPeriod, tagKey, headerKey, stream, active)" + + " timePeriod, tagKey, headerKey, stream, active)" + " VALUES (?, ?, ?, ?, ?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setInt(1, c.getInt()); ps.setString(2, k.getTransportId().getString()); OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); - ps.setLong(3, outCurr.getRotationPeriod()); + ps.setLong(3, outCurr.getTimePeriod()); ps.setBytes(4, outCurr.getTagKey().getBytes()); ps.setBytes(5, outCurr.getHeaderKey().getBytes()); ps.setLong(6, outCurr.getStreamCounter()); @@ -947,40 +990,39 @@ abstract class JdbcDatabase implements Database { rs.close(); ps.close(); // Store the incoming keys - sql = "INSERT INTO incomingKeys (keySetId, contactId, transportId," - + " rotationPeriod, tagKey, headerKey, base, bitmap," + sql = "INSERT INTO incomingKeys (keySetId, transportId," + + " timePeriod, tagKey, headerKey, base, bitmap," + " periodOffset)" - + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setInt(1, keySetId.getInt()); - ps.setInt(2, c.getInt()); - ps.setString(3, k.getTransportId().getString()); - // Previous rotation period + ps.setString(2, k.getTransportId().getString()); + // Previous time period IncomingKeys inPrev = k.getPreviousIncomingKeys(); - ps.setLong(4, inPrev.getRotationPeriod()); - ps.setBytes(5, inPrev.getTagKey().getBytes()); - ps.setBytes(6, inPrev.getHeaderKey().getBytes()); - ps.setLong(7, inPrev.getWindowBase()); - ps.setBytes(8, inPrev.getWindowBitmap()); - ps.setInt(9, OFFSET_PREV); + ps.setLong(3, inPrev.getTimePeriod()); + ps.setBytes(4, inPrev.getTagKey().getBytes()); + ps.setBytes(5, inPrev.getHeaderKey().getBytes()); + ps.setLong(6, inPrev.getWindowBase()); + ps.setBytes(7, inPrev.getWindowBitmap()); + ps.setInt(8, OFFSET_PREV); ps.addBatch(); - // Current rotation period + // Current time period IncomingKeys inCurr = k.getCurrentIncomingKeys(); - ps.setLong(4, inCurr.getRotationPeriod()); - ps.setBytes(5, inCurr.getTagKey().getBytes()); - ps.setBytes(6, inCurr.getHeaderKey().getBytes()); - ps.setLong(7, inCurr.getWindowBase()); - ps.setBytes(8, inCurr.getWindowBitmap()); - ps.setInt(9, OFFSET_CURR); + ps.setLong(3, inCurr.getTimePeriod()); + ps.setBytes(4, inCurr.getTagKey().getBytes()); + ps.setBytes(5, inCurr.getHeaderKey().getBytes()); + ps.setLong(6, inCurr.getWindowBase()); + ps.setBytes(7, inCurr.getWindowBitmap()); + ps.setInt(8, OFFSET_CURR); ps.addBatch(); - // Next rotation period + // Next time period IncomingKeys inNext = k.getNextIncomingKeys(); - ps.setLong(4, inNext.getRotationPeriod()); - ps.setBytes(5, inNext.getTagKey().getBytes()); - ps.setBytes(6, inNext.getHeaderKey().getBytes()); - ps.setLong(7, inNext.getWindowBase()); - ps.setBytes(8, inNext.getWindowBitmap()); - ps.setInt(9, OFFSET_NEXT); + ps.setLong(3, inNext.getTimePeriod()); + ps.setBytes(4, inNext.getTagKey().getBytes()); + ps.setBytes(5, inNext.getHeaderKey().getBytes()); + ps.setLong(6, inNext.getWindowBase()); + ps.setBytes(7, inNext.getWindowBitmap()); + ps.setInt(8, OFFSET_NEXT); ps.addBatch(); int[] batchAffected = ps.executeBatch(); if (batchAffected.length != 3) throw new DbStateException(); @@ -2155,8 +2197,7 @@ abstract class JdbcDatabase implements Database { ResultSet rs = null; try { // Retrieve the incoming keys - String sql = "SELECT rotationPeriod, tagKey, headerKey," - + " base, bitmap" + String sql = "SELECT timePeriod, tagKey, headerKey, base, bitmap" + " FROM incomingKeys" + " WHERE transportId = ?" + " ORDER BY keySetId, periodOffset"; @@ -2165,18 +2206,18 @@ abstract class JdbcDatabase implements Database { rs = ps.executeQuery(); List inKeys = new ArrayList<>(); while (rs.next()) { - long rotationPeriod = rs.getLong(1); + long timePeriod = rs.getLong(1); SecretKey tagKey = new SecretKey(rs.getBytes(2)); SecretKey headerKey = new SecretKey(rs.getBytes(3)); long windowBase = rs.getLong(4); byte[] windowBitmap = rs.getBytes(5); - inKeys.add(new IncomingKeys(tagKey, headerKey, rotationPeriod, + inKeys.add(new IncomingKeys(tagKey, headerKey, timePeriod, windowBase, windowBitmap)); } rs.close(); ps.close(); // Retrieve the outgoing keys in the same order - sql = "SELECT keySetId, contactId, rotationPeriod," + sql = "SELECT keySetId, contactId, timePeriod," + " tagKey, headerKey, stream, active" + " FROM outgoingKeys" + " WHERE transportId = ?" @@ -2190,13 +2231,13 @@ abstract class JdbcDatabase implements Database { if (inKeys.size() < (i + 1) * 3) throw new DbStateException(); KeySetId keySetId = new KeySetId(rs.getInt(1)); ContactId contactId = new ContactId(rs.getInt(2)); - long rotationPeriod = rs.getLong(3); + long timePeriod = rs.getLong(3); SecretKey tagKey = new SecretKey(rs.getBytes(4)); SecretKey headerKey = new SecretKey(rs.getBytes(5)); long streamCounter = rs.getLong(6); boolean active = rs.getBoolean(7); OutgoingKeys outCurr = new OutgoingKeys(tagKey, headerKey, - rotationPeriod, streamCounter, active); + timePeriod, streamCounter, active); IncomingKeys inPrev = inKeys.get(i * 3); IncomingKeys inCurr = inKeys.get(i * 3 + 1); IncomingKeys inNext = inKeys.get(i * 3 + 2); @@ -2894,18 +2935,18 @@ abstract class JdbcDatabase implements Database { @Override public void setReorderingWindow(Connection txn, KeySetId k, TransportId t, - long rotationPeriod, long base, byte[] bitmap) throws DbException { + long timePeriod, long base, byte[] bitmap) throws DbException { PreparedStatement ps = null; try { String sql = "UPDATE incomingKeys SET base = ?, bitmap = ?" + " WHERE transportId = ? AND keySetId = ?" - + " AND rotationPeriod = ?"; + + " AND timePeriod = ?"; ps = txn.prepareStatement(sql); ps.setLong(1, base); ps.setBytes(2, bitmap); ps.setString(3, t.getString()); ps.setInt(4, k.getInt()); - ps.setLong(5, rotationPeriod); + ps.setLong(5, timePeriod); int affected = ps.executeUpdate(); if (affected < 0 || affected > 1) throw new DbStateException(); ps.close(); @@ -2977,13 +3018,13 @@ abstract class JdbcDatabase implements Database { PreparedStatement ps = null; try { // Update the outgoing keys - String sql = "UPDATE outgoingKeys SET rotationPeriod = ?," + String sql = "UPDATE outgoingKeys SET timePeriod = ?," + " tagKey = ?, headerKey = ?, stream = ?" + " WHERE transportId = ? AND keySetId = ?"; ps = txn.prepareStatement(sql); TransportKeys k = ks.getTransportKeys(); OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); - ps.setLong(1, outCurr.getRotationPeriod()); + ps.setLong(1, outCurr.getTimePeriod()); ps.setBytes(2, outCurr.getTagKey().getBytes()); ps.setBytes(3, outCurr.getHeaderKey().getBytes()); ps.setLong(4, outCurr.getStreamCounter()); @@ -2993,34 +3034,34 @@ abstract class JdbcDatabase implements Database { if (affected < 0 || affected > 1) throw new DbStateException(); ps.close(); // Update the incoming keys - sql = "UPDATE incomingKeys SET rotationPeriod = ?," + sql = "UPDATE incomingKeys SET timePeriod = ?," + " tagKey = ?, headerKey = ?, base = ?, bitmap = ?" + " WHERE transportId = ? AND keySetId = ?" + " AND periodOffset = ?"; ps = txn.prepareStatement(sql); ps.setString(6, k.getTransportId().getString()); ps.setInt(7, ks.getKeySetId().getInt()); - // Previous rotation period + // Previous time period IncomingKeys inPrev = k.getPreviousIncomingKeys(); - ps.setLong(1, inPrev.getRotationPeriod()); + ps.setLong(1, inPrev.getTimePeriod()); ps.setBytes(2, inPrev.getTagKey().getBytes()); ps.setBytes(3, inPrev.getHeaderKey().getBytes()); ps.setLong(4, inPrev.getWindowBase()); ps.setBytes(5, inPrev.getWindowBitmap()); ps.setInt(8, OFFSET_PREV); ps.addBatch(); - // Current rotation period + // Current time period IncomingKeys inCurr = k.getCurrentIncomingKeys(); - ps.setLong(1, inCurr.getRotationPeriod()); + ps.setLong(1, inCurr.getTimePeriod()); ps.setBytes(2, inCurr.getTagKey().getBytes()); ps.setBytes(3, inCurr.getHeaderKey().getBytes()); ps.setLong(4, inCurr.getWindowBase()); ps.setBytes(5, inCurr.getWindowBitmap()); ps.setInt(8, OFFSET_CURR); ps.addBatch(); - // Next rotation period + // Next time period IncomingKeys inNext = k.getNextIncomingKeys(); - ps.setLong(1, inNext.getRotationPeriod()); + ps.setLong(1, inNext.getTimePeriod()); ps.setBytes(2, inNext.getTagKey().getBytes()); ps.setBytes(3, inNext.getHeaderKey().getBytes()); ps.setLong(4, inNext.getWindowBase()); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Migration40_41.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration40_41.java index 709be524d..8c7f9bcf6 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Migration40_41.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration40_41.java @@ -17,7 +17,7 @@ class Migration40_41 implements Migration { private final DatabaseTypes dbTypes; - public Migration40_41(DatabaseTypes databaseTypes) { + Migration40_41(DatabaseTypes databaseTypes) { this.dbTypes = databaseTypes; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java new file mode 100644 index 000000000..879eebd6a --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java @@ -0,0 +1,89 @@ +package org.briarproject.bramble.db; + +import org.briarproject.bramble.api.db.DbException; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.logging.Logger; + +import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.db.JdbcUtils.tryToClose; + +class Migration41_42 implements Migration { + + private static final Logger LOG = getLogger(Migration41_42.class.getName()); + + private final DatabaseTypes dbTypes; + + Migration41_42(DatabaseTypes dbTypes) { + this.dbTypes = dbTypes; + } + + @Override + public int getStartVersion() { + return 41; + } + + @Override + public int getEndVersion() { + return 42; + } + + @Override + public void migrate(Connection txn) throws DbException { + Statement s = null; + try { + s = txn.createStatement(); + s.execute("ALTER TABLE outgoingKeys" + + " ALTER COLUMN rotationPeriod" + + " RENAME TO timePeriod"); + s.execute("ALTER TABLE incomingKeys" + + " ALTER COLUMN rotationPeriod" + + " RENAME TO timePeriod"); + s.execute("ALTER TABLE incomingKeys" + + " DROP COLUMN contactId"); + s.execute(dbTypes.replaceTypes("CREATE TABLE pendingContacts" + + " (pendingContactId _HASH NOT NULL," + + " PRIMARY KEY (pendingContactId))")); + s.execute(dbTypes.replaceTypes("CREATE TABLE outgoingStaticKeys" + + " (transportId _STRING NOT NULL," + + " staticKeySetId _COUNTER," + + " rootKey _SECRET NOT NULL," + + " timePeriod BIGINT NOT NULL," + + " stream BIGINT NOT NULL," + + " contactId INT," // Null if contact is pending + + " pendingContactId _HASH," // Null if not pending + + " PRIMARY KEY (transportId, staticKeySetId)," + + " FOREIGN KEY (transportId)" + + " REFERENCES transports (transportId)" + + " ON DELETE CASCADE," + + " UNIQUE (staticKeySetId)," + + " FOREIGN KEY (contactId)" + + " REFERENCES contacts (contactId)" + + " ON DELETE CASCADE," + + " FOREIGN KEY (pendingContactId)" + + " REFERENCES pendingContacts (pendingContactId)" + + " ON DELETE CASCADE)")); + s.execute(dbTypes.replaceTypes("CREATE TABLE incomingStaticKeys" + + " (transportId _STRING NOT NULL," + + " staticKeySetId INT NOT NULL," + + " timePeriod BIGINT NOT NULL," + + " base BIGINT NOT NULL," + + " bitmap _BINARY NOT NULL," + + " periodOffset INT NOT NULL," + + " PRIMARY KEY (transportId, staticKeySetId," + + " periodOffset)," + + " FOREIGN KEY (transportId)" + + " REFERENCES transports (transportId)" + + " ON DELETE CASCADE," + + " FOREIGN KEY (staticKeySetId)" + + " REFERENCES outgoingStaticKeys (staticKeySetId)" + + " ON DELETE CASCADE)")); + } catch (SQLException e) { + tryToClose(s, LOG, WARNING); + throw new DbException(e); + } + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableIncomingKeys.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableIncomingKeys.java index 3f2f94a5c..994013044 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableIncomingKeys.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableIncomingKeys.java @@ -11,18 +11,18 @@ import javax.annotation.concurrent.NotThreadSafe; class MutableIncomingKeys { private final SecretKey tagKey, headerKey; - private final long rotationPeriod; + private final long timePeriod; private final ReorderingWindow window; MutableIncomingKeys(IncomingKeys in) { tagKey = in.getTagKey(); headerKey = in.getHeaderKey(); - rotationPeriod = in.getRotationPeriod(); + timePeriod = in.getTimePeriod(); window = new ReorderingWindow(in.getWindowBase(), in.getWindowBitmap()); } IncomingKeys snapshot() { - return new IncomingKeys(tagKey, headerKey, rotationPeriod, + return new IncomingKeys(tagKey, headerKey, timePeriod, window.getBase(), window.getBitmap()); } @@ -34,8 +34,8 @@ class MutableIncomingKeys { return headerKey; } - long getRotationPeriod() { - return rotationPeriod; + long getTimePeriod() { + return timePeriod; } ReorderingWindow getWindow() { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableOutgoingKeys.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableOutgoingKeys.java index c195f445c..44ba3a3ea 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableOutgoingKeys.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableOutgoingKeys.java @@ -11,20 +11,20 @@ import javax.annotation.concurrent.NotThreadSafe; class MutableOutgoingKeys { private final SecretKey tagKey, headerKey; - private final long rotationPeriod; + private final long timePeriod; private long streamCounter; private boolean active; MutableOutgoingKeys(OutgoingKeys out) { tagKey = out.getTagKey(); headerKey = out.getHeaderKey(); - rotationPeriod = out.getRotationPeriod(); + timePeriod = out.getTimePeriod(); streamCounter = out.getStreamCounter(); active = out.isActive(); } OutgoingKeys snapshot() { - return new OutgoingKeys(tagKey, headerKey, rotationPeriod, + return new OutgoingKeys(tagKey, headerKey, timePeriod, streamCounter, active); } @@ -36,8 +36,8 @@ class MutableOutgoingKeys { return headerKey; } - long getRotationPeriod() { - return rotationPeriod; + long getTimePeriod() { + return timePeriod; } long getStreamCounter() { 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 ed51c3919..f23ad45f3 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 @@ -51,7 +51,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { private final ScheduledExecutorService scheduler; private final Clock clock; private final TransportId transportId; - private final long rotationPeriodLength; + private final long timePeriodLength; private final AtomicBoolean used = new AtomicBoolean(false); private final ReentrantLock lock = new ReentrantLock(); @@ -70,7 +70,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { this.scheduler = scheduler; this.clock = clock; this.transportId = transportId; - rotationPeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE; + timePeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE; } @Override @@ -81,7 +81,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { try { // Load the transport keys from the DB Collection loaded = db.getTransportKeys(txn, transportId); - // Rotate the keys to the current rotation period + // Rotate the keys to the current time period RotationResult rotationResult = rotateKeys(loaded, now); // Initialise mutable state for all contacts addKeys(rotationResult.current); @@ -97,13 +97,13 @@ class TransportKeyManagerImpl implements TransportKeyManager { private RotationResult rotateKeys(Collection keys, long now) { RotationResult rotationResult = new RotationResult(); - long rotationPeriod = now / rotationPeriodLength; + long timePeriod = now / timePeriodLength; for (KeySet ks : keys) { TransportKeys k = ks.getTransportKeys(); TransportKeys k1 = - transportCrypto.rotateTransportKeys(k, rotationPeriod); + transportCrypto.rotateTransportKeys(k, timePeriod); KeySet ks1 = new KeySet(ks.getKeySetId(), ks.getContactId(), k1); - if (k1.getRotationPeriod() > k.getRotationPeriod()) + if (k1.getTimePeriod() > k.getTimePeriod()) rotationResult.rotated.add(ks1); rotationResult.current.add(ks1); } @@ -155,7 +155,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { } private void scheduleKeyRotation(long now) { - long delay = rotationPeriodLength - now % rotationPeriodLength; + long delay = timePeriodLength - now % timePeriodLength; scheduler.schedule((Runnable) this::rotateKeys, delay, MILLISECONDS); } @@ -174,14 +174,14 @@ class TransportKeyManagerImpl implements TransportKeyManager { long timestamp, boolean alice, boolean active) throws DbException { lock.lock(); try { - // Work out what rotation period the timestamp belongs to - long rotationPeriod = timestamp / rotationPeriodLength; + // Work out what time period the timestamp belongs to + long timePeriod = timestamp / timePeriodLength; // Derive the transport keys TransportKeys k = transportCrypto.deriveTransportKeys(transportId, - master, rotationPeriod, alice, active); - // Rotate the keys to the current rotation period if necessary - rotationPeriod = clock.currentTimeMillis() / rotationPeriodLength; - k = transportCrypto.rotateTransportKeys(k, rotationPeriod); + master, timePeriod, alice, active); + // Rotate the keys to the current time period if necessary + timePeriod = clock.currentTimeMillis() / timePeriodLength; + k = transportCrypto.rotateTransportKeys(k, timePeriod); // Write the keys back to the DB KeySetId keySetId = db.addTransportKeys(txn, c, k); // Initialise mutable state for the contact @@ -300,7 +300,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { } // Write the window back to the DB db.setReorderingWindow(txn, tagCtx.keySetId, transportId, - inKeys.getRotationPeriod(), window.getBase(), + inKeys.getTimePeriod(), window.getBase(), window.getBitmap()); // If the outgoing keys are inactive, activate them MutableKeySet ks = keys.get(tagCtx.keySetId); @@ -322,7 +322,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { long now = clock.currentTimeMillis(); lock.lock(); try { - // Rotate the keys to the current rotation period + // Rotate the keys to the current time period Collection snapshot = new ArrayList<>(keys.size()); for (MutableKeySet ks : keys.values()) { snapshot.add(new KeySet(ks.getKeySetId(), ks.getContactId(), 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 969d62588..45c68c818 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 @@ -40,7 +40,7 @@ public class KeyDerivationTest extends BrambleTestCase { @Test public void testCurrentKeysMatchCurrentKeysOfContact() { - // Start in rotation period 123 + // Start in time period 123 TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, master, 123, true, true); TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, @@ -72,7 +72,7 @@ public class KeyDerivationTest extends BrambleTestCase { @Test public void testPreviousKeysMatchPreviousKeysOfContact() { - // Start in rotation period 123 + // Start in time period 123 TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, master, 123, true, true); TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, @@ -99,7 +99,7 @@ public class KeyDerivationTest extends BrambleTestCase { @Test public void testNextKeysMatchNextKeysOfContact() { - // Start in rotation period 123 + // Start in time period 123 TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, master, 123, true, true); TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java index b303b5060..481cf23b2 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java @@ -653,10 +653,10 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { @Test public void testTransportKeys() throws Exception { - long rotationPeriod = 123, rotationPeriod1 = 234; + long timePeriod = 123, timePeriod1 = 234; boolean active = random.nextBoolean(); - TransportKeys keys = createTransportKeys(rotationPeriod, active); - TransportKeys keys1 = createTransportKeys(rotationPeriod1, active); + TransportKeys keys = createTransportKeys(timePeriod, active); + TransportKeys keys1 = createTransportKeys(timePeriod1, active); Database db = open(false); Connection txn = db.startTransaction(); @@ -686,9 +686,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { } // Rotate the transport keys - TransportKeys rotated = createTransportKeys(rotationPeriod + 1, active); + TransportKeys rotated = createTransportKeys(timePeriod + 1, active); TransportKeys rotated1 = - createTransportKeys(rotationPeriod1 + 1, active); + createTransportKeys(timePeriod1 + 1, active); db.updateTransportKeys(txn, new KeySet(keySetId, contactId, rotated)); db.updateTransportKeys(txn, new KeySet(keySetId1, contactId, rotated1)); @@ -716,7 +716,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { private void assertKeysEquals(TransportKeys expected, TransportKeys actual) { assertEquals(expected.getTransportId(), actual.getTransportId()); - assertEquals(expected.getRotationPeriod(), actual.getRotationPeriod()); + assertEquals(expected.getTimePeriod(), actual.getTimePeriod()); assertKeysEquals(expected.getPreviousIncomingKeys(), actual.getPreviousIncomingKeys()); assertKeysEquals(expected.getCurrentIncomingKeys(), @@ -732,7 +732,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { actual.getTagKey().getBytes()); assertArrayEquals(expected.getHeaderKey().getBytes(), actual.getHeaderKey().getBytes()); - assertEquals(expected.getRotationPeriod(), actual.getRotationPeriod()); + assertEquals(expected.getTimePeriod(), actual.getTimePeriod()); assertEquals(expected.getWindowBase(), actual.getWindowBase()); assertArrayEquals(expected.getWindowBitmap(), actual.getWindowBitmap()); } @@ -742,15 +742,15 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { actual.getTagKey().getBytes()); assertArrayEquals(expected.getHeaderKey().getBytes(), actual.getHeaderKey().getBytes()); - assertEquals(expected.getRotationPeriod(), actual.getRotationPeriod()); + assertEquals(expected.getTimePeriod(), actual.getTimePeriod()); assertEquals(expected.getStreamCounter(), actual.getStreamCounter()); assertEquals(expected.isActive(), actual.isActive()); } @Test public void testIncrementStreamCounter() throws Exception { - long rotationPeriod = 123; - TransportKeys keys = createTransportKeys(rotationPeriod, true); + long timePeriod = 123; + TransportKeys keys = createTransportKeys(timePeriod, true); long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter(); Database db = open(false); @@ -774,7 +774,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { TransportKeys k = ks.getTransportKeys(); assertEquals(transportId, k.getTransportId()); OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); - assertEquals(rotationPeriod, outCurr.getRotationPeriod()); + assertEquals(timePeriod, outCurr.getTimePeriod()); assertEquals(streamCounter + 2, outCurr.getStreamCounter()); // The rest of the keys should be unaffected @@ -791,8 +791,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { @Test public void testSetReorderingWindow() throws Exception { boolean active = random.nextBoolean(); - long rotationPeriod = 123; - TransportKeys keys = createTransportKeys(rotationPeriod, active); + long timePeriod = 123; + TransportKeys keys = createTransportKeys(timePeriod, active); long base = keys.getCurrentIncomingKeys().getWindowBase(); byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap(); @@ -808,7 +808,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Update the reordering window and retrieve the transport keys random.nextBytes(bitmap); - db.setReorderingWindow(txn, keySetId, transportId, rotationPeriod, + db.setReorderingWindow(txn, keySetId, transportId, timePeriod, base + 1, bitmap); Collection newKeys = db.getTransportKeys(txn, transportId); assertEquals(1, newKeys.size()); @@ -818,7 +818,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { TransportKeys k = ks.getTransportKeys(); assertEquals(transportId, k.getTransportId()); IncomingKeys inCurr = k.getCurrentIncomingKeys(); - assertEquals(rotationPeriod, inCurr.getRotationPeriod()); + assertEquals(timePeriod, inCurr.getTimePeriod()); assertEquals(base + 1, inCurr.getWindowBase()); assertArrayEquals(bitmap, inCurr.getWindowBitmap()); @@ -1978,24 +1978,23 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { return db; } - private TransportKeys createTransportKeys(long rotationPeriod, - boolean active) { + private TransportKeys createTransportKeys(long timePeriod, boolean active) { SecretKey inPrevTagKey = getSecretKey(); SecretKey inPrevHeaderKey = getSecretKey(); IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey, - rotationPeriod - 1, 123, new byte[4]); + timePeriod - 1, 123, new byte[4]); SecretKey inCurrTagKey = getSecretKey(); SecretKey inCurrHeaderKey = getSecretKey(); IncomingKeys inCurr = new IncomingKeys(inCurrTagKey, inCurrHeaderKey, - rotationPeriod, 234, new byte[4]); + timePeriod, 234, new byte[4]); SecretKey inNextTagKey = getSecretKey(); SecretKey inNextHeaderKey = getSecretKey(); IncomingKeys inNext = new IncomingKeys(inNextTagKey, inNextHeaderKey, - rotationPeriod + 1, 345, new byte[4]); + timePeriod + 1, 345, new byte[4]); SecretKey outCurrTagKey = getSecretKey(); SecretKey outCurrHeaderKey = getSecretKey(); OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey, - rotationPeriod, 456, active); + timePeriod, 456, active); return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr); } 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 1c13a8107..8b79d4849 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 @@ -57,7 +57,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { private final TransportId transportId = getTransportId(); private final long maxLatency = 30 * 1000; // 30 seconds - private final long rotationPeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE; + private final long timePeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE; private final ContactId contactId = new ContactId(123); private final ContactId contactId1 = new ContactId(234); private final KeySetId keySetId = new KeySetId(345); @@ -79,9 +79,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { Transaction txn = new Transaction(null, false); context.checking(new Expectations() {{ - // Get the current time (1 ms after start of rotation period 1000) + // Get the current time (1 ms after start of time period 1000) oneOf(clock).currentTimeMillis(); - will(returnValue(rotationPeriodLength * 1000 + 1)); + will(returnValue(timePeriodLength * 1000 + 1)); // Load the transport keys oneOf(db).getTransportKeys(txn, transportId); will(returnValue(loaded)); @@ -100,9 +100,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { // Save the keys that were rotated oneOf(db).updateTransportKeys(txn, singletonList(new KeySet(keySetId, contactId, rotated))); - // Schedule key rotation at the start of the next rotation period + // Schedule key rotation at the start of the next time period oneOf(scheduler).schedule(with(any(Runnable.class)), - with(rotationPeriodLength - 1), with(MILLISECONDS)); + with(timePeriodLength - 1), with(MILLISECONDS)); }}); TransportKeyManager transportKeyManager = new TransportKeyManagerImpl( @@ -123,9 +123,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, 999, alice, true); will(returnValue(transportKeys)); - // Get the current time (1 ms after start of rotation period 1000) + // Get the current time (1 ms after start of time period 1000) oneOf(clock).currentTimeMillis(); - will(returnValue(rotationPeriodLength * 1000 + 1)); + will(returnValue(timePeriodLength * 1000 + 1)); // Rotate the transport keys oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000); will(returnValue(rotated)); @@ -144,8 +144,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { 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; + // The timestamp is 1 ms before the start of time period 1000 + long timestamp = timePeriodLength * 1000 - 1; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice, true)); assertTrue(transportKeyManager.canSendOutgoingStreams(contactId)); @@ -177,8 +177,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { 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; + // The timestamp is at the start of time period 1000 + long timestamp = timePeriodLength * 1000; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice, true)); assertFalse(transportKeyManager.canSendOutgoingStreams(contactId)); @@ -203,8 +203,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { 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; + // The timestamp is at the start of time period 1000 + long timestamp = timePeriodLength * 1000; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice, true)); // The first request should return a stream context @@ -235,8 +235,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { 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; + // The timestamp is at the start of time period 1000 + long timestamp = timePeriodLength * 1000; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice, active)); assertEquals(active, @@ -259,9 +259,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, 1000, alice, true); will(returnValue(transportKeys)); - // Get the current time (the start of rotation period 1000) + // Get the current time (the start of time period 1000) oneOf(clock).currentTimeMillis(); - will(returnValue(rotationPeriodLength * 1000)); + will(returnValue(timePeriodLength * 1000)); // Encode the tags (3 sets) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { exactly(3).of(transportCrypto).encodeTag( @@ -280,7 +280,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { with(tagKey), with(PROTOCOL_VERSION), with((long) REORDERING_WINDOW_SIZE)); will(new EncodeTagAction(tags)); - // Save the reordering window (previous rotation period, base 1) + // Save the reordering window (previous time period, base 1) oneOf(db).setReorderingWindow(txn, keySetId, transportId, 999, 1, new byte[REORDERING_WINDOW_SIZE / 8]); }}); @@ -288,12 +288,12 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { 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; + // The timestamp is at the start of time period 1000 + long timestamp = timePeriodLength * 1000; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice, true)); assertTrue(transportKeyManager.canSendOutgoingStreams(contactId)); - // Use the first tag (previous rotation period, stream number 0) + // Use the first tag (previous time period, stream number 0) assertEquals(REORDERING_WINDOW_SIZE * 3, tags.size()); byte[] tag = tags.get(0); // The first request should return a stream context @@ -320,9 +320,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { Transaction txn1 = new Transaction(null, false); context.checking(new DbExpectations() {{ - // Get the current time (the start of rotation period 1000) + // Get the current time (the start of time period 1000) oneOf(clock).currentTimeMillis(); - will(returnValue(rotationPeriodLength * 1000)); + will(returnValue(timePeriodLength * 1000)); // Load the transport keys oneOf(db).getTransportKeys(txn, transportId); will(returnValue(loaded)); @@ -336,17 +336,17 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { with(PROTOCOL_VERSION), with(i)); will(new EncodeTagAction()); } - // Schedule key rotation at the start of the next rotation period + // Schedule key rotation at the start of the next time period oneOf(scheduler).schedule(with(any(Runnable.class)), - with(rotationPeriodLength), with(MILLISECONDS)); + with(timePeriodLength), with(MILLISECONDS)); will(new RunAction()); oneOf(dbExecutor).execute(with(any(Runnable.class))); will(new RunAction()); // Start a transaction for key rotation oneOf(db).transaction(with(false), withDbRunnable(txn1)); - // Get the current time (the start of rotation period 1001) + // Get the current time (the start of time period 1001) oneOf(clock).currentTimeMillis(); - will(returnValue(rotationPeriodLength * 1001)); + will(returnValue(timePeriodLength * 1001)); // Rotate the transport keys oneOf(transportCrypto).rotateTransportKeys( with(any(TransportKeys.class)), with(1001L)); @@ -361,9 +361,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { // Save the keys that were rotated oneOf(db).updateTransportKeys(txn1, singletonList(new KeySet(keySetId, contactId, rotated))); - // Schedule key rotation at the start of the next rotation period + // Schedule key rotation at the start of the next time period oneOf(scheduler).schedule(with(any(Runnable.class)), - with(rotationPeriodLength), with(MILLISECONDS)); + with(timePeriodLength), with(MILLISECONDS)); }}); TransportKeyManager transportKeyManager = new TransportKeyManagerImpl( @@ -391,8 +391,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { 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; + // The timestamp is at the start of time period 1000 + long timestamp = timePeriodLength * 1000; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice, false)); // The keys are inactive so no stream context should be returned @@ -424,9 +424,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, 1000, alice, false); will(returnValue(transportKeys)); - // Get the current time (the start of rotation period 1000) + // Get the current time (the start of time period 1000) oneOf(clock).currentTimeMillis(); - will(returnValue(rotationPeriodLength * 1000)); + will(returnValue(timePeriodLength * 1000)); // Encode the tags (3 sets) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { exactly(3).of(transportCrypto).encodeTag( @@ -445,7 +445,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { with(tagKey), with(PROTOCOL_VERSION), with((long) REORDERING_WINDOW_SIZE)); will(new EncodeTagAction(tags)); - // Save the reordering window (previous rotation period, base 1) + // Save the reordering window (previous time period, base 1) oneOf(db).setReorderingWindow(txn, keySetId, transportId, 999, 1, new byte[REORDERING_WINDOW_SIZE / 8]); // Activate the keys @@ -457,8 +457,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { 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; + // The timestamp is at the start of time period 1000 + long timestamp = timePeriodLength * 1000; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice, false)); // The keys are inactive so no stream context should be returned @@ -491,9 +491,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, 1000, alice, active); will(returnValue(transportKeys)); - // Get the current time (the start of rotation period 1000) + // Get the current time (the start of time period 1000) oneOf(clock).currentTimeMillis(); - will(returnValue(rotationPeriodLength * 1000)); + will(returnValue(timePeriodLength * 1000)); // Encode the tags (3 sets) for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { exactly(3).of(transportCrypto).encodeTag( @@ -510,16 +510,16 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { }}); } - private TransportKeys createTransportKeys(long rotationPeriod, + private TransportKeys createTransportKeys(long timePeriod, long streamCounter, boolean active) { IncomingKeys inPrev = new IncomingKeys(tagKey, headerKey, - rotationPeriod - 1); + timePeriod - 1); IncomingKeys inCurr = new IncomingKeys(tagKey, headerKey, - rotationPeriod); + timePeriod); IncomingKeys inNext = new IncomingKeys(tagKey, headerKey, - rotationPeriod + 1); + timePeriod + 1); OutgoingKeys outCurr = new OutgoingKeys(tagKey, headerKey, - rotationPeriod, streamCounter, active); + timePeriod, streamCounter, active); return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr); } From d4b929fc6c1f82c00d93703e8d349e407d0c5145 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 10 Apr 2019 13:22:50 +0100 Subject: [PATCH 02/19] Add key derivation for static keys. --- .../bramble/api/crypto/TransportCrypto.java | 18 +++ .../api/transport/StaticTransportKeys.java | 31 +++++ .../api/transport/TransportConstants.java | 23 ++++ .../bramble/crypto/TransportCryptoImpl.java | 110 ++++++++++++++++-- .../bramble/crypto/KeyDerivationTest.java | 3 +- 5 files changed, 176 insertions(+), 9 deletions(-) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java index b51dc972a..37be4fe8c 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java @@ -1,6 +1,7 @@ package org.briarproject.bramble.api.crypto; import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.transport.StaticTransportKeys; import org.briarproject.bramble.api.transport.TransportKeys; /** @@ -25,6 +26,23 @@ public interface TransportCrypto { */ TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod); + /** + * Derives static transport keys for the given transport in the given time + * period from the given root key. + * + * @param alice whether the keys are for use by Alice or Bob. + */ + StaticTransportKeys deriveStaticTransportKeys(TransportId t, + SecretKey rootKey, boolean alice, long timePeriod); + + /** + * Updates the given static transport keys to the given time period. If + * the keys are for the given period or any later period they are not + * updated. + */ + StaticTransportKeys updateTransportKeys(StaticTransportKeys k, + long timePeriod); + /** * Encodes the pseudo-random tag that is used to recognise a stream. */ diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java new file mode 100644 index 000000000..22f85d976 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java @@ -0,0 +1,31 @@ +package org.briarproject.bramble.api.transport; + +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public class StaticTransportKeys extends TransportKeys { + + private final SecretKey rootKey; + private final boolean alice; + + public StaticTransportKeys(TransportId transportId, IncomingKeys inPrev, + IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr, + SecretKey rootKey, boolean alice) { + super(transportId, inPrev, inCurr, inNext, outCurr); + this.rootKey = rootKey; + this.alice = alice; + } + + public SecretKey getRootKey() { + return rootKey; + } + + public boolean isAlice() { + return alice; + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportConstants.java index cf5502a5f..2f58af225 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 @@ -108,4 +108,27 @@ public interface TransportConstants { */ String ROTATE_LABEL = "org.briarproject.bramble.transport/ROTATE"; + /** + * Label for deriving Alice's static tag key from the root key. + */ + String ALICE_STATIC_TAG_LABEL = + "org.briarproject.bramble.transport/ALICE_STATIC_TAG_KEY"; + + /** + * Label for deriving Bob's static tag key from the root key. + */ + String BOB_STATIC_TAG_LABEL = + "org.briarproject.bramble.transport/BOB_STATIC_TAG_KEY"; + + /** + * Label for deriving Alice's static header key from the root key. + */ + String ALICE_STATIC_HEADER_LABEL = + "org.briarproject.bramble.transport/ALICE_STATIC_HEADER_KEY"; + + /** + * Label for deriving Bob's static header key from the root key. + */ + String BOB_STATIC_HEADER_LABEL = + "org.briarproject.bramble.transport/BOB_STATIC_HEADER_KEY"; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java index 003a2ab63..a05b2487b 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java @@ -6,17 +6,21 @@ 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.StaticTransportKeys; 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 org.spongycastle.crypto.digests.Blake2bDigest; import javax.inject.Inject; +import static java.lang.System.arraycopy; import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_HEADER_LABEL; +import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_STATIC_HEADER_LABEL; +import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_STATIC_TAG_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_TAG_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.BOB_HEADER_LABEL; +import static org.briarproject.bramble.api.transport.TransportConstants.BOB_STATIC_HEADER_LABEL; +import static org.briarproject.bramble.api.transport.TransportConstants.BOB_STATIC_TAG_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.BOB_TAG_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.ROTATE_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; @@ -24,6 +28,9 @@ 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; +import static org.briarproject.bramble.util.ByteUtils.writeUint16; +import static org.briarproject.bramble.util.ByteUtils.writeUint64; +import static org.briarproject.bramble.util.StringUtils.toUtf8; class TransportCryptoImpl implements TransportCrypto { @@ -90,24 +97,111 @@ class TransportCryptoImpl implements TransportCrypto { private SecretKey rotateKey(SecretKey k, long timePeriod) { byte[] period = new byte[INT_64_BYTES]; - ByteUtils.writeUint64(timePeriod, period, 0); + writeUint64(timePeriod, period, 0); return crypto.deriveKey(ROTATE_LABEL, k, period); } private SecretKey deriveTagKey(SecretKey master, TransportId t, boolean alice) { String label = alice ? ALICE_TAG_LABEL : BOB_TAG_LABEL; - byte[] id = StringUtils.toUtf8(t.getString()); + byte[] id = toUtf8(t.getString()); return crypto.deriveKey(label, master, id); } private SecretKey deriveHeaderKey(SecretKey master, TransportId t, boolean alice) { String label = alice ? ALICE_HEADER_LABEL : BOB_HEADER_LABEL; - byte[] id = StringUtils.toUtf8(t.getString()); + byte[] id = toUtf8(t.getString()); return crypto.deriveKey(label, master, id); } + @Override + public StaticTransportKeys deriveStaticTransportKeys(TransportId t, + SecretKey rootKey, boolean alice, long timePeriod) { + if (timePeriod < 1) throw new IllegalArgumentException(); + IncomingKeys inPrev = deriveStaticIncomingKeys(t, rootKey, alice, + timePeriod - 1); + IncomingKeys inCurr = deriveStaticIncomingKeys(t, rootKey, alice, + timePeriod); + IncomingKeys inNext = deriveStaticIncomingKeys(t, rootKey, alice, + timePeriod + 1); + OutgoingKeys outCurr = deriveStaticOutgoingKeys(t, rootKey, alice, + timePeriod); + return new StaticTransportKeys(t, inPrev, inCurr, inNext, outCurr, + rootKey, alice); + } + + private IncomingKeys deriveStaticIncomingKeys(TransportId t, + SecretKey rootKey, boolean alice, long timePeriod) { + SecretKey tag = deriveStaticTagKey(t, rootKey, !alice, timePeriod); + SecretKey header = deriveStaticHeaderKey(t, rootKey, !alice, + timePeriod); + return new IncomingKeys(tag, header, timePeriod); + } + + private OutgoingKeys deriveStaticOutgoingKeys(TransportId t, + SecretKey rootKey, boolean alice, long timePeriod) { + SecretKey tag = deriveStaticTagKey(t, rootKey, alice, timePeriod); + SecretKey header = deriveStaticHeaderKey(t, rootKey, alice, timePeriod); + return new OutgoingKeys(tag, header, timePeriod, true); + } + + private SecretKey deriveStaticTagKey(TransportId t, SecretKey root, + boolean alice, long timePeriod) { + String label = alice ? ALICE_STATIC_TAG_LABEL : BOB_STATIC_TAG_LABEL; + byte[] id = toUtf8(t.getString()); + byte[] period = new byte[INT_64_BYTES]; + writeUint64(timePeriod, period, 0); + return crypto.deriveKey(label, root, id, period); + } + + private SecretKey deriveStaticHeaderKey(TransportId t, SecretKey root, + boolean alice, long timePeriod) { + String label = + alice ? ALICE_STATIC_HEADER_LABEL : BOB_STATIC_HEADER_LABEL; + byte[] id = toUtf8(t.getString()); + byte[] period = new byte[INT_64_BYTES]; + writeUint64(timePeriod, period, 0); + return crypto.deriveKey(label, root, id, period); + } + + @Override + public StaticTransportKeys updateTransportKeys(StaticTransportKeys k, + long timePeriod) { + long elapsed = timePeriod - k.getTimePeriod(); + TransportId t = k.getTransportId(); + SecretKey rootKey = k.getRootKey(); + boolean alice = k.isAlice(); + if (elapsed <= 0) { + // The keys are for the given period or later - don't update them + return k; + } else if (elapsed == 1) { + // The keys are one period old - shift by one period + IncomingKeys inPrev = k.getCurrentIncomingKeys(); + IncomingKeys inCurr = k.getNextIncomingKeys(); + IncomingKeys inNext = deriveStaticIncomingKeys(t, rootKey, alice, + timePeriod + 1); + OutgoingKeys outCurr = deriveStaticOutgoingKeys(t, rootKey, alice, + timePeriod); + return new StaticTransportKeys(t, inPrev, inCurr, inNext, outCurr, + rootKey, alice); + } else if (elapsed == 2) { + // The keys are two periods old - shift by two periods + IncomingKeys inPrev = k.getNextIncomingKeys(); + IncomingKeys inCurr = deriveStaticIncomingKeys(t, rootKey, alice, + timePeriod); + IncomingKeys inNext = deriveStaticIncomingKeys(t, rootKey, alice, + timePeriod + 1); + OutgoingKeys outCurr = deriveStaticOutgoingKeys(t, rootKey, alice, + timePeriod); + return new StaticTransportKeys(t, inPrev, inCurr, inNext, outCurr, + rootKey, alice); + } else { + // The keys are more than two periods old - derive fresh keys + return deriveStaticTransportKeys(t, rootKey, alice, timePeriod); + } + } + @Override public void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion, long streamNumber) { @@ -124,14 +218,14 @@ class TransportCryptoImpl implements TransportCrypto { // 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); + writeUint16(protocolVersion, protocolVersionBytes, 0); prf.update(protocolVersionBytes, 0, protocolVersionBytes.length); byte[] streamNumberBytes = new byte[INT_64_BYTES]; - ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0); + 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); + arraycopy(mac, 0, tag, 0, TAG_LENGTH); } } 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 45c68c818..41bbc11db 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 @@ -20,6 +20,7 @@ import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getTransportId; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; public class KeyDerivationTest extends BrambleTestCase { @@ -137,7 +138,7 @@ public class KeyDerivationTest extends BrambleTestCase { @Test public void testTransportIdAffectsOutput() { TransportId transportId1 = getTransportId(); - assertFalse(transportId.getString().equals(transportId1.getString())); + assertNotEquals(transportId.getString(), transportId1.getString()); TransportKeys k = transportCrypto.deriveTransportKeys(transportId, master, 123, true, true); TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId1, From d5ac2c9ead5626b54f36808a87ccc51f8d1dd4cd Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 10 Apr 2019 14:30:01 +0100 Subject: [PATCH 03/19] Fix master secret/master key/root key terminology. In the key agreement, contact exchange and introduction protocols we refer to the master key. In the transport protocol we refer to the root key. When adding a contact in person, the key agreement protocol's master key is used as the transport root key. When a contact is introduced, the introduction protocol's master key is used as the transport root key. --- .../api/contact/ContactExchangeTask.java | 10 +++--- .../bramble/api/contact/ContactManager.java | 6 ++-- .../bramble/api/crypto/TransportCrypto.java | 4 +-- .../keyagreement/KeyAgreementConstants.java | 4 +-- .../bramble/api/transport/KeyManager.java | 2 +- .../api/transport/TransportConstants.java | 8 ++--- .../contact/ContactExchangeTaskImpl.java | 18 +++++------ .../bramble/contact/ContactManagerImpl.java | 12 +++---- .../bramble/crypto/TransportCryptoImpl.java | 31 +++++++++---------- .../keyagreement/KeyAgreementProtocol.java | 6 ++-- .../keyagreement/KeyAgreementTaskImpl.java | 4 +-- .../bramble/transport/KeyManagerImpl.java | 4 +-- .../transport/TransportKeyManager.java | 2 +- .../transport/TransportKeyManagerImpl.java | 4 +-- .../contact/ContactManagerImplTest.java | 6 ++-- .../bramble/crypto/KeyDerivationTest.java | 30 +++++++++--------- .../KeyAgreementProtocolTest.java | 26 ++++++++-------- .../TransportKeyManagerImplTest.java | 24 +++++++------- .../introduction/IntroductionCrypto.java | 3 +- .../SimplexMessagingIntegrationTest.java | 4 +-- 20 files changed, 103 insertions(+), 105 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactExchangeTask.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactExchangeTask.java index d54bff1c3..c72b0fa7e 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactExchangeTask.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactExchangeTask.java @@ -18,30 +18,30 @@ public interface ContactExchangeTask { byte PROTOCOL_VERSION = 1; /** - * Label for deriving Alice's header key from the master secret. + * Label for deriving Alice's header key from the master key. */ String ALICE_KEY_LABEL = "org.briarproject.bramble.contact/ALICE_HEADER_KEY"; /** - * Label for deriving Bob's header key from the master secret. + * Label for deriving Bob's header key from the master key. */ String BOB_KEY_LABEL = "org.briarproject.bramble.contact/BOB_HEADER_KEY"; /** - * Label for deriving Alice's key binding nonce from the master secret. + * Label for deriving Alice's key binding nonce from the master key. */ String ALICE_NONCE_LABEL = "org.briarproject.bramble.contact/ALICE_NONCE"; /** - * Label for deriving Bob's key binding nonce from the master secret. + * Label for deriving Bob's key binding nonce from the master key. */ String BOB_NONCE_LABEL = "org.briarproject.bramble.contact/BOB_NONCE"; /** * Exchanges contact information with a remote peer. */ - void startExchange(LocalAuthor localAuthor, SecretKey masterSecret, + void startExchange(LocalAuthor localAuthor, SecretKey masterKey, DuplexTransportConnection conn, TransportId transportId, boolean alice); } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java index 7996cbf54..72c352206 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java @@ -13,8 +13,6 @@ import java.util.Collection; import javax.annotation.Nullable; -import static org.briarproject.bramble.api.contact.PendingContact.PendingContactState.FAILED; - @NotNullByDefault public interface ContactManager { @@ -33,7 +31,7 @@ public interface ContactManager { * @param alice true if the local party is Alice */ ContactId addContact(Transaction txn, Author remote, AuthorId local, - SecretKey master, long timestamp, boolean alice, boolean verified, + SecretKey rootKey, long timestamp, boolean alice, boolean verified, boolean active) throws DbException; /** @@ -50,7 +48,7 @@ public interface ContactManager { * * @param alice true if the local party is Alice */ - ContactId addContact(Author remote, AuthorId local, SecretKey master, + ContactId addContact(Author remote, AuthorId local, SecretKey rootKey, long timestamp, boolean alice, boolean verified, boolean active) throws DbException; diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java index 37be4fe8c..a984a5c6f 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java @@ -12,12 +12,12 @@ public interface TransportCrypto { /** * Derives initial transport keys for the given transport in the given - * time period from the given master secret. + * time period from the given root key. * * @param alice whether the keys are for use by Alice or Bob. * @param active whether the keys are usable for outgoing streams. */ - TransportKeys deriveTransportKeys(TransportId t, SecretKey master, + TransportKeys deriveTransportKeys(TransportId t, SecretKey rootKey, long timePeriod, boolean alice, boolean active); /** diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/keyagreement/KeyAgreementConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/keyagreement/KeyAgreementConstants.java index 4041d0ce4..2f5170b91 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/keyagreement/KeyAgreementConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/keyagreement/KeyAgreementConstants.java @@ -40,8 +40,8 @@ public interface KeyAgreementConstants { "org.briarproject.bramble.keyagreement/SHARED_SECRET"; /** - * Label for deriving the master secret. + * Label for deriving the master key. */ - String MASTER_SECRET_LABEL = + String MASTER_KEY_LABEL = "org.briarproject.bramble.keyagreement/MASTER_SECRET"; } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java index 7071a5e47..827c94fb7 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java @@ -28,7 +28,7 @@ public interface KeyManager { * @param active whether the derived keys can be used for outgoing streams */ Map addContact(Transaction txn, ContactId c, - SecretKey master, long timestamp, boolean alice, boolean active) + SecretKey rootKey, long timestamp, boolean alice, boolean active) throws DbException; /** 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 2f58af225..60e9197ee 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 @@ -82,23 +82,23 @@ public interface TransportConstants { int REORDERING_WINDOW_SIZE = 32; /** - * Label for deriving Alice's initial tag key from the master secret. + * Label for deriving Alice's initial tag key from the root key. */ String ALICE_TAG_LABEL = "org.briarproject.bramble.transport/ALICE_TAG_KEY"; /** - * Label for deriving Bob's initial tag key from the master secret. + * Label for deriving Bob's initial tag key from the root key. */ String BOB_TAG_LABEL = "org.briarproject.bramble.transport/BOB_TAG_KEY"; /** - * Label for deriving Alice's initial header key from the master secret. + * Label for deriving Alice's initial header key from the root key. */ String ALICE_HEADER_LABEL = "org.briarproject.bramble.transport/ALICE_HEADER_KEY"; /** - * Label for deriving Bob's initial header key from the master secret. + * Label for deriving Bob's initial header key from the root key. */ String BOB_HEADER_LABEL = "org.briarproject.bramble.transport/BOB_HEADER_KEY"; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactExchangeTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactExchangeTaskImpl.java index 76163e696..061a43a48 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactExchangeTaskImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactExchangeTaskImpl.java @@ -77,7 +77,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask { private volatile LocalAuthor localAuthor; private volatile DuplexTransportConnection conn; private volatile TransportId transportId; - private volatile SecretKey masterSecret; + private volatile SecretKey masterKey; private volatile boolean alice; @Inject @@ -104,13 +104,13 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask { } @Override - public void startExchange(LocalAuthor localAuthor, SecretKey masterSecret, + public void startExchange(LocalAuthor localAuthor, SecretKey masterKey, DuplexTransportConnection conn, TransportId transportId, boolean alice) { this.localAuthor = localAuthor; this.conn = conn; this.transportId = transportId; - this.masterSecret = masterSecret; + this.masterKey = masterKey; this.alice = alice; start(); } @@ -142,9 +142,9 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask { } // Derive the header keys for the transport streams - SecretKey aliceHeaderKey = crypto.deriveKey(ALICE_KEY_LABEL, - masterSecret, new byte[] {PROTOCOL_VERSION}); - SecretKey bobHeaderKey = crypto.deriveKey(BOB_KEY_LABEL, masterSecret, + SecretKey aliceHeaderKey = crypto.deriveKey(ALICE_KEY_LABEL, masterKey, + new byte[] {PROTOCOL_VERSION}); + SecretKey bobHeaderKey = crypto.deriveKey(BOB_KEY_LABEL, masterKey, new byte[] {PROTOCOL_VERSION}); // Create the readers @@ -163,9 +163,9 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask { .createRecordWriter(streamWriter.getOutputStream()); // Derive the nonces to be signed - byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret, + byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterKey, new byte[] {PROTOCOL_VERSION}); - byte[] bobNonce = crypto.mac(BOB_NONCE_LABEL, masterSecret, + byte[] bobNonce = crypto.mac(BOB_NONCE_LABEL, masterKey, new byte[] {PROTOCOL_VERSION}); byte[] localNonce = alice ? aliceNonce : bobNonce; byte[] remoteNonce = alice ? bobNonce : aliceNonce; @@ -293,7 +293,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask { throws DbException { return db.transactionWithResult(false, txn -> { ContactId contactId = contactManager.addContact(txn, remoteAuthor, - localAuthor.getId(), masterSecret, timestamp, alice, + localAuthor.getId(), masterKey, timestamp, alice, true, true); transportPropertyManager.addRemoteProperties(txn, contactId, remoteProperties); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java index bee28f7d2..1bae6b16d 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java @@ -69,10 +69,10 @@ class ContactManagerImpl implements ContactManager { @Override public ContactId addContact(Transaction txn, Author remote, AuthorId local, - SecretKey master, long timestamp, boolean alice, boolean verified, + SecretKey rootKey, long timestamp, boolean alice, boolean verified, boolean active) throws DbException { ContactId c = db.addContact(txn, remote, local, verified, active); - keyManager.addContact(txn, c, master, timestamp, alice, active); + keyManager.addContact(txn, c, rootKey, timestamp, alice, active); Contact contact = db.getContact(txn, c); for (ContactHook hook : hooks) hook.addingContact(txn, contact); return c; @@ -88,11 +88,11 @@ class ContactManagerImpl implements ContactManager { } @Override - public ContactId addContact(Author remote, AuthorId local, SecretKey master, - long timestamp, boolean alice, boolean verified, boolean active) - throws DbException { + public ContactId addContact(Author remote, AuthorId local, + SecretKey rootKey, long timestamp, boolean alice, boolean verified, + boolean active) throws DbException { return db.transactionWithResult(false, txn -> - addContact(txn, remote, local, master, timestamp, alice, + addContact(txn, remote, local, rootKey, timestamp, alice, verified, active)); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java index a05b2487b..350fd2257 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java @@ -43,12 +43,12 @@ class TransportCryptoImpl implements TransportCrypto { @Override public TransportKeys deriveTransportKeys(TransportId t, - SecretKey master, long timePeriod, boolean alice, boolean active) { - // 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); + SecretKey rootKey, long timePeriod, boolean alice, boolean active) { + // Keys for the previous period are derived from the root key + SecretKey inTagPrev = deriveTagKey(rootKey, t, !alice); + SecretKey inHeaderPrev = deriveHeaderKey(rootKey, t, !alice); + SecretKey outTagPrev = deriveTagKey(rootKey, t, alice); + SecretKey outHeaderPrev = deriveHeaderKey(rootKey, t, alice); // Derive the keys for the current and next periods SecretKey inTagCurr = rotateKey(inTagPrev, timePeriod); SecretKey inHeaderCurr = rotateKey(inHeaderPrev, timePeriod); @@ -70,8 +70,7 @@ class TransportCryptoImpl implements TransportCrypto { } @Override - public TransportKeys rotateTransportKeys(TransportKeys k, - long timePeriod) { + public TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod) { if (k.getTimePeriod() >= timePeriod) return k; IncomingKeys inPrev = k.getPreviousIncomingKeys(); IncomingKeys inCurr = k.getCurrentIncomingKeys(); @@ -101,18 +100,18 @@ class TransportCryptoImpl implements TransportCrypto { return crypto.deriveKey(ROTATE_LABEL, k, period); } - private SecretKey deriveTagKey(SecretKey master, TransportId t, + private SecretKey deriveTagKey(SecretKey rootKey, TransportId t, boolean alice) { String label = alice ? ALICE_TAG_LABEL : BOB_TAG_LABEL; byte[] id = toUtf8(t.getString()); - return crypto.deriveKey(label, master, id); + return crypto.deriveKey(label, rootKey, id); } - private SecretKey deriveHeaderKey(SecretKey master, TransportId t, + private SecretKey deriveHeaderKey(SecretKey rootKey, TransportId t, boolean alice) { String label = alice ? ALICE_HEADER_LABEL : BOB_HEADER_LABEL; byte[] id = toUtf8(t.getString()); - return crypto.deriveKey(label, master, id); + return crypto.deriveKey(label, rootKey, id); } @Override @@ -146,23 +145,23 @@ class TransportCryptoImpl implements TransportCrypto { return new OutgoingKeys(tag, header, timePeriod, true); } - private SecretKey deriveStaticTagKey(TransportId t, SecretKey root, + private SecretKey deriveStaticTagKey(TransportId t, SecretKey rootKey, boolean alice, long timePeriod) { String label = alice ? ALICE_STATIC_TAG_LABEL : BOB_STATIC_TAG_LABEL; byte[] id = toUtf8(t.getString()); byte[] period = new byte[INT_64_BYTES]; writeUint64(timePeriod, period, 0); - return crypto.deriveKey(label, root, id, period); + return crypto.deriveKey(label, rootKey, id, period); } - private SecretKey deriveStaticHeaderKey(TransportId t, SecretKey root, + private SecretKey deriveStaticHeaderKey(TransportId t, SecretKey rootKey, boolean alice, long timePeriod) { String label = alice ? ALICE_STATIC_HEADER_LABEL : BOB_STATIC_HEADER_LABEL; byte[] id = toUtf8(t.getString()); byte[] period = new byte[INT_64_BYTES]; writeUint64(timePeriod, period, 0); - return crypto.deriveKey(label, root, id, period); + return crypto.deriveKey(label, rootKey, id, period); } @Override diff --git a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocol.java b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocol.java index 5825c9500..682041c90 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocol.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocol.java @@ -14,7 +14,7 @@ import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Arrays; -import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_SECRET_LABEL; +import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_KEY_LABEL; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL; @@ -90,7 +90,7 @@ class KeyAgreementProtocol { /** * Perform the BQP protocol. * - * @return the negotiated master secret. + * @return the negotiated master key. * @throws AbortException when the protocol may have been tampered with. * @throws IOException for all other other connection errors. */ @@ -115,7 +115,7 @@ class KeyAgreementProtocol { receiveConfirm(s, theirPublicKey); sendConfirm(s, theirPublicKey); } - return crypto.deriveKey(MASTER_SECRET_LABEL, s); + return crypto.deriveKey(MASTER_KEY_LABEL, s); } catch (AbortException e) { sendAbort(e.getCause() != null); throw e; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskImpl.java index b6e994231..e2735c394 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskImpl.java @@ -114,9 +114,9 @@ class KeyAgreementTaskImpl extends Thread implements KeyAgreementTask, keyAgreementCrypto, payloadEncoder, transport, remotePayload, localPayload, localKeyPair, alice); try { - SecretKey master = protocol.perform(); + SecretKey masterKey = protocol.perform(); KeyAgreementResult result = - new KeyAgreementResult(master, transport.getConnection(), + new KeyAgreementResult(masterKey, transport.getConnection(), transport.getTransportId(), alice); LOG.info("Finished BQP protocol"); // Broadcast result to caller diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java index 624c8b2b8..482ee5b7f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java @@ -96,13 +96,13 @@ class KeyManagerImpl implements KeyManager, Service, EventListener { @Override public Map addContact(Transaction txn, ContactId c, - SecretKey master, long timestamp, boolean alice, boolean active) + SecretKey rootKey, long timestamp, boolean alice, boolean active) throws DbException { Map ids = new HashMap<>(); for (Entry e : managers.entrySet()) { TransportId t = e.getKey(); TransportKeyManager m = e.getValue(); - ids.put(t, m.addContact(txn, c, master, timestamp, alice, active)); + ids.put(t, m.addContact(txn, c, rootKey, timestamp, alice, active)); } return ids; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java index b407db16c..fa3f54e11 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java @@ -15,7 +15,7 @@ interface TransportKeyManager { void start(Transaction txn) throws DbException; - KeySetId addContact(Transaction txn, ContactId c, SecretKey master, + KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey, long timestamp, boolean alice, boolean active) throws DbException; void activateKeys(Transaction txn, KeySetId k) throws DbException; 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 f23ad45f3..d5442f356 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 @@ -170,7 +170,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { } @Override - public KeySetId addContact(Transaction txn, ContactId c, SecretKey master, + public KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey, long timestamp, boolean alice, boolean active) throws DbException { lock.lock(); try { @@ -178,7 +178,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { long timePeriod = timestamp / timePeriodLength; // Derive the transport keys TransportKeys k = transportCrypto.deriveTransportKeys(transportId, - master, timePeriod, alice, active); + rootKey, timePeriod, alice, active); // Rotate the keys to the current time period if necessary timePeriod = clock.currentTimeMillis() / timePeriodLength; k = transportCrypto.rotateTransportKeys(k, timePeriod); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/contact/ContactManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/contact/ContactManagerImplTest.java index 375fcade5..9289bf4e8 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/contact/ContactManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/contact/ContactManagerImplTest.java @@ -64,7 +64,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase { @Test public void testAddContact() throws Exception { - SecretKey master = getSecretKey(); + SecretKey rootKey = getSecretKey(); long timestamp = System.currentTimeMillis(); boolean alice = new Random().nextBoolean(); Transaction txn = new Transaction(null, false); @@ -73,14 +73,14 @@ public class ContactManagerImplTest extends BrambleMockTestCase { oneOf(db).transactionWithResult(with(false), withDbCallable(txn)); oneOf(db).addContact(txn, remote, local, verified, active); will(returnValue(contactId)); - oneOf(keyManager).addContact(txn, contactId, master, timestamp, + oneOf(keyManager).addContact(txn, contactId, rootKey, timestamp, alice, active); oneOf(db).getContact(txn, contactId); will(returnValue(contact)); }}); assertEquals(contactId, contactManager.addContact(remote, local, - master, timestamp, alice, verified, active)); + rootKey, timestamp, alice, verified, active)); } @Test 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 41bbc11db..33c13753b 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 @@ -30,12 +30,12 @@ public class KeyDerivationTest extends BrambleTestCase { private final TransportCrypto transportCrypto = new TransportCryptoImpl(crypto); private final TransportId transportId = getTransportId(); - private final SecretKey master = getSecretKey(); + private final SecretKey rootKey = getSecretKey(); @Test public void testKeysAreDistinct() { TransportKeys k = transportCrypto.deriveTransportKeys(transportId, - master, 123, true, true); + rootKey, 123, true, true); assertAllDifferent(k); } @@ -43,9 +43,9 @@ public class KeyDerivationTest extends BrambleTestCase { public void testCurrentKeysMatchCurrentKeysOfContact() { // Start in time period 123 TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, - master, 123, true, true); + rootKey, 123, true, true); TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, - master, 123, false, true); + rootKey, 123, false, true); // Alice's incoming keys should equal Bob's outgoing keys assertArrayEquals(kA.getCurrentIncomingKeys().getTagKey().getBytes(), kB.getCurrentOutgoingKeys().getTagKey().getBytes()); @@ -75,9 +75,9 @@ public class KeyDerivationTest extends BrambleTestCase { public void testPreviousKeysMatchPreviousKeysOfContact() { // Start in time period 123 TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, - master, 123, true, true); + rootKey, 123, true, true); TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, - master, 123, false, true); + rootKey, 123, false, true); // Compare Alice's previous keys in period 456 with Bob's current keys // in period 455 kA = transportCrypto.rotateTransportKeys(kA, 456); @@ -102,9 +102,9 @@ public class KeyDerivationTest extends BrambleTestCase { public void testNextKeysMatchNextKeysOfContact() { // Start in time period 123 TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, - master, 123, true, true); + rootKey, 123, true, true); TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, - master, 123, false, true); + rootKey, 123, false, true); // Compare Alice's current keys in period 456 with Bob's next keys in // period 455 kA = transportCrypto.rotateTransportKeys(kA, 456); @@ -125,13 +125,13 @@ public class KeyDerivationTest extends BrambleTestCase { } @Test - public void testMasterKeyAffectsOutput() { - SecretKey master1 = getSecretKey(); - assertFalse(Arrays.equals(master.getBytes(), master1.getBytes())); + public void testRootKeyAffectsOutput() { + SecretKey rootKey1 = getSecretKey(); + assertFalse(Arrays.equals(rootKey.getBytes(), rootKey1.getBytes())); TransportKeys k = transportCrypto.deriveTransportKeys(transportId, - master, 123, true, true); + rootKey, 123, true, true); TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId, - master1, 123, true, true); + rootKey1, 123, true, true); assertAllDifferent(k, k1); } @@ -140,9 +140,9 @@ public class KeyDerivationTest extends BrambleTestCase { TransportId transportId1 = getTransportId(); assertNotEquals(transportId.getString(), transportId1.getString()); TransportKeys k = transportCrypto.deriveTransportKeys(transportId, - master, 123, true, true); + rootKey, 123, true, true); TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId1, - master, 123, true, true); + rootKey, 123, true, true); assertAllDifferent(k, k1); } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocolTest.java b/bramble-core/src/test/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocolTest.java index e070db6a9..516f7f1b2 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocolTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocolTest.java @@ -17,7 +17,7 @@ import org.junit.Rule; import org.junit.Test; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH; -import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_SECRET_LABEL; +import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_KEY_LABEL; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; @@ -74,7 +74,7 @@ public class KeyAgreementProtocolTest extends BrambleTestCase { Payload ourPayload = new Payload(aliceCommit, null); KeyPair ourKeyPair = new KeyPair(ourPubKey, null); SecretKey sharedSecret = getSecretKey(); - SecretKey masterSecret = getSecretKey(); + SecretKey masterKey = getSecretKey(); KeyAgreementProtocol protocol = new KeyAgreementProtocol(callbacks, crypto, keyAgreementCrypto, payloadEncoder, transport, @@ -134,13 +134,13 @@ public class KeyAgreementProtocolTest extends BrambleTestCase { true, false); will(returnValue(bobConfirm)); - // Alice computes master secret - oneOf(crypto).deriveKey(MASTER_SECRET_LABEL, sharedSecret); - will(returnValue(masterSecret)); + // Alice derives master key + oneOf(crypto).deriveKey(MASTER_KEY_LABEL, sharedSecret); + will(returnValue(masterKey)); }}); // execute - assertThat(masterSecret, is(equalTo(protocol.perform()))); + assertThat(masterKey, is(equalTo(protocol.perform()))); } @Test @@ -150,7 +150,7 @@ public class KeyAgreementProtocolTest extends BrambleTestCase { Payload ourPayload = new Payload(bobCommit, null); KeyPair ourKeyPair = new KeyPair(ourPubKey, null); SecretKey sharedSecret = getSecretKey(); - SecretKey masterSecret = getSecretKey(); + SecretKey masterKey = getSecretKey(); KeyAgreementProtocol protocol = new KeyAgreementProtocol(callbacks, crypto, keyAgreementCrypto, payloadEncoder, transport, @@ -209,13 +209,13 @@ public class KeyAgreementProtocolTest extends BrambleTestCase { will(returnValue(bobConfirm)); oneOf(transport).sendConfirm(bobConfirm); - // Bob computes master secret - oneOf(crypto).deriveKey(MASTER_SECRET_LABEL, sharedSecret); - will(returnValue(masterSecret)); + // Bob derives master key + oneOf(crypto).deriveKey(MASTER_KEY_LABEL, sharedSecret); + will(returnValue(masterKey)); }}); // execute - assertThat(masterSecret, is(equalTo(protocol.perform()))); + assertThat(masterKey, is(equalTo(protocol.perform()))); } @Test(expected = AbortException.class) @@ -373,8 +373,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase { // Alice aborts oneOf(transport).sendAbort(false); - // Alice never computes master secret - never(crypto).deriveKey(MASTER_SECRET_LABEL, sharedSecret); + // Alice never derives master key + never(crypto).deriveKey(MASTER_KEY_LABEL, sharedSecret); }}); // execute 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 8b79d4849..2f0b7d58a 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 @@ -64,7 +64,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { private final KeySetId keySetId1 = new KeySetId(456); private final SecretKey tagKey = TestUtils.getSecretKey(); private final SecretKey headerKey = TestUtils.getSecretKey(); - private final SecretKey masterKey = TestUtils.getSecretKey(); + private final SecretKey rootKey = TestUtils.getSecretKey(); private final Random random = new Random(); @Test @@ -120,7 +120,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { Transaction txn = new Transaction(null, false); context.checking(new Expectations() {{ - oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, + oneOf(transportCrypto).deriveTransportKeys(transportId, rootKey, 999, alice, true); will(returnValue(transportKeys)); // Get the current time (1 ms after start of time period 1000) @@ -147,7 +147,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { // The timestamp is 1 ms before the start of time period 1000 long timestamp = timePeriodLength * 1000 - 1; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, - masterKey, timestamp, alice, true)); + rootKey, timestamp, alice, true)); assertTrue(transportKeyManager.canSendOutgoingStreams(contactId)); } @@ -180,7 +180,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { // The timestamp is at the start of time period 1000 long timestamp = timePeriodLength * 1000; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, - masterKey, timestamp, alice, true)); + rootKey, timestamp, alice, true)); assertFalse(transportKeyManager.canSendOutgoingStreams(contactId)); assertNull(transportKeyManager.getStreamContext(txn, contactId)); } @@ -206,7 +206,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { // The timestamp is at the start of time period 1000 long timestamp = timePeriodLength * 1000; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, - masterKey, timestamp, alice, true)); + rootKey, timestamp, alice, true)); // The first request should return a stream context assertTrue(transportKeyManager.canSendOutgoingStreams(contactId)); StreamContext ctx = transportKeyManager.getStreamContext(txn, @@ -238,7 +238,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { // The timestamp is at the start of time period 1000 long timestamp = timePeriodLength * 1000; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, - masterKey, timestamp, alice, active)); + rootKey, timestamp, alice, active)); assertEquals(active, transportKeyManager.canSendOutgoingStreams(contactId)); // The tag should not be recognised @@ -256,7 +256,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { List tags = new ArrayList<>(); context.checking(new Expectations() {{ - oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, + oneOf(transportCrypto).deriveTransportKeys(transportId, rootKey, 1000, alice, true); will(returnValue(transportKeys)); // Get the current time (the start of time period 1000) @@ -291,7 +291,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { // The timestamp is at the start of time period 1000 long timestamp = timePeriodLength * 1000; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, - masterKey, timestamp, alice, true)); + rootKey, timestamp, alice, true)); assertTrue(transportKeyManager.canSendOutgoingStreams(contactId)); // Use the first tag (previous time period, stream number 0) assertEquals(REORDERING_WINDOW_SIZE * 3, tags.size()); @@ -394,7 +394,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { // The timestamp is at the start of time period 1000 long timestamp = timePeriodLength * 1000; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, - masterKey, timestamp, alice, false)); + rootKey, timestamp, alice, false)); // The keys are inactive so no stream context should be returned assertFalse(transportKeyManager.canSendOutgoingStreams(contactId)); assertNull(transportKeyManager.getStreamContext(txn, contactId)); @@ -421,7 +421,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { List tags = new ArrayList<>(); context.checking(new Expectations() {{ - oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, + oneOf(transportCrypto).deriveTransportKeys(transportId, rootKey, 1000, alice, false); will(returnValue(transportKeys)); // Get the current time (the start of time period 1000) @@ -460,7 +460,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { // The timestamp is at the start of time period 1000 long timestamp = timePeriodLength * 1000; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, - masterKey, timestamp, alice, false)); + rootKey, timestamp, alice, false)); // The keys are inactive so no stream context should be returned assertFalse(transportKeyManager.canSendOutgoingStreams(contactId)); assertNull(transportKeyManager.getStreamContext(txn, contactId)); @@ -488,7 +488,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { private void expectAddContactNoRotation(boolean alice, boolean active, TransportKeys transportKeys, Transaction txn) throws Exception { context.checking(new Expectations() {{ - oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey, + oneOf(transportCrypto).deriveTransportKeys(transportId, rootKey, 1000, alice, active); will(returnValue(transportKeys)); // Get the current time (the start of time period 1000) diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCrypto.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCrypto.java index 37f7aa10f..79b77a149 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCrypto.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCrypto.java @@ -41,7 +41,8 @@ interface IntroductionCrypto { /** * Derives a MAC key from the session's master key for Alice or Bob. * - * @param masterKey The key returned by {@link #deriveMasterKey(IntroduceeSession)} + * @param masterKey The key returned by + * {@link #deriveMasterKey(IntroduceeSession)} * @param alice true for Alice's MAC key, false for Bob's * @return The MAC key */ diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java index af0c4bea9..bbe1baaf3 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java @@ -56,7 +56,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { private final File testDir = getTestDirectory(); private final File aliceDir = new File(testDir, "alice"); private final File bobDir = new File(testDir, "bob"); - private final SecretKey master = getSecretKey(); + private final SecretKey rootKey = getSecretKey(); private final long timestamp = System.currentTimeMillis(); private SimplexMessagingIntegrationTestComponent alice, bob; @@ -110,7 +110,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { lifecycleManager.waitForStartup(); // Add the other user as a contact ContactManager contactManager = device.getContactManager(); - return contactManager.addContact(remote, local.getId(), master, + return contactManager.addContact(remote, local.getId(), rootKey, timestamp, alice, true, true); } From fccf735a8905e7c09683e95ede6c9ccf984e9973 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 10 Apr 2019 15:18:26 +0100 Subject: [PATCH 04/19] Add unit tests for static key derivation. --- .../bramble/api/crypto/TransportCrypto.java | 4 +- .../bramble/crypto/TransportCryptoImpl.java | 6 +- .../bramble/crypto/KeyDerivationTest.java | 168 ----------------- .../crypto/KeyDerivationTestUtils.java | 45 +++++ .../StaticTransportKeyDerivationTest.java | 172 ++++++++++++++++++ .../crypto/TransportKeyDerivationTest.java | 167 +++++++++++++++++ 6 files changed, 389 insertions(+), 173 deletions(-) delete mode 100644 bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTest.java create mode 100644 bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTestUtils.java create mode 100644 bramble-core/src/test/java/org/briarproject/bramble/crypto/StaticTransportKeyDerivationTest.java create mode 100644 bramble-core/src/test/java/org/briarproject/bramble/crypto/TransportKeyDerivationTest.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java index a984a5c6f..60972619b 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java @@ -33,14 +33,14 @@ public interface TransportCrypto { * @param alice whether the keys are for use by Alice or Bob. */ StaticTransportKeys deriveStaticTransportKeys(TransportId t, - SecretKey rootKey, boolean alice, long timePeriod); + SecretKey rootKey, long timePeriod, boolean alice); /** * Updates the given static transport keys to the given time period. If * the keys are for the given period or any later period they are not * updated. */ - StaticTransportKeys updateTransportKeys(StaticTransportKeys k, + StaticTransportKeys updateStaticTransportKeys(StaticTransportKeys k, long timePeriod); /** diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java index 350fd2257..9f6ea73e8 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java @@ -116,7 +116,7 @@ class TransportCryptoImpl implements TransportCrypto { @Override public StaticTransportKeys deriveStaticTransportKeys(TransportId t, - SecretKey rootKey, boolean alice, long timePeriod) { + SecretKey rootKey, long timePeriod, boolean alice) { if (timePeriod < 1) throw new IllegalArgumentException(); IncomingKeys inPrev = deriveStaticIncomingKeys(t, rootKey, alice, timePeriod - 1); @@ -165,7 +165,7 @@ class TransportCryptoImpl implements TransportCrypto { } @Override - public StaticTransportKeys updateTransportKeys(StaticTransportKeys k, + public StaticTransportKeys updateStaticTransportKeys(StaticTransportKeys k, long timePeriod) { long elapsed = timePeriod - k.getTimePeriod(); TransportId t = k.getTransportId(); @@ -197,7 +197,7 @@ class TransportCryptoImpl implements TransportCrypto { rootKey, alice); } else { // The keys are more than two periods old - derive fresh keys - return deriveStaticTransportKeys(t, rootKey, alice, timePeriod); + return deriveStaticTransportKeys(t, rootKey, timePeriod, alice); } } 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 deleted file mode 100644 index 33c13753b..000000000 --- a/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTest.java +++ /dev/null @@ -1,168 +0,0 @@ -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.junit.Test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static org.briarproject.bramble.test.TestUtils.getSecretKey; -import static org.briarproject.bramble.test.TestUtils.getTransportId; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; - -public class KeyDerivationTest extends BrambleTestCase { - - private final CryptoComponent crypto = - new CryptoComponentImpl(new TestSecureRandomProvider(), null); - private final TransportCrypto transportCrypto = - new TransportCryptoImpl(crypto); - private final TransportId transportId = getTransportId(); - private final SecretKey rootKey = getSecretKey(); - - @Test - public void testKeysAreDistinct() { - TransportKeys k = transportCrypto.deriveTransportKeys(transportId, - rootKey, 123, true, true); - assertAllDifferent(k); - } - - @Test - public void testCurrentKeysMatchCurrentKeysOfContact() { - // Start in time period 123 - TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, - rootKey, 123, true, true); - TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, - rootKey, 123, false, true); - // Alice's incoming keys should equal Bob's outgoing keys - assertArrayEquals(kA.getCurrentIncomingKeys().getTagKey().getBytes(), - kB.getCurrentOutgoingKeys().getTagKey().getBytes()); - assertArrayEquals(kA.getCurrentIncomingKeys().getHeaderKey().getBytes(), - kB.getCurrentOutgoingKeys().getHeaderKey().getBytes()); - // Alice's outgoing keys should equal Bob's incoming keys - assertArrayEquals(kA.getCurrentOutgoingKeys().getTagKey().getBytes(), - kB.getCurrentIncomingKeys().getTagKey().getBytes()); - assertArrayEquals(kA.getCurrentOutgoingKeys().getHeaderKey().getBytes(), - kB.getCurrentIncomingKeys().getHeaderKey().getBytes()); - // Rotate into the future - 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()); - assertArrayEquals(kA.getCurrentIncomingKeys().getHeaderKey().getBytes(), - kB.getCurrentOutgoingKeys().getHeaderKey().getBytes()); - // Alice's outgoing keys should equal Bob's incoming keys - assertArrayEquals(kA.getCurrentOutgoingKeys().getTagKey().getBytes(), - kB.getCurrentIncomingKeys().getTagKey().getBytes()); - assertArrayEquals(kA.getCurrentOutgoingKeys().getHeaderKey().getBytes(), - kB.getCurrentIncomingKeys().getHeaderKey().getBytes()); - } - - @Test - public void testPreviousKeysMatchPreviousKeysOfContact() { - // Start in time period 123 - TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, - rootKey, 123, true, true); - TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, - rootKey, 123, false, true); - // Compare Alice's previous keys in period 456 with Bob's current keys - // in period 455 - kA = transportCrypto.rotateTransportKeys(kA, 456); - kB = transportCrypto.rotateTransportKeys(kB, 455); - // 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(), - kB.getCurrentOutgoingKeys().getHeaderKey().getBytes()); - // Compare Alice's current keys in period 456 with Bob's previous keys - // in period 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()); - assertArrayEquals(kA.getCurrentOutgoingKeys().getHeaderKey().getBytes(), - kB.getPreviousIncomingKeys().getHeaderKey().getBytes()); - } - - @Test - public void testNextKeysMatchNextKeysOfContact() { - // Start in time period 123 - TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, - rootKey, 123, true, true); - TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, - rootKey, 123, false, true); - // Compare Alice's current keys in period 456 with Bob's next keys in - // period 455 - kA = transportCrypto.rotateTransportKeys(kA, 456); - kB = transportCrypto.rotateTransportKeys(kB, 455); - // Alice's outgoing keys should equal Bob's next incoming keys - assertArrayEquals(kA.getCurrentOutgoingKeys().getTagKey().getBytes(), - kB.getNextIncomingKeys().getTagKey().getBytes()); - assertArrayEquals(kA.getCurrentOutgoingKeys().getHeaderKey().getBytes(), - kB.getNextIncomingKeys().getHeaderKey().getBytes()); - // Compare Alice's next keys in period 456 with Bob's current keys - // in period 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()); - assertArrayEquals(kA.getNextIncomingKeys().getHeaderKey().getBytes(), - kB.getCurrentOutgoingKeys().getHeaderKey().getBytes()); - } - - @Test - public void testRootKeyAffectsOutput() { - SecretKey rootKey1 = getSecretKey(); - assertFalse(Arrays.equals(rootKey.getBytes(), rootKey1.getBytes())); - TransportKeys k = transportCrypto.deriveTransportKeys(transportId, - rootKey, 123, true, true); - TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId, - rootKey1, 123, true, true); - assertAllDifferent(k, k1); - } - - @Test - public void testTransportIdAffectsOutput() { - TransportId transportId1 = getTransportId(); - assertNotEquals(transportId.getString(), transportId1.getString()); - TransportKeys k = transportCrypto.deriveTransportKeys(transportId, - rootKey, 123, true, true); - TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId1, - rootKey, 123, true, true); - assertAllDifferent(k, k1); - } - - private void assertAllDifferent(TransportKeys... transportKeys) { - List secretKeys = new ArrayList<>(); - for (TransportKeys k : transportKeys) { - secretKeys.add(k.getPreviousIncomingKeys().getTagKey()); - secretKeys.add(k.getPreviousIncomingKeys().getHeaderKey()); - secretKeys.add(k.getCurrentIncomingKeys().getTagKey()); - secretKeys.add(k.getCurrentIncomingKeys().getHeaderKey()); - secretKeys.add(k.getNextIncomingKeys().getTagKey()); - secretKeys.add(k.getNextIncomingKeys().getHeaderKey()); - secretKeys.add(k.getCurrentOutgoingKeys().getTagKey()); - secretKeys.add(k.getCurrentOutgoingKeys().getHeaderKey()); - } - assertAllDifferent(secretKeys); - } - - private void assertAllDifferent(List keys) { - Set set = new HashSet<>(); - for (SecretKey k : keys) assertTrue(set.add(new Bytes(k.getBytes()))); - } -} diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTestUtils.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTestUtils.java new file mode 100644 index 000000000..470ae5b99 --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTestUtils.java @@ -0,0 +1,45 @@ +package org.briarproject.bramble.crypto; + +import org.briarproject.bramble.api.Bytes; +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.transport.IncomingKeys; +import org.briarproject.bramble.api.transport.OutgoingKeys; +import org.briarproject.bramble.api.transport.TransportKeys; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertTrue; + +class KeyDerivationTestUtils { + + static void assertAllDifferent(TransportKeys... transportKeys) { + List secretKeys = new ArrayList<>(); + for (TransportKeys k : transportKeys) { + secretKeys.add(k.getPreviousIncomingKeys().getTagKey()); + secretKeys.add(k.getPreviousIncomingKeys().getHeaderKey()); + secretKeys.add(k.getCurrentIncomingKeys().getTagKey()); + secretKeys.add(k.getCurrentIncomingKeys().getHeaderKey()); + secretKeys.add(k.getNextIncomingKeys().getTagKey()); + secretKeys.add(k.getNextIncomingKeys().getHeaderKey()); + secretKeys.add(k.getCurrentOutgoingKeys().getTagKey()); + secretKeys.add(k.getCurrentOutgoingKeys().getHeaderKey()); + } + assertAllDifferent(secretKeys); + } + + static void assertAllDifferent(List keys) { + Set set = new HashSet<>(); + for (SecretKey k : keys) assertTrue(set.add(new Bytes(k.getBytes()))); + } + + static void assertMatches(IncomingKeys in, OutgoingKeys out) { + assertArrayEquals(in.getTagKey().getBytes(), + out.getTagKey().getBytes()); + assertArrayEquals(in.getHeaderKey().getBytes(), + out.getHeaderKey().getBytes()); + } +} diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/StaticTransportKeyDerivationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/StaticTransportKeyDerivationTest.java new file mode 100644 index 000000000..c4f9a05a2 --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/StaticTransportKeyDerivationTest.java @@ -0,0 +1,172 @@ +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.StaticTransportKeys; +import org.briarproject.bramble.test.BrambleTestCase; +import org.briarproject.bramble.test.TestSecureRandomProvider; +import org.junit.Test; + +import java.util.Arrays; + +import static org.briarproject.bramble.crypto.KeyDerivationTestUtils.assertAllDifferent; +import static org.briarproject.bramble.crypto.KeyDerivationTestUtils.assertMatches; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; +import static org.briarproject.bramble.test.TestUtils.getTransportId; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertSame; + +public class StaticTransportKeyDerivationTest extends BrambleTestCase { + + private final CryptoComponent crypto = + new CryptoComponentImpl(new TestSecureRandomProvider(), null); + private final TransportCrypto transportCrypto = + new TransportCryptoImpl(crypto); + private final TransportId transportId = getTransportId(); + private final SecretKey rootKey = getSecretKey(); + + @Test + public void testKeysAreDistinct() { + StaticTransportKeys kA = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, true); + StaticTransportKeys kB = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, false); + assertAllDifferent(kA); + assertAllDifferent(kB); + } + + @Test + public void testKeysAreNotUpdatedToPreviousPeriod() { + StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, true); + StaticTransportKeys k1 = + transportCrypto.updateStaticTransportKeys(k, 122); + assertSame(k, k1); + } + + @Test + public void testKeysAreNotUpdatedToCurrentPeriod() { + StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, true); + StaticTransportKeys k1 = + transportCrypto.updateStaticTransportKeys(k, 123); + assertSame(k, k1); + } + + @Test + public void testKeysAreUpdatedByOnePeriod() { + StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, true); + StaticTransportKeys k1 = + transportCrypto.updateStaticTransportKeys(k, 124); + assertSame(k.getCurrentIncomingKeys(), k1.getPreviousIncomingKeys()); + assertSame(k.getNextIncomingKeys(), k1.getCurrentIncomingKeys()); + } + + @Test + public void testKeysAreUpdatedByTwoPeriods() { + StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, true); + StaticTransportKeys k1 = + transportCrypto.updateStaticTransportKeys(k, 125); + assertSame(k.getNextIncomingKeys(), k1.getPreviousIncomingKeys()); + } + + @Test + public void testKeysAreUpdatedByThreePeriods() { + StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, true); + StaticTransportKeys k1 = + transportCrypto.updateStaticTransportKeys(k, 126); + assertAllDifferent(k, k1); + } + + @Test + public void testCurrentKeysMatchContact() { + // Start in time period 123 + StaticTransportKeys kA = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, true); + StaticTransportKeys kB = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, false); + // Alice's incoming keys should equal Bob's outgoing keys + assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); + // Bob's incoming keys should equal Alice's outgoing keys + assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys()); + // Update into the future + kA = transportCrypto.updateStaticTransportKeys(kA, 456); + kB = transportCrypto.updateStaticTransportKeys(kB, 456); + // Alice's incoming keys should equal Bob's outgoing keys + assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); + // Bob's incoming keys should equal Alice's outgoing keys + assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys()); + } + + @Test + public void testPreviousKeysMatchContact() { + // Start in time period 123 + StaticTransportKeys kA = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, true); + StaticTransportKeys kB = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, false); + // Compare Alice's previous keys in period 456 with Bob's current keys + // in period 455 + kA = transportCrypto.updateStaticTransportKeys(kA, 456); + kB = transportCrypto.updateStaticTransportKeys(kB, 455); + // Alice's previous incoming keys should equal Bob's current + // outgoing keys + assertMatches(kA.getPreviousIncomingKeys(), + kB.getCurrentOutgoingKeys()); + // Compare Alice's current keys in period 456 with Bob's previous keys + // in period 457 + kB = transportCrypto.updateStaticTransportKeys(kB, 457); + // Bob's previous incoming keys should equal Alice's current + // outgoing keys + assertMatches(kB.getPreviousIncomingKeys(), + kA.getCurrentOutgoingKeys()); + } + + @Test + public void testNextKeysMatchContact() { + // Start in time period 123 + StaticTransportKeys kA = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, true); + StaticTransportKeys kB = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, false); + // Compare Alice's current keys in period 456 with Bob's next keys in + // period 455 + kA = transportCrypto.updateStaticTransportKeys(kA, 456); + kB = transportCrypto.updateStaticTransportKeys(kB, 455); + // Bob's next incoming keys should equal Alice's current outgoing keys + assertMatches(kB.getNextIncomingKeys(), kA.getCurrentOutgoingKeys()); + // Compare Alice's next keys in period 456 with Bob's current keys + // in period 457 + kB = transportCrypto.updateStaticTransportKeys(kB, 457); + // Alice's next incoming keys should equal Bob's current outgoing keys + assertMatches(kA.getNextIncomingKeys(), kB.getCurrentOutgoingKeys()); + } + + @Test + public void testRootKeyAffectsOutput() { + SecretKey rootKey1 = getSecretKey(); + assertFalse(Arrays.equals(rootKey.getBytes(), rootKey1.getBytes())); + StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, true); + StaticTransportKeys k1 = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey1, 123, true); + assertAllDifferent(k, k1); + } + + @Test + public void testTransportIdAffectsOutput() { + TransportId transportId1 = getTransportId(); + assertNotEquals(transportId.getString(), transportId1.getString()); + StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( + transportId, rootKey, 123, true); + StaticTransportKeys k1 = transportCrypto.deriveStaticTransportKeys( + transportId1, rootKey, 123, true); + assertAllDifferent(k, k1); + } +} \ No newline at end of file diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/TransportKeyDerivationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/TransportKeyDerivationTest.java new file mode 100644 index 000000000..bfa031e73 --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/TransportKeyDerivationTest.java @@ -0,0 +1,167 @@ +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.TransportKeys; +import org.briarproject.bramble.test.BrambleTestCase; +import org.briarproject.bramble.test.TestSecureRandomProvider; +import org.junit.Test; + +import java.util.Arrays; + +import static org.briarproject.bramble.crypto.KeyDerivationTestUtils.assertAllDifferent; +import static org.briarproject.bramble.crypto.KeyDerivationTestUtils.assertMatches; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; +import static org.briarproject.bramble.test.TestUtils.getTransportId; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertSame; + +public class TransportKeyDerivationTest extends BrambleTestCase { + + private final CryptoComponent crypto = + new CryptoComponentImpl(new TestSecureRandomProvider(), null); + private final TransportCrypto transportCrypto = + new TransportCryptoImpl(crypto); + private final TransportId transportId = getTransportId(); + private final SecretKey rootKey = getSecretKey(); + + @Test + public void testKeysAreDistinct() { + TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, true, true); + TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, false, true); + assertAllDifferent(kA); + assertAllDifferent(kB); + } + + @Test + public void testKeysAreNotRotatedToPreviousPeriod() { + TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, true, true); + TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 122); + assertSame(k, k1); + } + + @Test + public void testKeysAreNotRotatedToCurrentPeriod() { + TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, true, true); + TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 123); + assertSame(k, k1); + } + + @Test + public void testKeysAreRotatedByOnePeriod() { + TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, true, true); + TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 124); + assertSame(k.getCurrentIncomingKeys(), k1.getPreviousIncomingKeys()); + assertSame(k.getNextIncomingKeys(), k1.getCurrentIncomingKeys()); + } + + @Test + public void testKeysAreRotatedByTwoPeriods() { + TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, true, true); + TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 125); + assertSame(k.getNextIncomingKeys(), k1.getPreviousIncomingKeys()); + } + + @Test + public void testKeysAreRotatedByThreePeriods() { + TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, true, true); + TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 126); + assertAllDifferent(k, k1); + } + + @Test + public void testCurrentKeysMatchContact() { + // Start in time period 123 + TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, true, true); + TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, false, true); + // Alice's incoming keys should equal Bob's outgoing keys + assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); + // Bob's incoming keys should equal Alice's outgoing keys + assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys()); + // Rotate into the future + kA = transportCrypto.rotateTransportKeys(kA, 456); + kB = transportCrypto.rotateTransportKeys(kB, 456); + // Alice's incoming keys should equal Bob's outgoing keys + assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); + // Bob's incoming keys should equal Alice's outgoing keys + assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys()); + } + + @Test + public void testPreviousKeysMatchContact() { + // Start in time period 123 + TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, true, true); + TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, false, true); + // Compare Alice's previous keys in period 456 with Bob's current keys + // in period 455 + kA = transportCrypto.rotateTransportKeys(kA, 456); + kB = transportCrypto.rotateTransportKeys(kB, 455); + // Alice's previous incoming keys should equal Bob's current + // outgoing keys + assertMatches(kA.getPreviousIncomingKeys(), + kB.getCurrentOutgoingKeys()); + // Compare Alice's current keys in period 456 with Bob's previous keys + // in period 457 + kB = transportCrypto.rotateTransportKeys(kB, 457); + // Bob's previous incoming keys should equal Alice's current + // outgoing keys + assertMatches(kB.getPreviousIncomingKeys(), + kA.getCurrentOutgoingKeys()); + } + + @Test + public void testNextKeysMatchContact() { + // Start in time period 123 + TransportKeys kA = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, true, true); + TransportKeys kB = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, false, true); + // Compare Alice's current keys in period 456 with Bob's next keys in + // period 455 + kA = transportCrypto.rotateTransportKeys(kA, 456); + kB = transportCrypto.rotateTransportKeys(kB, 455); + // Bob's next incoming keys should equal Alice's current outgoing keys + assertMatches(kB.getNextIncomingKeys(), kA.getCurrentOutgoingKeys()); + // Compare Alice's next keys in period 456 with Bob's current keys + // in period 457 + kB = transportCrypto.rotateTransportKeys(kB, 457); + // Alice's next incoming keys should equal Bob's current outgoing keys + assertMatches(kA.getNextIncomingKeys(), kB.getCurrentOutgoingKeys()); + } + + @Test + public void testRootKeyAffectsOutput() { + SecretKey rootKey1 = getSecretKey(); + assertFalse(Arrays.equals(rootKey.getBytes(), rootKey1.getBytes())); + TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, true, true); + TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId, + rootKey1, 123, true, true); + assertAllDifferent(k, k1); + } + + @Test + public void testTransportIdAffectsOutput() { + TransportId transportId1 = getTransportId(); + assertNotEquals(transportId.getString(), transportId1.getString()); + TransportKeys k = transportCrypto.deriveTransportKeys(transportId, + rootKey, 123, true, true); + TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId1, + rootKey, 123, true, true); + assertAllDifferent(k, k1); + } +} From 7acbe56197d0702e2ce435b1731573f08b930b62 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 10 Apr 2019 16:14:45 +0100 Subject: [PATCH 05/19] Add abstract superclass for transport keys. --- .../api/transport/AbstractTransportKeys.java | 58 +++++++++++++++++++ .../api/transport/StaticTransportKeys.java | 6 +- .../bramble/api/transport/TransportKeys.java | 45 ++------------ .../crypto/KeyDerivationTestUtils.java | 6 +- 4 files changed, 70 insertions(+), 45 deletions(-) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/transport/AbstractTransportKeys.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/AbstractTransportKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/AbstractTransportKeys.java new file mode 100644 index 000000000..a53631803 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/AbstractTransportKeys.java @@ -0,0 +1,58 @@ +package org.briarproject.bramble.api.transport; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; + +import javax.annotation.concurrent.Immutable; + +/** + * Abstract superclass for {@link TransportKeys} and + * {@link StaticTransportKeys}. + */ +@Immutable +@NotNullByDefault +public abstract class AbstractTransportKeys { + + private final TransportId transportId; + private final IncomingKeys inPrev, inCurr, inNext; + private final OutgoingKeys outCurr; + + AbstractTransportKeys(TransportId transportId, IncomingKeys inPrev, + IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) { + if (inPrev.getTimePeriod() != outCurr.getTimePeriod() - 1) + throw new IllegalArgumentException(); + if (inCurr.getTimePeriod() != outCurr.getTimePeriod()) + throw new IllegalArgumentException(); + if (inNext.getTimePeriod() != outCurr.getTimePeriod() + 1) + throw new IllegalArgumentException(); + this.transportId = transportId; + this.inPrev = inPrev; + this.inCurr = inCurr; + this.inNext = inNext; + this.outCurr = outCurr; + } + + public TransportId getTransportId() { + return transportId; + } + + public IncomingKeys getPreviousIncomingKeys() { + return inPrev; + } + + public IncomingKeys getCurrentIncomingKeys() { + return inCurr; + } + + public IncomingKeys getNextIncomingKeys() { + return inNext; + } + + public OutgoingKeys getCurrentOutgoingKeys() { + return outCurr; + } + + public long getTimePeriod() { + return outCurr.getTimePeriod(); + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java index 22f85d976..8f02b240f 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java @@ -6,9 +6,13 @@ import org.briarproject.bramble.api.plugin.TransportId; import javax.annotation.concurrent.Immutable; +/** + * Keys for communicating with a given contact over a given transport. Unlike + * {@link TransportKeys} these do not provide forward secrecy. + */ @Immutable @NotNullByDefault -public class StaticTransportKeys extends TransportKeys { +public class StaticTransportKeys extends AbstractTransportKeys { private final SecretKey rootKey; private final boolean alice; diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java index 860916457..9cd861df9 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java @@ -6,52 +6,15 @@ import org.briarproject.bramble.api.plugin.TransportId; import javax.annotation.concurrent.Immutable; /** - * Keys for communicating with a given contact over a given transport. + * Keys for communicating with a given contact over a given transport. Unlike + * {@link StaticTransportKeys}, these keys provide forward secrecy. */ @Immutable @NotNullByDefault -public class TransportKeys { - - private final TransportId transportId; - private final IncomingKeys inPrev, inCurr, inNext; - private final OutgoingKeys outCurr; +public class TransportKeys extends AbstractTransportKeys { public TransportKeys(TransportId transportId, IncomingKeys inPrev, IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) { - if (inPrev.getTimePeriod() != outCurr.getTimePeriod() - 1) - throw new IllegalArgumentException(); - if (inCurr.getTimePeriod() != outCurr.getTimePeriod()) - throw new IllegalArgumentException(); - if (inNext.getTimePeriod() != outCurr.getTimePeriod() + 1) - throw new IllegalArgumentException(); - this.transportId = transportId; - this.inPrev = inPrev; - this.inCurr = inCurr; - this.inNext = inNext; - this.outCurr = outCurr; - } - - public TransportId getTransportId() { - return transportId; - } - - public IncomingKeys getPreviousIncomingKeys() { - return inPrev; - } - - public IncomingKeys getCurrentIncomingKeys() { - return inCurr; - } - - public IncomingKeys getNextIncomingKeys() { - return inNext; - } - - public OutgoingKeys getCurrentOutgoingKeys() { - return outCurr; - } - - public long getTimePeriod() { - return outCurr.getTimePeriod(); + super(transportId, inPrev, inCurr, inNext, outCurr); } } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTestUtils.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTestUtils.java index 470ae5b99..878dc5488 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTestUtils.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyDerivationTestUtils.java @@ -2,9 +2,9 @@ package org.briarproject.bramble.crypto; import org.briarproject.bramble.api.Bytes; import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.transport.AbstractTransportKeys; import org.briarproject.bramble.api.transport.IncomingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys; -import org.briarproject.bramble.api.transport.TransportKeys; import java.util.ArrayList; import java.util.HashSet; @@ -16,9 +16,9 @@ import static org.junit.Assert.assertTrue; class KeyDerivationTestUtils { - static void assertAllDifferent(TransportKeys... transportKeys) { + static void assertAllDifferent(AbstractTransportKeys... transportKeys) { List secretKeys = new ArrayList<>(); - for (TransportKeys k : transportKeys) { + for (AbstractTransportKeys k : transportKeys) { secretKeys.add(k.getPreviousIncomingKeys().getTagKey()); secretKeys.add(k.getPreviousIncomingKeys().getHeaderKey()); secretKeys.add(k.getCurrentIncomingKeys().getTagKey()); From 0f5f440f1c0a39b0dd501f055ead248549fe8e39 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 16 Apr 2019 16:56:50 +0100 Subject: [PATCH 06/19] Add key set and key set ID classes for static keys. --- .../bramble/api/db/DatabaseComponent.java | 27 ++++---- .../bramble/api/transport/KeyManager.java | 4 +- .../api/transport/StaticTransportKeySet.java | 69 +++++++++++++++++++ .../transport/StaticTransportKeySetId.java | 36 ++++++++++ .../api/transport/StaticTransportKeys.java | 4 +- .../{KeySet.java => TransportKeySet.java} | 21 +++--- .../{KeySetId.java => TransportKeySetId.java} | 12 ++-- .../org/briarproject/bramble/db/Database.java | 32 +++++---- .../bramble/db/DatabaseComponentImpl.java | 28 ++++---- .../briarproject/bramble/db/JdbcDatabase.java | 37 +++++----- .../bramble/transport/KeyManagerImpl.java | 16 ++--- .../bramble/transport/MutableKeySet.java | 8 +-- .../transport/TransportKeyManager.java | 9 +-- .../transport/TransportKeyManagerImpl.java | 57 ++++++++------- .../bramble/db/DatabaseComponentImplTest.java | 13 ++-- .../bramble/db/JdbcDatabaseTest.java | 45 ++++++------ .../bramble/transport/KeyManagerImplTest.java | 8 +-- .../TransportKeyManagerImplTest.java | 26 +++---- .../IntroduceeProtocolEngine.java | 4 +- .../briar/introduction/IntroduceeSession.java | 13 ++-- .../introduction/SessionEncoderImpl.java | 6 +- .../briar/introduction/SessionParserImpl.java | 11 ++- .../SessionEncoderParserIntegrationTest.java | 11 +-- 23 files changed, 313 insertions(+), 184 deletions(-) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySet.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySetId.java rename bramble-api/src/main/java/org/briarproject/bramble/api/transport/{KeySet.java => TransportKeySet.java} (60%) rename bramble-api/src/main/java/org/briarproject/bramble/api/transport/{KeySetId.java => TransportKeySetId.java} (60%) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java index d44398747..0f40e707a 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java @@ -20,8 +20,8 @@ import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.validation.MessageState; -import org.briarproject.bramble.api.transport.KeySet; -import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.bramble.api.transport.TransportKeySet; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import java.util.Collection; @@ -129,7 +129,7 @@ public interface DatabaseComponent { * Stores the given transport keys for the given contact and returns a * key set ID. */ - KeySetId addTransportKeys(Transaction txn, ContactId c, + TransportKeySetId addTransportKeys(Transaction txn, ContactId c, TransportKeys k) throws DbException; /** @@ -429,14 +429,14 @@ public interface DatabaseComponent { *

* Read-only. */ - Collection getTransportKeys(Transaction txn, TransportId t) + Collection getTransportKeys(Transaction txn, TransportId t) throws DbException; /** * Increments the outgoing stream counter for the given transport keys. */ - void incrementStreamCounter(Transaction txn, TransportId t, KeySetId k) - throws DbException; + void incrementStreamCounter(Transaction txn, TransportId t, + TransportKeySetId k) throws DbException; /** * Merges the given metadata with the existing metadata for the given @@ -509,8 +509,8 @@ public interface DatabaseComponent { /** * Removes the given transport keys from the database. */ - void removeTransportKeys(Transaction txn, TransportId t, KeySetId k) - throws DbException; + void removeTransportKeys(Transaction txn, TransportId t, + TransportKeySetId k) throws DbException; /** * Marks the given contact as verified. @@ -556,18 +556,19 @@ public interface DatabaseComponent { * Sets the reordering window for the given key set and transport in the * given time period. */ - void setReorderingWindow(Transaction txn, KeySetId k, TransportId t, - long timePeriod, long base, byte[] bitmap) throws DbException; + void setReorderingWindow(Transaction txn, TransportKeySetId k, + TransportId t, long timePeriod, long base, byte[] bitmap) + throws DbException; /** * Marks the given transport keys as usable for outgoing streams. */ - void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k) - throws DbException; + void setTransportKeysActive(Transaction txn, TransportId t, + TransportKeySetId k) throws DbException; /** * Stores the given transport keys, deleting any keys they have replaced. */ - void updateTransportKeys(Transaction txn, Collection keys) + void updateTransportKeys(Transaction txn, Collection keys) throws DbException; } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java index 827c94fb7..e5c1ac541 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java @@ -27,14 +27,14 @@ public interface KeyManager { * @param alice true if the local party is Alice * @param active whether the derived keys can be used for outgoing streams */ - Map addContact(Transaction txn, ContactId c, + Map addContact(Transaction txn, ContactId c, SecretKey rootKey, long timestamp, boolean alice, boolean active) throws DbException; /** * Marks the given transport keys as usable for outgoing streams. */ - void activateKeys(Transaction txn, Map keys) + void activateKeys(Transaction txn, Map keys) throws DbException; /** diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySet.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySet.java new file mode 100644 index 000000000..f8430f615 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySet.java @@ -0,0 +1,69 @@ +package org.briarproject.bramble.api.transport; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.PendingContactId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +/** + * A set of transport keys for communicating with a contact or pending contact. + * Unlike a {@link TransportKeySet} these keys do not provide forward secrecy. + */ +@Immutable +@NotNullByDefault +public class StaticTransportKeySet { + + private final StaticTransportKeySetId keySetId; + @Nullable + private final ContactId contactId; + @Nullable + private final PendingContactId pendingContactId; + private final StaticTransportKeys keys; + + public StaticTransportKeySet(StaticTransportKeySetId keySetId, + ContactId contactId, StaticTransportKeys keys) { + this.keySetId = keySetId; + this.contactId = contactId; + this.keys = keys; + pendingContactId = null; + } + + public StaticTransportKeySet(StaticTransportKeySetId keySetId, + PendingContactId pendingContactId, StaticTransportKeys keys) { + this.keySetId = keySetId; + this.pendingContactId = pendingContactId; + this.keys = keys; + contactId = null; + } + + public StaticTransportKeySetId getKeySetId() { + return keySetId; + } + + @Nullable + public ContactId getContactId() { + return contactId; + } + + @Nullable + public PendingContactId getPendingContactId() { + return pendingContactId; + } + + public StaticTransportKeys getKeys() { + return keys; + } + + @Override + public int hashCode() { + return keySetId.hashCode(); + } + + @Override + public boolean equals(Object o) { + return o instanceof StaticTransportKeySet && + keySetId.equals(((StaticTransportKeySet) o).keySetId); + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySetId.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySetId.java new file mode 100644 index 000000000..fbf6eb152 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySetId.java @@ -0,0 +1,36 @@ +package org.briarproject.bramble.api.transport; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +/** + * Type-safe wrapper for an integer that uniquely identifies a + * {@link StaticTransportKeySet set of static transport keys} within the scope + * of the local device. + */ +@Immutable +@NotNullByDefault +public class StaticTransportKeySetId { + + private final int id; + + public StaticTransportKeySetId(int id) { + this.id = id; + } + + public int getInt() { + return id; + } + + @Override + public int hashCode() { + return id; + } + + @Override + public boolean equals(Object o) { + return o instanceof StaticTransportKeySetId && + id == ((StaticTransportKeySetId) o).id; + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java index 8f02b240f..9c6ba3831 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java @@ -7,8 +7,8 @@ import org.briarproject.bramble.api.plugin.TransportId; import javax.annotation.concurrent.Immutable; /** - * Keys for communicating with a given contact over a given transport. Unlike - * {@link TransportKeys} these do not provide forward secrecy. + * Keys for communicating with a given contact or pending contact over a given + * transport. Unlike {@link TransportKeys} these do not provide forward secrecy. */ @Immutable @NotNullByDefault diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeySet.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java similarity index 60% rename from bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeySet.java rename to bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java index 47fc65288..0400287ab 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeySet.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java @@ -10,20 +10,20 @@ import javax.annotation.concurrent.Immutable; */ @Immutable @NotNullByDefault -public class KeySet { +public class TransportKeySet { - private final KeySetId keySetId; + private final TransportKeySetId keySetId; private final ContactId contactId; - private final TransportKeys transportKeys; + private final TransportKeys keys; - public KeySet(KeySetId keySetId, ContactId contactId, - TransportKeys transportKeys) { + public TransportKeySet(TransportKeySetId keySetId, ContactId contactId, + TransportKeys keys) { this.keySetId = keySetId; this.contactId = contactId; - this.transportKeys = transportKeys; + this.keys = keys; } - public KeySetId getKeySetId() { + public TransportKeySetId getKeySetId() { return keySetId; } @@ -31,8 +31,8 @@ public class KeySet { return contactId; } - public TransportKeys getTransportKeys() { - return transportKeys; + public TransportKeys getKeys() { + return keys; } @Override @@ -42,6 +42,7 @@ public class KeySet { @Override public boolean equals(Object o) { - return o instanceof KeySet && keySetId.equals(((KeySet) o).keySetId); + return o instanceof TransportKeySet && + keySetId.equals(((TransportKeySet) o).keySetId); } } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeySetId.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySetId.java similarity index 60% rename from bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeySetId.java rename to bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySetId.java index 1f872e72a..c4b1ae088 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeySetId.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySetId.java @@ -5,18 +5,19 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import javax.annotation.concurrent.Immutable; /** - * Type-safe wrapper for an integer that uniquely identifies a set of transport - * keys within the scope of the local device. + * Type-safe wrapper for an integer that uniquely identifies a + * {@link TransportKeySet set of transport keys} within the scope of the local + * device. *

* Key sets created on a given device must have increasing identifiers. */ @Immutable @NotNullByDefault -public class KeySetId { +public class TransportKeySetId { private final int id; - public KeySetId(int id) { + public TransportKeySetId(int id) { this.id = id; } @@ -31,6 +32,7 @@ public class KeySetId { @Override public boolean equals(Object o) { - return o instanceof KeySetId && id == ((KeySetId) o).id; + return o instanceof TransportKeySetId && + id == ((TransportKeySetId) o).id; } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java index 8b57537d2..55b9abf8a 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java @@ -5,6 +5,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DataTooNewException; import org.briarproject.bramble.api.db.DataTooOldException; +import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.MessageDeletedException; import org.briarproject.bramble.api.db.Metadata; @@ -23,8 +24,8 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.validation.MessageState; -import org.briarproject.bramble.api.transport.KeySet; -import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.bramble.api.transport.TransportKeySet; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import java.util.Collection; @@ -33,11 +34,14 @@ import java.util.Map; import javax.annotation.Nullable; /** - * A low-level interface to the database (DatabaseComponent provides a - * high-level interface). Most operations take a transaction argument, which is - * obtained by calling {@link #startTransaction()}. Every transaction must be - * terminated by calling either {@link #abortTransaction(Object) abortTransaction(T)} or - * {@link #commitTransaction(Object) commitTransaction(T)}, even if an exception is thrown. + * A low-level interface to the database ({@link DatabaseComponent} provides a + * high-level interface). + *

+ * Most operations take a transaction argument, which is obtained by calling + * {@link #startTransaction()}. Every transaction must be terminated by calling + * either {@link #abortTransaction(Object) abortTransaction(T)} or + * {@link #commitTransaction(Object) commitTransaction(T)}, even if an + * exception is thrown. */ @NotNullByDefault interface Database { @@ -131,7 +135,7 @@ interface Database { * Stores the given transport keys for the given contact and returns a * key set ID. */ - KeySetId addTransportKeys(T txn, ContactId c, TransportKeys k) + TransportKeySetId addTransportKeys(T txn, ContactId c, TransportKeys k) throws DbException; /** @@ -489,13 +493,13 @@ interface Database { *

* Read-only. */ - Collection getTransportKeys(T txn, TransportId t) + Collection getTransportKeys(T txn, TransportId t) throws DbException; /** * Increments the outgoing stream counter for the given transport keys. */ - void incrementStreamCounter(T txn, TransportId t, KeySetId k) + void incrementStreamCounter(T txn, TransportId t, TransportKeySetId k) throws DbException; /** @@ -589,7 +593,7 @@ interface Database { /** * Removes the given transport keys from the database. */ - void removeTransportKeys(T txn, TransportId t, KeySetId k) + void removeTransportKeys(T txn, TransportId t, TransportKeySetId k) throws DbException; /** @@ -637,13 +641,13 @@ interface Database { * Sets the reordering window for the given key set and transport in the * given time period. */ - void setReorderingWindow(T txn, KeySetId k, TransportId t, + void setReorderingWindow(T txn, TransportKeySetId k, TransportId t, long timePeriod, long base, byte[] bitmap) throws DbException; /** * Marks the given transport keys as usable for outgoing streams. */ - void setTransportKeysActive(T txn, TransportId t, KeySetId k) + void setTransportKeysActive(T txn, TransportId t, TransportKeySetId k) throws DbException; /** @@ -657,5 +661,5 @@ interface Database { /** * Updates the given transport keys following key rotation. */ - void updateTransportKeys(T txn, KeySet ks) throws DbException; + void updateTransportKeys(T txn, TransportKeySet ks) throws DbException; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java index ef5ec82f9..88db0b19d 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java @@ -59,8 +59,8 @@ import org.briarproject.bramble.api.sync.event.MessageToRequestEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesSentEvent; import org.briarproject.bramble.api.sync.validation.MessageState; -import org.briarproject.bramble.api.transport.KeySet; -import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.bramble.api.transport.TransportKeySet; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import java.util.ArrayList; @@ -291,8 +291,8 @@ class DatabaseComponentImpl implements DatabaseComponent { } @Override - public KeySetId addTransportKeys(Transaction transaction, ContactId c, - TransportKeys k) throws DbException { + public TransportKeySetId addTransportKeys(Transaction transaction, + ContactId c, TransportKeys k) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) @@ -663,7 +663,7 @@ class DatabaseComponentImpl implements DatabaseComponent { } @Override - public Collection getTransportKeys(Transaction transaction, + public Collection getTransportKeys(Transaction transaction, TransportId t) throws DbException { T txn = unbox(transaction); if (!db.containsTransport(txn, t)) @@ -673,7 +673,7 @@ class DatabaseComponentImpl implements DatabaseComponent { @Override public void incrementStreamCounter(Transaction transaction, TransportId t, - KeySetId k) throws DbException { + TransportKeySetId k) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsTransport(txn, t)) @@ -856,7 +856,7 @@ class DatabaseComponentImpl implements DatabaseComponent { @Override public void removeTransportKeys(Transaction transaction, - TransportId t, KeySetId k) throws DbException { + TransportId t, TransportKeySetId k) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsTransport(txn, t)) @@ -955,9 +955,9 @@ class DatabaseComponentImpl implements DatabaseComponent { } @Override - public void setReorderingWindow(Transaction transaction, KeySetId k, - TransportId t, long timePeriod, long base, byte[] bitmap) - throws DbException { + public void setReorderingWindow(Transaction transaction, + TransportKeySetId k, TransportId t, long timePeriod, long base, + byte[] bitmap) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsTransport(txn, t)) @@ -967,7 +967,7 @@ class DatabaseComponentImpl implements DatabaseComponent { @Override public void setTransportKeysActive(Transaction transaction, TransportId t, - KeySetId k) throws DbException { + TransportKeySetId k) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsTransport(txn, t)) @@ -977,11 +977,11 @@ class DatabaseComponentImpl implements DatabaseComponent { @Override public void updateTransportKeys(Transaction transaction, - Collection keys) throws DbException { + Collection keys) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); - for (KeySet ks : keys) { - TransportId t = ks.getTransportKeys().getTransportId(); + for (TransportKeySet ks : keys) { + TransportId t = ks.getKeys().getTransportId(); if (db.containsTransport(txn, t)) db.updateTransportKeys(txn, ks); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index 5d5605fc9..599d60ac2 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -27,9 +27,9 @@ import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.IncomingKeys; -import org.briarproject.bramble.api.transport.KeySet; -import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.OutgoingKeys; +import org.briarproject.bramble.api.transport.TransportKeySet; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import java.sql.Connection; @@ -958,7 +958,7 @@ abstract class JdbcDatabase implements Database { } @Override - public KeySetId addTransportKeys(Connection txn, ContactId c, + public TransportKeySetId addTransportKeys(Connection txn, ContactId c, TransportKeys k) throws DbException { PreparedStatement ps = null; ResultSet rs = null; @@ -985,7 +985,7 @@ abstract class JdbcDatabase implements Database { ps = txn.prepareStatement(sql); rs = ps.executeQuery(); if (!rs.next()) throw new DbStateException(); - KeySetId keySetId = new KeySetId(rs.getInt(1)); + TransportKeySetId keySetId = new TransportKeySetId(rs.getInt(1)); if (rs.next()) throw new DbStateException(); rs.close(); ps.close(); @@ -2191,8 +2191,8 @@ abstract class JdbcDatabase implements Database { } @Override - public Collection getTransportKeys(Connection txn, TransportId t) - throws DbException { + public Collection getTransportKeys(Connection txn, + TransportId t) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { @@ -2225,11 +2225,12 @@ abstract class JdbcDatabase implements Database { ps = txn.prepareStatement(sql); ps.setString(1, t.getString()); rs = ps.executeQuery(); - Collection keys = new ArrayList<>(); + Collection keys = new ArrayList<>(); for (int i = 0; rs.next(); i++) { // There should be three times as many incoming keys if (inKeys.size() < (i + 1) * 3) throw new DbStateException(); - KeySetId keySetId = new KeySetId(rs.getInt(1)); + TransportKeySetId keySetId = + new TransportKeySetId(rs.getInt(1)); ContactId contactId = new ContactId(rs.getInt(2)); long timePeriod = rs.getLong(3); SecretKey tagKey = new SecretKey(rs.getBytes(4)); @@ -2243,7 +2244,8 @@ abstract class JdbcDatabase implements Database { IncomingKeys inNext = inKeys.get(i * 3 + 2); TransportKeys transportKeys = new TransportKeys(t, inPrev, inCurr, inNext, outCurr); - keys.add(new KeySet(keySetId, contactId, transportKeys)); + keys.add(new TransportKeySet(keySetId, contactId, + transportKeys)); } rs.close(); ps.close(); @@ -2257,7 +2259,7 @@ abstract class JdbcDatabase implements Database { @Override public void incrementStreamCounter(Connection txn, TransportId t, - KeySetId k) throws DbException { + TransportKeySetId k) throws DbException { PreparedStatement ps = null; try { String sql = "UPDATE outgoingKeys SET stream = stream + 1" @@ -2730,8 +2732,8 @@ abstract class JdbcDatabase implements Database { } @Override - public void removeTransportKeys(Connection txn, TransportId t, KeySetId k) - throws DbException { + public void removeTransportKeys(Connection txn, TransportId t, + TransportKeySetId k) throws DbException { PreparedStatement ps = null; try { // Delete any existing outgoing keys - this will also remove any @@ -2934,8 +2936,9 @@ abstract class JdbcDatabase implements Database { } @Override - public void setReorderingWindow(Connection txn, KeySetId k, TransportId t, - long timePeriod, long base, byte[] bitmap) throws DbException { + public void setReorderingWindow(Connection txn, TransportKeySetId k, + TransportId t, long timePeriod, long base, byte[] bitmap) + throws DbException { PreparedStatement ps = null; try { String sql = "UPDATE incomingKeys SET base = ?, bitmap = ?" @@ -2958,7 +2961,7 @@ abstract class JdbcDatabase implements Database { @Override public void setTransportKeysActive(Connection txn, TransportId t, - KeySetId k) throws DbException { + TransportKeySetId k) throws DbException { PreparedStatement ps = null; try { String sql = "UPDATE outgoingKeys SET active = true" @@ -3013,7 +3016,7 @@ abstract class JdbcDatabase implements Database { } @Override - public void updateTransportKeys(Connection txn, KeySet ks) + public void updateTransportKeys(Connection txn, TransportKeySet ks) throws DbException { PreparedStatement ps = null; try { @@ -3022,7 +3025,7 @@ abstract class JdbcDatabase implements Database { + " tagKey = ?, headerKey = ?, stream = ?" + " WHERE transportId = ? AND keySetId = ?"; ps = txn.prepareStatement(sql); - TransportKeys k = ks.getTransportKeys(); + TransportKeys k = ks.getKeys(); OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); ps.setLong(1, outCurr.getTimePeriod()); ps.setBytes(2, outCurr.getTagKey().getBytes()); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java index 482ee5b7f..8e34a78dd 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java @@ -19,8 +19,8 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; import org.briarproject.bramble.api.transport.KeyManager; -import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.StreamContext; +import org.briarproject.bramble.api.transport.TransportKeySetId; import java.util.HashMap; import java.util.Map; @@ -95,10 +95,10 @@ class KeyManagerImpl implements KeyManager, Service, EventListener { } @Override - public Map addContact(Transaction txn, ContactId c, - SecretKey rootKey, long timestamp, boolean alice, boolean active) - throws DbException { - Map ids = new HashMap<>(); + public Map addContact(Transaction txn, + ContactId c, SecretKey rootKey, long timestamp, boolean alice, + boolean active) throws DbException { + Map ids = new HashMap<>(); for (Entry e : managers.entrySet()) { TransportId t = e.getKey(); TransportKeyManager m = e.getValue(); @@ -108,9 +108,9 @@ class KeyManagerImpl implements KeyManager, Service, EventListener { } @Override - public void activateKeys(Transaction txn, Map keys) - throws DbException { - for (Entry e : keys.entrySet()) { + public void activateKeys(Transaction txn, Map keys) throws DbException { + for (Entry e : keys.entrySet()) { TransportId t = e.getKey(); TransportKeyManager m = managers.get(t); if (m == null) { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableKeySet.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableKeySet.java index 63ce3134f..5c24b2220 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableKeySet.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/MutableKeySet.java @@ -1,22 +1,22 @@ package org.briarproject.bramble.transport; import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.bramble.api.transport.TransportKeySetId; class MutableKeySet { - private final KeySetId keySetId; + private final TransportKeySetId keySetId; private final ContactId contactId; private final MutableTransportKeys transportKeys; - MutableKeySet(KeySetId keySetId, ContactId contactId, + MutableKeySet(TransportKeySetId keySetId, ContactId contactId, MutableTransportKeys transportKeys) { this.keySetId = keySetId; this.contactId = contactId; this.transportKeys = transportKeys; } - KeySetId getKeySetId() { + TransportKeySetId getKeySetId() { return keySetId; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java index fa3f54e11..2d08ec4c1 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java @@ -5,8 +5,8 @@ import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.StreamContext; +import org.briarproject.bramble.api.transport.TransportKeySetId; import javax.annotation.Nullable; @@ -15,10 +15,11 @@ interface TransportKeyManager { void start(Transaction txn) throws DbException; - KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey, - long timestamp, boolean alice, boolean active) throws DbException; + TransportKeySetId addContact(Transaction txn, ContactId c, + SecretKey rootKey, long timestamp, boolean alice, boolean active) + throws DbException; - void activateKeys(Transaction txn, KeySetId k) throws DbException; + void activateKeys(Transaction txn, TransportKeySetId k) throws DbException; void removeContact(ContactId c); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java index d5442f356..e93aab417 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java @@ -11,9 +11,9 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Scheduler; -import org.briarproject.bramble.api.transport.KeySet; -import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.StreamContext; +import org.briarproject.bramble.api.transport.TransportKeySet; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.transport.ReorderingWindow.Change; @@ -56,7 +56,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { private final ReentrantLock lock = new ReentrantLock(); // The following are locking: lock - private final Map keys = new HashMap<>(); + private final Map keys = new HashMap<>(); private final Map inContexts = new HashMap<>(); private final Map outContexts = new HashMap<>(); @@ -80,7 +80,8 @@ class TransportKeyManagerImpl implements TransportKeyManager { lock.lock(); try { // Load the transport keys from the DB - Collection loaded = db.getTransportKeys(txn, transportId); + Collection loaded = + db.getTransportKeys(txn, transportId); // Rotate the keys to the current time period RotationResult rotationResult = rotateKeys(loaded, now); // Initialise mutable state for all contacts @@ -95,14 +96,16 @@ class TransportKeyManagerImpl implements TransportKeyManager { scheduleKeyRotation(now); } - private RotationResult rotateKeys(Collection keys, long now) { + private RotationResult rotateKeys(Collection keys, + long now) { RotationResult rotationResult = new RotationResult(); long timePeriod = now / timePeriodLength; - for (KeySet ks : keys) { - TransportKeys k = ks.getTransportKeys(); - TransportKeys k1 = - transportCrypto.rotateTransportKeys(k, timePeriod); - KeySet ks1 = new KeySet(ks.getKeySetId(), ks.getContactId(), k1); + for (TransportKeySet ks : keys) { + TransportKeys k = ks.getKeys(); + TransportKeys k1 = transportCrypto.rotateTransportKeys(k, + timePeriod); + TransportKeySet ks1 = new TransportKeySet(ks.getKeySetId(), + ks.getContactId(), k1); if (k1.getTimePeriod() > k.getTimePeriod()) rotationResult.rotated.add(ks1); rotationResult.current.add(ks1); @@ -111,15 +114,15 @@ class TransportKeyManagerImpl implements TransportKeyManager { } // Locking: lock - private void addKeys(Collection keys) { - for (KeySet ks : keys) { + private void addKeys(Collection keys) { + for (TransportKeySet ks : keys) { addKeys(ks.getKeySetId(), ks.getContactId(), - new MutableTransportKeys(ks.getTransportKeys())); + new MutableTransportKeys(ks.getKeys())); } } // Locking: lock - private void addKeys(KeySetId keySetId, ContactId contactId, + private void addKeys(TransportKeySetId keySetId, ContactId contactId, MutableTransportKeys m) { MutableKeySet ks = new MutableKeySet(keySetId, contactId, m); keys.put(keySetId, ks); @@ -130,7 +133,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { } // Locking: lock - private void encodeTags(KeySetId keySetId, ContactId contactId, + private void encodeTags(TransportKeySetId keySetId, ContactId contactId, MutableIncomingKeys inKeys) { for (long streamNumber : inKeys.getWindow().getUnseen()) { TagContext tagCtx = @@ -170,8 +173,9 @@ class TransportKeyManagerImpl implements TransportKeyManager { } @Override - public KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey, - long timestamp, boolean alice, boolean active) throws DbException { + public TransportKeySetId addContact(Transaction txn, ContactId c, + SecretKey rootKey, long timestamp, boolean alice, boolean active) + throws DbException { lock.lock(); try { // Work out what time period the timestamp belongs to @@ -183,7 +187,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { timePeriod = clock.currentTimeMillis() / timePeriodLength; k = transportCrypto.rotateTransportKeys(k, timePeriod); // Write the keys back to the DB - KeySetId keySetId = db.addTransportKeys(txn, c, k); + TransportKeySetId keySetId = db.addTransportKeys(txn, c, k); // Initialise mutable state for the contact addKeys(keySetId, c, new MutableTransportKeys(k)); return keySetId; @@ -193,7 +197,8 @@ class TransportKeyManagerImpl implements TransportKeyManager { } @Override - public void activateKeys(Transaction txn, KeySetId k) throws DbException { + public void activateKeys(Transaction txn, TransportKeySetId k) + throws DbException { lock.lock(); try { MutableKeySet ks = keys.get(k); @@ -323,10 +328,10 @@ class TransportKeyManagerImpl implements TransportKeyManager { lock.lock(); try { // Rotate the keys to the current time period - Collection snapshot = new ArrayList<>(keys.size()); + Collection snapshot = new ArrayList<>(keys.size()); for (MutableKeySet ks : keys.values()) { - snapshot.add(new KeySet(ks.getKeySetId(), ks.getContactId(), - ks.getTransportKeys().snapshot())); + snapshot.add(new TransportKeySet(ks.getKeySetId(), + ks.getContactId(), ks.getTransportKeys().snapshot())); } RotationResult rotationResult = rotateKeys(snapshot, now); // Rebuild the mutable state for all contacts @@ -346,12 +351,12 @@ class TransportKeyManagerImpl implements TransportKeyManager { private static class TagContext { - private final KeySetId keySetId; + private final TransportKeySetId keySetId; private final ContactId contactId; private final MutableIncomingKeys inKeys; private final long streamNumber; - private TagContext(KeySetId keySetId, ContactId contactId, + private TagContext(TransportKeySetId keySetId, ContactId contactId, MutableIncomingKeys inKeys, long streamNumber) { this.keySetId = keySetId; this.contactId = contactId; @@ -362,7 +367,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { private static class RotationResult { - private final Collection current = new ArrayList<>(); - private final Collection rotated = new ArrayList<>(); + private final Collection current = new ArrayList<>(); + private final Collection rotated = new ArrayList<>(); } } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java index d230ea878..49afd2c46 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java @@ -45,9 +45,9 @@ import org.briarproject.bramble.api.sync.event.MessageToRequestEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesSentEvent; import org.briarproject.bramble.api.transport.IncomingKeys; -import org.briarproject.bramble.api.transport.KeySet; -import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.OutgoingKeys; +import org.briarproject.bramble.api.transport.TransportKeySet; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.CaptureArgumentAction; @@ -111,7 +111,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { private final int maxLatency; private final ContactId contactId; private final Contact contact; - private final KeySetId keySetId; + private final TransportKeySetId keySetId; public DatabaseComponentImplTest() { clientId = getClientId(); @@ -132,7 +132,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { contactId = new ContactId(234); contact = new Contact(contactId, author, localAuthor.getId(), alias, true, true); - keySetId = new KeySetId(345); + keySetId = new TransportKeySetId(345); } private DatabaseComponent createDatabaseComponent(Database database, @@ -1117,8 +1117,9 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { @Test public void testTransportKeys() throws Exception { TransportKeys transportKeys = createTransportKeys(); - KeySet ks = new KeySet(keySetId, contactId, transportKeys); - Collection keys = singletonList(ks); + TransportKeySet ks = + new TransportKeySet(keySetId, contactId, transportKeys); + Collection keys = singletonList(ks); context.checking(new Expectations() {{ // startTransaction() diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java index 481cf23b2..280b14f5a 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java @@ -21,9 +21,9 @@ import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.IncomingKeys; -import org.briarproject.bramble.api.transport.KeySet; -import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.OutgoingKeys; +import org.briarproject.bramble.api.transport.TransportKeySet; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.system.SystemClock; import org.briarproject.bramble.test.BrambleTestCase; @@ -103,7 +103,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { private final MessageId messageId; private final TransportId transportId; private final ContactId contactId; - private final KeySetId keySetId, keySetId1; + private final TransportKeySetId keySetId, keySetId1; private final Random random = new Random(); JdbcDatabaseTest() { @@ -117,8 +117,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { messageId = message.getId(); transportId = getTransportId(); contactId = new ContactId(1); - keySetId = new KeySetId(1); - keySetId1 = new KeySetId(2); + keySetId = new TransportKeySetId(1); + keySetId1 = new TransportKeySetId(2); } protected abstract JdbcDatabase createDatabase(DatabaseConfig config, @@ -673,15 +673,16 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { assertEquals(keySetId1, db.addTransportKeys(txn, contactId, keys1)); // Retrieve the transport keys - Collection allKeys = db.getTransportKeys(txn, transportId); + Collection allKeys = + db.getTransportKeys(txn, transportId); assertEquals(2, allKeys.size()); - for (KeySet ks : allKeys) { + for (TransportKeySet ks : allKeys) { assertEquals(contactId, ks.getContactId()); if (ks.getKeySetId().equals(keySetId)) { - assertKeysEquals(keys, ks.getTransportKeys()); + assertKeysEquals(keys, ks.getKeys()); } else { assertEquals(keySetId1, ks.getKeySetId()); - assertKeysEquals(keys1, ks.getTransportKeys()); + assertKeysEquals(keys1, ks.getKeys()); } } @@ -689,19 +690,21 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { TransportKeys rotated = createTransportKeys(timePeriod + 1, active); TransportKeys rotated1 = createTransportKeys(timePeriod1 + 1, active); - db.updateTransportKeys(txn, new KeySet(keySetId, contactId, rotated)); - db.updateTransportKeys(txn, new KeySet(keySetId1, contactId, rotated1)); + db.updateTransportKeys(txn, new TransportKeySet(keySetId, contactId, + rotated)); + db.updateTransportKeys(txn, new TransportKeySet(keySetId1, contactId, + rotated1)); // Retrieve the transport keys again allKeys = db.getTransportKeys(txn, transportId); assertEquals(2, allKeys.size()); - for (KeySet ks : allKeys) { + for (TransportKeySet ks : allKeys) { assertEquals(contactId, ks.getContactId()); if (ks.getKeySetId().equals(keySetId)) { - assertKeysEquals(rotated, ks.getTransportKeys()); + assertKeysEquals(rotated, ks.getKeys()); } else { assertEquals(keySetId1, ks.getKeySetId()); - assertKeysEquals(rotated1, ks.getTransportKeys()); + assertKeysEquals(rotated1, ks.getKeys()); } } @@ -766,12 +769,13 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Increment the stream counter twice and retrieve the transport keys db.incrementStreamCounter(txn, transportId, keySetId); db.incrementStreamCounter(txn, transportId, keySetId); - Collection newKeys = db.getTransportKeys(txn, transportId); + Collection newKeys = + db.getTransportKeys(txn, transportId); assertEquals(1, newKeys.size()); - KeySet ks = newKeys.iterator().next(); + TransportKeySet ks = newKeys.iterator().next(); assertEquals(keySetId, ks.getKeySetId()); assertEquals(contactId, ks.getContactId()); - TransportKeys k = ks.getTransportKeys(); + TransportKeys k = ks.getKeys(); assertEquals(transportId, k.getTransportId()); OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); assertEquals(timePeriod, outCurr.getTimePeriod()); @@ -810,12 +814,13 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { random.nextBytes(bitmap); db.setReorderingWindow(txn, keySetId, transportId, timePeriod, base + 1, bitmap); - Collection newKeys = db.getTransportKeys(txn, transportId); + Collection newKeys = + db.getTransportKeys(txn, transportId); assertEquals(1, newKeys.size()); - KeySet ks = newKeys.iterator().next(); + TransportKeySet ks = newKeys.iterator().next(); assertEquals(keySetId, ks.getKeySetId()); assertEquals(contactId, ks.getContactId()); - TransportKeys k = ks.getTransportKeys(); + TransportKeys k = ks.getKeys(); assertEquals(transportId, k.getTransportId()); IncomingKeys inCurr = k.getCurrentIncomingKeys(); assertEquals(timePeriod, inCurr.getTimePeriod()); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/transport/KeyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/transport/KeyManagerImplTest.java index c09185f65..d57a3d793 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/transport/KeyManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/transport/KeyManagerImplTest.java @@ -12,8 +12,8 @@ import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.plugin.PluginConfig; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; -import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.StreamContext; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.DbExpectations; import org.jmock.Expectations; @@ -51,7 +51,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase { private final Transaction txn = new Transaction(null, false); private final ContactId contactId = new ContactId(123); private final ContactId inactiveContactId = new ContactId(234); - private final KeySetId keySetId = new KeySetId(345); + private final TransportKeySetId keySetId = new TransportKeySetId(345); private final TransportId transportId = getTransportId(); private final TransportId unknownTransportId = getTransportId(); private final StreamContext streamContext = @@ -113,8 +113,8 @@ public class KeyManagerImplTest extends BrambleMockTestCase { will(returnValue(keySetId)); }}); - Map ids = keyManager.addContact(txn, contactId, - secretKey, timestamp, alice, active); + Map ids = keyManager.addContact(txn, + contactId, secretKey, timestamp, alice, active); assertEquals(singletonMap(transportId, keySetId), ids); } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java index 2f0b7d58a..8dc7531c0 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java @@ -8,10 +8,10 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.IncomingKeys; -import org.briarproject.bramble.api.transport.KeySet; -import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.StreamContext; +import org.briarproject.bramble.api.transport.TransportKeySet; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.DbExpectations; @@ -60,8 +60,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { private final long timePeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE; private final ContactId contactId = new ContactId(123); private final ContactId contactId1 = new ContactId(234); - private final KeySetId keySetId = new KeySetId(345); - private final KeySetId keySetId1 = new KeySetId(456); + private final TransportKeySetId keySetId = new TransportKeySetId(345); + private final TransportKeySetId keySetId1 = new TransportKeySetId(456); private final SecretKey tagKey = TestUtils.getSecretKey(); private final SecretKey headerKey = TestUtils.getSecretKey(); private final SecretKey rootKey = TestUtils.getSecretKey(); @@ -71,9 +71,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { public void testKeysAreRotatedAtStartup() throws Exception { TransportKeys shouldRotate = createTransportKeys(900, 0, true); TransportKeys shouldNotRotate = createTransportKeys(1000, 0, true); - Collection loaded = asList( - new KeySet(keySetId, contactId, shouldRotate), - new KeySet(keySetId1, contactId1, shouldNotRotate) + Collection loaded = asList( + new TransportKeySet(keySetId, contactId, shouldRotate), + new TransportKeySet(keySetId1, contactId1, shouldNotRotate) ); TransportKeys rotated = createTransportKeys(1000, 0, true); Transaction txn = new Transaction(null, false); @@ -98,8 +98,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { will(new EncodeTagAction()); } // Save the keys that were rotated - oneOf(db).updateTransportKeys(txn, - singletonList(new KeySet(keySetId, contactId, rotated))); + oneOf(db).updateTransportKeys(txn, singletonList( + new TransportKeySet(keySetId, contactId, rotated))); // Schedule key rotation at the start of the next time period oneOf(scheduler).schedule(with(any(Runnable.class)), with(timePeriodLength - 1), with(MILLISECONDS)); @@ -313,8 +313,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { @Test public void testKeysAreRotatedToCurrentPeriod() throws Exception { TransportKeys transportKeys = createTransportKeys(1000, 0, true); - Collection loaded = - singletonList(new KeySet(keySetId, contactId, transportKeys)); + Collection loaded = singletonList( + new TransportKeySet(keySetId, contactId, transportKeys)); TransportKeys rotated = createTransportKeys(1001, 0, true); Transaction txn = new Transaction(null, false); Transaction txn1 = new Transaction(null, false); @@ -359,8 +359,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { will(new EncodeTagAction()); } // Save the keys that were rotated - oneOf(db).updateTransportKeys(txn1, - singletonList(new KeySet(keySetId, contactId, rotated))); + oneOf(db).updateTransportKeys(txn1, singletonList( + new TransportKeySet(keySetId, contactId, rotated))); // Schedule key rotation at the start of the next time period oneOf(scheduler).schedule(with(any(Runnable.class)), with(timePeriodLength), with(MILLISECONDS)); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java index 5639e848f..3a96c3eba 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java @@ -23,7 +23,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.KeyManager; -import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.SessionId; @@ -430,7 +430,7 @@ class IntroduceeProtocolEngine s.getRemote().acceptTimestamp); if (timestamp == -1) throw new AssertionError(); - Map keys = null; + Map keys = null; try { contactManager .addContact(txn, s.getRemote().author, localAuthor.getId(), diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java index b952b3dc5..5a6967a90 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java @@ -8,7 +8,7 @@ import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.introduction.Role; @@ -17,9 +17,9 @@ import java.util.Map; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import static org.briarproject.briar.api.introduction.Role.INTRODUCEE; import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_ACTIVATE; import static org.briarproject.briar.introduction.IntroduceeState.START; -import static org.briarproject.briar.api.introduction.Role.INTRODUCEE; @Immutable @NotNullByDefault @@ -33,12 +33,12 @@ class IntroduceeSession extends Session @Nullable private final byte[] masterKey; @Nullable - private final Map transportKeys; + private final Map transportKeys; IntroduceeSession(SessionId sessionId, IntroduceeState state, long requestTimestamp, GroupId contactGroupId, Author introducer, Local local, Remote remote, @Nullable byte[] masterKey, - @Nullable Map transportKeys) { + @Nullable Map transportKeys) { super(sessionId, state, requestTimestamp); this.contactGroupId = contactGroupId; this.introducer = introducer; @@ -113,7 +113,8 @@ class IntroduceeSession extends Session } static IntroduceeSession awaitActivate(IntroduceeSession s, AuthMessage m, - Message sent, @Nullable Map transportKeys) { + Message sent, + @Nullable Map transportKeys) { Local local = new Local(s.local, sent.getId(), sent.getTimestamp()); Remote remote = new Remote(s.remote, m.getMessageId()); return new IntroduceeSession(s.getSessionId(), AWAIT_ACTIVATE, @@ -180,7 +181,7 @@ class IntroduceeSession extends Session } @Nullable - Map getTransportKeys() { + Map getTransportKeys() { return transportKeys; } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoderImpl.java index 9023f0d94..434608503 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoderImpl.java @@ -6,7 +6,7 @@ import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; -import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.briar.introduction.IntroduceeSession.Common; import org.briarproject.briar.introduction.IntroduceeSession.Local; import org.briarproject.briar.introduction.IntroduceeSession.Remote; @@ -143,10 +143,10 @@ class SessionEncoderImpl implements SessionEncoder { @Nullable private BdfDictionary encodeTransportKeys( - @Nullable Map keys) { + @Nullable Map keys) { if (keys == null) return null; BdfDictionary d = new BdfDictionary(); - for (Map.Entry e : keys.entrySet()) { + for (Map.Entry e : keys.entrySet()) { d.put(e.getKey().getString(), e.getValue().getInt()); } return d; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java index 52c12e547..471d8efa2 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java @@ -10,7 +10,7 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.introduction.Role; import org.briarproject.briar.introduction.IntroduceeSession.Local; @@ -110,7 +110,7 @@ class SessionParserImpl implements SessionParser { Local local = parseLocal(d.getDictionary(SESSION_KEY_LOCAL)); Remote remote = parseRemote(d.getDictionary(SESSION_KEY_REMOTE)); byte[] masterKey = d.getOptionalRaw(SESSION_KEY_MASTER_KEY); - Map transportKeys = parseTransportKeys( + Map transportKeys = parseTransportKeys( d.getOptionalDictionary(SESSION_KEY_TRANSPORT_KEYS)); return new IntroduceeSession(sessionId, state, requestTimestamp, introducerGroupId, introducer, local, remote, @@ -184,14 +184,13 @@ class SessionParserImpl implements SessionParser { } @Nullable - private Map parseTransportKeys( + private Map parseTransportKeys( @Nullable BdfDictionary d) throws FormatException { if (d == null) return null; - Map map = new HashMap<>(d.size()); + Map map = new HashMap<>(d.size()); for (String key : d.keySet()) { map.put(new TransportId(key), - new KeySetId(d.getLong(key).intValue()) - ); + new TransportKeySetId(d.getLong(key).intValue())); } return map; } diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java index 9ddb00632..df29af3d7 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java @@ -10,7 +10,7 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.introduction.IntroducerSession.Introducee; @@ -75,7 +75,8 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase { getTransportPropertiesMap(3); private final Map remoteTransportProperties = getTransportPropertiesMap(3); - private final Map transportKeys = new HashMap<>(); + private final Map transportKeys = + new HashMap<>(); private final byte[] localMacKey = getRandomBytes(SecretKey.LENGTH); private final byte[] remoteMacKey = getRandomBytes(SecretKey.LENGTH); @@ -88,9 +89,9 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase { sessionParser = new SessionParserImpl(clientHelper); author1 = getRealAuthor(authorFactory); author2 = getRealAuthor(authorFactory); - transportKeys.put(getTransportId(), new KeySetId(1)); - transportKeys.put(getTransportId(), new KeySetId(2)); - transportKeys.put(getTransportId(), new KeySetId(3)); + transportKeys.put(getTransportId(), new TransportKeySetId(1)); + transportKeys.put(getTransportId(), new TransportKeySetId(2)); + transportKeys.put(getTransportId(), new TransportKeySetId(3)); } @Test From f72ff9f81225e34c0acc17bf292e8e4f20002a68 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 16 Apr 2019 17:51:31 +0100 Subject: [PATCH 07/19] Add database methods for static keys. --- .../bramble/api/db/DatabaseComponent.java | 46 +++ .../org/briarproject/bramble/db/Database.java | 55 ++- .../bramble/db/DatabaseComponentImpl.java | 67 +++ .../briarproject/bramble/db/JdbcDatabase.java | 383 ++++++++++++++++-- .../bramble/db/Migration41_42.java | 72 ++-- 5 files changed, 562 insertions(+), 61 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java index 0f40e707a..8488c7bf0 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.api.db; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.AuthorId; @@ -20,6 +21,9 @@ import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.validation.MessageState; +import org.briarproject.bramble.api.transport.StaticTransportKeySet; +import org.briarproject.bramble.api.transport.StaticTransportKeySetId; +import org.briarproject.bramble.api.transport.StaticTransportKeys; import org.briarproject.bramble.api.transport.TransportKeySet; import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; @@ -119,6 +123,20 @@ public interface DatabaseComponent { void addLocalMessage(Transaction txn, Message m, Metadata meta, boolean shared) throws DbException; + /** + * Stores the given static transport keys for the given contact and returns + * a key set ID. + */ + StaticTransportKeySetId addStaticTransportKeys(Transaction txn, ContactId c, + StaticTransportKeys k) throws DbException; + + /** + * Stores the given static transport keys for the given pending contact and + * returns a key set ID. + */ + StaticTransportKeySetId addStaticTransportKeys(Transaction txn, + PendingContactId p, StaticTransportKeys k) throws DbException; + /** * Stores a transport. */ @@ -424,6 +442,14 @@ public interface DatabaseComponent { */ Settings getSettings(Transaction txn, String namespace) throws DbException; + /** + * Returns all static transport keys for the given transport. + *

+ * Read-only. + */ + Collection getStaticTransportKeys(Transaction txn, + TransportId t) throws DbException; + /** * Returns all transport keys for the given transport. *

@@ -432,6 +458,13 @@ public interface DatabaseComponent { Collection getTransportKeys(Transaction txn, TransportId t) throws DbException; + /** + * Increments the outgoing stream counter for the given static transport + * keys. + */ + void incrementStreamCounter(Transaction txn, TransportId t, + StaticTransportKeySetId k) throws DbException; + /** * Increments the outgoing stream counter for the given transport keys. */ @@ -501,6 +534,12 @@ public interface DatabaseComponent { */ void removeMessage(Transaction txn, MessageId m) throws DbException; + /** + * Removes the given static transport keys from the database. + */ + void removeStaticTransportKeys(Transaction txn, TransportId t, + StaticTransportKeySetId k) throws DbException; + /** * Removes a transport (and all associated state) from the database. */ @@ -566,6 +605,13 @@ public interface DatabaseComponent { void setTransportKeysActive(Transaction txn, TransportId t, TransportKeySetId k) throws DbException; + /** + * Stores the given static transport keys, deleting any keys they have + * replaced. + */ + void updateStaticTransportKeys(Transaction txn, + Collection keys) throws DbException; + /** * Stores the given transport keys, deleting any keys they have replaced. */ diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java index 55b9abf8a..3db95d1c8 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.db; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DataTooNewException; import org.briarproject.bramble.api.db.DataTooOldException; @@ -24,6 +25,9 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.validation.MessageState; +import org.briarproject.bramble.api.transport.StaticTransportKeySet; +import org.briarproject.bramble.api.transport.StaticTransportKeySetId; +import org.briarproject.bramble.api.transport.StaticTransportKeys; import org.briarproject.bramble.api.transport.TransportKeySet; import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; @@ -36,7 +40,7 @@ import javax.annotation.Nullable; /** * A low-level interface to the database ({@link DatabaseComponent} provides a * high-level interface). - *

+ *

* Most operations take a transaction argument, which is obtained by calling * {@link #startTransaction()}. Every transaction must be terminated by calling * either {@link #abortTransaction(Object) abortTransaction(T)} or @@ -125,6 +129,20 @@ interface Database { */ void addOfferedMessage(T txn, ContactId c, MessageId m) throws DbException; + /** + * Stores the given static transport keys for the given contact and returns + * a key set ID. + */ + StaticTransportKeySetId addStaticTransportKeys(T txn, ContactId c, + StaticTransportKeys k) throws DbException; + + /** + * Stores the given static transport keys for the given pending contact and + * returns a key set ID. + */ + StaticTransportKeySetId addStaticTransportKeys(T txn, PendingContactId p, + StaticTransportKeys k) throws DbException; + /** * Stores a transport. */ @@ -175,6 +193,14 @@ interface Database { */ boolean containsMessage(T txn, MessageId m) throws DbException; + /** + * Returns true if the database contains the given pending contact. + *

+ * Read-only. + */ + boolean containsPendingContact(T txn, PendingContactId p) + throws DbException; + /** * Returns true if the database contains the given transport. *

@@ -488,6 +514,14 @@ interface Database { */ Settings getSettings(T txn, String namespace) throws DbException; + /** + * Returns all static transport keys for the given transport. + *

+ * Read-only. + */ + Collection getStaticTransportKeys(T txn, + TransportId t) throws DbException; + /** * Returns all transport keys for the given transport. *

@@ -496,6 +530,13 @@ interface Database { Collection getTransportKeys(T txn, TransportId t) throws DbException; + /** + * Increments the outgoing stream counter for the given static transport + * keys. + */ + void incrementStreamCounter(T txn, TransportId t, StaticTransportKeySetId k) + throws DbException; + /** * Increments the outgoing stream counter for the given transport keys. */ @@ -585,6 +626,12 @@ interface Database { void removeOfferedMessages(T txn, ContactId c, Collection requested) throws DbException; + /** + * Removes the given static transport keys from the database. + */ + void removeStaticTransportKeys(T txn, TransportId t, + StaticTransportKeySetId k) throws DbException; + /** * Removes a transport (and all associated state) from the database. */ @@ -658,6 +705,12 @@ interface Database { void updateExpiryTimeAndEta(T txn, ContactId c, MessageId m, int maxLatency) throws DbException; + /** + * Updates the given static transport keys following key rotation. + */ + void updateStaticTransportKeys(T txn, StaticTransportKeySet ks) + throws DbException; + /** * Updates the given transport keys following key rotation. */ diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java index 88db0b19d..e96c533e7 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.db; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.contact.event.ContactAddedEvent; import org.briarproject.bramble.api.contact.event.ContactRemovedEvent; import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent; @@ -59,6 +60,9 @@ import org.briarproject.bramble.api.sync.event.MessageToRequestEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesSentEvent; import org.briarproject.bramble.api.sync.validation.MessageState; +import org.briarproject.bramble.api.transport.StaticTransportKeySet; +import org.briarproject.bramble.api.transport.StaticTransportKeySetId; +import org.briarproject.bramble.api.transport.StaticTransportKeys; import org.briarproject.bramble.api.transport.TransportKeySet; import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; @@ -281,6 +285,32 @@ class DatabaseComponentImpl implements DatabaseComponent { db.mergeMessageMetadata(txn, m.getId(), meta); } + @Override + public StaticTransportKeySetId addStaticTransportKeys( + Transaction transaction, ContactId c, StaticTransportKeys k) + throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); + T txn = unbox(transaction); + if (!db.containsContact(txn, c)) + throw new NoSuchContactException(); + if (!db.containsTransport(txn, k.getTransportId())) + throw new NoSuchTransportException(); + return db.addStaticTransportKeys(txn, c, k); + } + + @Override + public StaticTransportKeySetId addStaticTransportKeys( + Transaction transaction, PendingContactId p, + StaticTransportKeys k) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); + T txn = unbox(transaction); + if (!db.containsPendingContact(txn, p)) + throw new NoSuchContactException(); + if (!db.containsTransport(txn, k.getTransportId())) + throw new NoSuchTransportException(); + return db.addStaticTransportKeys(txn, p, k); + } + @Override public void addTransport(Transaction transaction, TransportId t, int maxLatency) throws DbException { @@ -662,6 +692,15 @@ class DatabaseComponentImpl implements DatabaseComponent { return db.getSettings(txn, namespace); } + @Override + public Collection getStaticTransportKeys( + Transaction transaction, TransportId t) throws DbException { + T txn = unbox(transaction); + if (!db.containsTransport(txn, t)) + throw new NoSuchTransportException(); + return db.getStaticTransportKeys(txn, t); + } + @Override public Collection getTransportKeys(Transaction transaction, TransportId t) throws DbException { @@ -671,6 +710,12 @@ class DatabaseComponentImpl implements DatabaseComponent { return db.getTransportKeys(txn, t); } + @Override + public void incrementStreamCounter(Transaction txn, TransportId t, + StaticTransportKeySetId k) throws DbException { + + } + @Override public void incrementStreamCounter(Transaction transaction, TransportId t, TransportKeySetId k) throws DbException { @@ -844,6 +889,16 @@ class DatabaseComponentImpl implements DatabaseComponent { db.removeMessage(txn, m); } + @Override + public void removeStaticTransportKeys(Transaction transaction, + TransportId t, StaticTransportKeySetId k) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); + T txn = unbox(transaction); + if (!db.containsTransport(txn, t)) + throw new NoSuchTransportException(); + db.removeStaticTransportKeys(txn, t, k); + } + @Override public void removeTransport(Transaction transaction, TransportId t) throws DbException { @@ -975,6 +1030,18 @@ class DatabaseComponentImpl implements DatabaseComponent { db.setTransportKeysActive(txn, t, k); } + @Override + public void updateStaticTransportKeys(Transaction transaction, + Collection keys) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); + T txn = unbox(transaction); + for (StaticTransportKeySet ks : keys) { + TransportId t = ks.getKeys().getTransportId(); + if (db.containsTransport(txn, t)) + db.updateStaticTransportKeys(txn, ks); + } + } + @Override public void updateTransportKeys(Transaction transaction, Collection keys) throws DbException { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index 599d60ac2..56978f1ba 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.db; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DataTooNewException; import org.briarproject.bramble.api.db.DataTooOldException; @@ -28,6 +29,9 @@ import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.IncomingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys; +import org.briarproject.bramble.api.transport.StaticTransportKeySet; +import org.briarproject.bramble.api.transport.StaticTransportKeySetId; +import org.briarproject.bramble.api.transport.StaticTransportKeys; import org.briarproject.bramble.api.transport.TransportKeySet; import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; @@ -55,6 +59,7 @@ import java.util.logging.Logger; import javax.annotation.Nullable; +import static java.sql.Types.BINARY; import static java.sql.Types.INTEGER; import static java.sql.Types.VARCHAR; import static java.util.logging.Level.INFO; @@ -283,23 +288,26 @@ abstract class JdbcDatabase implements Database { private static final String CREATE_PENDING_CONTACTS = "CREATE TABLE pendingContacts" - + " (pendingContactId _HASH NOT NULL," - + " PRIMARY KEY (pendingContactId))"; + + " (pendingContactId _HASH NOT NULL," + + " PRIMARY KEY (pendingContactId))"; private static final String CREATE_OUTGOING_STATIC_KEYS = "CREATE TABLE outgoingStaticKeys" + " (transportId _STRING NOT NULL," - + " staticKeySetId _COUNTER," - + " rootKey _SECRET NOT NULL," + + " keySetId _COUNTER," + " timePeriod BIGINT NOT NULL," - + " stream BIGINT NOT NULL," + " contactId INT," // Null if contact is pending + " pendingContactId _HASH," // Null if not pending - + " PRIMARY KEY (transportId, staticKeySetId)," + + " rootKey _SECRET NOT NULL," + + " alice BOOLEAN NOT NULL," + + " tagKey _SECRET NOT NULL," + + " headerKey _SECRET NOT NULL," + + " stream BIGINT NOT NULL," + + " PRIMARY KEY (transportId, keySetId)," + " FOREIGN KEY (transportId)" + " REFERENCES transports (transportId)" + " ON DELETE CASCADE," - + " UNIQUE (staticKeySetId)," + + " UNIQUE (keySetId)," + " FOREIGN KEY (contactId)" + " REFERENCES contacts (contactId)" + " ON DELETE CASCADE," @@ -310,18 +318,19 @@ abstract class JdbcDatabase implements Database { private static final String CREATE_INCOMING_STATIC_KEYS = "CREATE TABLE incomingStaticKeys" + " (transportId _STRING NOT NULL," - + " staticKeySetId INT NOT NULL," + + " keySetId INT NOT NULL," + " timePeriod BIGINT NOT NULL," + + " tagKey _SECRET NOT NULL," + + " headerKey _SECRET NOT NULL," + " base BIGINT NOT NULL," + " bitmap _BINARY NOT NULL," + " periodOffset INT NOT NULL," - + " PRIMARY KEY (transportId, staticKeySetId," - + " periodOffset)," + + " PRIMARY KEY (transportId, keySetId, periodOffset)," + " FOREIGN KEY (transportId)" + " REFERENCES transports (transportId)" + " ON DELETE CASCADE," - + " FOREIGN KEY (staticKeySetId)" - + " REFERENCES outgoingStaticKeys (staticKeySetId)" + + " FOREIGN KEY (keySetId)" + + " REFERENCES outgoingStaticKeys (keySetId)" + " ON DELETE CASCADE)"; private static final String INDEX_CONTACTS_BY_AUTHOR_ID = @@ -938,6 +947,104 @@ abstract class JdbcDatabase implements Database { } } + @Override + public StaticTransportKeySetId addStaticTransportKeys(Connection txn, + ContactId c, StaticTransportKeys k) throws DbException { + return addStaticTransportKeys(txn, c, null, k); + } + + @Override + public StaticTransportKeySetId addStaticTransportKeys(Connection txn, + PendingContactId p, StaticTransportKeys k) throws DbException { + return addStaticTransportKeys(txn, null, p, k); + } + + private StaticTransportKeySetId addStaticTransportKeys(Connection txn, + @Nullable ContactId c, @Nullable PendingContactId p, + StaticTransportKeys k) throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + // Store the outgoing keys + String sql = "INSERT INTO outgoingStaticKeys (contactId," + + " pendingContactId, transportId, rootKey, alice," + + " timePeriod, tagKey, headerKey, stream)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; + ps = txn.prepareStatement(sql); + if (c == null) ps.setNull(1, INTEGER); + else ps.setInt(1, c.getInt()); + if (p == null) ps.setNull(2, BINARY); + else ps.setBytes(2, p.getBytes()); + ps.setString(3, k.getTransportId().getString()); + ps.setBytes(4, k.getRootKey().getBytes()); + ps.setBoolean(5, k.isAlice()); + OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); + ps.setLong(6, outCurr.getTimePeriod()); + ps.setBytes(7, outCurr.getTagKey().getBytes()); + ps.setBytes(8, outCurr.getHeaderKey().getBytes()); + ps.setLong(9, outCurr.getStreamCounter()); + int affected = ps.executeUpdate(); + if (affected != 1) throw new DbStateException(); + ps.close(); + // Get the new (highest) key set ID + sql = "SELECT keySetId FROM outgoingStaticKeys" + + " ORDER BY keySetId DESC LIMIT 1"; + ps = txn.prepareStatement(sql); + rs = ps.executeQuery(); + if (!rs.next()) throw new DbStateException(); + StaticTransportKeySetId keySetId = new + StaticTransportKeySetId(rs.getInt(1)); + if (rs.next()) throw new DbStateException(); + rs.close(); + ps.close(); + // Store the incoming keys + sql = "INSERT INTO incomingStaticKeys (keySetId, transportId," + + " timePeriod, tagKey, headerKey, base, bitmap," + + " periodOffset)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + ps = txn.prepareStatement(sql); + ps.setInt(1, keySetId.getInt()); + ps.setString(2, k.getTransportId().getString()); + // Previous time period + IncomingKeys inPrev = k.getPreviousIncomingKeys(); + ps.setLong(3, inPrev.getTimePeriod()); + ps.setBytes(4, inPrev.getTagKey().getBytes()); + ps.setBytes(5, inPrev.getHeaderKey().getBytes()); + ps.setLong(6, inPrev.getWindowBase()); + ps.setBytes(7, inPrev.getWindowBitmap()); + ps.setInt(8, OFFSET_PREV); + ps.addBatch(); + // Current time period + IncomingKeys inCurr = k.getCurrentIncomingKeys(); + ps.setLong(3, inCurr.getTimePeriod()); + ps.setBytes(4, inCurr.getTagKey().getBytes()); + ps.setBytes(5, inCurr.getHeaderKey().getBytes()); + ps.setLong(6, inCurr.getWindowBase()); + ps.setBytes(7, inCurr.getWindowBitmap()); + ps.setInt(8, OFFSET_CURR); + ps.addBatch(); + // Next time period + IncomingKeys inNext = k.getNextIncomingKeys(); + ps.setLong(3, inNext.getTimePeriod()); + ps.setBytes(4, inNext.getTagKey().getBytes()); + ps.setBytes(5, inNext.getHeaderKey().getBytes()); + ps.setLong(6, inNext.getWindowBase()); + ps.setBytes(7, inNext.getWindowBitmap()); + ps.setInt(8, OFFSET_NEXT); + ps.addBatch(); + int[] batchAffected = ps.executeBatch(); + if (batchAffected.length != 3) throw new DbStateException(); + for (int rows : batchAffected) + if (rows != 1) throw new DbStateException(); + ps.close(); + return keySetId; + } catch (SQLException e) { + tryToClose(rs, LOG, WARNING); + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public void addTransport(Connection txn, TransportId t, int maxLatency) throws DbException { @@ -1149,6 +1256,29 @@ abstract class JdbcDatabase implements Database { } } + @Override + public boolean containsPendingContact(Connection txn, PendingContactId p) + throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = "SELECT NULL FROM pendingContacts" + + " WHERE pendingContactId = ?"; + ps = txn.prepareStatement(sql); + ps.setBytes(1, p.getBytes()); + rs = ps.executeQuery(); + boolean found = rs.next(); + if (rs.next()) throw new DbStateException(); + rs.close(); + ps.close(); + return found; + } catch (SQLException e) { + tryToClose(rs, LOG, WARNING); + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public boolean containsTransport(Connection txn, TransportId t) throws DbException { @@ -2190,6 +2320,87 @@ abstract class JdbcDatabase implements Database { } } + @Override + public Collection getStaticTransportKeys( + Connection txn, TransportId t) throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + // Retrieve the incoming keys + String sql = "SELECT timePeriod, tagKey, headerKey, base, bitmap" + + " FROM incomingStaticKeys" + + " WHERE transportId = ?" + + " ORDER BY keySetId, periodOffset"; + ps = txn.prepareStatement(sql); + ps.setString(1, t.getString()); + rs = ps.executeQuery(); + List inKeys = new ArrayList<>(); + while (rs.next()) { + long timePeriod = rs.getLong(1); + SecretKey tagKey = new SecretKey(rs.getBytes(2)); + SecretKey headerKey = new SecretKey(rs.getBytes(3)); + long windowBase = rs.getLong(4); + byte[] windowBitmap = rs.getBytes(5); + inKeys.add(new IncomingKeys(tagKey, headerKey, timePeriod, + windowBase, windowBitmap)); + } + rs.close(); + ps.close(); + // Retrieve the outgoing keys in the same order + sql = "SELECT keySetId, contactId, pendingContactId, timePeriod," + + " tagKey, headerKey, rootKey, alice, stream" + + " FROM outgoingStaticKeys" + + " WHERE transportId = ?" + + " ORDER BY keySetId"; + ps = txn.prepareStatement(sql); + ps.setString(1, t.getString()); + rs = ps.executeQuery(); + Collection keys = new ArrayList<>(); + for (int i = 0; rs.next(); i++) { + // There should be three times as many incoming keys + if (inKeys.size() < (i + 1) * 3) throw new DbStateException(); + StaticTransportKeySetId keySetId = + new StaticTransportKeySetId(rs.getInt(1)); + ContactId contactId = null; + int cId = rs.getInt(2); + if (!rs.wasNull()) contactId = new ContactId(cId); + PendingContactId pendingContactId = null; + byte[] pId = rs.getBytes(3); + if (!rs.wasNull()) pendingContactId = new PendingContactId(pId); + long timePeriod = rs.getLong(4); + SecretKey tagKey = new SecretKey(rs.getBytes(5)); + SecretKey headerKey = new SecretKey(rs.getBytes(6)); + SecretKey rootKey = new SecretKey(rs.getBytes(7)); + boolean alice = rs.getBoolean(8); + long streamCounter = rs.getLong(9); + OutgoingKeys outCurr = new OutgoingKeys(tagKey, headerKey, + timePeriod, streamCounter, true); + IncomingKeys inPrev = inKeys.get(i * 3); + IncomingKeys inCurr = inKeys.get(i * 3 + 1); + IncomingKeys inNext = inKeys.get(i * 3 + 2); + StaticTransportKeys staticTransportKeys = + new StaticTransportKeys(t, inPrev, inCurr, inNext, + outCurr, rootKey, alice); + if (contactId == null) { + if (pendingContactId == null) throw new DbStateException(); + keys.add(new StaticTransportKeySet(keySetId, + pendingContactId, staticTransportKeys)); + } else { + if (pendingContactId != null) throw new DbStateException(); + keys.add(new StaticTransportKeySet(keySetId, contactId, + staticTransportKeys)); + } + } + rs.close(); + ps.close(); + return keys; + } catch (SQLException e) { + tryToClose(rs, LOG, WARNING); + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public Collection getTransportKeys(Connection txn, TransportId t) throws DbException { @@ -2257,6 +2468,25 @@ abstract class JdbcDatabase implements Database { } } + @Override + public void incrementStreamCounter(Connection txn, TransportId t, + StaticTransportKeySetId k) throws DbException { + PreparedStatement ps = null; + try { + String sql = "UPDATE outgoingStaticKeys SET stream = stream + 1" + + " WHERE transportId = ? AND keySetId = ?"; + ps = txn.prepareStatement(sql); + ps.setString(1, t.getString()); + ps.setInt(2, k.getInt()); + int affected = ps.executeUpdate(); + if (affected != 1) throw new DbStateException(); + ps.close(); + } catch (SQLException e) { + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public void incrementStreamCounter(Connection txn, TransportId t, TransportKeySetId k) throws DbException { @@ -2339,8 +2569,9 @@ abstract class JdbcDatabase implements Database { g.getBytes(), meta, "groupMetadata", "groupId"); if (added.isEmpty()) return; // Insert any keys that don't already exist - String sql = "INSERT INTO groupMetadata (groupId, metaKey, value)" - + " VALUES (?, ?, ?)"; + String sql = + "INSERT INTO groupMetadata (groupId, metaKey, value)" + + " VALUES (?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setBytes(1, g.getBytes()); for (Entry e : added.entrySet()) { @@ -2488,7 +2719,8 @@ abstract class JdbcDatabase implements Database { ps.addBatch(); } int[] batchAffected = ps.executeBatch(); - if (batchAffected.length != s.size()) throw new DbStateException(); + if (batchAffected.length != s.size()) + throw new DbStateException(); for (int rows : batchAffected) { if (rows < 0) throw new DbStateException(); if (rows > 1) throw new DbStateException(); @@ -2509,7 +2741,8 @@ abstract class JdbcDatabase implements Database { updateIndex++; } batchAffected = ps.executeBatch(); - if (batchAffected.length != inserted) throw new DbStateException(); + if (batchAffected.length != inserted) + throw new DbStateException(); for (int rows : batchAffected) if (rows != 1) throw new DbStateException(); ps.close(); @@ -2610,7 +2843,8 @@ abstract class JdbcDatabase implements Database { } @Override - public void removeGroupVisibility(Connection txn, ContactId c, GroupId g) + public void removeGroupVisibility(Connection txn, ContactId c, GroupId + g) throws DbException { PreparedStatement ps = null; try { @@ -2655,7 +2889,8 @@ abstract class JdbcDatabase implements Database { } @Override - public void removeMessage(Connection txn, MessageId m) throws DbException { + public void removeMessage(Connection txn, MessageId m) throws + DbException { PreparedStatement ps = null; try { String sql = "DELETE FROM messages WHERE messageId = ?"; @@ -2714,6 +2949,27 @@ abstract class JdbcDatabase implements Database { } } + @Override + public void removeStaticTransportKeys(Connection txn, TransportId t, + StaticTransportKeySetId k) throws DbException { + PreparedStatement ps = null; + try { + // Delete any existing outgoing keys - this will also remove any + // incoming keys with the same key set ID + String sql = "DELETE FROM outgoingStaticKeys" + + " WHERE transportId = ? AND keySetId = ?"; + ps = txn.prepareStatement(sql); + ps.setString(1, t.getString()); + ps.setInt(2, k.getInt()); + int affected = ps.executeUpdate(); + if (affected < 0) throw new DbStateException(); + ps.close(); + } catch (SQLException e) { + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public void removeTransport(Connection txn, TransportId t) throws DbException { @@ -2776,7 +3032,8 @@ abstract class JdbcDatabase implements Database { throws DbException { PreparedStatement ps = null; try { - String sql = "UPDATE contacts SET verified = ? WHERE contactId = ?"; + String sql = + "UPDATE contacts SET verified = ? WHERE contactId = ?"; ps = txn.prepareStatement(sql); ps.setBoolean(1, true); ps.setInt(2, c.getInt()); @@ -2794,7 +3051,8 @@ abstract class JdbcDatabase implements Database { throws DbException { PreparedStatement ps = null; try { - String sql = "UPDATE contacts SET active = ? WHERE contactId = ?"; + String sql = + "UPDATE contacts SET active = ? WHERE contactId = ?"; ps = txn.prepareStatement(sql); ps.setBoolean(1, active); ps.setInt(2, c.getInt()); @@ -2812,7 +3070,8 @@ abstract class JdbcDatabase implements Database { @Nullable String alias) throws DbException { PreparedStatement ps = null; try { - String sql = "UPDATE contacts SET alias = ? WHERE contactId = ?"; + String sql = + "UPDATE contacts SET alias = ? WHERE contactId = ?"; ps = txn.prepareStatement(sql); if (alias == null) ps.setNull(1, VARCHAR); else ps.setString(1, alias); @@ -2883,11 +3142,13 @@ abstract class JdbcDatabase implements Database { } @Override - public void setMessageState(Connection txn, MessageId m, MessageState state) + public void setMessageState(Connection txn, MessageId m, MessageState + state) throws DbException { PreparedStatement ps = null; try { - String sql = "UPDATE messages SET state = ? WHERE messageId = ?"; + String sql = + "UPDATE messages SET state = ? WHERE messageId = ?"; ps = txn.prepareStatement(sql); ps.setInt(1, state.getValue()); ps.setBytes(2, m.getBytes()); @@ -2895,7 +3156,8 @@ abstract class JdbcDatabase implements Database { if (affected < 0 || affected > 1) throw new DbStateException(); ps.close(); // Update denormalised column in messageMetadata - sql = "UPDATE messageMetadata SET state = ? WHERE messageId = ?"; + sql = + "UPDATE messageMetadata SET state = ? WHERE messageId = ?"; ps = txn.prepareStatement(sql); ps.setInt(1, state.getValue()); ps.setBytes(2, m.getBytes()); @@ -2922,7 +3184,8 @@ abstract class JdbcDatabase implements Database { // Update denormalised column in messageDependencies if dependency // is present and in same group as dependent sql = "UPDATE messageDependencies SET dependencyState = ?" - + " WHERE dependencyId = ? AND dependencyState IS NOT NULL"; + + + " WHERE dependencyId = ? AND dependencyState IS NOT NULL"; ps = txn.prepareStatement(sql); ps.setInt(1, state.getValue()); ps.setBytes(2, m.getBytes()); @@ -2979,7 +3242,8 @@ abstract class JdbcDatabase implements Database { } @Override - public void updateExpiryTimeAndEta(Connection txn, ContactId c, MessageId m, + public void updateExpiryTimeAndEta(Connection txn, ContactId + c, MessageId m, int maxLatency) throws DbException { PreparedStatement ps = null; ResultSet rs = null; @@ -3081,4 +3345,71 @@ abstract class JdbcDatabase implements Database { throw new DbException(e); } } + + @Override + public void updateStaticTransportKeys(Connection txn, + StaticTransportKeySet ks) throws DbException { + PreparedStatement ps = null; + try { + // Update the outgoing keys + String sql = "UPDATE outgoingStaticKeys SET timePeriod = ?," + + " tagKey = ?, headerKey = ?, stream = ?" + + " WHERE transportId = ? AND keySetId = ?"; + ps = txn.prepareStatement(sql); + StaticTransportKeys k = ks.getKeys(); + OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); + ps.setLong(1, outCurr.getTimePeriod()); + ps.setBytes(2, outCurr.getTagKey().getBytes()); + ps.setBytes(3, outCurr.getHeaderKey().getBytes()); + ps.setLong(4, outCurr.getStreamCounter()); + ps.setString(5, k.getTransportId().getString()); + ps.setInt(6, ks.getKeySetId().getInt()); + int affected = ps.executeUpdate(); + if (affected < 0 || affected > 1) throw new DbStateException(); + ps.close(); + // Update the incoming keys + sql = "UPDATE incomingStaticKeys SET timePeriod = ?," + + " tagKey = ?, headerKey = ?, base = ?, bitmap = ?" + + " WHERE transportId = ? AND keySetId = ?" + + " AND periodOffset = ?"; + ps = txn.prepareStatement(sql); + ps.setString(6, k.getTransportId().getString()); + ps.setInt(7, ks.getKeySetId().getInt()); + // Previous time period + IncomingKeys inPrev = k.getPreviousIncomingKeys(); + ps.setLong(1, inPrev.getTimePeriod()); + ps.setBytes(2, inPrev.getTagKey().getBytes()); + ps.setBytes(3, inPrev.getHeaderKey().getBytes()); + ps.setLong(4, inPrev.getWindowBase()); + ps.setBytes(5, inPrev.getWindowBitmap()); + ps.setInt(8, OFFSET_PREV); + ps.addBatch(); + // Current time period + IncomingKeys inCurr = k.getCurrentIncomingKeys(); + ps.setLong(1, inCurr.getTimePeriod()); + ps.setBytes(2, inCurr.getTagKey().getBytes()); + ps.setBytes(3, inCurr.getHeaderKey().getBytes()); + ps.setLong(4, inCurr.getWindowBase()); + ps.setBytes(5, inCurr.getWindowBitmap()); + ps.setInt(8, OFFSET_CURR); + ps.addBatch(); + // Next time period + IncomingKeys inNext = k.getNextIncomingKeys(); + ps.setLong(1, inNext.getTimePeriod()); + ps.setBytes(2, inNext.getTagKey().getBytes()); + ps.setBytes(3, inNext.getHeaderKey().getBytes()); + ps.setLong(4, inNext.getWindowBase()); + ps.setBytes(5, inNext.getWindowBitmap()); + ps.setInt(8, OFFSET_NEXT); + ps.addBatch(); + int[] batchAffected = ps.executeBatch(); + if (batchAffected.length != 3) throw new DbStateException(); + for (int rows : batchAffected) + if (rows < 0 || rows > 1) throw new DbStateException(); + ps.close(); + } catch (SQLException e) { + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java index 879eebd6a..a10592793 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java @@ -45,42 +45,46 @@ class Migration41_42 implements Migration { s.execute("ALTER TABLE incomingKeys" + " DROP COLUMN contactId"); s.execute(dbTypes.replaceTypes("CREATE TABLE pendingContacts" - + " (pendingContactId _HASH NOT NULL," - + " PRIMARY KEY (pendingContactId))")); + + " (pendingContactId _HASH NOT NULL," + + " PRIMARY KEY (pendingContactId))")); s.execute(dbTypes.replaceTypes("CREATE TABLE outgoingStaticKeys" - + " (transportId _STRING NOT NULL," - + " staticKeySetId _COUNTER," - + " rootKey _SECRET NOT NULL," - + " timePeriod BIGINT NOT NULL," - + " stream BIGINT NOT NULL," - + " contactId INT," // Null if contact is pending - + " pendingContactId _HASH," // Null if not pending - + " PRIMARY KEY (transportId, staticKeySetId)," - + " FOREIGN KEY (transportId)" - + " REFERENCES transports (transportId)" - + " ON DELETE CASCADE," - + " UNIQUE (staticKeySetId)," - + " FOREIGN KEY (contactId)" - + " REFERENCES contacts (contactId)" - + " ON DELETE CASCADE," - + " FOREIGN KEY (pendingContactId)" - + " REFERENCES pendingContacts (pendingContactId)" - + " ON DELETE CASCADE)")); + + " (transportId _STRING NOT NULL," + + " keySetId _COUNTER," + + " timePeriod BIGINT NOT NULL," + + " contactId INT," // Null if contact is pending + + " pendingContactId _HASH," // Null if not pending + + " rootKey _SECRET NOT NULL," + + " alice BOOLEAN NOT NULL," + + " tagKey _SECRET NOT NULL," + + " headerKey _SECRET NOT NULL," + + " stream BIGINT NOT NULL," + + " PRIMARY KEY (transportId, keySetId)," + + " FOREIGN KEY (transportId)" + + " REFERENCES transports (transportId)" + + " ON DELETE CASCADE," + + " UNIQUE (keySetId)," + + " FOREIGN KEY (contactId)" + + " REFERENCES contacts (contactId)" + + " ON DELETE CASCADE," + + " FOREIGN KEY (pendingContactId)" + + " REFERENCES pendingContacts (pendingContactId)" + + " ON DELETE CASCADE)")); s.execute(dbTypes.replaceTypes("CREATE TABLE incomingStaticKeys" - + " (transportId _STRING NOT NULL," - + " staticKeySetId INT NOT NULL," - + " timePeriod BIGINT NOT NULL," - + " base BIGINT NOT NULL," - + " bitmap _BINARY NOT NULL," - + " periodOffset INT NOT NULL," - + " PRIMARY KEY (transportId, staticKeySetId," - + " periodOffset)," - + " FOREIGN KEY (transportId)" - + " REFERENCES transports (transportId)" - + " ON DELETE CASCADE," - + " FOREIGN KEY (staticKeySetId)" - + " REFERENCES outgoingStaticKeys (staticKeySetId)" - + " ON DELETE CASCADE)")); + + " (transportId _STRING NOT NULL," + + " keySetId INT NOT NULL," + + " timePeriod BIGINT NOT NULL," + + " tagKey _SECRET NOT NULL," + + " headerKey _SECRET NOT NULL," + + " base BIGINT NOT NULL," + + " bitmap _BINARY NOT NULL," + + " periodOffset INT NOT NULL," + + " PRIMARY KEY (transportId, keySetId, periodOffset)," + + " FOREIGN KEY (transportId)" + + " REFERENCES transports (transportId)" + + " ON DELETE CASCADE," + + " FOREIGN KEY (keySetId)" + + " REFERENCES outgoingStaticKeys (keySetId)" + + " ON DELETE CASCADE)")); } catch (SQLException e) { tryToClose(s, LOG, WARNING); throw new DbException(e); From 6b24eeb84c2e633862bb28f798c56266700d805d Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 17 Apr 2019 09:58:36 +0100 Subject: [PATCH 08/19] Add method to set reordering window for static keys. --- .../org/briarproject/bramble/db/Database.java | 8 +++++++ .../briarproject/bramble/db/JdbcDatabase.java | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java index 3db95d1c8..6643419e0 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java @@ -691,6 +691,14 @@ interface Database { void setReorderingWindow(T txn, TransportKeySetId k, TransportId t, long timePeriod, long base, byte[] bitmap) throws DbException; + /** + * Sets the reordering window for the given static key set and transport in + * the given time period. + */ + void setStaticReorderingWindow(T txn, StaticTransportKeySetId k, + TransportId t, long timePeriod, long base, byte[] bitmap) + throws DbException; + /** * Marks the given transport keys as usable for outgoing streams. */ diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index 56978f1ba..d38dfb101 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -3222,6 +3222,30 @@ abstract class JdbcDatabase implements Database { } } + @Override + public void setStaticReorderingWindow(Connection txn, + StaticTransportKeySetId k, TransportId t, long timePeriod, + long base, byte[] bitmap) throws DbException { + PreparedStatement ps = null; + try { + String sql = "UPDATE incomingStaticKeys SET base = ?, bitmap = ?" + + " WHERE transportId = ? AND keySetId = ?" + + " AND timePeriod = ?"; + ps = txn.prepareStatement(sql); + ps.setLong(1, base); + ps.setBytes(2, bitmap); + ps.setString(3, t.getString()); + ps.setInt(4, k.getInt()); + ps.setLong(5, timePeriod); + int affected = ps.executeUpdate(); + if (affected < 0 || affected > 1) throw new DbStateException(); + ps.close(); + } catch (SQLException e) { + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public void setTransportKeysActive(Connection txn, TransportId t, TransportKeySetId k) throws DbException { From 94de1834b8f4c22fa3549faa52cd2117444e10c9 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 17 Apr 2019 12:06:47 +0100 Subject: [PATCH 09/19] Add unit tests for DB static key methods. --- .../bramble/db/JdbcDatabaseTest.java | 217 +++++++++++++++++- 1 file changed, 216 insertions(+), 1 deletion(-) diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java index 280b14f5a..0fe39b79b 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java @@ -22,6 +22,9 @@ import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.IncomingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys; +import org.briarproject.bramble.api.transport.StaticTransportKeySet; +import org.briarproject.bramble.api.transport.StaticTransportKeySetId; +import org.briarproject.bramble.api.transport.StaticTransportKeys; import org.briarproject.bramble.api.transport.TransportKeySet; import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; @@ -90,7 +93,6 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // All our transports use a maximum latency of 30 seconds private static final int MAX_LATENCY = 30 * 1000; - private final SecretKey key = getSecretKey(); private final File testDir = getTestDirectory(); private final GroupId groupId; @@ -104,6 +106,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { private final TransportId transportId; private final ContactId contactId; private final TransportKeySetId keySetId, keySetId1; + private final StaticTransportKeySetId staticKeySetId, staticKeySetId1; private final Random random = new Random(); JdbcDatabaseTest() { @@ -119,6 +122,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { contactId = new ContactId(1); keySetId = new TransportKeySetId(1); keySetId1 = new TransportKeySetId(2); + staticKeySetId = new StaticTransportKeySetId(1); + staticKeySetId1 = new StaticTransportKeySetId(2); } protected abstract JdbcDatabase createDatabase(DatabaseConfig config, @@ -750,6 +755,95 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { assertEquals(expected.isActive(), actual.isActive()); } + @Test + public void testStaticTransportKeys() throws Exception { + long timePeriod = 123, timePeriod1 = 234; + boolean alice = random.nextBoolean(); + SecretKey rootKey = getSecretKey(); + SecretKey rootKey1 = getSecretKey(); + StaticTransportKeys keys = + createStaticTransportKeys(timePeriod, rootKey, alice); + StaticTransportKeys keys1 = + createStaticTransportKeys(timePeriod1, rootKey1, alice); + + Database db = open(false); + Connection txn = db.startTransaction(); + + // Initially there should be no static transport keys in the database + assertEquals(emptyList(), db.getStaticTransportKeys(txn, transportId)); + + // Add the contact, the transport and the static transport keys + db.addLocalAuthor(txn, localAuthor); + assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), + true, true)); + db.addTransport(txn, transportId, 123); + assertEquals(staticKeySetId, + db.addStaticTransportKeys(txn, contactId, keys)); + assertEquals(staticKeySetId1, + db.addStaticTransportKeys(txn, contactId, keys1)); + + // Retrieve the static transport keys + Collection allKeys = + db.getStaticTransportKeys(txn, transportId); + assertEquals(2, allKeys.size()); + for (StaticTransportKeySet ks : allKeys) { + assertEquals(contactId, ks.getContactId()); + if (ks.getKeySetId().equals(staticKeySetId)) { + assertKeysEquals(keys, ks.getKeys()); + } else { + assertEquals(staticKeySetId1, ks.getKeySetId()); + assertKeysEquals(keys1, ks.getKeys()); + } + } + + // Update the transport keys + StaticTransportKeys updated = + createStaticTransportKeys(timePeriod + 1, rootKey, alice); + StaticTransportKeys updated1 = + createStaticTransportKeys(timePeriod1 + 1, rootKey1, alice); + db.updateStaticTransportKeys(txn, new StaticTransportKeySet( + staticKeySetId, contactId, updated)); + db.updateStaticTransportKeys(txn, new StaticTransportKeySet( + staticKeySetId1, contactId, updated1)); + + // Retrieve the static transport keys again + allKeys = db.getStaticTransportKeys(txn, transportId); + assertEquals(2, allKeys.size()); + for (StaticTransportKeySet ks : allKeys) { + assertEquals(contactId, ks.getContactId()); + if (ks.getKeySetId().equals(staticKeySetId)) { + assertKeysEquals(updated, ks.getKeys()); + } else { + assertEquals(staticKeySetId1, ks.getKeySetId()); + assertKeysEquals(updated1, ks.getKeys()); + } + } + + // Removing the contact should remove the static transport keys + db.removeContact(txn, contactId); + assertEquals(emptyList(), db.getStaticTransportKeys(txn, transportId)); + + db.commitTransaction(txn); + db.close(); + } + + private void assertKeysEquals(StaticTransportKeys expected, + StaticTransportKeys actual) { + assertEquals(expected.getTransportId(), actual.getTransportId()); + assertEquals(expected.getTimePeriod(), actual.getTimePeriod()); + assertArrayEquals(expected.getRootKey().getBytes(), + actual.getRootKey().getBytes()); + assertEquals(expected.isAlice(), actual.isAlice()); + assertKeysEquals(expected.getPreviousIncomingKeys(), + actual.getPreviousIncomingKeys()); + assertKeysEquals(expected.getCurrentIncomingKeys(), + actual.getCurrentIncomingKeys()); + assertKeysEquals(expected.getNextIncomingKeys(), + actual.getNextIncomingKeys()); + assertKeysEquals(expected.getCurrentOutgoingKeys(), + actual.getCurrentOutgoingKeys()); + } + @Test public void testIncrementStreamCounter() throws Exception { long timePeriod = 123; @@ -792,6 +886,54 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { db.close(); } + @Test + public void testIncrementStaticStreamCounter() throws Exception { + long timePeriod = 123; + SecretKey rootKey = getSecretKey(); + boolean alice = random.nextBoolean(); + StaticTransportKeys keys = + createStaticTransportKeys(timePeriod, rootKey, alice); + long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter(); + + Database db = open(false); + Connection txn = db.startTransaction(); + + // Add the contact, transport and static transport keys + db.addLocalAuthor(txn, localAuthor); + assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), + true, true)); + db.addTransport(txn, transportId, 123); + assertEquals(staticKeySetId, + db.addStaticTransportKeys(txn, contactId, keys)); + + // Increment the stream counter twice and retrieve the keys + db.incrementStreamCounter(txn, transportId, staticKeySetId); + db.incrementStreamCounter(txn, transportId, staticKeySetId); + Collection newKeys = + db.getStaticTransportKeys(txn, transportId); + assertEquals(1, newKeys.size()); + StaticTransportKeySet ks = newKeys.iterator().next(); + assertEquals(staticKeySetId, ks.getKeySetId()); + assertEquals(contactId, ks.getContactId()); + StaticTransportKeys k = ks.getKeys(); + assertEquals(transportId, k.getTransportId()); + assertArrayEquals(rootKey.getBytes(), k.getRootKey().getBytes()); + assertEquals(alice, k.isAlice()); + OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); + assertEquals(timePeriod, outCurr.getTimePeriod()); + assertEquals(streamCounter + 2, outCurr.getStreamCounter()); + + // The rest of the keys should be unaffected + assertKeysEquals(keys.getPreviousIncomingKeys(), + k.getPreviousIncomingKeys()); + assertKeysEquals(keys.getCurrentIncomingKeys(), + k.getCurrentIncomingKeys()); + assertKeysEquals(keys.getNextIncomingKeys(), k.getNextIncomingKeys()); + + db.commitTransaction(txn); + db.close(); + } + @Test public void testSetReorderingWindow() throws Exception { boolean active = random.nextBoolean(); @@ -838,6 +980,57 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { db.close(); } + @Test + public void testSetStaticReorderingWindow() throws Exception { + long timePeriod = 123; + SecretKey rootKey = getSecretKey(); + boolean alice = random.nextBoolean(); + StaticTransportKeys keys = + createStaticTransportKeys(timePeriod, rootKey, alice); + long base = keys.getCurrentIncomingKeys().getWindowBase(); + byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap(); + + Database db = open(false); + Connection txn = db.startTransaction(); + + // Add the contact, transport and static transport keys + db.addLocalAuthor(txn, localAuthor); + assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), + true, true)); + db.addTransport(txn, transportId, 123); + assertEquals(staticKeySetId, + db.addStaticTransportKeys(txn, contactId, keys)); + + // Update the reordering window and retrieve the static transport keys + random.nextBytes(bitmap); + db.setStaticReorderingWindow(txn, staticKeySetId, transportId, + timePeriod, base + 1, bitmap); + Collection newKeys = + db.getStaticTransportKeys(txn, transportId); + assertEquals(1, newKeys.size()); + StaticTransportKeySet ks = newKeys.iterator().next(); + assertEquals(staticKeySetId, ks.getKeySetId()); + assertEquals(contactId, ks.getContactId()); + StaticTransportKeys k = ks.getKeys(); + assertEquals(transportId, k.getTransportId()); + assertArrayEquals(rootKey.getBytes(), k.getRootKey().getBytes()); + assertEquals(alice, k.isAlice()); + IncomingKeys inCurr = k.getCurrentIncomingKeys(); + assertEquals(timePeriod, inCurr.getTimePeriod()); + assertEquals(base + 1, inCurr.getWindowBase()); + assertArrayEquals(bitmap, inCurr.getWindowBitmap()); + + // The rest of the keys should be unaffected + assertKeysEquals(keys.getPreviousIncomingKeys(), + k.getPreviousIncomingKeys()); + assertKeysEquals(keys.getNextIncomingKeys(), k.getNextIncomingKeys()); + assertKeysEquals(keys.getCurrentOutgoingKeys(), + k.getCurrentOutgoingKeys()); + + db.commitTransaction(txn); + db.close(); + } + @Test public void testGetContactsByAuthorId() throws Exception { Database db = open(false); @@ -2003,6 +2196,28 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr); } + private StaticTransportKeys createStaticTransportKeys(long timePeriod, + SecretKey rootKey, boolean alice) { + SecretKey inPrevTagKey = getSecretKey(); + SecretKey inPrevHeaderKey = getSecretKey(); + IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey, + timePeriod - 1, 123, new byte[4]); + SecretKey inCurrTagKey = getSecretKey(); + SecretKey inCurrHeaderKey = getSecretKey(); + IncomingKeys inCurr = new IncomingKeys(inCurrTagKey, inCurrHeaderKey, + timePeriod, 234, new byte[4]); + SecretKey inNextTagKey = getSecretKey(); + SecretKey inNextHeaderKey = getSecretKey(); + IncomingKeys inNext = new IncomingKeys(inNextTagKey, inNextHeaderKey, + timePeriod + 1, 345, new byte[4]); + SecretKey outCurrTagKey = getSecretKey(); + SecretKey outCurrHeaderKey = getSecretKey(); + OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey, + timePeriod, 456, true); + return new StaticTransportKeys(transportId, inPrev, inCurr, inNext, + outCurr, rootKey, alice); + } + @After public void tearDown() { deleteTestDirectory(testDir); From f08e3a58e6c5775e5ee14d40e96ae6efb99b3be1 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 17 Apr 2019 12:44:43 +0100 Subject: [PATCH 10/19] Add database methods for pending contacts. --- .../bramble/api/contact/PendingContact.java | 11 +- .../api/contact/PendingContactState.java | 30 +++++ .../PendingContactStateChangedEvent.java | 2 +- .../bramble/contact/ContactManagerImpl.java | 2 +- .../org/briarproject/bramble/db/Database.java | 25 +++++ .../briarproject/bramble/db/JdbcDatabase.java | 104 +++++++++++++++++- .../bramble/db/Migration41_42.java | 3 + 7 files changed, 163 insertions(+), 14 deletions(-) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContactState.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContact.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContact.java index 025803026..7b77cd805 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContact.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContact.java @@ -8,13 +8,6 @@ import javax.annotation.concurrent.Immutable; @NotNullByDefault public class PendingContact { - public enum PendingContactState { - WAITING_FOR_CONNECTION, - CONNECTED, - ADDING_CONTACT, - FAILED - } - private final PendingContactId id; private final String alias; private final PendingContactState state; @@ -28,6 +21,10 @@ public class PendingContact { this.timestamp = timestamp; } + public PendingContactId getId() { + return id; + } + public String getAlias() { return alias; } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContactState.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContactState.java new file mode 100644 index 000000000..5fd5a9919 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContactState.java @@ -0,0 +1,30 @@ +package org.briarproject.bramble.api.contact; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public enum PendingContactState { + + WAITING_FOR_CONNECTION(0), + CONNECTED(1), + ADDING_CONTACT(2), + FAILED(3); + + private final int value; + + PendingContactState(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static PendingContactState fromValue(int value) { + for (PendingContactState s : values()) if (s.value == value) return s; + throw new IllegalArgumentException(); + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/event/PendingContactStateChangedEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/event/PendingContactStateChangedEvent.java index b5a8dc11a..6e7b454c3 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/event/PendingContactStateChangedEvent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/event/PendingContactStateChangedEvent.java @@ -1,7 +1,7 @@ package org.briarproject.bramble.api.contact.event; -import org.briarproject.bramble.api.contact.PendingContact.PendingContactState; import org.briarproject.bramble.api.contact.PendingContactId; +import org.briarproject.bramble.api.contact.PendingContactState; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java index 1bae6b16d..3d9c0790f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java @@ -30,7 +30,7 @@ import javax.annotation.concurrent.ThreadSafe; import javax.inject.Inject; import static java.util.Collections.emptyList; -import static org.briarproject.bramble.api.contact.PendingContact.PendingContactState.WAITING_FOR_CONNECTION; +import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES; import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java index 6643419e0..a75094362 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java @@ -2,7 +2,9 @@ package org.briarproject.bramble.db; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.PendingContact; import org.briarproject.bramble.api.contact.PendingContactId; +import org.briarproject.bramble.api.contact.PendingContactState; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DataTooNewException; import org.briarproject.bramble.api.db.DataTooOldException; @@ -129,6 +131,11 @@ interface Database { */ void addOfferedMessage(T txn, ContactId c, MessageId m) throws DbException; + /** + * Stores a pending contact. + */ + void addPendingContact(T txn, PendingContact p) throws DbException; + /** * Stores the given static transport keys for the given contact and returns * a key set ID. @@ -497,6 +504,13 @@ interface Database { */ long getNextSendTime(T txn, ContactId c) throws DbException; + /** + * Returns all pending contacts. + *

+ * Read-only. + */ + Collection getPendingContacts(T txn) throws DbException; + /** * Returns the IDs of some messages that are eligible to be sent to the * given contact and have been requested by the contact, up to the given @@ -626,6 +640,11 @@ interface Database { void removeOfferedMessages(T txn, ContactId c, Collection requested) throws DbException; + /** + * Removes a pending contact (and all associated state) from the database. + */ + void removePendingContact(T txn, PendingContactId p) throws DbException; + /** * Removes the given static transport keys from the database. */ @@ -684,6 +703,12 @@ interface Database { void setMessageState(T txn, MessageId m, MessageState state) throws DbException; + /** + * Sets the state of the given pending contact. + */ + void setPendingContactState(T txn, PendingContactId p, + PendingContactState state) throws DbException; + /** * Sets the reordering window for the given key set and transport in the * given time period. diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index d38dfb101..440e025d1 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -2,7 +2,9 @@ package org.briarproject.bramble.db; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.PendingContact; import org.briarproject.bramble.api.contact.PendingContactId; +import org.briarproject.bramble.api.contact.PendingContactState; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DataTooNewException; import org.briarproject.bramble.api.db.DataTooOldException; @@ -289,6 +291,9 @@ abstract class JdbcDatabase implements Database { private static final String CREATE_PENDING_CONTACTS = "CREATE TABLE pendingContacts" + " (pendingContactId _HASH NOT NULL," + + " alias _STRING NOT NULL," + + " state INT NOT NULL," + + " timestamp BIGINT NOT NULL," + " PRIMARY KEY (pendingContactId))"; private static final String CREATE_OUTGOING_STATIC_KEYS = @@ -947,6 +952,28 @@ abstract class JdbcDatabase implements Database { } } + @Override + public void addPendingContact(Connection txn, PendingContact p) + throws DbException { + PreparedStatement ps = null; + try { + String sql = "INSERT INTO pendingContacts (pendingContactId," + + " alias, state, timestamp)" + + " VALUES (?, ?, ?, ?)"; + ps = txn.prepareStatement(sql); + ps.setBytes(1, p.getId().getBytes()); + ps.setString(2, p.getAlias()); + ps.setInt(3, p.getState().getValue()); + ps.setLong(4, p.getTimestamp()); + int affected = ps.executeUpdate(); + if (affected != 1) throw new DbStateException(); + ps.close(); + } catch (SQLException e) { + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public StaticTransportKeySetId addStaticTransportKeys(Connection txn, ContactId c, StaticTransportKeys k) throws DbException { @@ -1428,14 +1455,14 @@ abstract class JdbcDatabase implements Database { @Override public Collection getContacts(Connection txn) throws DbException { - PreparedStatement ps = null; + Statement s = null; ResultSet rs = null; try { String sql = "SELECT contactId, authorId, formatVersion, name," + " alias, publicKey, localAuthorId, verified, active" + " FROM contacts"; - ps = txn.prepareStatement(sql); - rs = ps.executeQuery(); + s = txn.createStatement(); + rs = s.executeQuery(sql); List contacts = new ArrayList<>(); while (rs.next()) { ContactId contactId = new ContactId(rs.getInt(1)); @@ -1453,11 +1480,11 @@ abstract class JdbcDatabase implements Database { alias, verified, active)); } rs.close(); - ps.close(); + s.close(); return contacts; } catch (SQLException e) { tryToClose(rs, LOG, WARNING); - tryToClose(ps, LOG, WARNING); + tryToClose(s, LOG, WARNING); throw new DbException(e); } } @@ -2258,6 +2285,36 @@ abstract class JdbcDatabase implements Database { } } + @Override + public Collection getPendingContacts(Connection txn) + throws DbException { + Statement s = null; + ResultSet rs = null; + try { + String sql = "SELECT pendingContactId, alias, state, timestamp" + + " FROM pendingContacts"; + s = txn.createStatement(); + rs = s.executeQuery(sql); + List pendingContacts = new ArrayList<>(); + while (rs.next()) { + PendingContactId id = new PendingContactId(rs.getBytes(1)); + String alias = rs.getString(2); + PendingContactState state = + PendingContactState.fromValue(rs.getInt(3)); + long timestamp = rs.getLong(4); + pendingContacts.add(new PendingContact(id, alias, state, + timestamp)); + } + rs.close(); + s.close(); + return pendingContacts; + } catch (SQLException e) { + tryToClose(rs, LOG, WARNING); + tryToClose(s, LOG, WARNING); + throw new DbException(e); + } + } + @Override public Collection getRequestedMessagesToSend(Connection txn, ContactId c, int maxLength, int maxLatency) throws DbException { @@ -2949,6 +3006,24 @@ abstract class JdbcDatabase implements Database { } } + @Override + public void removePendingContact(Connection txn, PendingContactId p) + throws DbException { + PreparedStatement ps = null; + try { + String sql = "DELETE FROM pendingContacts" + + " WHERE pendingContactId = ?"; + ps = txn.prepareStatement(sql); + ps.setBytes(1, p.getBytes()); + int affected = ps.executeUpdate(); + if (affected != 1) throw new DbStateException(); + ps.close(); + } catch (SQLException e) { + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public void removeStaticTransportKeys(Connection txn, TransportId t, StaticTransportKeySetId k) throws DbException { @@ -3198,6 +3273,25 @@ abstract class JdbcDatabase implements Database { } } + @Override + public void setPendingContactState(Connection txn, PendingContactId p, + PendingContactState state) throws DbException { + PreparedStatement ps = null; + try { + String sql = "UPDATE pendingContacts SET state = ?" + + " WHERE pendingContactId = ?"; + ps = txn.prepareStatement(sql); + ps.setInt(1, state.getValue()); + ps.setBytes(2, p.getBytes()); + int affected = ps.executeUpdate(); + if (affected != 1) throw new DbStateException(); + ps.close(); + } catch (SQLException e) { + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public void setReorderingWindow(Connection txn, TransportKeySetId k, TransportId t, long timePeriod, long base, byte[] bitmap) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java index a10592793..9dd523e4f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java @@ -46,6 +46,9 @@ class Migration41_42 implements Migration { + " DROP COLUMN contactId"); s.execute(dbTypes.replaceTypes("CREATE TABLE pendingContacts" + " (pendingContactId _HASH NOT NULL," + + " alias _STRING NOT NULL," + + " state INT NOT NULL," + + " timestamp BIGINT NOT NULL," + " PRIMARY KEY (pendingContactId))")); s.execute(dbTypes.replaceTypes("CREATE TABLE outgoingStaticKeys" + " (transportId _STRING NOT NULL," From e91a7c64d8e83c496c46998035cf612b9cc9beaf Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 17 Apr 2019 13:06:41 +0100 Subject: [PATCH 11/19] Add unit tests for DB pending contact methods. --- .../briarproject/bramble/test/TestUtils.java | 13 ++ .../bramble/db/JdbcDatabaseTest.java | 112 ++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java b/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java index d33304dd0..4c4d77ae6 100644 --- a/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java +++ b/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java @@ -1,6 +1,8 @@ package org.briarproject.bramble.test; import org.briarproject.bramble.api.UniqueId; +import org.briarproject.bramble.api.contact.PendingContact; +import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.AuthorId; @@ -25,6 +27,7 @@ import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import static java.util.Arrays.asList; +import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION; import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; @@ -140,6 +143,16 @@ public class TestUtils { return new Message(id, groupId, timestamp, body); } + public static PendingContact getPendingContact() { + return getPendingContact(1 + random.nextInt(MAX_AUTHOR_NAME_LENGTH)); + } + + public static PendingContact getPendingContact(int nameLength) { + PendingContactId id = new PendingContactId(getRandomId()); + String alias = getRandomString(nameLength); + return new PendingContact(id, alias, WAITING_FOR_CONNECTION, timestamp); + } + public static double getMedian(Collection samples) { int size = samples.size(); if (size == 0) throw new IllegalArgumentException(); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java index 0fe39b79b..a37c6fb94 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.db; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.PendingContact; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DbException; @@ -55,6 +56,7 @@ import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static java.util.concurrent.TimeUnit.SECONDS; +import static org.briarproject.bramble.api.contact.PendingContactState.FAILED; import static org.briarproject.bramble.api.db.Metadata.REMOVE; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; @@ -73,6 +75,7 @@ import static org.briarproject.bramble.test.TestUtils.getClientId; import static org.briarproject.bramble.test.TestUtils.getGroup; import static org.briarproject.bramble.test.TestUtils.getLocalAuthor; import static org.briarproject.bramble.test.TestUtils.getMessage; +import static org.briarproject.bramble.test.TestUtils.getPendingContact; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getTestDirectory; @@ -107,6 +110,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { private final ContactId contactId; private final TransportKeySetId keySetId, keySetId1; private final StaticTransportKeySetId staticKeySetId, staticKeySetId1; + private final PendingContact pendingContact; private final Random random = new Random(); JdbcDatabaseTest() { @@ -124,6 +128,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { keySetId1 = new TransportKeySetId(2); staticKeySetId = new StaticTransportKeySetId(1); staticKeySetId1 = new StaticTransportKeySetId(2); + pendingContact = getPendingContact(); } protected abstract JdbcDatabase createDatabase(DatabaseConfig config, @@ -788,6 +793,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { assertEquals(2, allKeys.size()); for (StaticTransportKeySet ks : allKeys) { assertEquals(contactId, ks.getContactId()); + assertNull(ks.getPendingContactId()); if (ks.getKeySetId().equals(staticKeySetId)) { assertKeysEquals(keys, ks.getKeys()); } else { @@ -811,6 +817,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { assertEquals(2, allKeys.size()); for (StaticTransportKeySet ks : allKeys) { assertEquals(contactId, ks.getContactId()); + assertNull(ks.getPendingContactId()); if (ks.getKeySetId().equals(staticKeySetId)) { assertKeysEquals(updated, ks.getKeys()); } else { @@ -844,6 +851,78 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { actual.getCurrentOutgoingKeys()); } + @Test + public void testStaticTransportKeysForPendingContact() throws Exception { + long timePeriod = 123, timePeriod1 = 234; + boolean alice = random.nextBoolean(); + SecretKey rootKey = getSecretKey(); + SecretKey rootKey1 = getSecretKey(); + StaticTransportKeys keys = + createStaticTransportKeys(timePeriod, rootKey, alice); + StaticTransportKeys keys1 = + createStaticTransportKeys(timePeriod1, rootKey1, alice); + + Database db = open(false); + Connection txn = db.startTransaction(); + + // Initially there should be no static transport keys in the database + assertEquals(emptyList(), db.getStaticTransportKeys(txn, transportId)); + + // Add the pending contact, the transport and the static transport keys + db.addPendingContact(txn, pendingContact); + db.addTransport(txn, transportId, 123); + assertEquals(staticKeySetId, + db.addStaticTransportKeys(txn, pendingContact.getId(), keys)); + assertEquals(staticKeySetId1, + db.addStaticTransportKeys(txn, pendingContact.getId(), keys1)); + + // Retrieve the static transport keys + Collection allKeys = + db.getStaticTransportKeys(txn, transportId); + assertEquals(2, allKeys.size()); + for (StaticTransportKeySet ks : allKeys) { + assertNull(ks.getContactId()); + assertEquals(pendingContact.getId(), ks.getPendingContactId()); + if (ks.getKeySetId().equals(staticKeySetId)) { + assertKeysEquals(keys, ks.getKeys()); + } else { + assertEquals(staticKeySetId1, ks.getKeySetId()); + assertKeysEquals(keys1, ks.getKeys()); + } + } + + // Update the transport keys + StaticTransportKeys updated = + createStaticTransportKeys(timePeriod + 1, rootKey, alice); + StaticTransportKeys updated1 = + createStaticTransportKeys(timePeriod1 + 1, rootKey1, alice); + db.updateStaticTransportKeys(txn, new StaticTransportKeySet( + staticKeySetId, pendingContact.getId(), updated)); + db.updateStaticTransportKeys(txn, new StaticTransportKeySet( + staticKeySetId1, pendingContact.getId(), updated1)); + + // Retrieve the static transport keys again + allKeys = db.getStaticTransportKeys(txn, transportId); + assertEquals(2, allKeys.size()); + for (StaticTransportKeySet ks : allKeys) { + assertNull(ks.getContactId()); + assertEquals(pendingContact.getId(), ks.getPendingContactId()); + if (ks.getKeySetId().equals(staticKeySetId)) { + assertKeysEquals(updated, ks.getKeys()); + } else { + assertEquals(staticKeySetId1, ks.getKeySetId()); + assertKeysEquals(updated1, ks.getKeys()); + } + } + + // Removing the pending contact should remove the static transport keys + db.removePendingContact(txn, pendingContact.getId()); + assertEquals(emptyList(), db.getStaticTransportKeys(txn, transportId)); + + db.commitTransaction(txn); + db.close(); + } + @Test public void testIncrementStreamCounter() throws Exception { long timePeriod = 123; @@ -2163,6 +2242,39 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { db.close(); } + @Test + public void testPendingContacts() throws Exception { + Database db = open(false); + Connection txn = db.startTransaction(); + + assertEquals(emptyList(), db.getPendingContacts(txn)); + + db.addPendingContact(txn, pendingContact); + Collection pendingContacts = + db.getPendingContacts(txn); + assertEquals(1, pendingContacts.size()); + PendingContact retrieved = pendingContacts.iterator().next(); + assertEquals(pendingContact.getId(), retrieved.getId()); + assertEquals(pendingContact.getAlias(), retrieved.getAlias()); + assertEquals(pendingContact.getState(), retrieved.getState()); + assertEquals(pendingContact.getTimestamp(), retrieved.getTimestamp()); + + db.setPendingContactState(txn, pendingContact.getId(), FAILED); + pendingContacts = db.getPendingContacts(txn); + assertEquals(1, pendingContacts.size()); + retrieved = pendingContacts.iterator().next(); + assertEquals(pendingContact.getId(), retrieved.getId()); + assertEquals(pendingContact.getAlias(), retrieved.getAlias()); + assertEquals(FAILED, retrieved.getState()); + assertEquals(pendingContact.getTimestamp(), retrieved.getTimestamp()); + + db.removePendingContact(txn, pendingContact.getId()); + assertEquals(emptyList(), db.getPendingContacts(txn)); + + db.commitTransaction(txn); + db.close(); + } + private Database open(boolean resume) throws Exception { return open(resume, new TestMessageFactory(), new SystemClock()); } From fafd0c7ff9f5904f708c092efe65608392787d06 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 17 Apr 2019 14:52:52 +0100 Subject: [PATCH 12/19] Rename static transport keys to handshake keys. --- .../bramble/api/crypto/TransportCrypto.java | 18 +- .../bramble/api/db/DatabaseComponent.java | 74 ++- .../api/transport/AbstractTransportKeys.java | 3 +- ...nsportKeySet.java => HandshakeKeySet.java} | 27 +- ...rtKeySetId.java => HandshakeKeySetId.java} | 12 +- ...cTransportKeys.java => HandshakeKeys.java} | 9 +- .../api/transport/TransportConstants.java | 16 +- .../api/transport/TransportKeySet.java | 3 +- .../bramble/api/transport/TransportKeys.java | 2 +- .../bramble/crypto/TransportCryptoImpl.java | 79 ++-- .../org/briarproject/bramble/db/Database.java | 85 ++-- .../bramble/db/DatabaseComponentImpl.java | 106 +++-- .../briarproject/bramble/db/JdbcDatabase.java | 442 +++++++++--------- .../bramble/db/Migration41_42.java | 6 +- ...t.java => HandshakeKeyDerivationTest.java} | 103 ++-- .../bramble/db/JdbcDatabaseTest.java | 203 ++++---- 16 files changed, 585 insertions(+), 603 deletions(-) rename bramble-api/src/main/java/org/briarproject/bramble/api/transport/{StaticTransportKeySet.java => HandshakeKeySet.java} (58%) rename bramble-api/src/main/java/org/briarproject/bramble/api/transport/{StaticTransportKeySetId.java => HandshakeKeySetId.java} (61%) rename bramble-api/src/main/java/org/briarproject/bramble/api/transport/{StaticTransportKeys.java => HandshakeKeys.java} (69%) rename bramble-core/src/test/java/org/briarproject/bramble/crypto/{StaticTransportKeyDerivationTest.java => HandshakeKeyDerivationTest.java} (58%) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java index 60972619b..a77f46157 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/TransportCrypto.java @@ -1,7 +1,7 @@ package org.briarproject.bramble.api.crypto; import org.briarproject.bramble.api.plugin.TransportId; -import org.briarproject.bramble.api.transport.StaticTransportKeys; +import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.TransportKeys; /** @@ -27,21 +27,19 @@ public interface TransportCrypto { TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod); /** - * Derives static transport keys for the given transport in the given time - * period from the given root key. + * Derives handshake keys for the given transport in the given time period + * from the given root key. * * @param alice whether the keys are for use by Alice or Bob. */ - StaticTransportKeys deriveStaticTransportKeys(TransportId t, - SecretKey rootKey, long timePeriod, boolean alice); + HandshakeKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey, + long timePeriod, boolean alice); /** - * Updates the given static transport keys to the given time period. If - * the keys are for the given period or any later period they are not - * updated. + * Updates the given handshake keys to the given time period. If the keys + * are for the given period or any later period they are not updated. */ - StaticTransportKeys updateStaticTransportKeys(StaticTransportKeys k, - long timePeriod); + HandshakeKeys updateHandshakeKeys(HandshakeKeys k, long timePeriod); /** * Encodes the pseudo-random tag that is used to recognise a stream. diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java index 8488c7bf0..e5be04b55 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java @@ -21,9 +21,9 @@ import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.validation.MessageState; -import org.briarproject.bramble.api.transport.StaticTransportKeySet; -import org.briarproject.bramble.api.transport.StaticTransportKeySetId; -import org.briarproject.bramble.api.transport.StaticTransportKeys; +import org.briarproject.bramble.api.transport.HandshakeKeySet; +import org.briarproject.bramble.api.transport.HandshakeKeySetId; +import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.TransportKeySet; import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; @@ -112,6 +112,20 @@ public interface DatabaseComponent { */ void addGroup(Transaction txn, Group g) throws DbException; + /** + * Stores the given handshake keys for the given contact and returns a + * key set ID. + */ + HandshakeKeySetId addHandshakeKeys(Transaction txn, ContactId c, + HandshakeKeys k) throws DbException; + + /** + * Stores the given handshake keys for the given pending contact and + * returns a key set ID. + */ + HandshakeKeySetId addHandshakeKeys(Transaction txn, PendingContactId p, + HandshakeKeys k) throws DbException; + /** * Stores a local pseudonym. */ @@ -123,20 +137,6 @@ public interface DatabaseComponent { void addLocalMessage(Transaction txn, Message m, Metadata meta, boolean shared) throws DbException; - /** - * Stores the given static transport keys for the given contact and returns - * a key set ID. - */ - StaticTransportKeySetId addStaticTransportKeys(Transaction txn, ContactId c, - StaticTransportKeys k) throws DbException; - - /** - * Stores the given static transport keys for the given pending contact and - * returns a key set ID. - */ - StaticTransportKeySetId addStaticTransportKeys(Transaction txn, - PendingContactId p, StaticTransportKeys k) throws DbException; - /** * Stores a transport. */ @@ -287,6 +287,14 @@ public interface DatabaseComponent { Visibility getGroupVisibility(Transaction txn, ContactId c, GroupId g) throws DbException; + /** + * Returns all handshake keys for the given transport. + *

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

@@ -442,14 +450,6 @@ public interface DatabaseComponent { */ Settings getSettings(Transaction txn, String namespace) throws DbException; - /** - * Returns all static transport keys for the given transport. - *

- * Read-only. - */ - Collection getStaticTransportKeys(Transaction txn, - TransportId t) throws DbException; - /** * Returns all transport keys for the given transport. *

@@ -459,11 +459,10 @@ public interface DatabaseComponent { throws DbException; /** - * Increments the outgoing stream counter for the given static transport - * keys. + * Increments the outgoing stream counter for the given handshake keys. */ void incrementStreamCounter(Transaction txn, TransportId t, - StaticTransportKeySetId k) throws DbException; + HandshakeKeySetId k) throws DbException; /** * Increments the outgoing stream counter for the given transport keys. @@ -524,6 +523,12 @@ public interface DatabaseComponent { */ void removeGroup(Transaction txn, Group g) throws DbException; + /** + * Removes the given handshake keys from the database. + */ + void removeHandshakeKeys(Transaction txn, TransportId t, + HandshakeKeySetId k) throws DbException; + /** * Removes a local pseudonym (and all associated state) from the database. */ @@ -534,12 +539,6 @@ public interface DatabaseComponent { */ void removeMessage(Transaction txn, MessageId m) throws DbException; - /** - * Removes the given static transport keys from the database. - */ - void removeStaticTransportKeys(Transaction txn, TransportId t, - StaticTransportKeySetId k) throws DbException; - /** * Removes a transport (and all associated state) from the database. */ @@ -606,11 +605,10 @@ public interface DatabaseComponent { TransportKeySetId k) throws DbException; /** - * Stores the given static transport keys, deleting any keys they have - * replaced. + * Stores the given handshake keys, deleting any keys they have replaced. */ - void updateStaticTransportKeys(Transaction txn, - Collection keys) throws DbException; + void updateHandshakeKeys(Transaction txn, Collection keys) + throws DbException; /** * Stores the given transport keys, deleting any keys they have replaced. diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/AbstractTransportKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/AbstractTransportKeys.java index a53631803..d054983d2 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/AbstractTransportKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/AbstractTransportKeys.java @@ -6,8 +6,7 @@ import org.briarproject.bramble.api.plugin.TransportId; import javax.annotation.concurrent.Immutable; /** - * Abstract superclass for {@link TransportKeys} and - * {@link StaticTransportKeys}. + * Abstract superclass for {@link TransportKeys} and {@link HandshakeKeys}. */ @Immutable @NotNullByDefault diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySet.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySet.java similarity index 58% rename from bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySet.java rename to bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySet.java index f8430f615..cb40da1da 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySet.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySet.java @@ -8,37 +8,38 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; /** - * A set of transport keys for communicating with a contact or pending contact. - * Unlike a {@link TransportKeySet} these keys do not provide forward secrecy. + * A set of keys for handshaking with a given contact or pending contact over a + * given transport. Unlike a {@link TransportKeySet} these keys do not provide + * forward secrecy. */ @Immutable @NotNullByDefault -public class StaticTransportKeySet { +public class HandshakeKeySet { - private final StaticTransportKeySetId keySetId; + private final HandshakeKeySetId keySetId; @Nullable private final ContactId contactId; @Nullable private final PendingContactId pendingContactId; - private final StaticTransportKeys keys; + private final HandshakeKeys keys; - public StaticTransportKeySet(StaticTransportKeySetId keySetId, - ContactId contactId, StaticTransportKeys keys) { + public HandshakeKeySet(HandshakeKeySetId keySetId, ContactId contactId, + HandshakeKeys keys) { this.keySetId = keySetId; this.contactId = contactId; this.keys = keys; pendingContactId = null; } - public StaticTransportKeySet(StaticTransportKeySetId keySetId, - PendingContactId pendingContactId, StaticTransportKeys keys) { + public HandshakeKeySet(HandshakeKeySetId keySetId, + PendingContactId pendingContactId, HandshakeKeys keys) { this.keySetId = keySetId; this.pendingContactId = pendingContactId; this.keys = keys; contactId = null; } - public StaticTransportKeySetId getKeySetId() { + public HandshakeKeySetId getKeySetId() { return keySetId; } @@ -52,7 +53,7 @@ public class StaticTransportKeySet { return pendingContactId; } - public StaticTransportKeys getKeys() { + public HandshakeKeys getKeys() { return keys; } @@ -63,7 +64,7 @@ public class StaticTransportKeySet { @Override public boolean equals(Object o) { - return o instanceof StaticTransportKeySet && - keySetId.equals(((StaticTransportKeySet) o).keySetId); + return o instanceof HandshakeKeySet && + keySetId.equals(((HandshakeKeySet) o).keySetId); } } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySetId.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySetId.java similarity index 61% rename from bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySetId.java rename to bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySetId.java index fbf6eb152..f54c3bb7a 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeySetId.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeySetId.java @@ -6,16 +6,16 @@ import javax.annotation.concurrent.Immutable; /** * Type-safe wrapper for an integer that uniquely identifies a - * {@link StaticTransportKeySet set of static transport keys} within the scope - * of the local device. + * {@link HandshakeKeySet set of handshake keys} within the scope of the local + * device. */ @Immutable @NotNullByDefault -public class StaticTransportKeySetId { +public class HandshakeKeySetId { private final int id; - public StaticTransportKeySetId(int id) { + public HandshakeKeySetId(int id) { this.id = id; } @@ -30,7 +30,7 @@ public class StaticTransportKeySetId { @Override public boolean equals(Object o) { - return o instanceof StaticTransportKeySetId && - id == ((StaticTransportKeySetId) o).id; + return o instanceof HandshakeKeySetId && + id == ((HandshakeKeySetId) o).id; } } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeys.java similarity index 69% rename from bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java rename to bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeys.java index 9c6ba3831..4a27e9adc 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StaticTransportKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/HandshakeKeys.java @@ -7,17 +7,18 @@ import org.briarproject.bramble.api.plugin.TransportId; import javax.annotation.concurrent.Immutable; /** - * Keys for communicating with a given contact or pending contact over a given - * transport. Unlike {@link TransportKeys} these do not provide forward secrecy. + * Keys for handshaking with a given contact or pending contact over a given + * transport. Unlike {@link TransportKeys} these keys do not provide forward + * secrecy. */ @Immutable @NotNullByDefault -public class StaticTransportKeys extends AbstractTransportKeys { +public class HandshakeKeys extends AbstractTransportKeys { private final SecretKey rootKey; private final boolean alice; - public StaticTransportKeys(TransportId transportId, IncomingKeys inPrev, + public HandshakeKeys(TransportId transportId, IncomingKeys inPrev, IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr, SecretKey rootKey, boolean alice) { super(transportId, inPrev, inCurr, inNext, outCurr); 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 60e9197ee..c40c5556b 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 @@ -109,26 +109,26 @@ public interface TransportConstants { String ROTATE_LABEL = "org.briarproject.bramble.transport/ROTATE"; /** - * Label for deriving Alice's static tag key from the root key. + * Label for deriving Alice's handshake tag key from the root key. */ - String ALICE_STATIC_TAG_LABEL = + String ALICE_HANDSHAKE_TAG_LABEL = "org.briarproject.bramble.transport/ALICE_STATIC_TAG_KEY"; /** - * Label for deriving Bob's static tag key from the root key. + * Label for deriving Bob's handshake tag key from the root key. */ - String BOB_STATIC_TAG_LABEL = + String BOB_HANDSHAKE_TAG_LABEL = "org.briarproject.bramble.transport/BOB_STATIC_TAG_KEY"; /** - * Label for deriving Alice's static header key from the root key. + * Label for deriving Alice's handshake header key from the root key. */ - String ALICE_STATIC_HEADER_LABEL = + String ALICE_HANDSHAKE_HEADER_LABEL = "org.briarproject.bramble.transport/ALICE_STATIC_HEADER_KEY"; /** - * Label for deriving Bob's static header key from the root key. + * Label for deriving Bob's handshake header key from the root key. */ - String BOB_STATIC_HEADER_LABEL = + String BOB_HANDSHAKE_HEADER_LABEL = "org.briarproject.bramble.transport/BOB_STATIC_HEADER_KEY"; } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java index 0400287ab..4b3831bc3 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java @@ -6,7 +6,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import javax.annotation.concurrent.Immutable; /** - * A set of transport keys for communicating with a contact. + * A set of keys for communicating with a given contact over a given transport. + * Unlike a {@link HandshakeKeySet} these keys provide forward secrecy. */ @Immutable @NotNullByDefault diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java index 9cd861df9..39a27d45b 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java @@ -7,7 +7,7 @@ import javax.annotation.concurrent.Immutable; /** * Keys for communicating with a given contact over a given transport. Unlike - * {@link StaticTransportKeys}, these keys provide forward secrecy. + * {@link HandshakeKeys} these keys provide forward secrecy. */ @Immutable @NotNullByDefault diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java index 9f6ea73e8..939ea2f41 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java @@ -4,9 +4,9 @@ import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.TransportCrypto; import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.IncomingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys; -import org.briarproject.bramble.api.transport.StaticTransportKeys; import org.briarproject.bramble.api.transport.TransportKeys; import org.spongycastle.crypto.Digest; import org.spongycastle.crypto.digests.Blake2bDigest; @@ -14,13 +14,13 @@ import org.spongycastle.crypto.digests.Blake2bDigest; import javax.inject.Inject; import static java.lang.System.arraycopy; +import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_HANDSHAKE_HEADER_LABEL; +import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_HANDSHAKE_TAG_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_HEADER_LABEL; -import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_STATIC_HEADER_LABEL; -import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_STATIC_TAG_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_TAG_LABEL; +import static org.briarproject.bramble.api.transport.TransportConstants.BOB_HANDSHAKE_HEADER_LABEL; +import static org.briarproject.bramble.api.transport.TransportConstants.BOB_HANDSHAKE_TAG_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.BOB_HEADER_LABEL; -import static org.briarproject.bramble.api.transport.TransportConstants.BOB_STATIC_HEADER_LABEL; -import static org.briarproject.bramble.api.transport.TransportConstants.BOB_STATIC_TAG_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.BOB_TAG_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.ROTATE_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; @@ -115,49 +115,51 @@ class TransportCryptoImpl implements TransportCrypto { } @Override - public StaticTransportKeys deriveStaticTransportKeys(TransportId t, - SecretKey rootKey, long timePeriod, boolean alice) { + public HandshakeKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey, + long timePeriod, boolean alice) { if (timePeriod < 1) throw new IllegalArgumentException(); - IncomingKeys inPrev = deriveStaticIncomingKeys(t, rootKey, alice, + IncomingKeys inPrev = deriveIncomingHandshakeKeys(t, rootKey, alice, timePeriod - 1); - IncomingKeys inCurr = deriveStaticIncomingKeys(t, rootKey, alice, + IncomingKeys inCurr = deriveIncomingHandshakeKeys(t, rootKey, alice, timePeriod); - IncomingKeys inNext = deriveStaticIncomingKeys(t, rootKey, alice, + IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey, alice, timePeriod + 1); - OutgoingKeys outCurr = deriveStaticOutgoingKeys(t, rootKey, alice, + OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, alice, timePeriod); - return new StaticTransportKeys(t, inPrev, inCurr, inNext, outCurr, - rootKey, alice); + return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, rootKey, + alice); } - private IncomingKeys deriveStaticIncomingKeys(TransportId t, + private IncomingKeys deriveIncomingHandshakeKeys(TransportId t, SecretKey rootKey, boolean alice, long timePeriod) { - SecretKey tag = deriveStaticTagKey(t, rootKey, !alice, timePeriod); - SecretKey header = deriveStaticHeaderKey(t, rootKey, !alice, + SecretKey tag = deriveHandshakeTagKey(t, rootKey, !alice, timePeriod); + SecretKey header = deriveHandshakeHeaderKey(t, rootKey, !alice, timePeriod); return new IncomingKeys(tag, header, timePeriod); } - private OutgoingKeys deriveStaticOutgoingKeys(TransportId t, + private OutgoingKeys deriveOutgoingHandshakeKeys(TransportId t, SecretKey rootKey, boolean alice, long timePeriod) { - SecretKey tag = deriveStaticTagKey(t, rootKey, alice, timePeriod); - SecretKey header = deriveStaticHeaderKey(t, rootKey, alice, timePeriod); + SecretKey tag = deriveHandshakeTagKey(t, rootKey, alice, timePeriod); + SecretKey header = deriveHandshakeHeaderKey(t, rootKey, alice, + timePeriod); return new OutgoingKeys(tag, header, timePeriod, true); } - private SecretKey deriveStaticTagKey(TransportId t, SecretKey rootKey, + private SecretKey deriveHandshakeTagKey(TransportId t, SecretKey rootKey, boolean alice, long timePeriod) { - String label = alice ? ALICE_STATIC_TAG_LABEL : BOB_STATIC_TAG_LABEL; + String label = alice ? ALICE_HANDSHAKE_TAG_LABEL : + BOB_HANDSHAKE_TAG_LABEL; byte[] id = toUtf8(t.getString()); byte[] period = new byte[INT_64_BYTES]; writeUint64(timePeriod, period, 0); return crypto.deriveKey(label, rootKey, id, period); } - private SecretKey deriveStaticHeaderKey(TransportId t, SecretKey rootKey, + private SecretKey deriveHandshakeHeaderKey(TransportId t, SecretKey rootKey, boolean alice, long timePeriod) { - String label = - alice ? ALICE_STATIC_HEADER_LABEL : BOB_STATIC_HEADER_LABEL; + String label = alice ? ALICE_HANDSHAKE_HEADER_LABEL : + BOB_HANDSHAKE_HEADER_LABEL; byte[] id = toUtf8(t.getString()); byte[] period = new byte[INT_64_BYTES]; writeUint64(timePeriod, period, 0); @@ -165,8 +167,7 @@ class TransportCryptoImpl implements TransportCrypto { } @Override - public StaticTransportKeys updateStaticTransportKeys(StaticTransportKeys k, - long timePeriod) { + public HandshakeKeys updateHandshakeKeys(HandshakeKeys k, long timePeriod) { long elapsed = timePeriod - k.getTimePeriod(); TransportId t = k.getTransportId(); SecretKey rootKey = k.getRootKey(); @@ -178,26 +179,26 @@ class TransportCryptoImpl implements TransportCrypto { // The keys are one period old - shift by one period IncomingKeys inPrev = k.getCurrentIncomingKeys(); IncomingKeys inCurr = k.getNextIncomingKeys(); - IncomingKeys inNext = deriveStaticIncomingKeys(t, rootKey, alice, - timePeriod + 1); - OutgoingKeys outCurr = deriveStaticOutgoingKeys(t, rootKey, alice, - timePeriod); - return new StaticTransportKeys(t, inPrev, inCurr, inNext, outCurr, + IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey, + alice, timePeriod + 1); + OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, + alice, timePeriod); + return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, rootKey, alice); } else if (elapsed == 2) { // The keys are two periods old - shift by two periods IncomingKeys inPrev = k.getNextIncomingKeys(); - IncomingKeys inCurr = deriveStaticIncomingKeys(t, rootKey, alice, - timePeriod); - IncomingKeys inNext = deriveStaticIncomingKeys(t, rootKey, alice, - timePeriod + 1); - OutgoingKeys outCurr = deriveStaticOutgoingKeys(t, rootKey, alice, - timePeriod); - return new StaticTransportKeys(t, inPrev, inCurr, inNext, outCurr, + IncomingKeys inCurr = deriveIncomingHandshakeKeys(t, rootKey, + alice, timePeriod); + IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey, + alice, timePeriod + 1); + OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, + alice, timePeriod); + return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, rootKey, alice); } else { // The keys are more than two periods old - derive fresh keys - return deriveStaticTransportKeys(t, rootKey, timePeriod, alice); + return deriveHandshakeKeys(t, rootKey, timePeriod, alice); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java index a75094362..c63760177 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java @@ -27,9 +27,9 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.validation.MessageState; -import org.briarproject.bramble.api.transport.StaticTransportKeySet; -import org.briarproject.bramble.api.transport.StaticTransportKeySetId; -import org.briarproject.bramble.api.transport.StaticTransportKeys; +import org.briarproject.bramble.api.transport.HandshakeKeySet; +import org.briarproject.bramble.api.transport.HandshakeKeySetId; +import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.TransportKeySet; import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; @@ -105,6 +105,20 @@ interface Database { void addGroupVisibility(T txn, ContactId c, GroupId g, boolean shared) throws DbException; + /** + * Stores the given handshake keys for the given contact and returns a + * key set ID. + */ + HandshakeKeySetId addHandshakeKeys(T txn, ContactId c, HandshakeKeys k) + throws DbException; + + /** + * Stores the given handshake keys for the given pending contact and + * returns a key set ID. + */ + HandshakeKeySetId addHandshakeKeys(T txn, PendingContactId p, + HandshakeKeys k) throws DbException; + /** * Stores a local pseudonym. */ @@ -136,20 +150,6 @@ interface Database { */ void addPendingContact(T txn, PendingContact p) throws DbException; - /** - * Stores the given static transport keys for the given contact and returns - * a key set ID. - */ - StaticTransportKeySetId addStaticTransportKeys(T txn, ContactId c, - StaticTransportKeys k) throws DbException; - - /** - * Stores the given static transport keys for the given pending contact and - * returns a key set ID. - */ - StaticTransportKeySetId addStaticTransportKeys(T txn, PendingContactId p, - StaticTransportKeys k) throws DbException; - /** * Stores a transport. */ @@ -314,6 +314,14 @@ interface Database { Map getGroupVisibility(T txn, GroupId g) throws DbException; + /** + * Returns all handshake keys for the given transport. + *

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

@@ -528,14 +536,6 @@ interface Database { */ Settings getSettings(T txn, String namespace) throws DbException; - /** - * Returns all static transport keys for the given transport. - *

- * Read-only. - */ - Collection getStaticTransportKeys(T txn, - TransportId t) throws DbException; - /** * Returns all transport keys for the given transport. *

@@ -545,10 +545,9 @@ interface Database { throws DbException; /** - * Increments the outgoing stream counter for the given static transport - * keys. + * Increments the outgoing stream counter for the given handshake keys. */ - void incrementStreamCounter(T txn, TransportId t, StaticTransportKeySetId k) + void incrementStreamCounter(T txn, TransportId t, HandshakeKeySetId k) throws DbException; /** @@ -623,6 +622,12 @@ interface Database { void removeGroupVisibility(T txn, ContactId c, GroupId g) throws DbException; + /** + * Removes the given handshake keys from the database. + */ + void removeHandshakeKeys(T txn, TransportId t, HandshakeKeySetId k) + throws DbException; + /** * Removes a local pseudonym (and all associated state) from the database. */ @@ -645,12 +650,6 @@ interface Database { */ void removePendingContact(T txn, PendingContactId p) throws DbException; - /** - * Removes the given static transport keys from the database. - */ - void removeStaticTransportKeys(T txn, TransportId t, - StaticTransportKeySetId k) throws DbException; - /** * Removes a transport (and all associated state) from the database. */ @@ -710,19 +709,18 @@ interface Database { PendingContactState state) throws DbException; /** - * Sets the reordering window for the given key set and transport in the - * given time period. + * Sets the reordering window for the given transport key set in the given + * time period. */ void setReorderingWindow(T txn, TransportKeySetId k, TransportId t, long timePeriod, long base, byte[] bitmap) throws DbException; /** - * Sets the reordering window for the given static key set and transport in - * the given time period. + * Sets the reordering window for the given handshake key set in the given + * time period. */ - void setStaticReorderingWindow(T txn, StaticTransportKeySetId k, - TransportId t, long timePeriod, long base, byte[] bitmap) - throws DbException; + void setReorderingWindow(T txn, HandshakeKeySetId k, TransportId t, + long timePeriod, long base, byte[] bitmap) throws DbException; /** * Marks the given transport keys as usable for outgoing streams. @@ -739,10 +737,9 @@ interface Database { throws DbException; /** - * Updates the given static transport keys following key rotation. + * Updates the given handshake keys. */ - void updateStaticTransportKeys(T txn, StaticTransportKeySet ks) - throws DbException; + void updateHandshakeKeys(T txn, HandshakeKeySet ks) throws DbException; /** * Updates the given transport keys following key rotation. diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java index e96c533e7..a70d1ca6b 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java @@ -60,9 +60,9 @@ import org.briarproject.bramble.api.sync.event.MessageToRequestEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesSentEvent; import org.briarproject.bramble.api.sync.validation.MessageState; -import org.briarproject.bramble.api.transport.StaticTransportKeySet; -import org.briarproject.bramble.api.transport.StaticTransportKeySetId; -import org.briarproject.bramble.api.transport.StaticTransportKeys; +import org.briarproject.bramble.api.transport.HandshakeKeySet; +import org.briarproject.bramble.api.transport.HandshakeKeySetId; +import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.TransportKeySet; import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; @@ -257,6 +257,30 @@ class DatabaseComponentImpl implements DatabaseComponent { } } + @Override + public HandshakeKeySetId addHandshakeKeys(Transaction transaction, + ContactId c, HandshakeKeys k) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); + T txn = unbox(transaction); + if (!db.containsContact(txn, c)) + throw new NoSuchContactException(); + if (!db.containsTransport(txn, k.getTransportId())) + throw new NoSuchTransportException(); + return db.addHandshakeKeys(txn, c, k); + } + + @Override + public HandshakeKeySetId addHandshakeKeys(Transaction transaction, + PendingContactId p, HandshakeKeys k) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); + T txn = unbox(transaction); + if (!db.containsPendingContact(txn, p)) + throw new NoSuchContactException(); + if (!db.containsTransport(txn, k.getTransportId())) + throw new NoSuchTransportException(); + return db.addHandshakeKeys(txn, p, k); + } + @Override public void addLocalAuthor(Transaction transaction, LocalAuthor a) throws DbException { @@ -285,32 +309,6 @@ class DatabaseComponentImpl implements DatabaseComponent { db.mergeMessageMetadata(txn, m.getId(), meta); } - @Override - public StaticTransportKeySetId addStaticTransportKeys( - Transaction transaction, ContactId c, StaticTransportKeys k) - throws DbException { - if (transaction.isReadOnly()) throw new IllegalArgumentException(); - T txn = unbox(transaction); - if (!db.containsContact(txn, c)) - throw new NoSuchContactException(); - if (!db.containsTransport(txn, k.getTransportId())) - throw new NoSuchTransportException(); - return db.addStaticTransportKeys(txn, c, k); - } - - @Override - public StaticTransportKeySetId addStaticTransportKeys( - Transaction transaction, PendingContactId p, - StaticTransportKeys k) throws DbException { - if (transaction.isReadOnly()) throw new IllegalArgumentException(); - T txn = unbox(transaction); - if (!db.containsPendingContact(txn, p)) - throw new NoSuchContactException(); - if (!db.containsTransport(txn, k.getTransportId())) - throw new NoSuchTransportException(); - return db.addStaticTransportKeys(txn, p, k); - } - @Override public void addTransport(Transaction transaction, TransportId t, int maxLatency) throws DbException { @@ -528,6 +526,15 @@ class DatabaseComponentImpl implements DatabaseComponent { return db.getGroupVisibility(txn, c, g); } + @Override + public Collection getHandshakeKeys(Transaction transaction, + TransportId t) throws DbException { + T txn = unbox(transaction); + if (!db.containsTransport(txn, t)) + throw new NoSuchTransportException(); + return db.getHandshakeKeys(txn, t); + } + @Override public LocalAuthor getLocalAuthor(Transaction transaction, AuthorId a) throws DbException { @@ -692,15 +699,6 @@ class DatabaseComponentImpl implements DatabaseComponent { return db.getSettings(txn, namespace); } - @Override - public Collection getStaticTransportKeys( - Transaction transaction, TransportId t) throws DbException { - T txn = unbox(transaction); - if (!db.containsTransport(txn, t)) - throw new NoSuchTransportException(); - return db.getStaticTransportKeys(txn, t); - } - @Override public Collection getTransportKeys(Transaction transaction, TransportId t) throws DbException { @@ -712,8 +710,8 @@ class DatabaseComponentImpl implements DatabaseComponent { @Override public void incrementStreamCounter(Transaction txn, TransportId t, - StaticTransportKeySetId k) throws DbException { - + HandshakeKeySetId k) throws DbException { + // TODO } @Override @@ -867,6 +865,16 @@ class DatabaseComponentImpl implements DatabaseComponent { transaction.attach(new GroupVisibilityUpdatedEvent(affected)); } + @Override + public void removeHandshakeKeys(Transaction transaction, + TransportId t, HandshakeKeySetId k) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); + T txn = unbox(transaction); + if (!db.containsTransport(txn, t)) + throw new NoSuchTransportException(); + db.removeHandshakeKeys(txn, t, k); + } + @Override public void removeLocalAuthor(Transaction transaction, AuthorId a) throws DbException { @@ -889,16 +897,6 @@ class DatabaseComponentImpl implements DatabaseComponent { db.removeMessage(txn, m); } - @Override - public void removeStaticTransportKeys(Transaction transaction, - TransportId t, StaticTransportKeySetId k) throws DbException { - if (transaction.isReadOnly()) throw new IllegalArgumentException(); - T txn = unbox(transaction); - if (!db.containsTransport(txn, t)) - throw new NoSuchTransportException(); - db.removeStaticTransportKeys(txn, t, k); - } - @Override public void removeTransport(Transaction transaction, TransportId t) throws DbException { @@ -1031,14 +1029,14 @@ class DatabaseComponentImpl implements DatabaseComponent { } @Override - public void updateStaticTransportKeys(Transaction transaction, - Collection keys) throws DbException { + public void updateHandshakeKeys(Transaction transaction, + Collection keys) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); - for (StaticTransportKeySet ks : keys) { + for (HandshakeKeySet ks : keys) { TransportId t = ks.getKeys().getTransportId(); if (db.containsTransport(txn, t)) - db.updateStaticTransportKeys(txn, ks); + db.updateHandshakeKeys(txn, ks); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index 440e025d1..6b51253a3 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -29,11 +29,11 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.transport.HandshakeKeySet; +import org.briarproject.bramble.api.transport.HandshakeKeySetId; +import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.IncomingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys; -import org.briarproject.bramble.api.transport.StaticTransportKeySet; -import org.briarproject.bramble.api.transport.StaticTransportKeySetId; -import org.briarproject.bramble.api.transport.StaticTransportKeys; import org.briarproject.bramble.api.transport.TransportKeySet; import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; @@ -296,8 +296,8 @@ abstract class JdbcDatabase implements Database { + " timestamp BIGINT NOT NULL," + " PRIMARY KEY (pendingContactId))"; - private static final String CREATE_OUTGOING_STATIC_KEYS = - "CREATE TABLE outgoingStaticKeys" + private static final String CREATE_OUTGOING_HANDSHAKE_KEYS = + "CREATE TABLE outgoingHandshakeKeys" + " (transportId _STRING NOT NULL," + " keySetId _COUNTER," + " timePeriod BIGINT NOT NULL," @@ -320,8 +320,8 @@ abstract class JdbcDatabase implements Database { + " REFERENCES pendingContacts (pendingContactId)" + " ON DELETE CASCADE)"; - private static final String CREATE_INCOMING_STATIC_KEYS = - "CREATE TABLE incomingStaticKeys" + private static final String CREATE_INCOMING_HANDSHAKE_KEYS = + "CREATE TABLE incomingHandshakeKeys" + " (transportId _STRING NOT NULL," + " keySetId INT NOT NULL," + " timePeriod BIGINT NOT NULL," @@ -335,7 +335,7 @@ abstract class JdbcDatabase implements Database { + " REFERENCES transports (transportId)" + " ON DELETE CASCADE," + " FOREIGN KEY (keySetId)" - + " REFERENCES outgoingStaticKeys (keySetId)" + + " REFERENCES outgoingHandshakeKeys (keySetId)" + " ON DELETE CASCADE)"; private static final String INDEX_CONTACTS_BY_AUTHOR_ID = @@ -533,8 +533,10 @@ abstract class JdbcDatabase implements Database { s.executeUpdate(dbTypes.replaceTypes(CREATE_OUTGOING_KEYS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_INCOMING_KEYS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_PENDING_CONTACTS)); - s.executeUpdate(dbTypes.replaceTypes(CREATE_OUTGOING_STATIC_KEYS)); - s.executeUpdate(dbTypes.replaceTypes(CREATE_INCOMING_STATIC_KEYS)); + s.executeUpdate(dbTypes.replaceTypes( + CREATE_OUTGOING_HANDSHAKE_KEYS)); + s.executeUpdate(dbTypes.replaceTypes( + CREATE_INCOMING_HANDSHAKE_KEYS)); s.close(); } catch (SQLException e) { tryToClose(s, LOG, WARNING); @@ -772,6 +774,103 @@ abstract class JdbcDatabase implements Database { } } + @Override + public HandshakeKeySetId addHandshakeKeys(Connection txn, ContactId c, + HandshakeKeys k) throws DbException { + return addHandshakeKeys(txn, c, null, k); + } + + @Override + public HandshakeKeySetId addHandshakeKeys(Connection txn, + PendingContactId p, HandshakeKeys k) throws DbException { + return addHandshakeKeys(txn, null, p, k); + } + + private HandshakeKeySetId addHandshakeKeys(Connection txn, + @Nullable ContactId c, @Nullable PendingContactId p, + HandshakeKeys k) throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + // Store the outgoing keys + String sql = "INSERT INTO outgoingHandshakeKeys (contactId," + + " pendingContactId, transportId, rootKey, alice," + + " timePeriod, tagKey, headerKey, stream)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; + ps = txn.prepareStatement(sql); + if (c == null) ps.setNull(1, INTEGER); + else ps.setInt(1, c.getInt()); + if (p == null) ps.setNull(2, BINARY); + else ps.setBytes(2, p.getBytes()); + ps.setString(3, k.getTransportId().getString()); + ps.setBytes(4, k.getRootKey().getBytes()); + ps.setBoolean(5, k.isAlice()); + OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); + ps.setLong(6, outCurr.getTimePeriod()); + ps.setBytes(7, outCurr.getTagKey().getBytes()); + ps.setBytes(8, outCurr.getHeaderKey().getBytes()); + ps.setLong(9, outCurr.getStreamCounter()); + int affected = ps.executeUpdate(); + if (affected != 1) throw new DbStateException(); + ps.close(); + // Get the new (highest) key set ID + sql = "SELECT keySetId FROM outgoingHandshakeKeys" + + " ORDER BY keySetId DESC LIMIT 1"; + ps = txn.prepareStatement(sql); + rs = ps.executeQuery(); + if (!rs.next()) throw new DbStateException(); + HandshakeKeySetId keySetId = new HandshakeKeySetId(rs.getInt(1)); + if (rs.next()) throw new DbStateException(); + rs.close(); + ps.close(); + // Store the incoming keys + sql = "INSERT INTO incomingHandshakeKeys (keySetId, transportId," + + " timePeriod, tagKey, headerKey, base, bitmap," + + " periodOffset)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + ps = txn.prepareStatement(sql); + ps.setInt(1, keySetId.getInt()); + ps.setString(2, k.getTransportId().getString()); + // Previous time period + IncomingKeys inPrev = k.getPreviousIncomingKeys(); + ps.setLong(3, inPrev.getTimePeriod()); + ps.setBytes(4, inPrev.getTagKey().getBytes()); + ps.setBytes(5, inPrev.getHeaderKey().getBytes()); + ps.setLong(6, inPrev.getWindowBase()); + ps.setBytes(7, inPrev.getWindowBitmap()); + ps.setInt(8, OFFSET_PREV); + ps.addBatch(); + // Current time period + IncomingKeys inCurr = k.getCurrentIncomingKeys(); + ps.setLong(3, inCurr.getTimePeriod()); + ps.setBytes(4, inCurr.getTagKey().getBytes()); + ps.setBytes(5, inCurr.getHeaderKey().getBytes()); + ps.setLong(6, inCurr.getWindowBase()); + ps.setBytes(7, inCurr.getWindowBitmap()); + ps.setInt(8, OFFSET_CURR); + ps.addBatch(); + // Next time period + IncomingKeys inNext = k.getNextIncomingKeys(); + ps.setLong(3, inNext.getTimePeriod()); + ps.setBytes(4, inNext.getTagKey().getBytes()); + ps.setBytes(5, inNext.getHeaderKey().getBytes()); + ps.setLong(6, inNext.getWindowBase()); + ps.setBytes(7, inNext.getWindowBitmap()); + ps.setInt(8, OFFSET_NEXT); + ps.addBatch(); + int[] batchAffected = ps.executeBatch(); + if (batchAffected.length != 3) throw new DbStateException(); + for (int rows : batchAffected) + if (rows != 1) throw new DbStateException(); + ps.close(); + return keySetId; + } catch (SQLException e) { + tryToClose(rs, LOG, WARNING); + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public void addLocalAuthor(Connection txn, LocalAuthor a) throws DbException { @@ -974,104 +1073,6 @@ abstract class JdbcDatabase implements Database { } } - @Override - public StaticTransportKeySetId addStaticTransportKeys(Connection txn, - ContactId c, StaticTransportKeys k) throws DbException { - return addStaticTransportKeys(txn, c, null, k); - } - - @Override - public StaticTransportKeySetId addStaticTransportKeys(Connection txn, - PendingContactId p, StaticTransportKeys k) throws DbException { - return addStaticTransportKeys(txn, null, p, k); - } - - private StaticTransportKeySetId addStaticTransportKeys(Connection txn, - @Nullable ContactId c, @Nullable PendingContactId p, - StaticTransportKeys k) throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - // Store the outgoing keys - String sql = "INSERT INTO outgoingStaticKeys (contactId," - + " pendingContactId, transportId, rootKey, alice," - + " timePeriod, tagKey, headerKey, stream)" - + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; - ps = txn.prepareStatement(sql); - if (c == null) ps.setNull(1, INTEGER); - else ps.setInt(1, c.getInt()); - if (p == null) ps.setNull(2, BINARY); - else ps.setBytes(2, p.getBytes()); - ps.setString(3, k.getTransportId().getString()); - ps.setBytes(4, k.getRootKey().getBytes()); - ps.setBoolean(5, k.isAlice()); - OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); - ps.setLong(6, outCurr.getTimePeriod()); - ps.setBytes(7, outCurr.getTagKey().getBytes()); - ps.setBytes(8, outCurr.getHeaderKey().getBytes()); - ps.setLong(9, outCurr.getStreamCounter()); - int affected = ps.executeUpdate(); - if (affected != 1) throw new DbStateException(); - ps.close(); - // Get the new (highest) key set ID - sql = "SELECT keySetId FROM outgoingStaticKeys" - + " ORDER BY keySetId DESC LIMIT 1"; - ps = txn.prepareStatement(sql); - rs = ps.executeQuery(); - if (!rs.next()) throw new DbStateException(); - StaticTransportKeySetId keySetId = new - StaticTransportKeySetId(rs.getInt(1)); - if (rs.next()) throw new DbStateException(); - rs.close(); - ps.close(); - // Store the incoming keys - sql = "INSERT INTO incomingStaticKeys (keySetId, transportId," - + " timePeriod, tagKey, headerKey, base, bitmap," - + " periodOffset)" - + " VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; - ps = txn.prepareStatement(sql); - ps.setInt(1, keySetId.getInt()); - ps.setString(2, k.getTransportId().getString()); - // Previous time period - IncomingKeys inPrev = k.getPreviousIncomingKeys(); - ps.setLong(3, inPrev.getTimePeriod()); - ps.setBytes(4, inPrev.getTagKey().getBytes()); - ps.setBytes(5, inPrev.getHeaderKey().getBytes()); - ps.setLong(6, inPrev.getWindowBase()); - ps.setBytes(7, inPrev.getWindowBitmap()); - ps.setInt(8, OFFSET_PREV); - ps.addBatch(); - // Current time period - IncomingKeys inCurr = k.getCurrentIncomingKeys(); - ps.setLong(3, inCurr.getTimePeriod()); - ps.setBytes(4, inCurr.getTagKey().getBytes()); - ps.setBytes(5, inCurr.getHeaderKey().getBytes()); - ps.setLong(6, inCurr.getWindowBase()); - ps.setBytes(7, inCurr.getWindowBitmap()); - ps.setInt(8, OFFSET_CURR); - ps.addBatch(); - // Next time period - IncomingKeys inNext = k.getNextIncomingKeys(); - ps.setLong(3, inNext.getTimePeriod()); - ps.setBytes(4, inNext.getTagKey().getBytes()); - ps.setBytes(5, inNext.getHeaderKey().getBytes()); - ps.setLong(6, inNext.getWindowBase()); - ps.setBytes(7, inNext.getWindowBitmap()); - ps.setInt(8, OFFSET_NEXT); - ps.addBatch(); - int[] batchAffected = ps.executeBatch(); - if (batchAffected.length != 3) throw new DbStateException(); - for (int rows : batchAffected) - if (rows != 1) throw new DbStateException(); - ps.close(); - return keySetId; - } catch (SQLException e) { - tryToClose(rs, LOG, WARNING); - tryToClose(ps, LOG, WARNING); - throw new DbException(e); - } - } - @Override public void addTransport(Connection txn, TransportId t, int maxLatency) throws DbException { @@ -1684,6 +1685,86 @@ abstract class JdbcDatabase implements Database { } } + @Override + public Collection getHandshakeKeys(Connection txn, + TransportId t) throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + // Retrieve the incoming keys + String sql = "SELECT timePeriod, tagKey, headerKey, base, bitmap" + + " FROM incomingHandshakeKeys" + + " WHERE transportId = ?" + + " ORDER BY keySetId, periodOffset"; + ps = txn.prepareStatement(sql); + ps.setString(1, t.getString()); + rs = ps.executeQuery(); + List inKeys = new ArrayList<>(); + while (rs.next()) { + long timePeriod = rs.getLong(1); + SecretKey tagKey = new SecretKey(rs.getBytes(2)); + SecretKey headerKey = new SecretKey(rs.getBytes(3)); + long windowBase = rs.getLong(4); + byte[] windowBitmap = rs.getBytes(5); + inKeys.add(new IncomingKeys(tagKey, headerKey, timePeriod, + windowBase, windowBitmap)); + } + rs.close(); + ps.close(); + // Retrieve the outgoing keys in the same order + sql = "SELECT keySetId, contactId, pendingContactId, timePeriod," + + " tagKey, headerKey, rootKey, alice, stream" + + " FROM outgoingHandshakeKeys" + + " WHERE transportId = ?" + + " ORDER BY keySetId"; + ps = txn.prepareStatement(sql); + ps.setString(1, t.getString()); + rs = ps.executeQuery(); + Collection keys = new ArrayList<>(); + for (int i = 0; rs.next(); i++) { + // There should be three times as many incoming keys + if (inKeys.size() < (i + 1) * 3) throw new DbStateException(); + HandshakeKeySetId keySetId = + new HandshakeKeySetId(rs.getInt(1)); + ContactId contactId = null; + int cId = rs.getInt(2); + if (!rs.wasNull()) contactId = new ContactId(cId); + PendingContactId pendingContactId = null; + byte[] pId = rs.getBytes(3); + if (!rs.wasNull()) pendingContactId = new PendingContactId(pId); + long timePeriod = rs.getLong(4); + SecretKey tagKey = new SecretKey(rs.getBytes(5)); + SecretKey headerKey = new SecretKey(rs.getBytes(6)); + SecretKey rootKey = new SecretKey(rs.getBytes(7)); + boolean alice = rs.getBoolean(8); + long streamCounter = rs.getLong(9); + OutgoingKeys outCurr = new OutgoingKeys(tagKey, headerKey, + timePeriod, streamCounter, true); + IncomingKeys inPrev = inKeys.get(i * 3); + IncomingKeys inCurr = inKeys.get(i * 3 + 1); + IncomingKeys inNext = inKeys.get(i * 3 + 2); + HandshakeKeys handshakeKeys = new HandshakeKeys(t, inPrev, + inCurr, inNext, outCurr, rootKey, alice); + if (contactId == null) { + if (pendingContactId == null) throw new DbStateException(); + keys.add(new HandshakeKeySet(keySetId, pendingContactId, + handshakeKeys)); + } else { + if (pendingContactId != null) throw new DbStateException(); + keys.add(new HandshakeKeySet(keySetId, contactId, + handshakeKeys)); + } + } + rs.close(); + ps.close(); + return keys; + } catch (SQLException e) { + tryToClose(rs, LOG, WARNING); + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public Collection getLocalAuthors(Connection txn) throws DbException { @@ -2377,87 +2458,6 @@ abstract class JdbcDatabase implements Database { } } - @Override - public Collection getStaticTransportKeys( - Connection txn, TransportId t) throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - // Retrieve the incoming keys - String sql = "SELECT timePeriod, tagKey, headerKey, base, bitmap" - + " FROM incomingStaticKeys" - + " WHERE transportId = ?" - + " ORDER BY keySetId, periodOffset"; - ps = txn.prepareStatement(sql); - ps.setString(1, t.getString()); - rs = ps.executeQuery(); - List inKeys = new ArrayList<>(); - while (rs.next()) { - long timePeriod = rs.getLong(1); - SecretKey tagKey = new SecretKey(rs.getBytes(2)); - SecretKey headerKey = new SecretKey(rs.getBytes(3)); - long windowBase = rs.getLong(4); - byte[] windowBitmap = rs.getBytes(5); - inKeys.add(new IncomingKeys(tagKey, headerKey, timePeriod, - windowBase, windowBitmap)); - } - rs.close(); - ps.close(); - // Retrieve the outgoing keys in the same order - sql = "SELECT keySetId, contactId, pendingContactId, timePeriod," - + " tagKey, headerKey, rootKey, alice, stream" - + " FROM outgoingStaticKeys" - + " WHERE transportId = ?" - + " ORDER BY keySetId"; - ps = txn.prepareStatement(sql); - ps.setString(1, t.getString()); - rs = ps.executeQuery(); - Collection keys = new ArrayList<>(); - for (int i = 0; rs.next(); i++) { - // There should be three times as many incoming keys - if (inKeys.size() < (i + 1) * 3) throw new DbStateException(); - StaticTransportKeySetId keySetId = - new StaticTransportKeySetId(rs.getInt(1)); - ContactId contactId = null; - int cId = rs.getInt(2); - if (!rs.wasNull()) contactId = new ContactId(cId); - PendingContactId pendingContactId = null; - byte[] pId = rs.getBytes(3); - if (!rs.wasNull()) pendingContactId = new PendingContactId(pId); - long timePeriod = rs.getLong(4); - SecretKey tagKey = new SecretKey(rs.getBytes(5)); - SecretKey headerKey = new SecretKey(rs.getBytes(6)); - SecretKey rootKey = new SecretKey(rs.getBytes(7)); - boolean alice = rs.getBoolean(8); - long streamCounter = rs.getLong(9); - OutgoingKeys outCurr = new OutgoingKeys(tagKey, headerKey, - timePeriod, streamCounter, true); - IncomingKeys inPrev = inKeys.get(i * 3); - IncomingKeys inCurr = inKeys.get(i * 3 + 1); - IncomingKeys inNext = inKeys.get(i * 3 + 2); - StaticTransportKeys staticTransportKeys = - new StaticTransportKeys(t, inPrev, inCurr, inNext, - outCurr, rootKey, alice); - if (contactId == null) { - if (pendingContactId == null) throw new DbStateException(); - keys.add(new StaticTransportKeySet(keySetId, - pendingContactId, staticTransportKeys)); - } else { - if (pendingContactId != null) throw new DbStateException(); - keys.add(new StaticTransportKeySet(keySetId, contactId, - staticTransportKeys)); - } - } - rs.close(); - ps.close(); - return keys; - } catch (SQLException e) { - tryToClose(rs, LOG, WARNING); - tryToClose(ps, LOG, WARNING); - throw new DbException(e); - } - } - @Override public Collection getTransportKeys(Connection txn, TransportId t) throws DbException { @@ -2527,10 +2527,10 @@ abstract class JdbcDatabase implements Database { @Override public void incrementStreamCounter(Connection txn, TransportId t, - StaticTransportKeySetId k) throws DbException { + HandshakeKeySetId k) throws DbException { PreparedStatement ps = null; try { - String sql = "UPDATE outgoingStaticKeys SET stream = stream + 1" + String sql = "UPDATE outgoingHandshakeKeys SET stream = stream + 1" + " WHERE transportId = ? AND keySetId = ?"; ps = txn.prepareStatement(sql); ps.setString(1, t.getString()); @@ -2928,6 +2928,27 @@ abstract class JdbcDatabase implements Database { } } + @Override + public void removeHandshakeKeys(Connection txn, TransportId t, + HandshakeKeySetId k) throws DbException { + PreparedStatement ps = null; + try { + // Delete any existing outgoing keys - this will also remove any + // incoming keys with the same key set ID + String sql = "DELETE FROM outgoingHandshakeKeys" + + " WHERE transportId = ? AND keySetId = ?"; + ps = txn.prepareStatement(sql); + ps.setString(1, t.getString()); + ps.setInt(2, k.getInt()); + int affected = ps.executeUpdate(); + if (affected < 0) throw new DbStateException(); + ps.close(); + } catch (SQLException e) { + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public void removeLocalAuthor(Connection txn, AuthorId a) throws DbException { @@ -3024,27 +3045,6 @@ abstract class JdbcDatabase implements Database { } } - @Override - public void removeStaticTransportKeys(Connection txn, TransportId t, - StaticTransportKeySetId k) throws DbException { - PreparedStatement ps = null; - try { - // Delete any existing outgoing keys - this will also remove any - // incoming keys with the same key set ID - String sql = "DELETE FROM outgoingStaticKeys" - + " WHERE transportId = ? AND keySetId = ?"; - ps = txn.prepareStatement(sql); - ps.setString(1, t.getString()); - ps.setInt(2, k.getInt()); - int affected = ps.executeUpdate(); - if (affected < 0) throw new DbStateException(); - ps.close(); - } catch (SQLException e) { - tryToClose(ps, LOG, WARNING); - throw new DbException(e); - } - } - @Override public void removeTransport(Connection txn, TransportId t) throws DbException { @@ -3317,12 +3317,12 @@ abstract class JdbcDatabase implements Database { } @Override - public void setStaticReorderingWindow(Connection txn, - StaticTransportKeySetId k, TransportId t, long timePeriod, - long base, byte[] bitmap) throws DbException { + public void setReorderingWindow(Connection txn, HandshakeKeySetId k, + TransportId t, long timePeriod, long base, byte[] bitmap) + throws DbException { PreparedStatement ps = null; try { - String sql = "UPDATE incomingStaticKeys SET base = ?, bitmap = ?" + String sql = "UPDATE incomingHandshakeKeys SET base = ?, bitmap = ?" + " WHERE transportId = ? AND keySetId = ?" + " AND timePeriod = ?"; ps = txn.prepareStatement(sql); @@ -3465,16 +3465,16 @@ abstract class JdbcDatabase implements Database { } @Override - public void updateStaticTransportKeys(Connection txn, - StaticTransportKeySet ks) throws DbException { + public void updateHandshakeKeys(Connection txn, HandshakeKeySet ks) + throws DbException { PreparedStatement ps = null; try { // Update the outgoing keys - String sql = "UPDATE outgoingStaticKeys SET timePeriod = ?," + String sql = "UPDATE outgoingHandshakeKeys SET timePeriod = ?," + " tagKey = ?, headerKey = ?, stream = ?" + " WHERE transportId = ? AND keySetId = ?"; ps = txn.prepareStatement(sql); - StaticTransportKeys k = ks.getKeys(); + HandshakeKeys k = ks.getKeys(); OutgoingKeys outCurr = k.getCurrentOutgoingKeys(); ps.setLong(1, outCurr.getTimePeriod()); ps.setBytes(2, outCurr.getTagKey().getBytes()); @@ -3486,7 +3486,7 @@ abstract class JdbcDatabase implements Database { if (affected < 0 || affected > 1) throw new DbStateException(); ps.close(); // Update the incoming keys - sql = "UPDATE incomingStaticKeys SET timePeriod = ?," + sql = "UPDATE incomingHandshakeKeys SET timePeriod = ?," + " tagKey = ?, headerKey = ?, base = ?, bitmap = ?" + " WHERE transportId = ? AND keySetId = ?" + " AND periodOffset = ?"; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java index 9dd523e4f..62d4c0705 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java @@ -50,7 +50,7 @@ class Migration41_42 implements Migration { + " state INT NOT NULL," + " timestamp BIGINT NOT NULL," + " PRIMARY KEY (pendingContactId))")); - s.execute(dbTypes.replaceTypes("CREATE TABLE outgoingStaticKeys" + s.execute(dbTypes.replaceTypes("CREATE TABLE outgoingHandshakeKeys" + " (transportId _STRING NOT NULL," + " keySetId _COUNTER," + " timePeriod BIGINT NOT NULL," @@ -72,7 +72,7 @@ class Migration41_42 implements Migration { + " FOREIGN KEY (pendingContactId)" + " REFERENCES pendingContacts (pendingContactId)" + " ON DELETE CASCADE)")); - s.execute(dbTypes.replaceTypes("CREATE TABLE incomingStaticKeys" + s.execute(dbTypes.replaceTypes("CREATE TABLE incomingHandshakeKeys" + " (transportId _STRING NOT NULL," + " keySetId INT NOT NULL," + " timePeriod BIGINT NOT NULL," @@ -86,7 +86,7 @@ class Migration41_42 implements Migration { + " REFERENCES transports (transportId)" + " ON DELETE CASCADE," + " FOREIGN KEY (keySetId)" - + " REFERENCES outgoingStaticKeys (keySetId)" + + " REFERENCES outgoingHandshakeKeys (keySetId)" + " ON DELETE CASCADE)")); } catch (SQLException e) { tryToClose(s, LOG, WARNING); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/StaticTransportKeyDerivationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/HandshakeKeyDerivationTest.java similarity index 58% rename from bramble-core/src/test/java/org/briarproject/bramble/crypto/StaticTransportKeyDerivationTest.java rename to bramble-core/src/test/java/org/briarproject/bramble/crypto/HandshakeKeyDerivationTest.java index c4f9a05a2..e741b9f08 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/crypto/StaticTransportKeyDerivationTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/HandshakeKeyDerivationTest.java @@ -4,7 +4,7 @@ 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.StaticTransportKeys; +import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.TestSecureRandomProvider; import org.junit.Test; @@ -19,7 +19,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertSame; -public class StaticTransportKeyDerivationTest extends BrambleTestCase { +public class HandshakeKeyDerivationTest extends BrambleTestCase { private final CryptoComponent crypto = new CryptoComponentImpl(new TestSecureRandomProvider(), null); @@ -30,74 +30,69 @@ public class StaticTransportKeyDerivationTest extends BrambleTestCase { @Test public void testKeysAreDistinct() { - StaticTransportKeys kA = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, true); - StaticTransportKeys kB = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, false); + HandshakeKeys kA = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + HandshakeKeys kB = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, false); assertAllDifferent(kA); assertAllDifferent(kB); } @Test public void testKeysAreNotUpdatedToPreviousPeriod() { - StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, true); - StaticTransportKeys k1 = - transportCrypto.updateStaticTransportKeys(k, 122); + HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 122); assertSame(k, k1); } @Test public void testKeysAreNotUpdatedToCurrentPeriod() { - StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, true); - StaticTransportKeys k1 = - transportCrypto.updateStaticTransportKeys(k, 123); + HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 123); assertSame(k, k1); } @Test public void testKeysAreUpdatedByOnePeriod() { - StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, true); - StaticTransportKeys k1 = - transportCrypto.updateStaticTransportKeys(k, 124); + HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 124); assertSame(k.getCurrentIncomingKeys(), k1.getPreviousIncomingKeys()); assertSame(k.getNextIncomingKeys(), k1.getCurrentIncomingKeys()); } @Test public void testKeysAreUpdatedByTwoPeriods() { - StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, true); - StaticTransportKeys k1 = - transportCrypto.updateStaticTransportKeys(k, 125); + HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 125); assertSame(k.getNextIncomingKeys(), k1.getPreviousIncomingKeys()); } @Test public void testKeysAreUpdatedByThreePeriods() { - StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, true); - StaticTransportKeys k1 = - transportCrypto.updateStaticTransportKeys(k, 126); + HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 126); assertAllDifferent(k, k1); } @Test public void testCurrentKeysMatchContact() { // Start in time period 123 - StaticTransportKeys kA = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, true); - StaticTransportKeys kB = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, false); + HandshakeKeys kA = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + HandshakeKeys kB = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, false); // Alice's incoming keys should equal Bob's outgoing keys assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); // Bob's incoming keys should equal Alice's outgoing keys assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys()); // Update into the future - kA = transportCrypto.updateStaticTransportKeys(kA, 456); - kB = transportCrypto.updateStaticTransportKeys(kB, 456); + kA = transportCrypto.updateHandshakeKeys(kA, 456); + kB = transportCrypto.updateHandshakeKeys(kB, 456); // Alice's incoming keys should equal Bob's outgoing keys assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys()); // Bob's incoming keys should equal Alice's outgoing keys @@ -107,21 +102,21 @@ public class StaticTransportKeyDerivationTest extends BrambleTestCase { @Test public void testPreviousKeysMatchContact() { // Start in time period 123 - StaticTransportKeys kA = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, true); - StaticTransportKeys kB = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, false); + HandshakeKeys kA = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + HandshakeKeys kB = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, false); // Compare Alice's previous keys in period 456 with Bob's current keys // in period 455 - kA = transportCrypto.updateStaticTransportKeys(kA, 456); - kB = transportCrypto.updateStaticTransportKeys(kB, 455); + kA = transportCrypto.updateHandshakeKeys(kA, 456); + kB = transportCrypto.updateHandshakeKeys(kB, 455); // Alice's previous incoming keys should equal Bob's current // outgoing keys assertMatches(kA.getPreviousIncomingKeys(), kB.getCurrentOutgoingKeys()); // Compare Alice's current keys in period 456 with Bob's previous keys // in period 457 - kB = transportCrypto.updateStaticTransportKeys(kB, 457); + kB = transportCrypto.updateHandshakeKeys(kB, 457); // Bob's previous incoming keys should equal Alice's current // outgoing keys assertMatches(kB.getPreviousIncomingKeys(), @@ -131,19 +126,19 @@ public class StaticTransportKeyDerivationTest extends BrambleTestCase { @Test public void testNextKeysMatchContact() { // Start in time period 123 - StaticTransportKeys kA = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, true); - StaticTransportKeys kB = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, false); + HandshakeKeys kA = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + HandshakeKeys kB = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, false); // Compare Alice's current keys in period 456 with Bob's next keys in // period 455 - kA = transportCrypto.updateStaticTransportKeys(kA, 456); - kB = transportCrypto.updateStaticTransportKeys(kB, 455); + kA = transportCrypto.updateHandshakeKeys(kA, 456); + kB = transportCrypto.updateHandshakeKeys(kB, 455); // Bob's next incoming keys should equal Alice's current outgoing keys assertMatches(kB.getNextIncomingKeys(), kA.getCurrentOutgoingKeys()); // Compare Alice's next keys in period 456 with Bob's current keys // in period 457 - kB = transportCrypto.updateStaticTransportKeys(kB, 457); + kB = transportCrypto.updateHandshakeKeys(kB, 457); // Alice's next incoming keys should equal Bob's current outgoing keys assertMatches(kA.getNextIncomingKeys(), kB.getCurrentOutgoingKeys()); } @@ -152,10 +147,10 @@ public class StaticTransportKeyDerivationTest extends BrambleTestCase { public void testRootKeyAffectsOutput() { SecretKey rootKey1 = getSecretKey(); assertFalse(Arrays.equals(rootKey.getBytes(), rootKey1.getBytes())); - StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, true); - StaticTransportKeys k1 = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey1, 123, true); + HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + HandshakeKeys k1 = transportCrypto.deriveHandshakeKeys(transportId, + rootKey1, 123, true); assertAllDifferent(k, k1); } @@ -163,10 +158,10 @@ public class StaticTransportKeyDerivationTest extends BrambleTestCase { public void testTransportIdAffectsOutput() { TransportId transportId1 = getTransportId(); assertNotEquals(transportId.getString(), transportId1.getString()); - StaticTransportKeys k = transportCrypto.deriveStaticTransportKeys( - transportId, rootKey, 123, true); - StaticTransportKeys k1 = transportCrypto.deriveStaticTransportKeys( - transportId1, rootKey, 123, true); + HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, 123, true); + HandshakeKeys k1 = transportCrypto.deriveHandshakeKeys(transportId1, + rootKey, 123, true); assertAllDifferent(k, k1); } } \ No newline at end of file diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java index a37c6fb94..3ecb5104c 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java @@ -21,11 +21,11 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.transport.HandshakeKeySet; +import org.briarproject.bramble.api.transport.HandshakeKeySetId; +import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.IncomingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys; -import org.briarproject.bramble.api.transport.StaticTransportKeySet; -import org.briarproject.bramble.api.transport.StaticTransportKeySetId; -import org.briarproject.bramble.api.transport.StaticTransportKeys; import org.briarproject.bramble.api.transport.TransportKeySet; import org.briarproject.bramble.api.transport.TransportKeySetId; import org.briarproject.bramble.api.transport.TransportKeys; @@ -109,7 +109,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { private final TransportId transportId; private final ContactId contactId; private final TransportKeySetId keySetId, keySetId1; - private final StaticTransportKeySetId staticKeySetId, staticKeySetId1; + private final HandshakeKeySetId handshakeKeySetId, handshakeKeySetId1; private final PendingContact pendingContact; private final Random random = new Random(); @@ -126,8 +126,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { contactId = new ContactId(1); keySetId = new TransportKeySetId(1); keySetId1 = new TransportKeySetId(2); - staticKeySetId = new StaticTransportKeySetId(1); - staticKeySetId1 = new StaticTransportKeySetId(2); + handshakeKeySetId = new HandshakeKeySetId(1); + handshakeKeySetId1 = new HandshakeKeySetId(2); pendingContact = getPendingContact(); } @@ -761,81 +761,79 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { } @Test - public void testStaticTransportKeys() throws Exception { + public void testHandshakeKeys() throws Exception { long timePeriod = 123, timePeriod1 = 234; boolean alice = random.nextBoolean(); SecretKey rootKey = getSecretKey(); SecretKey rootKey1 = getSecretKey(); - StaticTransportKeys keys = - createStaticTransportKeys(timePeriod, rootKey, alice); - StaticTransportKeys keys1 = - createStaticTransportKeys(timePeriod1, rootKey1, alice); + HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); + HandshakeKeys keys1 = createHandshakeKeys(timePeriod1, rootKey1, alice); Database db = open(false); Connection txn = db.startTransaction(); - // Initially there should be no static transport keys in the database - assertEquals(emptyList(), db.getStaticTransportKeys(txn, transportId)); + // Initially there should be no handshake keys in the database + assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId)); - // Add the contact, the transport and the static transport keys + // Add the contact, the transport and the handshake keys db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), true, true)); db.addTransport(txn, transportId, 123); - assertEquals(staticKeySetId, - db.addStaticTransportKeys(txn, contactId, keys)); - assertEquals(staticKeySetId1, - db.addStaticTransportKeys(txn, contactId, keys1)); + assertEquals(handshakeKeySetId, + db.addHandshakeKeys(txn, contactId, keys)); + assertEquals(handshakeKeySetId1, + db.addHandshakeKeys(txn, contactId, keys1)); - // Retrieve the static transport keys - Collection allKeys = - db.getStaticTransportKeys(txn, transportId); + // Retrieve the handshake keys + Collection allKeys = + db.getHandshakeKeys(txn, transportId); assertEquals(2, allKeys.size()); - for (StaticTransportKeySet ks : allKeys) { + for (HandshakeKeySet ks : allKeys) { assertEquals(contactId, ks.getContactId()); assertNull(ks.getPendingContactId()); - if (ks.getKeySetId().equals(staticKeySetId)) { + if (ks.getKeySetId().equals(handshakeKeySetId)) { assertKeysEquals(keys, ks.getKeys()); } else { - assertEquals(staticKeySetId1, ks.getKeySetId()); + assertEquals(handshakeKeySetId1, ks.getKeySetId()); assertKeysEquals(keys1, ks.getKeys()); } } - // Update the transport keys - StaticTransportKeys updated = - createStaticTransportKeys(timePeriod + 1, rootKey, alice); - StaticTransportKeys updated1 = - createStaticTransportKeys(timePeriod1 + 1, rootKey1, alice); - db.updateStaticTransportKeys(txn, new StaticTransportKeySet( - staticKeySetId, contactId, updated)); - db.updateStaticTransportKeys(txn, new StaticTransportKeySet( - staticKeySetId1, contactId, updated1)); + // Update the handshake keys + HandshakeKeys updated = + createHandshakeKeys(timePeriod + 1, rootKey, alice); + HandshakeKeys updated1 = + createHandshakeKeys(timePeriod1 + 1, rootKey1, alice); + db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId, + contactId, updated)); + db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId1, + contactId, updated1)); - // Retrieve the static transport keys again - allKeys = db.getStaticTransportKeys(txn, transportId); + // Retrieve the handshake keys again + allKeys = db.getHandshakeKeys(txn, transportId); assertEquals(2, allKeys.size()); - for (StaticTransportKeySet ks : allKeys) { + for (HandshakeKeySet ks : allKeys) { assertEquals(contactId, ks.getContactId()); assertNull(ks.getPendingContactId()); - if (ks.getKeySetId().equals(staticKeySetId)) { + if (ks.getKeySetId().equals(handshakeKeySetId)) { assertKeysEquals(updated, ks.getKeys()); } else { - assertEquals(staticKeySetId1, ks.getKeySetId()); + assertEquals(handshakeKeySetId1, ks.getKeySetId()); assertKeysEquals(updated1, ks.getKeys()); } } - // Removing the contact should remove the static transport keys + // Removing the contact should remove the handshake keys db.removeContact(txn, contactId); - assertEquals(emptyList(), db.getStaticTransportKeys(txn, transportId)); + assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId)); db.commitTransaction(txn); db.close(); } - private void assertKeysEquals(StaticTransportKeys expected, - StaticTransportKeys actual) { + private void assertKeysEquals(HandshakeKeys expected, + HandshakeKeys actual) { assertEquals(expected.getTransportId(), actual.getTransportId()); assertEquals(expected.getTimePeriod(), actual.getTimePeriod()); assertArrayEquals(expected.getRootKey().getBytes(), @@ -852,72 +850,70 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { } @Test - public void testStaticTransportKeysForPendingContact() throws Exception { + public void testHandshakeKeysForPendingContact() throws Exception { long timePeriod = 123, timePeriod1 = 234; boolean alice = random.nextBoolean(); SecretKey rootKey = getSecretKey(); SecretKey rootKey1 = getSecretKey(); - StaticTransportKeys keys = - createStaticTransportKeys(timePeriod, rootKey, alice); - StaticTransportKeys keys1 = - createStaticTransportKeys(timePeriod1, rootKey1, alice); + HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); + HandshakeKeys keys1 = createHandshakeKeys(timePeriod1, rootKey1, alice); Database db = open(false); Connection txn = db.startTransaction(); - // Initially there should be no static transport keys in the database - assertEquals(emptyList(), db.getStaticTransportKeys(txn, transportId)); + // Initially there should be no handshake keys in the database + assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId)); - // Add the pending contact, the transport and the static transport keys + // Add the pending contact, the transport and the handshake keys db.addPendingContact(txn, pendingContact); db.addTransport(txn, transportId, 123); - assertEquals(staticKeySetId, - db.addStaticTransportKeys(txn, pendingContact.getId(), keys)); - assertEquals(staticKeySetId1, - db.addStaticTransportKeys(txn, pendingContact.getId(), keys1)); + assertEquals(handshakeKeySetId, db.addHandshakeKeys(txn, + pendingContact.getId(), keys)); + assertEquals(handshakeKeySetId1, db.addHandshakeKeys(txn, + pendingContact.getId(), keys1)); - // Retrieve the static transport keys - Collection allKeys = - db.getStaticTransportKeys(txn, transportId); + // Retrieve the handshake keys + Collection allKeys = + db.getHandshakeKeys(txn, transportId); assertEquals(2, allKeys.size()); - for (StaticTransportKeySet ks : allKeys) { + for (HandshakeKeySet ks : allKeys) { assertNull(ks.getContactId()); assertEquals(pendingContact.getId(), ks.getPendingContactId()); - if (ks.getKeySetId().equals(staticKeySetId)) { + if (ks.getKeySetId().equals(handshakeKeySetId)) { assertKeysEquals(keys, ks.getKeys()); } else { - assertEquals(staticKeySetId1, ks.getKeySetId()); + assertEquals(handshakeKeySetId1, ks.getKeySetId()); assertKeysEquals(keys1, ks.getKeys()); } } - // Update the transport keys - StaticTransportKeys updated = - createStaticTransportKeys(timePeriod + 1, rootKey, alice); - StaticTransportKeys updated1 = - createStaticTransportKeys(timePeriod1 + 1, rootKey1, alice); - db.updateStaticTransportKeys(txn, new StaticTransportKeySet( - staticKeySetId, pendingContact.getId(), updated)); - db.updateStaticTransportKeys(txn, new StaticTransportKeySet( - staticKeySetId1, pendingContact.getId(), updated1)); + // Update the handshake keys + HandshakeKeys updated = + createHandshakeKeys(timePeriod + 1, rootKey, alice); + HandshakeKeys updated1 = + createHandshakeKeys(timePeriod1 + 1, rootKey1, alice); + db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId, + pendingContact.getId(), updated)); + db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId1, + pendingContact.getId(), updated1)); - // Retrieve the static transport keys again - allKeys = db.getStaticTransportKeys(txn, transportId); + // Retrieve the handshake keys again + allKeys = db.getHandshakeKeys(txn, transportId); assertEquals(2, allKeys.size()); - for (StaticTransportKeySet ks : allKeys) { + for (HandshakeKeySet ks : allKeys) { assertNull(ks.getContactId()); assertEquals(pendingContact.getId(), ks.getPendingContactId()); - if (ks.getKeySetId().equals(staticKeySetId)) { + if (ks.getKeySetId().equals(handshakeKeySetId)) { assertKeysEquals(updated, ks.getKeys()); } else { - assertEquals(staticKeySetId1, ks.getKeySetId()); + assertEquals(handshakeKeySetId1, ks.getKeySetId()); assertKeysEquals(updated1, ks.getKeys()); } } - // Removing the pending contact should remove the static transport keys + // Removing the pending contact should remove the handshake keys db.removePendingContact(txn, pendingContact.getId()); - assertEquals(emptyList(), db.getStaticTransportKeys(txn, transportId)); + assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId)); db.commitTransaction(txn); db.close(); @@ -970,31 +966,29 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { long timePeriod = 123; SecretKey rootKey = getSecretKey(); boolean alice = random.nextBoolean(); - StaticTransportKeys keys = - createStaticTransportKeys(timePeriod, rootKey, alice); + HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter(); Database db = open(false); Connection txn = db.startTransaction(); - // Add the contact, transport and static transport keys + // Add the contact, transport and handshake keys db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), true, true)); db.addTransport(txn, transportId, 123); - assertEquals(staticKeySetId, - db.addStaticTransportKeys(txn, contactId, keys)); + assertEquals(handshakeKeySetId, db.addHandshakeKeys(txn, contactId, keys)); - // Increment the stream counter twice and retrieve the keys - db.incrementStreamCounter(txn, transportId, staticKeySetId); - db.incrementStreamCounter(txn, transportId, staticKeySetId); - Collection newKeys = - db.getStaticTransportKeys(txn, transportId); + // Increment the stream counter twice and retrieve the handshake keys + db.incrementStreamCounter(txn, transportId, handshakeKeySetId); + db.incrementStreamCounter(txn, transportId, handshakeKeySetId); + Collection newKeys = + db.getHandshakeKeys(txn, transportId); assertEquals(1, newKeys.size()); - StaticTransportKeySet ks = newKeys.iterator().next(); - assertEquals(staticKeySetId, ks.getKeySetId()); + HandshakeKeySet ks = newKeys.iterator().next(); + assertEquals(handshakeKeySetId, ks.getKeySetId()); assertEquals(contactId, ks.getContactId()); - StaticTransportKeys k = ks.getKeys(); + HandshakeKeys k = ks.getKeys(); assertEquals(transportId, k.getTransportId()); assertArrayEquals(rootKey.getBytes(), k.getRootKey().getBytes()); assertEquals(alice, k.isAlice()); @@ -1064,33 +1058,32 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { long timePeriod = 123; SecretKey rootKey = getSecretKey(); boolean alice = random.nextBoolean(); - StaticTransportKeys keys = - createStaticTransportKeys(timePeriod, rootKey, alice); + HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice); long base = keys.getCurrentIncomingKeys().getWindowBase(); byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap(); Database db = open(false); Connection txn = db.startTransaction(); - // Add the contact, transport and static transport keys + // Add the contact, transport and handshake keys db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), true, true)); db.addTransport(txn, transportId, 123); - assertEquals(staticKeySetId, - db.addStaticTransportKeys(txn, contactId, keys)); + assertEquals(handshakeKeySetId, + db.addHandshakeKeys(txn, contactId, keys)); - // Update the reordering window and retrieve the static transport keys + // Update the reordering window and retrieve the handshake keys random.nextBytes(bitmap); - db.setStaticReorderingWindow(txn, staticKeySetId, transportId, - timePeriod, base + 1, bitmap); - Collection newKeys = - db.getStaticTransportKeys(txn, transportId); + db.setReorderingWindow(txn, handshakeKeySetId, transportId, timePeriod, + base + 1, bitmap); + Collection newKeys = + db.getHandshakeKeys(txn, transportId); assertEquals(1, newKeys.size()); - StaticTransportKeySet ks = newKeys.iterator().next(); - assertEquals(staticKeySetId, ks.getKeySetId()); + HandshakeKeySet ks = newKeys.iterator().next(); + assertEquals(handshakeKeySetId, ks.getKeySetId()); assertEquals(contactId, ks.getContactId()); - StaticTransportKeys k = ks.getKeys(); + HandshakeKeys k = ks.getKeys(); assertEquals(transportId, k.getTransportId()); assertArrayEquals(rootKey.getBytes(), k.getRootKey().getBytes()); assertEquals(alice, k.isAlice()); @@ -2308,7 +2301,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr); } - private StaticTransportKeys createStaticTransportKeys(long timePeriod, + private HandshakeKeys createHandshakeKeys(long timePeriod, SecretKey rootKey, boolean alice) { SecretKey inPrevTagKey = getSecretKey(); SecretKey inPrevHeaderKey = getSecretKey(); @@ -2326,8 +2319,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { SecretKey outCurrHeaderKey = getSecretKey(); OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey, timePeriod, 456, true); - return new StaticTransportKeys(transportId, inPrev, inCurr, inNext, - outCurr, rootKey, alice); + return new HandshakeKeys(transportId, inPrev, inCurr, inNext, outCurr, + rootKey, alice); } @After From 724e6643bd83c5630e08f8b5ffdceeabc183c0c2 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 17 Apr 2019 15:07:58 +0100 Subject: [PATCH 13/19] Add DB methods for handshake keys and pending contacts. --- .../bramble/api/db/DatabaseComponent.java | 51 ++++++++++++++-- .../api/db/NoSuchPendingContactException.java | 9 +++ .../api/db/PendingContactExistsException.java | 9 +++ .../bramble/db/DatabaseComponentImpl.java | 58 ++++++++++++++++++- 4 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/db/NoSuchPendingContactException.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/db/PendingContactExistsException.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java index e5be04b55..563ce2d8e 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.api.db; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.PendingContact; import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.identity.Author; @@ -137,6 +138,12 @@ public interface DatabaseComponent { void addLocalMessage(Transaction txn, Message m, Metadata meta, boolean shared) throws DbException; + /** + * Stores a pending contact. + */ + void addPendingContact(Transaction txn, PendingContact p) + throws DbException; + /** * Stores a transport. */ @@ -153,21 +160,35 @@ public interface DatabaseComponent { /** * Returns true if the database contains the given contact for the given * local pseudonym. + *

+ * Read-only. */ boolean containsContact(Transaction txn, AuthorId remote, AuthorId local) throws DbException; /** * Returns true if the database contains the given group. + *

+ * Read-only. */ boolean containsGroup(Transaction txn, GroupId g) throws DbException; /** * Returns true if the database contains the given local author. + *

+ * Read-only. */ boolean containsLocalAuthor(Transaction txn, AuthorId local) throws DbException; + /** + * Returns true if the database contains the given pending contact. + *

+ * Read-only. + */ + boolean containsPendingContact(Transaction txn, PendingContactId p) + throws DbException; + /** * Deletes the message with the given ID. Unlike * {@link #removeMessage(Transaction, MessageId)}, the message ID, @@ -292,8 +313,8 @@ public interface DatabaseComponent { *

* Read-only. */ - Collection getHandshakeKeys(Transaction txn, - TransportId t) throws DbException; + Collection getHandshakeKeys(Transaction txn, TransportId t) + throws DbException; /** * Returns the local pseudonym with the given ID. @@ -443,6 +464,14 @@ public interface DatabaseComponent { */ long getNextSendTime(Transaction txn, ContactId c) throws DbException; + /** + * Returns all pending contacts. + *

+ * Read-only. + */ + Collection getPendingContacts(Transaction txn) + throws DbException; + /** * Returns all settings in the given namespace. *

@@ -539,6 +568,12 @@ public interface DatabaseComponent { */ void removeMessage(Transaction txn, MessageId m) throws DbException; + /** + * Removes a pending contact (and all associated state) from the database. + */ + void removePendingContact(Transaction txn, PendingContactId p) + throws DbException; + /** * Removes a transport (and all associated state) from the database. */ @@ -591,13 +626,21 @@ public interface DatabaseComponent { Collection dependencies) throws DbException; /** - * Sets the reordering window for the given key set and transport in the - * given time period. + * Sets the reordering window for the given transport key set in the given + * time period. */ void setReorderingWindow(Transaction txn, TransportKeySetId k, TransportId t, long timePeriod, long base, byte[] bitmap) throws DbException; + /** + * Sets the reordering window for the given handshake key set in the given + * time period. + */ + void setReorderingWindow(Transaction txn, HandshakeKeySetId k, + TransportId t, long timePeriod, long base, byte[] bitmap) + throws DbException; + /** * Marks the given transport keys as usable for outgoing streams. */ diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/NoSuchPendingContactException.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/NoSuchPendingContactException.java new file mode 100644 index 000000000..d620e6d36 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/NoSuchPendingContactException.java @@ -0,0 +1,9 @@ +package org.briarproject.bramble.api.db; + +/** + * Thrown when a database operation is attempted for a pending contact that is + * not in the database. This exception may occur due to concurrent updates and + * does not indicate a database error. + */ +public class NoSuchPendingContactException extends DbException { +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/PendingContactExistsException.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/PendingContactExistsException.java new file mode 100644 index 000000000..cefca3f0a --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/PendingContactExistsException.java @@ -0,0 +1,9 @@ +package org.briarproject.bramble.api.db; + +/** + * Thrown when a duplicate pending contact is added to the database. This + * exception may occur due to concurrent updates and does not indicate a + * database error. + */ +public class PendingContactExistsException extends DbException { +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java index a70d1ca6b..b92ab8660 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.db; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.PendingContact; import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.contact.event.ContactAddedEvent; import org.briarproject.bramble.api.contact.event.ContactRemovedEvent; @@ -22,8 +23,10 @@ import org.briarproject.bramble.api.db.NoSuchContactException; import org.briarproject.bramble.api.db.NoSuchGroupException; import org.briarproject.bramble.api.db.NoSuchLocalAuthorException; import org.briarproject.bramble.api.db.NoSuchMessageException; +import org.briarproject.bramble.api.db.NoSuchPendingContactException; import org.briarproject.bramble.api.db.NoSuchTransportException; import org.briarproject.bramble.api.db.NullableDbCallable; +import org.briarproject.bramble.api.db.PendingContactExistsException; import org.briarproject.bramble.api.db.TaskAction; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.event.EventBus; @@ -275,7 +278,7 @@ class DatabaseComponentImpl implements DatabaseComponent { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsPendingContact(txn, p)) - throw new NoSuchContactException(); + throw new NoSuchPendingContactException(); if (!db.containsTransport(txn, k.getTransportId())) throw new NoSuchTransportException(); return db.addHandshakeKeys(txn, p, k); @@ -309,6 +312,16 @@ class DatabaseComponentImpl implements DatabaseComponent { db.mergeMessageMetadata(txn, m.getId(), meta); } + @Override + public void addPendingContact(Transaction transaction, PendingContact p) + throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); + T txn = unbox(transaction); + if (db.containsPendingContact(txn, p.getId())) + throw new PendingContactExistsException(); + db.addPendingContact(txn, p); + } + @Override public void addTransport(Transaction transaction, TransportId t, int maxLatency) throws DbException { @@ -353,6 +366,13 @@ class DatabaseComponentImpl implements DatabaseComponent { return db.containsLocalAuthor(txn, local); } + @Override + public boolean containsPendingContact(Transaction transaction, + PendingContactId p) throws DbException { + T txn = unbox(transaction); + return db.containsPendingContact(txn, p); + } + @Override public void deleteMessage(Transaction transaction, MessageId m) throws DbException { @@ -692,6 +712,13 @@ class DatabaseComponentImpl implements DatabaseComponent { return db.getNextSendTime(txn, c); } + @Override + public Collection getPendingContacts( + Transaction transaction) throws DbException { + T txn = unbox(transaction); + return db.getPendingContacts(txn); + } + @Override public Settings getSettings(Transaction transaction, String namespace) throws DbException { @@ -709,9 +736,13 @@ class DatabaseComponentImpl implements DatabaseComponent { } @Override - public void incrementStreamCounter(Transaction txn, TransportId t, + public void incrementStreamCounter(Transaction transaction, TransportId t, HandshakeKeySetId k) throws DbException { - // TODO + if (transaction.isReadOnly()) throw new IllegalArgumentException(); + T txn = unbox(transaction); + if (!db.containsTransport(txn, t)) + throw new NoSuchTransportException(); + db.incrementStreamCounter(txn, t, k); } @Override @@ -897,6 +928,16 @@ class DatabaseComponentImpl implements DatabaseComponent { db.removeMessage(txn, m); } + @Override + public void removePendingContact(Transaction transaction, + PendingContactId p) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); + T txn = unbox(transaction); + if (!db.containsPendingContact(txn, p)) + throw new NoSuchPendingContactException(); + db.removePendingContact(txn, p); + } + @Override public void removeTransport(Transaction transaction, TransportId t) throws DbException { @@ -1018,6 +1059,17 @@ class DatabaseComponentImpl implements DatabaseComponent { db.setReorderingWindow(txn, k, t, timePeriod, base, bitmap); } + @Override + public void setReorderingWindow(Transaction transaction, + HandshakeKeySetId k, TransportId t, long timePeriod, long base, + byte[] bitmap) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); + T txn = unbox(transaction); + if (!db.containsTransport(txn, t)) + throw new NoSuchTransportException(); + db.setReorderingWindow(txn, k, t, timePeriod, base, bitmap); + } + @Override public void setTransportKeysActive(Transaction transaction, TransportId t, TransportKeySetId k) throws DbException { From 296ce080e254284bb976d56f7d33b280c30582ee Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 17 Apr 2019 15:14:53 +0100 Subject: [PATCH 14/19] Add unit tests for pending contact exception. --- .../bramble/db/DatabaseComponentImplTest.java | 74 ++++++++++++++++++- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java index 49afd2c46..e9a503a19 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.db; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.contact.event.ContactAddedEvent; import org.briarproject.bramble.api.contact.event.ContactRemovedEvent; import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent; @@ -13,6 +14,7 @@ import org.briarproject.bramble.api.db.NoSuchContactException; import org.briarproject.bramble.api.db.NoSuchGroupException; import org.briarproject.bramble.api.db.NoSuchLocalAuthorException; import org.briarproject.bramble.api.db.NoSuchMessageException; +import org.briarproject.bramble.api.db.NoSuchPendingContactException; import org.briarproject.bramble.api.db.NoSuchTransportException; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.EventBus; @@ -44,6 +46,7 @@ import org.briarproject.bramble.api.sync.event.MessageToAckEvent; import org.briarproject.bramble.api.sync.event.MessageToRequestEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesSentEvent; +import org.briarproject.bramble.api.transport.HandshakeKeys; import org.briarproject.bramble.api.transport.IncomingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.TransportKeySet; @@ -112,6 +115,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { private final ContactId contactId; private final Contact contact; private final TransportKeySetId keySetId; + private final PendingContactId pendingContactId; public DatabaseComponentImplTest() { clientId = getClientId(); @@ -133,6 +137,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { contact = new Contact(contactId, author, localAuthor.getId(), alias, true, true); keySetId = new TransportKeySetId(345); + pendingContactId = new PendingContactId(getRandomId()); } private DatabaseComponent createDatabaseComponent(Database database, @@ -279,15 +284,24 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { throws Exception { context.checking(new Expectations() {{ // Check whether the contact is in the DB (which it's not) - exactly(17).of(database).startTransaction(); + exactly(18).of(database).startTransaction(); will(returnValue(txn)); - exactly(17).of(database).containsContact(txn, contactId); + exactly(18).of(database).containsContact(txn, contactId); will(returnValue(false)); - exactly(17).of(database).abortTransaction(txn); + exactly(18).of(database).abortTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, eventBus, eventExecutor, shutdownManager); + try { + db.transaction(false, transaction -> + db.addHandshakeKeys(transaction, contactId, + createHandshakeKeys())); + fail(); + } catch (NoSuchContactException expected) { + // Expected + } + try { db.transaction(false, transaction -> db.addTransportKeys(transaction, contactId, @@ -718,6 +732,39 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { } } + @Test + public void testVariousMethodsThrowExceptionIfPendingContactIsMissing() + throws Exception { + context.checking(new Expectations() {{ + // Check whether the pending contact is in the DB (which it's not) + exactly(2).of(database).startTransaction(); + will(returnValue(txn)); + exactly(2).of(database).containsPendingContact(txn, + pendingContactId); + will(returnValue(false)); + exactly(2).of(database).abortTransaction(txn); + }}); + DatabaseComponent db = createDatabaseComponent(database, eventBus, + eventExecutor, shutdownManager); + + try { + db.transaction(false, transaction -> + db.addHandshakeKeys(transaction, pendingContactId, + createHandshakeKeys())); + fail(); + } catch (NoSuchPendingContactException expected) { + // Expected + } + + try { + db.transaction(false, transaction -> + db.removePendingContact(transaction, pendingContactId)); + fail(); + } catch (NoSuchPendingContactException expected) { + // Expected + } + } + @Test public void testGenerateAck() throws Exception { Collection messagesToAck = asList(messageId, messageId1); @@ -1246,6 +1293,27 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { }); } + private HandshakeKeys createHandshakeKeys() { + SecretKey inPrevTagKey = getSecretKey(); + SecretKey inPrevHeaderKey = getSecretKey(); + IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey, + 1, 123, new byte[4]); + SecretKey inCurrTagKey = getSecretKey(); + SecretKey inCurrHeaderKey = getSecretKey(); + IncomingKeys inCurr = new IncomingKeys(inCurrTagKey, inCurrHeaderKey, + 2, 234, new byte[4]); + SecretKey inNextTagKey = getSecretKey(); + SecretKey inNextHeaderKey = getSecretKey(); + IncomingKeys inNext = new IncomingKeys(inNextTagKey, inNextHeaderKey, + 3, 345, new byte[4]); + SecretKey outCurrTagKey = getSecretKey(); + SecretKey outCurrHeaderKey = getSecretKey(); + OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey, + 2, 456, true); + return new HandshakeKeys(transportId, inPrev, inCurr, inNext, outCurr, + getSecretKey(), true); + } + private TransportKeys createTransportKeys() { SecretKey inPrevTagKey = getSecretKey(); SecretKey inPrevHeaderKey = getSecretKey(); From 3aadcc17dd4f622012ce543e26824aab4a41259e Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 17 Apr 2019 15:30:15 +0100 Subject: [PATCH 15/19] Add public key to pending contacts. --- .../bramble/api/contact/ContactManager.java | 3 ++- .../bramble/api/contact/PendingContact.java | 11 +++++--- .../briarproject/bramble/test/TestUtils.java | 4 ++- .../bramble/contact/ContactManagerImpl.java | 5 ++-- .../briarproject/bramble/db/JdbcDatabase.java | 26 +++++++++++-------- .../bramble/db/Migration41_42.java | 1 + 6 files changed, 32 insertions(+), 18 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java index 72c352206..ce07140fa 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java @@ -77,7 +77,8 @@ public interface ContactManager { Collection getPendingContacts(); /** - * Removes a {@link PendingContact} that is in state {@link FAILED}. + * Removes a {@link PendingContact} that is in state + * {@link PendingContactState FAILED}. */ void removePendingContact(PendingContact pendingContact); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContact.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContact.java index 7b77cd805..4989a11cf 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContact.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContact.java @@ -9,13 +9,15 @@ import javax.annotation.concurrent.Immutable; public class PendingContact { private final PendingContactId id; + private final byte[] publicKey; private final String alias; private final PendingContactState state; private final long timestamp; - public PendingContact(PendingContactId id, String alias, - PendingContactState state, long timestamp) { + public PendingContact(PendingContactId id, byte[] publicKey, + String alias, PendingContactState state, long timestamp) { this.id = id; + this.publicKey = publicKey; this.alias = alias; this.state = state; this.timestamp = timestamp; @@ -25,6 +27,10 @@ public class PendingContact { return id; } + public byte[] getPublicKey() { + return publicKey; + } + public String getAlias() { return alias; } @@ -47,5 +53,4 @@ public class PendingContact { return o instanceof PendingContact && id.equals(((PendingContact) o).id); } - } diff --git a/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java b/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java index 4c4d77ae6..550fefbb5 100644 --- a/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java +++ b/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java @@ -149,8 +149,10 @@ public class TestUtils { public static PendingContact getPendingContact(int nameLength) { PendingContactId id = new PendingContactId(getRandomId()); + byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); String alias = getRandomString(nameLength); - return new PendingContact(id, alias, WAITING_FOR_CONNECTION, timestamp); + return new PendingContact(id, publicKey, alias, WAITING_FOR_CONNECTION, + timestamp); } public static double getMedian(Collection samples) { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java index 3d9c0790f..a0f0c4351 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java @@ -32,6 +32,7 @@ import javax.inject.Inject; import static java.util.Collections.emptyList; import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; +import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES; import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN; import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNVERIFIED; @@ -123,8 +124,8 @@ class ContactManagerImpl implements ContactManager { public PendingContact addRemoteContactRequest(String link, String alias) { // TODO replace with real implementation PendingContactId id = new PendingContactId(link.getBytes()); - return new PendingContact(id, alias, WAITING_FOR_CONNECTION, - System.currentTimeMillis()); + return new PendingContact(id, new byte[MAX_PUBLIC_KEY_LENGTH], alias, + WAITING_FOR_CONNECTION, System.currentTimeMillis()); } @Override diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index 6b51253a3..1f532b39d 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -291,6 +291,7 @@ abstract class JdbcDatabase implements Database { private static final String CREATE_PENDING_CONTACTS = "CREATE TABLE pendingContacts" + " (pendingContactId _HASH NOT NULL," + + " publicKey _BINARY NOT NULL," + " alias _STRING NOT NULL," + " state INT NOT NULL," + " timestamp BIGINT NOT NULL," @@ -1057,13 +1058,14 @@ abstract class JdbcDatabase implements Database { PreparedStatement ps = null; try { String sql = "INSERT INTO pendingContacts (pendingContactId," - + " alias, state, timestamp)" - + " VALUES (?, ?, ?, ?)"; + + " publicKey, alias, state, timestamp)" + + " VALUES (?, ?, ?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setBytes(1, p.getId().getBytes()); - ps.setString(2, p.getAlias()); - ps.setInt(3, p.getState().getValue()); - ps.setLong(4, p.getTimestamp()); + ps.setBytes(2, p.getPublicKey()); + ps.setString(3, p.getAlias()); + ps.setInt(4, p.getState().getValue()); + ps.setLong(5, p.getTimestamp()); int affected = ps.executeUpdate(); if (affected != 1) throw new DbStateException(); ps.close(); @@ -2372,19 +2374,21 @@ abstract class JdbcDatabase implements Database { Statement s = null; ResultSet rs = null; try { - String sql = "SELECT pendingContactId, alias, state, timestamp" + String sql = "SELECT pendingContactId, publicKey, alias, state," + + " timestamp" + " FROM pendingContacts"; s = txn.createStatement(); rs = s.executeQuery(sql); List pendingContacts = new ArrayList<>(); while (rs.next()) { PendingContactId id = new PendingContactId(rs.getBytes(1)); - String alias = rs.getString(2); + byte[] publicKey = rs.getBytes(2); + String alias = rs.getString(3); PendingContactState state = - PendingContactState.fromValue(rs.getInt(3)); - long timestamp = rs.getLong(4); - pendingContacts.add(new PendingContact(id, alias, state, - timestamp)); + PendingContactState.fromValue(rs.getInt(4)); + long timestamp = rs.getLong(5); + pendingContacts.add(new PendingContact(id, publicKey, alias, + state, timestamp)); } rs.close(); s.close(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java index 62d4c0705..9a9f01633 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Migration41_42.java @@ -46,6 +46,7 @@ class Migration41_42 implements Migration { + " DROP COLUMN contactId"); s.execute(dbTypes.replaceTypes("CREATE TABLE pendingContacts" + " (pendingContactId _HASH NOT NULL," + + " publicKey _BINARY NOT NULL," + " alias _STRING NOT NULL," + " state INT NOT NULL," + " timestamp BIGINT NOT NULL," From e9a3685bfd827d298fc145352b7538f816bfeea7 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 17 Apr 2019 17:20:08 +0100 Subject: [PATCH 16/19] Fix spurious line wrapping. --- .../briarproject/bramble/db/JdbcDatabase.java | 41 +++++++------------ 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index 1f532b39d..6ed18c229 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -2630,9 +2630,8 @@ abstract class JdbcDatabase implements Database { g.getBytes(), meta, "groupMetadata", "groupId"); if (added.isEmpty()) return; // Insert any keys that don't already exist - String sql = - "INSERT INTO groupMetadata (groupId, metaKey, value)" - + " VALUES (?, ?, ?)"; + String sql = "INSERT INTO groupMetadata (groupId, metaKey, value)" + + " VALUES (?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setBytes(1, g.getBytes()); for (Entry e : added.entrySet()) { @@ -2780,8 +2779,7 @@ abstract class JdbcDatabase implements Database { ps.addBatch(); } int[] batchAffected = ps.executeBatch(); - if (batchAffected.length != s.size()) - throw new DbStateException(); + if (batchAffected.length != s.size()) throw new DbStateException(); for (int rows : batchAffected) { if (rows < 0) throw new DbStateException(); if (rows > 1) throw new DbStateException(); @@ -2802,8 +2800,7 @@ abstract class JdbcDatabase implements Database { updateIndex++; } batchAffected = ps.executeBatch(); - if (batchAffected.length != inserted) - throw new DbStateException(); + if (batchAffected.length != inserted) throw new DbStateException(); for (int rows : batchAffected) if (rows != 1) throw new DbStateException(); ps.close(); @@ -2904,8 +2901,7 @@ abstract class JdbcDatabase implements Database { } @Override - public void removeGroupVisibility(Connection txn, ContactId c, GroupId - g) + public void removeGroupVisibility(Connection txn, ContactId c, GroupId g) throws DbException { PreparedStatement ps = null; try { @@ -2971,8 +2967,7 @@ abstract class JdbcDatabase implements Database { } @Override - public void removeMessage(Connection txn, MessageId m) throws - DbException { + public void removeMessage(Connection txn, MessageId m) throws DbException { PreparedStatement ps = null; try { String sql = "DELETE FROM messages WHERE messageId = ?"; @@ -3111,8 +3106,7 @@ abstract class JdbcDatabase implements Database { throws DbException { PreparedStatement ps = null; try { - String sql = - "UPDATE contacts SET verified = ? WHERE contactId = ?"; + String sql = "UPDATE contacts SET verified = ? WHERE contactId = ?"; ps = txn.prepareStatement(sql); ps.setBoolean(1, true); ps.setInt(2, c.getInt()); @@ -3130,8 +3124,7 @@ abstract class JdbcDatabase implements Database { throws DbException { PreparedStatement ps = null; try { - String sql = - "UPDATE contacts SET active = ? WHERE contactId = ?"; + String sql = "UPDATE contacts SET active = ? WHERE contactId = ?"; ps = txn.prepareStatement(sql); ps.setBoolean(1, active); ps.setInt(2, c.getInt()); @@ -3149,8 +3142,7 @@ abstract class JdbcDatabase implements Database { @Nullable String alias) throws DbException { PreparedStatement ps = null; try { - String sql = - "UPDATE contacts SET alias = ? WHERE contactId = ?"; + String sql = "UPDATE contacts SET alias = ? WHERE contactId = ?"; ps = txn.prepareStatement(sql); if (alias == null) ps.setNull(1, VARCHAR); else ps.setString(1, alias); @@ -3221,13 +3213,11 @@ abstract class JdbcDatabase implements Database { } @Override - public void setMessageState(Connection txn, MessageId m, MessageState - state) + public void setMessageState(Connection txn, MessageId m, MessageState state) throws DbException { PreparedStatement ps = null; try { - String sql = - "UPDATE messages SET state = ? WHERE messageId = ?"; + String sql = "UPDATE messages SET state = ? WHERE messageId = ?"; ps = txn.prepareStatement(sql); ps.setInt(1, state.getValue()); ps.setBytes(2, m.getBytes()); @@ -3235,8 +3225,7 @@ abstract class JdbcDatabase implements Database { if (affected < 0 || affected > 1) throw new DbStateException(); ps.close(); // Update denormalised column in messageMetadata - sql = - "UPDATE messageMetadata SET state = ? WHERE messageId = ?"; + sql = "UPDATE messageMetadata SET state = ? WHERE messageId = ?"; ps = txn.prepareStatement(sql); ps.setInt(1, state.getValue()); ps.setBytes(2, m.getBytes()); @@ -3263,8 +3252,7 @@ abstract class JdbcDatabase implements Database { // Update denormalised column in messageDependencies if dependency // is present and in same group as dependent sql = "UPDATE messageDependencies SET dependencyState = ?" - + - " WHERE dependencyId = ? AND dependencyState IS NOT NULL"; + + " WHERE dependencyId = ? AND dependencyState IS NOT NULL"; ps = txn.prepareStatement(sql); ps.setInt(1, state.getValue()); ps.setBytes(2, m.getBytes()); @@ -3364,8 +3352,7 @@ abstract class JdbcDatabase implements Database { } @Override - public void updateExpiryTimeAndEta(Connection txn, ContactId - c, MessageId m, + public void updateExpiryTimeAndEta(Connection txn, ContactId c, MessageId m, int maxLatency) throws DbException { PreparedStatement ps = null; ResultSet rs = null; From dcebd5a81c24e47a281b31b17e8e4ebf13fb9101 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 17 Apr 2019 17:28:22 +0100 Subject: [PATCH 17/19] Update terminology from static keys to handshake keys. --- .../java/org/briarproject/bramble/db/JdbcDatabaseTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java index 3ecb5104c..1687ec75a 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java @@ -962,7 +962,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { } @Test - public void testIncrementStaticStreamCounter() throws Exception { + public void testIncrementStreamCounterForHandshakeKeys() throws Exception { long timePeriod = 123; SecretKey rootKey = getSecretKey(); boolean alice = random.nextBoolean(); @@ -977,7 +977,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), true, true)); db.addTransport(txn, transportId, 123); - assertEquals(handshakeKeySetId, db.addHandshakeKeys(txn, contactId, keys)); + assertEquals(handshakeKeySetId, + db.addHandshakeKeys(txn, contactId, keys)); // Increment the stream counter twice and retrieve the handshake keys db.incrementStreamCounter(txn, transportId, handshakeKeySetId); @@ -1054,7 +1055,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { } @Test - public void testSetStaticReorderingWindow() throws Exception { + public void testSetReorderingWindowForHandshakeKeys() throws Exception { long timePeriod = 123; SecretKey rootKey = getSecretKey(); boolean alice = random.nextBoolean(); From 1a1a010ee7145ea8e3f20d82f70da10f9167eea1 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 19 Apr 2019 11:36:21 +0100 Subject: [PATCH 18/19] Update key derivation labels for handshake mode. --- .../api/transport/TransportConstants.java | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) 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 c40c5556b..ce2394d74 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 @@ -82,53 +82,58 @@ public interface TransportConstants { int REORDERING_WINDOW_SIZE = 32; /** - * Label for deriving Alice's initial tag key from the root key. + * Label for deriving Alice's initial tag key from the root key in + * rotation mode. */ String ALICE_TAG_LABEL = "org.briarproject.bramble.transport/ALICE_TAG_KEY"; /** - * Label for deriving Bob's initial tag key from the root key. + * Label for deriving Bob's initial tag key from the root key in rotation + * mode. */ String BOB_TAG_LABEL = "org.briarproject.bramble.transport/BOB_TAG_KEY"; /** - * Label for deriving Alice's initial header key from the root key. + * Label for deriving Alice's initial header key from the root key in + * rotation mode. */ String ALICE_HEADER_LABEL = "org.briarproject.bramble.transport/ALICE_HEADER_KEY"; /** - * Label for deriving Bob's initial header key from the root key. + * Label for deriving Bob's initial header key from the root key in + * rotation mode. */ String BOB_HEADER_LABEL = "org.briarproject.bramble.transport/BOB_HEADER_KEY"; /** - * Label for deriving the next period's key in key rotation. + * Label for deriving the next period's key in rotation mode. */ String ROTATE_LABEL = "org.briarproject.bramble.transport/ROTATE"; /** - * Label for deriving Alice's handshake tag key from the root key. + * Label for deriving Alice's tag key from the root key in handshake mode. */ String ALICE_HANDSHAKE_TAG_LABEL = - "org.briarproject.bramble.transport/ALICE_STATIC_TAG_KEY"; + "org.briarproject.bramble.transport/ALICE_HANDSHAKE_TAG_KEY"; /** - * Label for deriving Bob's handshake tag key from the root key. + * Label for deriving Bob's tag key from the root key in handshake mode. */ String BOB_HANDSHAKE_TAG_LABEL = - "org.briarproject.bramble.transport/BOB_STATIC_TAG_KEY"; + "org.briarproject.bramble.transport/BOB_HANDSHAKE_TAG_KEY"; /** - * Label for deriving Alice's handshake header key from the root key. + * Label for deriving Alice's header key from the root key in handshake + * mode. */ String ALICE_HANDSHAKE_HEADER_LABEL = - "org.briarproject.bramble.transport/ALICE_STATIC_HEADER_KEY"; + "org.briarproject.bramble.transport/ALICE_HANDSHAKE_HEADER_KEY"; /** - * Label for deriving Bob's handshake header key from the root key. + * Label for deriving Bob's header key from the root key in handshake mode. */ String BOB_HANDSHAKE_HEADER_LABEL = - "org.briarproject.bramble.transport/BOB_STATIC_HEADER_KEY"; + "org.briarproject.bramble.transport/BOB_HANDSHAKE_HEADER_KEY"; } From 9c8125d77a6eda1f2df0e6cb48a509140b87c35d Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 19 Apr 2019 11:57:55 +0100 Subject: [PATCH 19/19] Rename 'alice' flags to clarify usage, add comments. --- .../bramble/crypto/TransportCryptoImpl.java | 86 ++++++++++--------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java index 939ea2f41..5ee6b87ee 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/TransportCryptoImpl.java @@ -43,12 +43,13 @@ class TransportCryptoImpl implements TransportCrypto { @Override public TransportKeys deriveTransportKeys(TransportId t, - SecretKey rootKey, long timePeriod, boolean alice, boolean active) { + SecretKey rootKey, long timePeriod, boolean weAreAlice, + boolean active) { // Keys for the previous period are derived from the root key - SecretKey inTagPrev = deriveTagKey(rootKey, t, !alice); - SecretKey inHeaderPrev = deriveHeaderKey(rootKey, t, !alice); - SecretKey outTagPrev = deriveTagKey(rootKey, t, alice); - SecretKey outHeaderPrev = deriveHeaderKey(rootKey, t, alice); + SecretKey inTagPrev = deriveTagKey(rootKey, t, !weAreAlice); + SecretKey inHeaderPrev = deriveHeaderKey(rootKey, t, !weAreAlice); + SecretKey outTagPrev = deriveTagKey(rootKey, t, weAreAlice); + SecretKey outHeaderPrev = deriveHeaderKey(rootKey, t, weAreAlice); // Derive the keys for the current and next periods SecretKey inTagCurr = rotateKey(inTagPrev, timePeriod); SecretKey inHeaderCurr = rotateKey(inHeaderPrev, timePeriod); @@ -101,54 +102,57 @@ class TransportCryptoImpl implements TransportCrypto { } private SecretKey deriveTagKey(SecretKey rootKey, TransportId t, - boolean alice) { - String label = alice ? ALICE_TAG_LABEL : BOB_TAG_LABEL; + boolean keyBelongsToAlice) { + String label = keyBelongsToAlice ? ALICE_TAG_LABEL : BOB_TAG_LABEL; byte[] id = toUtf8(t.getString()); return crypto.deriveKey(label, rootKey, id); } private SecretKey deriveHeaderKey(SecretKey rootKey, TransportId t, - boolean alice) { - String label = alice ? ALICE_HEADER_LABEL : BOB_HEADER_LABEL; + boolean keyBelongsToAlice) { + String label = keyBelongsToAlice ? ALICE_HEADER_LABEL : + BOB_HEADER_LABEL; byte[] id = toUtf8(t.getString()); return crypto.deriveKey(label, rootKey, id); } @Override public HandshakeKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey, - long timePeriod, boolean alice) { + long timePeriod, boolean weAreAlice) { if (timePeriod < 1) throw new IllegalArgumentException(); - IncomingKeys inPrev = deriveIncomingHandshakeKeys(t, rootKey, alice, - timePeriod - 1); - IncomingKeys inCurr = deriveIncomingHandshakeKeys(t, rootKey, alice, - timePeriod); - IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey, alice, - timePeriod + 1); - OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, alice, - timePeriod); + IncomingKeys inPrev = deriveIncomingHandshakeKeys(t, rootKey, + weAreAlice, timePeriod - 1); + IncomingKeys inCurr = deriveIncomingHandshakeKeys(t, rootKey, + weAreAlice, timePeriod); + IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey, + weAreAlice, timePeriod + 1); + OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, + weAreAlice, timePeriod); return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, rootKey, - alice); + weAreAlice); } private IncomingKeys deriveIncomingHandshakeKeys(TransportId t, - SecretKey rootKey, boolean alice, long timePeriod) { - SecretKey tag = deriveHandshakeTagKey(t, rootKey, !alice, timePeriod); - SecretKey header = deriveHandshakeHeaderKey(t, rootKey, !alice, + SecretKey rootKey, boolean weAreAlice, long timePeriod) { + SecretKey tag = deriveHandshakeTagKey(t, rootKey, !weAreAlice, + timePeriod); + SecretKey header = deriveHandshakeHeaderKey(t, rootKey, !weAreAlice, timePeriod); return new IncomingKeys(tag, header, timePeriod); } private OutgoingKeys deriveOutgoingHandshakeKeys(TransportId t, - SecretKey rootKey, boolean alice, long timePeriod) { - SecretKey tag = deriveHandshakeTagKey(t, rootKey, alice, timePeriod); - SecretKey header = deriveHandshakeHeaderKey(t, rootKey, alice, + SecretKey rootKey, boolean weAreAlice, long timePeriod) { + SecretKey tag = deriveHandshakeTagKey(t, rootKey, weAreAlice, + timePeriod); + SecretKey header = deriveHandshakeHeaderKey(t, rootKey, weAreAlice, timePeriod); return new OutgoingKeys(tag, header, timePeriod, true); } private SecretKey deriveHandshakeTagKey(TransportId t, SecretKey rootKey, - boolean alice, long timePeriod) { - String label = alice ? ALICE_HANDSHAKE_TAG_LABEL : + boolean keyBelongsToAlice, long timePeriod) { + String label = keyBelongsToAlice ? ALICE_HANDSHAKE_TAG_LABEL : BOB_HANDSHAKE_TAG_LABEL; byte[] id = toUtf8(t.getString()); byte[] period = new byte[INT_64_BYTES]; @@ -157,8 +161,8 @@ class TransportCryptoImpl implements TransportCrypto { } private SecretKey deriveHandshakeHeaderKey(TransportId t, SecretKey rootKey, - boolean alice, long timePeriod) { - String label = alice ? ALICE_HANDSHAKE_HEADER_LABEL : + boolean keyBelongsToAlice, long timePeriod) { + String label = keyBelongsToAlice ? ALICE_HANDSHAKE_HEADER_LABEL : BOB_HANDSHAKE_HEADER_LABEL; byte[] id = toUtf8(t.getString()); byte[] period = new byte[INT_64_BYTES]; @@ -171,34 +175,36 @@ class TransportCryptoImpl implements TransportCrypto { long elapsed = timePeriod - k.getTimePeriod(); TransportId t = k.getTransportId(); SecretKey rootKey = k.getRootKey(); - boolean alice = k.isAlice(); + boolean weAreAlice = k.isAlice(); if (elapsed <= 0) { // The keys are for the given period or later - don't update them return k; } else if (elapsed == 1) { - // The keys are one period old - shift by one period + // The keys are one period old - shift by one period, keeping the + // reordering windows for keys we retain IncomingKeys inPrev = k.getCurrentIncomingKeys(); IncomingKeys inCurr = k.getNextIncomingKeys(); IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey, - alice, timePeriod + 1); + weAreAlice, timePeriod + 1); OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, - alice, timePeriod); + weAreAlice, timePeriod); return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, - rootKey, alice); + rootKey, weAreAlice); } else if (elapsed == 2) { - // The keys are two periods old - shift by two periods + // The keys are two periods old - shift by two periods, keeping + // the reordering windows for keys we retain IncomingKeys inPrev = k.getNextIncomingKeys(); IncomingKeys inCurr = deriveIncomingHandshakeKeys(t, rootKey, - alice, timePeriod); + weAreAlice, timePeriod); IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey, - alice, timePeriod + 1); + weAreAlice, timePeriod + 1); OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey, - alice, timePeriod); + weAreAlice, timePeriod); return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, - rootKey, alice); + rootKey, weAreAlice); } else { // The keys are more than two periods old - derive fresh keys - return deriveHandshakeKeys(t, rootKey, timePeriod, alice); + return deriveHandshakeKeys(t, rootKey, timePeriod, weAreAlice); } }