From 6a15c03e81ff3b1cdded825c284d112cb360af32 Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Tue, 15 Nov 2011 16:07:14 +0000 Subject: [PATCH] Store the incoming and outgoing secrets separately. --- .../sf/briar/api/crypto/CryptoComponent.java | 16 +-- .../sf/briar/api/db/DatabaseComponent.java | 7 +- .../transport/ConnectionReaderFactory.java | 5 +- .../transport/ConnectionWriterFactory.java | 5 +- .../sf/briar/crypto/CryptoComponentImpl.java | 68 ++++--------- .../net/sf/briar/crypto/SharedSecret.java | 58 ----------- components/net/sf/briar/db/Database.java | 8 +- .../sf/briar/db/DatabaseComponentImpl.java | 10 +- components/net/sf/briar/db/JdbcDatabase.java | 18 ++-- .../ConnectionReaderFactoryImpl.java | 10 +- .../transport/ConnectionRecogniserImpl.java | 13 ++- .../ConnectionWriterFactoryImpl.java | 10 +- .../batch/IncomingBatchConnection.java | 2 +- .../batch/OutgoingBatchConnection.java | 2 +- .../stream/IncomingStreamConnection.java | 4 +- .../stream/OutgoingStreamConnection.java | 4 +- test/build.xml | 2 - .../net/sf/briar/ProtocolIntegrationTest.java | 19 ++-- .../sf/briar/crypto/CryptoComponentTest.java | 49 ---------- .../net/sf/briar/crypto/SharedSecretTest.java | 39 -------- .../sf/briar/db/DatabaseComponentTest.java | 30 ++++-- test/net/sf/briar/db/H2DatabaseTest.java | 97 ++++++++++--------- .../ConnectionRecogniserImplTest.java | 22 +++-- .../briar/transport/ConnectionWriterTest.java | 7 +- .../briar/transport/FrameReadWriteTest.java | 14 +-- .../batch/BatchConnectionReadWriteTest.java | 15 +-- 26 files changed, 199 insertions(+), 335 deletions(-) delete mode 100644 components/net/sf/briar/crypto/SharedSecret.java delete mode 100644 test/net/sf/briar/crypto/CryptoComponentTest.java delete mode 100644 test/net/sf/briar/crypto/SharedSecretTest.java diff --git a/api/net/sf/briar/api/crypto/CryptoComponent.java b/api/net/sf/briar/api/crypto/CryptoComponent.java index a932231989..2b01765b7d 100644 --- a/api/net/sf/briar/api/crypto/CryptoComponent.java +++ b/api/net/sf/briar/api/crypto/CryptoComponent.java @@ -9,20 +9,16 @@ import javax.crypto.Mac; public interface CryptoComponent { - ErasableKey deriveIncomingFrameKey(byte[] secret); + ErasableKey deriveFrameKey(byte[] source, boolean initiator); - ErasableKey deriveIncomingIvKey(byte[] secret); + ErasableKey deriveIvKey(byte[] source, boolean initiator); - ErasableKey deriveIncomingMacKey(byte[] secret); - - ErasableKey deriveOutgoingFrameKey(byte[] secret); - - ErasableKey deriveOutgoingIvKey(byte[] secret); - - ErasableKey deriveOutgoingMacKey(byte[] secret); + ErasableKey deriveMacKey(byte[] source, boolean initiator); KeyPair generateKeyPair(); + ErasableKey generateTestKey(); + Cipher getFrameCipher(); Cipher getIvCipher(); @@ -36,6 +32,4 @@ public interface CryptoComponent { SecureRandom getSecureRandom(); Signature getSignature(); - - ErasableKey generateTestKey(); } diff --git a/api/net/sf/briar/api/db/DatabaseComponent.java b/api/net/sf/briar/api/db/DatabaseComponent.java index 857e6c1e5e..1717f00ca9 100644 --- a/api/net/sf/briar/api/db/DatabaseComponent.java +++ b/api/net/sf/briar/api/db/DatabaseComponent.java @@ -53,10 +53,11 @@ public interface DatabaseComponent { void removeListener(DatabaseListener d); /** - * Adds a new contact to the database with the given secret and returns an + * Adds a new contact to the database with the given secrets and returns an * ID for the contact. */ - ContactId addContact(byte[] secret) throws DbException; + ContactId addContact(byte[] incomingSecret, byte[] outgoingSecret) + throws DbException; /** Adds a locally generated group message to the database. */ void addLocalGroupMessage(Message m) throws DbException; @@ -158,7 +159,7 @@ public interface DatabaseComponent { throws DbException; /** Returns the secret shared with the given contact. */ - byte[] getSharedSecret(ContactId c) throws DbException; + byte[] getSharedSecret(ContactId c, boolean incoming) throws DbException; /** Returns the set of groups to which the user subscribes. */ Collection<Group> getSubscriptions() throws DbException; diff --git a/api/net/sf/briar/api/transport/ConnectionReaderFactory.java b/api/net/sf/briar/api/transport/ConnectionReaderFactory.java index 5d7c9142c7..db9dead7b0 100644 --- a/api/net/sf/briar/api/transport/ConnectionReaderFactory.java +++ b/api/net/sf/briar/api/transport/ConnectionReaderFactory.java @@ -8,14 +8,15 @@ public interface ConnectionReaderFactory { /** * Creates a connection reader for a batch-mode connection or the - * initiator's side of a stream-mode connection. + * initiator's side of a stream-mode connection. The secret is erased before + * returning. */ ConnectionReader createConnectionReader(InputStream in, TransportIndex i, byte[] encryptedIv, byte[] secret); /** * Creates a connection reader for the responder's side of a stream-mode - * connection. + * connection. The secret is erased before returning. */ ConnectionReader createConnectionReader(InputStream in, TransportIndex i, long connection, byte[] secret); diff --git a/api/net/sf/briar/api/transport/ConnectionWriterFactory.java b/api/net/sf/briar/api/transport/ConnectionWriterFactory.java index 63a13a3619..8b05d3e2a5 100644 --- a/api/net/sf/briar/api/transport/ConnectionWriterFactory.java +++ b/api/net/sf/briar/api/transport/ConnectionWriterFactory.java @@ -8,14 +8,15 @@ public interface ConnectionWriterFactory { /** * Creates a connection writer for a batch-mode connection or the - * initiator's side of a stream-mode connection. + * initiator's side of a stream-mode connection. The secret is erased before + * returning. */ ConnectionWriter createConnectionWriter(OutputStream out, long capacity, TransportIndex i, long connection, byte[] secret); /** * Creates a connection writer for the responder's side of a stream-mode - * connection. + * connection. The secret is erased before returning. */ ConnectionWriter createConnectionWriter(OutputStream out, long capacity, TransportIndex i, byte[] encryptedIv, byte[] secret); diff --git a/components/net/sf/briar/crypto/CryptoComponentImpl.java b/components/net/sf/briar/crypto/CryptoComponentImpl.java index cd64e05655..670245c2d4 100644 --- a/components/net/sf/briar/crypto/CryptoComponentImpl.java +++ b/components/net/sf/briar/crypto/CryptoComponentImpl.java @@ -53,17 +53,22 @@ class CryptoComponentImpl implements CryptoComponent { } } - public ErasableKey deriveIncomingFrameKey(byte[] secret) { - SharedSecret s = new SharedSecret(secret); - return deriveFrameKey(s, !s.getAlice()); + public ErasableKey deriveFrameKey(byte[] source, boolean initiator) { + if(initiator) return deriveKey("FRAME_I", source); + else return deriveKey("FRAME_R", source); } - private ErasableKey deriveFrameKey(SharedSecret s, boolean alice) { - if(alice) return deriveKey("F_A", s.getSecret()); - else return deriveKey("F_B", s.getSecret()); + public ErasableKey deriveIvKey(byte[] source, boolean initiator) { + if(initiator) return deriveKey("IV_I", source); + else return deriveKey("IV_R", source); } - private ErasableKey deriveKey(String name, byte[] secret) { + public ErasableKey deriveMacKey(byte[] source, boolean initiator) { + if(initiator) return deriveKey("MAC_I", source); + else return deriveKey("MAC_R", source); + } + + private ErasableKey deriveKey(String name, byte[] source) { MessageDigest digest = getMessageDigest(); assert digest.getDigestLength() == SECRET_KEY_BYTES; try { @@ -71,49 +76,20 @@ class CryptoComponentImpl implements CryptoComponent { } catch(UnsupportedEncodingException e) { throw new RuntimeException(e); } - digest.update(secret); + digest.update(source); return new ErasableKeyImpl(digest.digest(), SECRET_KEY_ALGO); } - public ErasableKey deriveIncomingIvKey(byte[] secret) { - SharedSecret s = new SharedSecret(secret); - return deriveIvKey(s, !s.getAlice()); - } - - private ErasableKey deriveIvKey(SharedSecret s, boolean alice) { - if(alice) return deriveKey("I_A", s.getSecret()); - else return deriveKey("I_B", s.getSecret()); - } - - public ErasableKey deriveIncomingMacKey(byte[] secret) { - SharedSecret s = new SharedSecret(secret); - return deriveMacKey(s, !s.getAlice()); - } - - private ErasableKey deriveMacKey(SharedSecret s, boolean alice) { - if(alice) return deriveKey("M_A", s.getSecret()); - else return deriveKey("M_B", s.getSecret()); - } - - public ErasableKey deriveOutgoingFrameKey(byte[] secret) { - SharedSecret s = new SharedSecret(secret); - return deriveFrameKey(s, s.getAlice()); - } - - public ErasableKey deriveOutgoingIvKey(byte[] secret) { - SharedSecret s = new SharedSecret(secret); - return deriveIvKey(s, s.getAlice()); - } - - public ErasableKey deriveOutgoingMacKey(byte[] secret) { - SharedSecret s = new SharedSecret(secret); - return deriveMacKey(s, s.getAlice()); - } - public KeyPair generateKeyPair() { return keyPairGenerator.generateKeyPair(); } + public ErasableKey generateTestKey() { + byte[] b = new byte[SECRET_KEY_BYTES]; + getSecureRandom().nextBytes(b); + return new ErasableKeyImpl(b, SECRET_KEY_ALGO); + } + public Cipher getFrameCipher() { try { return Cipher.getInstance(FRAME_CIPHER_ALGO, PROVIDER); @@ -177,10 +153,4 @@ class CryptoComponentImpl implements CryptoComponent { throw new RuntimeException(e); } } - - public ErasableKey generateTestKey() { - byte[] b = new byte[SECRET_KEY_BYTES]; - getSecureRandom().nextBytes(b); - return new ErasableKeyImpl(b, SECRET_KEY_ALGO); - } } diff --git a/components/net/sf/briar/crypto/SharedSecret.java b/components/net/sf/briar/crypto/SharedSecret.java deleted file mode 100644 index 0f2a984b9a..0000000000 --- a/components/net/sf/briar/crypto/SharedSecret.java +++ /dev/null @@ -1,58 +0,0 @@ -package net.sf.briar.crypto; - -/** - * A shared secret from which authentication and encryption keys can be derived. - * The secret carries a flag indicating whether Alice's keys or Bob's keys - * should be derived from the secret. When two parties agree on a shared secret, - * they must decide which of them will derive Alice's keys and which Bob's. - */ -class SharedSecret { - - private final boolean alice; - private final byte[] secret; - - SharedSecret(byte[] b) { - if(b.length < 2) throw new IllegalArgumentException(); - switch(b[0]) { - case 0: - alice = false; - break; - case 1: - alice = true; - break; - default: - throw new IllegalArgumentException(); - } - secret = new byte[b.length - 1]; - System.arraycopy(b, 1, secret, 0, secret.length); - } - - SharedSecret(boolean alice, byte[] secret) { - this.alice = alice; - this.secret = secret; - } - - /** - * Returns true if we should play the role of Alice in connections using - * this secret, or false if we should play the role of Bob. - */ - boolean getAlice() { - return alice; - } - - /** Returns the shared secret. */ - byte[] getSecret() { - return secret; - } - - /** - * Returns a raw representation of this object, suitable for storing in the - * database. - */ - byte[] getBytes() { - byte[] b = new byte[1 + secret.length]; - if(alice) b[0] = (byte) 1; - System.arraycopy(secret, 0, b, 1, secret.length); - return b; - } -} diff --git a/components/net/sf/briar/db/Database.java b/components/net/sf/briar/db/Database.java index 60a7b3a80d..a3281c7973 100644 --- a/components/net/sf/briar/db/Database.java +++ b/components/net/sf/briar/db/Database.java @@ -80,12 +80,13 @@ interface Database<T> { void addBatchToAck(T txn, ContactId c, BatchId b) throws DbException; /** - * Adds a new contact to the database with the given secret and returns an + * Adds a new contact to the database with the given secrets and returns an * ID for the contact. * <p> * Locking: contact write. */ - ContactId addContact(T txn, byte[] secret) throws DbException; + ContactId addContact(T txn, byte[] incomingSecret, byte[] outgoingSecret) + throws DbException; /** * Returns false if the given message is already in the database. Otherwise @@ -376,7 +377,8 @@ interface Database<T> { * <p> * Locking: contact read. */ - byte[] getSharedSecret(T txn, ContactId c) throws DbException; + byte[] getSharedSecret(T txn, ContactId c, boolean incoming) + throws DbException; /** * Returns true if the given message has been starred. diff --git a/components/net/sf/briar/db/DatabaseComponentImpl.java b/components/net/sf/briar/db/DatabaseComponentImpl.java index fe2172b965..a671f95c1c 100644 --- a/components/net/sf/briar/db/DatabaseComponentImpl.java +++ b/components/net/sf/briar/db/DatabaseComponentImpl.java @@ -135,14 +135,15 @@ DatabaseCleaner.Callback { } } - public ContactId addContact(byte[] secret) throws DbException { + public ContactId addContact(byte[] incomingSecret, byte[] outgoingSecret) + throws DbException { if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding contact"); ContactId c; contactLock.writeLock().lock(); try { T txn = db.startTransaction(); try { - c = db.addContact(txn, secret); + c = db.addContact(txn, incomingSecret, outgoingSecret); db.commitTransaction(txn); if(LOG.isLoggable(Level.FINE)) LOG.fine("Added contact " + c); } catch(DbException e) { @@ -905,13 +906,14 @@ DatabaseCleaner.Callback { } } - public byte[] getSharedSecret(ContactId c) throws DbException { + public byte[] getSharedSecret(ContactId c, boolean incoming) + throws DbException { contactLock.readLock().lock(); try { if(!containsContact(c)) throw new NoSuchContactException(); T txn = db.startTransaction(); try { - byte[] secret = db.getSharedSecret(txn, c); + byte[] secret = db.getSharedSecret(txn, c, incoming); db.commitTransaction(txn); return secret; } catch(DbException e) { diff --git a/components/net/sf/briar/db/JdbcDatabase.java b/components/net/sf/briar/db/JdbcDatabase.java index 458d39edc2..0398d75e6a 100644 --- a/components/net/sf/briar/db/JdbcDatabase.java +++ b/components/net/sf/briar/db/JdbcDatabase.java @@ -56,7 +56,8 @@ abstract class JdbcDatabase implements Database<Connection> { private static final String CREATE_CONTACTS = "CREATE TABLE contacts" + " (contactId COUNTER," - + " secret BINARY NOT NULL," + + " incomingSecret BINARY NOT NULL," + + " outgoingSecret BINARY NOT NULL," + " PRIMARY KEY (contactId))"; private static final String CREATE_MESSAGES = @@ -509,15 +510,17 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public ContactId addContact(Connection txn, byte[] secret) - throws DbException { + public ContactId addContact(Connection txn, byte[] incomingSecret, + byte[] outgoingSecret) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { // Create a new contact row - String sql = "INSERT INTO contacts (secret) VALUES (?)"; + String sql = "INSERT INTO contacts (incomingSecret, outgoingSecret)" + + " VALUES (?, ?)"; ps = txn.prepareStatement(sql); - ps.setBytes(1, secret); + ps.setBytes(1, incomingSecret); + ps.setBytes(2, outgoingSecret); int affected = ps.executeUpdate(); if(affected != 1) throw new DbStateException(); ps.close(); @@ -1643,12 +1646,13 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public byte[] getSharedSecret(Connection txn, ContactId c) + public byte[] getSharedSecret(Connection txn, ContactId c, boolean incoming) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { - String sql = "SELECT secret FROM contacts WHERE contactId = ?"; + String col = incoming ? "incomingSecret" : "outgoingSecret"; + String sql = "SELECT " + col + " FROM contacts WHERE contactId = ?"; ps = txn.prepareStatement(sql); ps.setInt(1, c.getInt()); rs = ps.executeQuery(); diff --git a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java index b48a564bad..6469e8b4e2 100644 --- a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java +++ b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java @@ -29,7 +29,7 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory { TransportIndex i, byte[] encryptedIv, byte[] secret) { // Decrypt the IV Cipher ivCipher = crypto.getIvCipher(); - ErasableKey ivKey = crypto.deriveIncomingIvKey(secret); + ErasableKey ivKey = crypto.deriveIvKey(secret, true); byte[] iv; try { ivCipher.init(Cipher.DECRYPT_MODE, ivKey); @@ -57,15 +57,17 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory { private ConnectionReader createConnectionReader(InputStream in, boolean initiator, TransportIndex i, long connection, byte[] secret) { - byte[] iv = IvEncoder.encodeIv(initiator, i, connection); + // Derive the keys and erase the secret + ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator); + ErasableKey macKey = crypto.deriveMacKey(secret, initiator); + for(int j = 0; j < secret.length; j++) secret[j] = 0; // Create the decrypter + byte[] iv = IvEncoder.encodeIv(initiator, i, connection); Cipher frameCipher = crypto.getFrameCipher(); - ErasableKey frameKey = crypto.deriveIncomingFrameKey(secret); ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in, iv, frameCipher, frameKey); // Create the reader Mac mac = crypto.getMac(); - ErasableKey macKey = crypto.deriveIncomingMacKey(secret); return new ConnectionReaderImpl(decrypter, mac, macKey); } } diff --git a/components/net/sf/briar/transport/ConnectionRecogniserImpl.java b/components/net/sf/briar/transport/ConnectionRecogniserImpl.java index 34bd3a2e15..6c139c6346 100644 --- a/components/net/sf/briar/transport/ConnectionRecogniserImpl.java +++ b/components/net/sf/briar/transport/ConnectionRecogniserImpl.java @@ -75,7 +75,9 @@ DatabaseListener { } private synchronized void calculateIvs(ContactId c) throws DbException { - ErasableKey ivKey = crypto.deriveIncomingIvKey(db.getSharedSecret(c)); + byte[] secret = db.getSharedSecret(c, true); + ErasableKey ivKey = crypto.deriveIvKey(secret, true); + for(int i = 0; i < secret.length; i++) secret[i] = 0; for(TransportId t : localTransportIds) { TransportIndex i = db.getRemoteIndex(c, t); if(i != null) { @@ -131,7 +133,9 @@ DatabaseListener { TransportIndex i1 = ctx1.getTransportIndex(); if(c1.equals(c) && i1.equals(i)) it.remove(); } - ErasableKey ivKey = crypto.deriveIncomingIvKey(db.getSharedSecret(c)); + byte[] secret = db.getSharedSecret(c, true); + ErasableKey ivKey = crypto.deriveIvKey(secret, true); + for(int j = 0; j < secret.length; j++) secret[j] = 0; calculateIvs(c, ctx.getTransportId(), i, ivKey, w); } catch(NoSuchContactException e) { // The contact was removed - clean up when we get the event @@ -181,8 +185,9 @@ DatabaseListener { private synchronized void calculateIvs(TransportId t) throws DbException { for(ContactId c : db.getContacts()) { try { - byte[] secret = db.getSharedSecret(c); - ErasableKey ivKey = crypto.deriveIncomingIvKey(secret); + byte[] secret = db.getSharedSecret(c, true); + ErasableKey ivKey = crypto.deriveIvKey(secret, true); + for(int i = 0; i < secret.length; i++) secret[i] = 0; TransportIndex i = db.getRemoteIndex(c, t); if(i != null) { ConnectionWindow w = db.getConnectionWindow(c, i); diff --git a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java index 822f6223b4..caab149260 100644 --- a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java +++ b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java @@ -36,7 +36,7 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory { byte[] secret) { // Decrypt the IV Cipher ivCipher = crypto.getIvCipher(); - ErasableKey ivKey = crypto.deriveIncomingIvKey(secret); + ErasableKey ivKey = crypto.deriveIvKey(secret, true); byte[] iv; try { ivCipher.init(Cipher.DECRYPT_MODE, ivKey); @@ -60,17 +60,19 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory { private ConnectionWriter createConnectionWriter(OutputStream out, long capacity, boolean initiator, TransportIndex i, long connection, byte[] secret) { + // Derive the keys and erase the secret + ErasableKey ivKey = crypto.deriveIvKey(secret, initiator); + ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator); + ErasableKey macKey = crypto.deriveMacKey(secret, initiator); + for(int j = 0; j < secret.length; j++) secret[j] = 0; // Create the encrypter Cipher ivCipher = crypto.getIvCipher(); Cipher frameCipher = crypto.getFrameCipher(); - ErasableKey ivKey = crypto.deriveOutgoingIvKey(secret); - ErasableKey frameKey = crypto.deriveOutgoingFrameKey(secret); byte[] iv = IvEncoder.encodeIv(initiator, i, connection); ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out, capacity, iv, ivCipher, frameCipher, ivKey, frameKey); // Create the writer Mac mac = crypto.getMac(); - ErasableKey macKey = crypto.deriveOutgoingMacKey(secret); return new ConnectionWriterImpl(encrypter, mac, macKey); } } diff --git a/components/net/sf/briar/transport/batch/IncomingBatchConnection.java b/components/net/sf/briar/transport/batch/IncomingBatchConnection.java index b1bfd1966c..a97c392c97 100644 --- a/components/net/sf/briar/transport/batch/IncomingBatchConnection.java +++ b/components/net/sf/briar/transport/batch/IncomingBatchConnection.java @@ -47,7 +47,7 @@ class IncomingBatchConnection { void read() { try { - byte[] secret = db.getSharedSecret(contactId); + byte[] secret = db.getSharedSecret(contactId, true); ConnectionReader conn = connFactory.createConnectionReader( reader.getInputStream(), transportIndex, encryptedIv, secret); diff --git a/components/net/sf/briar/transport/batch/OutgoingBatchConnection.java b/components/net/sf/briar/transport/batch/OutgoingBatchConnection.java index 810a4e7899..b9d8630b35 100644 --- a/components/net/sf/briar/transport/batch/OutgoingBatchConnection.java +++ b/components/net/sf/briar/transport/batch/OutgoingBatchConnection.java @@ -46,7 +46,7 @@ class OutgoingBatchConnection { void write() { try { - byte[] secret = db.getSharedSecret(contactId); + byte[] secret = db.getSharedSecret(contactId, false); long connection = db.getConnectionNumber(contactId, transportIndex); ConnectionWriter conn = connFactory.createConnectionWriter( writer.getOutputStream(), writer.getCapacity(), diff --git a/components/net/sf/briar/transport/stream/IncomingStreamConnection.java b/components/net/sf/briar/transport/stream/IncomingStreamConnection.java index 3518b75c92..bc01c5ad61 100644 --- a/components/net/sf/briar/transport/stream/IncomingStreamConnection.java +++ b/components/net/sf/briar/transport/stream/IncomingStreamConnection.java @@ -33,7 +33,7 @@ public class IncomingStreamConnection extends StreamConnection { @Override protected ConnectionReader createConnectionReader() throws DbException, IOException { - byte[] secret = db.getSharedSecret(contactId); + byte[] secret = db.getSharedSecret(contactId, true); return connReaderFactory.createConnectionReader( connection.getInputStream(), transportIndex, encryptedIv, secret); @@ -42,7 +42,7 @@ public class IncomingStreamConnection extends StreamConnection { @Override protected ConnectionWriter createConnectionWriter() throws DbException, IOException { - byte[] secret = db.getSharedSecret(contactId); + byte[] secret = db.getSharedSecret(contactId, false); return connWriterFactory.createConnectionWriter( connection.getOutputStream(), Long.MAX_VALUE, transportIndex, encryptedIv, secret); diff --git a/components/net/sf/briar/transport/stream/OutgoingStreamConnection.java b/components/net/sf/briar/transport/stream/OutgoingStreamConnection.java index 923fcf354f..4af22e161e 100644 --- a/components/net/sf/briar/transport/stream/OutgoingStreamConnection.java +++ b/components/net/sf/briar/transport/stream/OutgoingStreamConnection.java @@ -37,7 +37,7 @@ public class OutgoingStreamConnection extends StreamConnection { transportIndex); } } - byte[] secret = db.getSharedSecret(contactId); + byte[] secret = db.getSharedSecret(contactId, true); return connReaderFactory.createConnectionReader( connection.getInputStream(), transportIndex, connectionNum, secret); @@ -52,7 +52,7 @@ public class OutgoingStreamConnection extends StreamConnection { transportIndex); } } - byte[] secret = db.getSharedSecret(contactId); + byte[] secret = db.getSharedSecret(contactId, false); return connWriterFactory.createConnectionWriter( connection.getOutputStream(), Long.MAX_VALUE, transportIndex, connectionNum, secret); diff --git a/test/build.xml b/test/build.xml index b0d0118ed9..9dc9b7a109 100644 --- a/test/build.xml +++ b/test/build.xml @@ -17,8 +17,6 @@ <test name='net.sf.briar.LockFairnessTest'/> <test name='net.sf.briar.ProtocolIntegrationTest'/> <test name='net.sf.briar.crypto.CounterModeTest'/> - <test name='net.sf.briar.crypto.CryptoComponentTest'/> - <test name='net.sf.briar.crypto.SharedSecretTest'/> <test name='net.sf.briar.db.BasicH2Test'/> <test name='net.sf.briar.db.DatabaseCleanerImplTest'/> <test name='net.sf.briar.db.DatabaseComponentImplTest'/> diff --git a/test/net/sf/briar/ProtocolIntegrationTest.java b/test/net/sf/briar/ProtocolIntegrationTest.java index f7afcc9a62..907fc63d8f 100644 --- a/test/net/sf/briar/ProtocolIntegrationTest.java +++ b/test/net/sf/briar/ProtocolIntegrationTest.java @@ -13,6 +13,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Random; import junit.framework.TestCase; import net.sf.briar.api.crypto.CryptoComponent; @@ -56,6 +57,7 @@ import net.sf.briar.transport.TransportModule; import net.sf.briar.transport.batch.TransportBatchModule; import net.sf.briar.transport.stream.TransportStreamModule; +import org.bouncycastle.util.Arrays; import org.junit.Test; import com.google.inject.Guice; @@ -71,7 +73,7 @@ public class ProtocolIntegrationTest extends TestCase { private final ProtocolReaderFactory protocolReaderFactory; private final ProtocolWriterFactory protocolWriterFactory; private final CryptoComponent crypto; - private final byte[] aliceSecret, bobSecret; + private final byte[] aliceToBobSecret; private final TransportIndex transportIndex = new TransportIndex(13); private final long connection = 12345L; private final Author author; @@ -96,10 +98,9 @@ public class ProtocolIntegrationTest extends TestCase { crypto = i.getInstance(CryptoComponent.class); assertEquals(crypto.getMessageDigest().getDigestLength(), UniqueId.LENGTH); - // Create matching secrets: one for Alice, one for Bob - aliceSecret = new byte[123]; - aliceSecret[0] = (byte) 1; - bobSecret = new byte[123]; + Random r = new Random(); + aliceToBobSecret = new byte[123]; + r.nextBytes(aliceToBobSecret); // Create two groups: one restricted, one unrestricted GroupFactory groupFactory = i.getInstance(GroupFactory.class); group = groupFactory.createGroup("Unrestricted group", null); @@ -138,9 +139,9 @@ public class ProtocolIntegrationTest extends TestCase { private byte[] write() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); - // Use Alice's secret for writing + byte[] copyOfSecret = Arrays.clone(aliceToBobSecret); ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out, - Long.MAX_VALUE, transportIndex, connection, aliceSecret); + Long.MAX_VALUE, transportIndex, connection, copyOfSecret); OutputStream out1 = w.getOutputStream(); AckWriter a = protocolWriterFactory.createAckWriter(out1); @@ -193,9 +194,9 @@ public class ProtocolIntegrationTest extends TestCase { offset += read; } assertEquals(16, offset); - // Use Bob's secret for reading + byte[] copyOfSecret = Arrays.clone(aliceToBobSecret); ConnectionReader r = connectionReaderFactory.createConnectionReader(in, - transportIndex, encryptedIv, bobSecret); + transportIndex, encryptedIv, copyOfSecret); in = r.getInputStream(); ProtocolReader protocolReader = protocolReaderFactory.createProtocolReader(in); diff --git a/test/net/sf/briar/crypto/CryptoComponentTest.java b/test/net/sf/briar/crypto/CryptoComponentTest.java deleted file mode 100644 index fcc74391e0..0000000000 --- a/test/net/sf/briar/crypto/CryptoComponentTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package net.sf.briar.crypto; - -import junit.framework.TestCase; -import net.sf.briar.api.crypto.CryptoComponent; - -import org.junit.Test; - -import com.google.inject.Guice; -import com.google.inject.Injector; - -public class CryptoComponentTest extends TestCase { - - private final CryptoComponent crypto; - - public CryptoComponentTest() { - super(); - Injector i = Guice.createInjector(new CryptoModule()); - crypto = i.getInstance(CryptoComponent.class); - } - - @Test - public void testKeyDerivation() { - // Create matching secrets: one for Alice, one for Bob - byte[] aliceSecret = new byte[123]; - aliceSecret[0] = (byte) 1; - byte[] bobSecret = new byte[123]; - // Check that Alice's incoming keys match Bob's outgoing keys - assertEquals(crypto.deriveIncomingMacKey(aliceSecret), - crypto.deriveOutgoingMacKey(bobSecret)); - assertEquals(crypto.deriveIncomingFrameKey(aliceSecret), - crypto.deriveOutgoingFrameKey(bobSecret)); - assertEquals(crypto.deriveIncomingIvKey(aliceSecret), - crypto.deriveOutgoingIvKey(bobSecret)); - // Check that Alice's outgoing keys match Bob's incoming keys - assertEquals(crypto.deriveOutgoingMacKey(aliceSecret), - crypto.deriveIncomingMacKey(bobSecret)); - assertEquals(crypto.deriveOutgoingFrameKey(aliceSecret), - crypto.deriveIncomingFrameKey(bobSecret)); - assertEquals(crypto.deriveOutgoingIvKey(aliceSecret), - crypto.deriveIncomingIvKey(bobSecret)); - // Check that Alice's incoming and outgoing keys are different - assertFalse(crypto.deriveIncomingMacKey(aliceSecret).equals( - crypto.deriveOutgoingMacKey(aliceSecret))); - assertFalse(crypto.deriveIncomingFrameKey(aliceSecret).equals( - crypto.deriveOutgoingFrameKey(aliceSecret))); - assertFalse(crypto.deriveIncomingIvKey(aliceSecret).equals( - crypto.deriveOutgoingIvKey(aliceSecret))); - } -} diff --git a/test/net/sf/briar/crypto/SharedSecretTest.java b/test/net/sf/briar/crypto/SharedSecretTest.java deleted file mode 100644 index aa23d79aee..0000000000 --- a/test/net/sf/briar/crypto/SharedSecretTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.sf.briar.crypto; - -import static org.junit.Assert.assertArrayEquals; - -import java.util.Random; - -import junit.framework.TestCase; - -import org.junit.Test; - -public class SharedSecretTest extends TestCase { - - @Test - public void testDecodeAndEncode() { - Random random = new Random(); - byte[] secret = new byte[40]; - random.nextBytes(secret); - secret[0] = (byte) 0; - SharedSecret s = new SharedSecret(secret); - assertArrayEquals(secret, s.getBytes()); - secret[0] = (byte) 1; - s = new SharedSecret(secret); - assertArrayEquals(secret, s.getBytes()); - // The Alice flag must be either 0 or 1 - secret[0] = (byte) 2; - try { - s = new SharedSecret(secret); - fail(); - } catch(IllegalArgumentException expected) {} - // The secret must be at least 1 byte long - secret = new byte[1]; - random.nextBytes(secret); - secret[0] = (byte) 0; - try { - s = new SharedSecret(secret); - fail(); - } catch(IllegalArgumentException expected) {} - } -} diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java index 335d11d711..763bbf4bb7 100644 --- a/test/net/sf/briar/db/DatabaseComponentTest.java +++ b/test/net/sf/briar/db/DatabaseComponentTest.java @@ -5,6 +5,7 @@ import java.util.BitSet; import java.util.Collection; import java.util.Collections; import java.util.Map; +import java.util.Random; import junit.framework.TestCase; import net.sf.briar.TestUtils; @@ -46,6 +47,7 @@ import net.sf.briar.api.transport.ConnectionWindow; import org.jmock.Expectations; import org.jmock.Mockery; +import static org.junit.Assert.assertArrayEquals; import org.junit.Test; public abstract class DatabaseComponentTest extends TestCase { @@ -66,7 +68,7 @@ public abstract class DatabaseComponentTest extends TestCase { private final TransportIndex localIndex, remoteIndex; private final Collection<Transport> transports; private final Map<ContactId, TransportProperties> remoteProperties; - private final byte[] secret; + private final byte[] inSecret, outSecret; public DatabaseComponentTest() { super(); @@ -94,7 +96,11 @@ public abstract class DatabaseComponentTest extends TestCase { Transport transport = new Transport(transportId, localIndex, properties); transports = Collections.singletonList(transport); - secret = new byte[123]; + Random r = new Random(); + inSecret = new byte[123]; + r.nextBytes(inSecret); + outSecret = new byte[123]; + r.nextBytes(outSecret); } protected abstract <T> DatabaseComponent createDatabaseComponent( @@ -132,7 +138,7 @@ public abstract class DatabaseComponentTest extends TestCase { oneOf(database).setRating(txn, authorId, Rating.GOOD); will(returnValue(Rating.GOOD)); // addContact() - oneOf(database).addContact(txn, secret); + oneOf(database).addContact(txn, inSecret, outSecret); will(returnValue(contactId)); oneOf(listener).eventOccurred(with(any(ContactAddedEvent.class))); // getContacts() @@ -143,11 +149,16 @@ public abstract class DatabaseComponentTest extends TestCase { will(returnValue(true)); oneOf(database).getConnectionWindow(txn, contactId, remoteIndex); will(returnValue(connectionWindow)); - // getSharedSecret(contactId) + // getSharedSecret(contactId, true) oneOf(database).containsContact(txn, contactId); will(returnValue(true)); - oneOf(database).getSharedSecret(txn, contactId); - will(returnValue(secret)); + oneOf(database).getSharedSecret(txn, contactId, true); + will(returnValue(inSecret)); + // getSharedSecret(contactId, false) + oneOf(database).containsContact(txn, contactId); + will(returnValue(true)); + oneOf(database).getSharedSecret(txn, contactId, false); + will(returnValue(outSecret)); // getTransportProperties(transportId) oneOf(database).getRemoteProperties(txn, transportId); will(returnValue(remoteProperties)); @@ -198,11 +209,12 @@ public abstract class DatabaseComponentTest extends TestCase { assertEquals(Rating.UNRATED, db.getRating(authorId)); db.setRating(authorId, Rating.GOOD); // First time - listeners called db.setRating(authorId, Rating.GOOD); // Second time - not called - assertEquals(contactId, db.addContact(secret)); + assertEquals(contactId, db.addContact(inSecret, outSecret)); assertEquals(Collections.singletonList(contactId), db.getContacts()); assertEquals(connectionWindow, db.getConnectionWindow(contactId, remoteIndex)); - assertEquals(secret, db.getSharedSecret(contactId)); + assertArrayEquals(inSecret, db.getSharedSecret(contactId, true)); + assertArrayEquals(outSecret, db.getSharedSecret(contactId, false)); assertEquals(remoteProperties, db.getRemoteProperties(transportId)); db.subscribe(group); // First time - listeners called db.subscribe(group); // Second time - not called @@ -564,7 +576,7 @@ public abstract class DatabaseComponentTest extends TestCase { } catch(NoSuchContactException expected) {} try { - db.getSharedSecret(contactId); + db.getSharedSecret(contactId, true); fail(); } catch(NoSuchContactException expected) {} diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java index 9d9471f21b..ac3fee99c4 100644 --- a/test/net/sf/briar/db/H2DatabaseTest.java +++ b/test/net/sf/briar/db/H2DatabaseTest.java @@ -85,7 +85,7 @@ public class H2DatabaseTest extends TestCase { private final Map<ContactId, TransportProperties> remoteProperties; private final Collection<Transport> remoteTransports; private final Map<Group, Long> subscriptions; - private final byte[] secret; + private final byte[] inSecret, outSecret; public H2DatabaseTest() throws Exception { super(); @@ -122,7 +122,11 @@ public class H2DatabaseTest extends TestCase { properties); remoteTransports = Collections.singletonList(remoteTransport); subscriptions = Collections.singletonMap(group, 0L); - secret = new byte[123]; + Random r = new Random(); + inSecret = new byte[123]; + r.nextBytes(inSecret); + outSecret = new byte[123]; + r.nextBytes(outSecret); } @Before @@ -136,7 +140,8 @@ public class H2DatabaseTest extends TestCase { Database<Connection> db = open(false); Connection txn = db.startTransaction(); assertFalse(db.containsContact(txn, contactId)); - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, + db.addContact(txn, inSecret, outSecret)); assertTrue(db.containsContact(txn, contactId)); assertFalse(db.containsSubscription(txn, groupId)); db.addSubscription(txn, group); @@ -192,20 +197,20 @@ public class H2DatabaseTest extends TestCase { // Create three contacts assertFalse(db.containsContact(txn, contactId)); - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); assertTrue(db.containsContact(txn, contactId)); assertFalse(db.containsContact(txn, contactId1)); - assertEquals(contactId1, db.addContact(txn, secret)); + assertEquals(contactId1, db.addContact(txn, inSecret, outSecret)); assertTrue(db.containsContact(txn, contactId1)); assertFalse(db.containsContact(txn, contactId2)); - assertEquals(contactId2, db.addContact(txn, secret)); + assertEquals(contactId2, db.addContact(txn, inSecret, outSecret)); assertTrue(db.containsContact(txn, contactId2)); // Delete the contact with the highest ID db.removeContact(txn, contactId2); assertFalse(db.containsContact(txn, contactId2)); // Add another contact - a new ID should be created assertFalse(db.containsContact(txn, contactId3)); - assertEquals(contactId3, db.addContact(txn, secret)); + assertEquals(contactId3, db.addContact(txn, inSecret, outSecret)); assertTrue(db.containsContact(txn, contactId3)); db.commitTransaction(txn); @@ -252,7 +257,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact and store a private message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addPrivateMessage(txn, privateMessage, contactId); // Removing the contact should remove the message @@ -271,7 +276,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact and store a private message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addPrivateMessage(txn, privateMessage, contactId); // The message has no status yet, so it should not be sendable @@ -310,7 +315,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact and store a private message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addPrivateMessage(txn, privateMessage, contactId); db.setStatus(txn, contactId, privateMessageId, Status.NEW); @@ -338,7 +343,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); @@ -376,7 +381,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); @@ -418,7 +423,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.addGroupMessage(txn, message); @@ -457,7 +462,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.addGroupMessage(txn, message); @@ -492,7 +497,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); @@ -523,7 +528,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setSubscriptions(txn, contactId, subscriptions, 1); db.addGroupMessage(txn, message); @@ -556,7 +561,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact and some batches to ack - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addBatchToAck(txn, contactId, batchId); db.addBatchToAck(txn, contactId, batchId1); @@ -583,7 +588,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact and receive the same batch twice - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addBatchToAck(txn, contactId, batchId); db.addBatchToAck(txn, contactId, batchId); @@ -609,7 +614,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.addGroupMessage(txn, message); @@ -634,8 +639,8 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add two contacts, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); - ContactId contactId1 = db.addContact(txn, secret); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); + ContactId contactId1 = db.addContact(txn, inSecret, outSecret); db.addSubscription(txn, group); db.addGroupMessage(txn, message); @@ -657,7 +662,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); @@ -696,7 +701,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); @@ -741,7 +746,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); // Add some outstanding batches, a few ms apart for(int i = 0; i < ids.length; i++) { @@ -781,7 +786,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); // Add some outstanding batches, a few ms apart for(int i = 0; i < ids.length; i++) { @@ -1001,7 +1006,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact with a transport - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.setTransports(txn, contactId, remoteTransports, 1); assertEquals(remoteProperties, db.getRemoteProperties(txn, transportId)); @@ -1094,7 +1099,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact with a transport - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.setTransports(txn, contactId, remoteTransports, 1); assertEquals(remoteProperties, db.getRemoteProperties(txn, transportId)); @@ -1138,7 +1143,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact with some subscriptions - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.setSubscriptions(txn, contactId, subscriptions, 1); assertEquals(Collections.singletonList(group), db.getSubscriptions(txn, contactId)); @@ -1163,7 +1168,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact with some subscriptions - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.setSubscriptions(txn, contactId, subscriptions, 2); assertEquals(Collections.singletonList(group), db.getSubscriptions(txn, contactId)); @@ -1187,7 +1192,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact and subscribe to a group - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setSubscriptions(txn, contactId, subscriptions, 1); @@ -1205,7 +1210,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setSubscriptions(txn, contactId, subscriptions, 1); db.addGroupMessage(txn, message); @@ -1228,7 +1233,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setSubscriptions(txn, contactId, subscriptions, 1); db.addGroupMessage(txn, message); @@ -1251,7 +1256,7 @@ public class H2DatabaseTest extends TestCase { // Add a contact, subscribe to a group and store a message - // the message is older than the contact's subscription - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singletonList(contactId)); Map<Group, Long> subs = Collections.singletonMap(group, timestamp + 1); @@ -1275,7 +1280,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); @@ -1300,7 +1305,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact and subscribe to a group - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); @@ -1319,7 +1324,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact with a subscription - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.setSubscriptions(txn, contactId, subscriptions, 1); // There's no local subscription for the group @@ -1336,7 +1341,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.addGroupMessage(txn, message); db.setStatus(txn, contactId, messageId, Status.NEW); @@ -1355,7 +1360,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.addGroupMessage(txn, message); db.setSubscriptions(txn, contactId, subscriptions, 1); @@ -1375,7 +1380,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); @@ -1397,7 +1402,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); @@ -1418,7 +1423,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact and subscribe to a group - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); // The group should not be visible to the contact assertEquals(Collections.emptyList(), db.getVisibility(txn, groupId)); @@ -1441,7 +1446,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); // Get the connection window for a new index ConnectionWindow w = db.getConnectionWindow(txn, contactId, remoteIndex); @@ -1460,7 +1465,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); // Get the connection window for a new index ConnectionWindow w = db.getConnectionWindow(txn, contactId, remoteIndex); @@ -1564,7 +1569,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact and subscribe to a group - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); // A message with a private parent should return null @@ -1613,7 +1618,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); // The subscription and transport timestamps should be initialised to 0 assertEquals(0L, db.getSubscriptionsModified(txn, contactId)); @@ -1644,7 +1649,7 @@ public class H2DatabaseTest extends TestCase { Connection txn = db.startTransaction(); // Add a contact and subscribe to a group - assertEquals(contactId, db.addContact(txn, secret)); + assertEquals(contactId, db.addContact(txn, inSecret, outSecret)); db.addSubscription(txn, group); // Store a couple of messages diff --git a/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java b/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java index 056e478c92..31eab8d9bd 100644 --- a/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java +++ b/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java @@ -4,14 +4,15 @@ import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH; import java.util.Collection; import java.util.Collections; +import java.util.Random; import javax.crypto.Cipher; -import net.sf.briar.api.crypto.ErasableKey; import junit.framework.TestCase; import net.sf.briar.TestUtils; import net.sf.briar.api.ContactId; import net.sf.briar.api.crypto.CryptoComponent; +import net.sf.briar.api.crypto.ErasableKey; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.protocol.Transport; import net.sf.briar.api.protocol.TransportId; @@ -31,7 +32,7 @@ public class ConnectionRecogniserImplTest extends TestCase { private final CryptoComponent crypto; private final ContactId contactId; - private final byte[] secret; + private final byte[] inSecret; private final TransportId transportId; private final TransportIndex localIndex, remoteIndex; private final Collection<Transport> transports; @@ -42,7 +43,8 @@ public class ConnectionRecogniserImplTest extends TestCase { Injector i = Guice.createInjector(new CryptoModule()); crypto = i.getInstance(CryptoComponent.class); contactId = new ContactId(1); - secret = new byte[18]; + inSecret = new byte[123]; + new Random().nextBytes(inSecret); transportId = new TransportId(TestUtils.getRandomId()); localIndex = new TransportIndex(13); remoteIndex = new TransportIndex(7); @@ -63,8 +65,8 @@ public class ConnectionRecogniserImplTest extends TestCase { will(returnValue(transports)); oneOf(db).getContacts(); will(returnValue(Collections.singletonList(contactId))); - oneOf(db).getSharedSecret(contactId); - will(returnValue(secret)); + oneOf(db).getSharedSecret(contactId, true); + will(returnValue(inSecret)); oneOf(db).getRemoteIndex(contactId, transportId); will(returnValue(remoteIndex)); oneOf(db).getConnectionWindow(contactId, remoteIndex); @@ -79,7 +81,7 @@ public class ConnectionRecogniserImplTest extends TestCase { @Test public void testExpectedIv() throws Exception { // Calculate the expected IV for connection number 3 - ErasableKey ivKey = crypto.deriveIncomingIvKey(secret); + ErasableKey ivKey = crypto.deriveIvKey(inSecret, true); Cipher ivCipher = crypto.getIvCipher(); ivCipher.init(Cipher.ENCRYPT_MODE, ivKey); byte[] iv = IvEncoder.encodeIv(true, remoteIndex, 3L); @@ -94,8 +96,8 @@ public class ConnectionRecogniserImplTest extends TestCase { will(returnValue(transports)); oneOf(db).getContacts(); will(returnValue(Collections.singletonList(contactId))); - oneOf(db).getSharedSecret(contactId); - will(returnValue(secret)); + oneOf(db).getSharedSecret(contactId, true); + will(returnValue(inSecret)); oneOf(db).getRemoteIndex(contactId, transportId); will(returnValue(remoteIndex)); oneOf(db).getConnectionWindow(contactId, remoteIndex); @@ -105,8 +107,8 @@ public class ConnectionRecogniserImplTest extends TestCase { will(returnValue(connectionWindow)); oneOf(db).setConnectionWindow(contactId, remoteIndex, connectionWindow); - oneOf(db).getSharedSecret(contactId); - will(returnValue(secret)); + oneOf(db).getSharedSecret(contactId, true); + will(returnValue(inSecret)); }}); final ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db); diff --git a/test/net/sf/briar/transport/ConnectionWriterTest.java b/test/net/sf/briar/transport/ConnectionWriterTest.java index e623187017..f5ffa882f5 100644 --- a/test/net/sf/briar/transport/ConnectionWriterTest.java +++ b/test/net/sf/briar/transport/ConnectionWriterTest.java @@ -4,6 +4,7 @@ import static net.sf.briar.api.protocol.ProtocolConstants.MAX_PACKET_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MIN_CONNECTION_LENGTH; import java.io.ByteArrayOutputStream; +import java.util.Random; import junit.framework.TestCase; import net.sf.briar.TestDatabaseModule; @@ -26,7 +27,7 @@ import com.google.inject.Injector; public class ConnectionWriterTest extends TestCase { private final ConnectionWriterFactory connectionWriterFactory; - private final byte[] secret = new byte[100]; + private final byte[] outSecret; private final TransportIndex transportIndex = new TransportIndex(13); private final long connection = 12345L; @@ -38,6 +39,8 @@ public class ConnectionWriterTest extends TestCase { new TestDatabaseModule(), new TransportBatchModule(), new TransportModule(), new TransportStreamModule()); connectionWriterFactory = i.getInstance(ConnectionWriterFactory.class); + outSecret = new byte[123]; + new Random().nextBytes(outSecret); } @Test @@ -45,7 +48,7 @@ public class ConnectionWriterTest extends TestCase { ByteArrayOutputStream out = new ByteArrayOutputStream(MIN_CONNECTION_LENGTH); ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out, - MIN_CONNECTION_LENGTH, transportIndex, connection, secret); + MIN_CONNECTION_LENGTH, transportIndex, connection, outSecret); // Check that the connection writer thinks there's room for a packet long capacity = w.getRemainingCapacity(); assertTrue(capacity >= MAX_PACKET_LENGTH); diff --git a/test/net/sf/briar/transport/FrameReadWriteTest.java b/test/net/sf/briar/transport/FrameReadWriteTest.java index aa002a2536..5ed26f59a1 100644 --- a/test/net/sf/briar/transport/FrameReadWriteTest.java +++ b/test/net/sf/briar/transport/FrameReadWriteTest.java @@ -29,10 +29,10 @@ public class FrameReadWriteTest extends TestCase { private final CryptoComponent crypto; private final Cipher ivCipher, frameCipher; + private final Random random; + private final byte[] outSecret; private final ErasableKey ivKey, frameKey, macKey; private final Mac mac; - private final Random random; - private final byte[] secret = new byte[100]; private final TransportIndex transportIndex = new TransportIndex(13); private final long connection = 12345L; @@ -42,12 +42,14 @@ public class FrameReadWriteTest extends TestCase { crypto = i.getInstance(CryptoComponent.class); ivCipher = crypto.getIvCipher(); frameCipher = crypto.getFrameCipher(); + random = new Random(); // Since we're sending frames to ourselves, we only need outgoing keys - ivKey = crypto.deriveOutgoingIvKey(secret); - frameKey = crypto.deriveOutgoingFrameKey(secret); - macKey = crypto.deriveOutgoingMacKey(secret); + outSecret = new byte[123]; + random.nextBytes(outSecret); + ivKey = crypto.deriveIvKey(outSecret, true); + frameKey = crypto.deriveFrameKey(outSecret, true); + macKey = crypto.deriveMacKey(outSecret, true); mac = crypto.getMac(); - random = new Random(); } @Test diff --git a/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java b/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java index d972415507..8ecc2dc580 100644 --- a/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java +++ b/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java @@ -9,6 +9,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.Collection; import java.util.Collections; +import java.util.Random; import junit.framework.TestCase; import net.sf.briar.TestDatabaseModule; @@ -54,7 +55,7 @@ public class BatchConnectionReadWriteTest extends TestCase { private final File bobDir = new File(testDir, "bob"); private final TransportId transportId; private final TransportIndex transportIndex; - private final byte[] aliceSecret, bobSecret; + private final byte[] aliceToBobSecret, bobToAliceSecret; private Injector alice, bob; @@ -63,9 +64,11 @@ public class BatchConnectionReadWriteTest extends TestCase { transportId = new TransportId(TestUtils.getRandomId()); transportIndex = new TransportIndex(1); // Create matching secrets for Alice and Bob - aliceSecret = new byte[123]; - aliceSecret[0] = (byte) 1; - bobSecret = new byte[123]; + Random r = new Random(); + aliceToBobSecret = new byte[123]; + r.nextBytes(aliceToBobSecret); + bobToAliceSecret = new byte[123]; + r.nextBytes(bobToAliceSecret); } @Before @@ -102,7 +105,7 @@ public class BatchConnectionReadWriteTest extends TestCase { DatabaseComponent db = alice.getInstance(DatabaseComponent.class); db.open(false); // Add Bob as a contact and send him a message - ContactId contactId = db.addContact(aliceSecret); + ContactId contactId = db.addContact(bobToAliceSecret, aliceToBobSecret); String subject = "Hello"; byte[] messageBody = "Hi Bob!".getBytes("UTF-8"); MessageEncoder encoder = alice.getInstance(MessageEncoder.class); @@ -134,7 +137,7 @@ public class BatchConnectionReadWriteTest extends TestCase { MessageListener listener = new MessageListener(); db.addListener(listener); // Add Alice as a contact - ContactId contactId = db.addContact(bobSecret); + ContactId contactId = db.addContact(aliceToBobSecret, bobToAliceSecret); // Add the transport assertEquals(transportIndex, db.addTransport(transportId)); // Fake a transport update from Alice -- GitLab