diff --git a/api/net/sf/briar/api/crypto/CryptoComponent.java b/api/net/sf/briar/api/crypto/CryptoComponent.java index a9322319896fd0491abef6f1f96c1e5ab2e6fe92..2b01765b7d8f6e5b731db5cfc59fee69050dad84 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 857e6c1e5eaf86d5367ebd113c705be3a59e4634..1717f00ca9dbf22569a933bbe5f9af332cc4a907 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 5d7c9142c76a2727a146783a03f127c38c228866..db9dead7b067f82d92c3270a9d13b5e869680b21 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 63a13a3619f372e3a00a4a19278eb64931beea5a..8b05d3e2a59c5654ecd251967ba5e643f4f8a4ab 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 cd64e056554d7063185fef4aaa80082b9da32927..670245c2d43eebc4457b1258142216aa372e6981 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 0f2a984b9abd1352a608091480fdcc47abcc9fc2..0000000000000000000000000000000000000000 --- 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 60a7b3a80d94037dc665b9d289691890727b1d54..a3281c7973ed945524a8c1e1df5535c8ae73be79 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 fe2172b9651eabb4ba13092477957a558c23927b..a671f95c1cd886afd5b893930108fa96b544b219 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 458d39edc21900f477e5b55e050cd2cdf5911586..0398d75e6a8fc9bd89e69b46f27ef5c799185eb2 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 b48a564badfc33136bec625a8492eae10402b8e3..6469e8b4e28b1fd47fe069eee5ca5c0324e4fa2d 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 34bd3a2e1552f9d513193d0f8c0bd7f227d73a7c..6c139c6346438990f2c469e8d1295e9583e79c11 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 822f6223b43b311ee6c00969b860350560777476..caab149260216d42a5f888c483cf108e675755c3 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 b1bfd1966cf2232126b3ffcd8e3bd23bae39d240..a97c392c97844681c90d0ed5a319c22c93f0743a 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 810a4e789933d0b01daf50d6fb5b8c00e11bf7c6..b9d8630b3530652bd64dc0cd05ed3b1645c24eb7 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 3518b75c92b7775e32c8b915f7ff42ae0074409e..bc01c5ad618edd359c5b016e6b14473a29cef01b 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 923fcf354f88101ca01a6e5d5243d3c0683c4ba5..4af22e161ea9c24183d3cbc258c46ad117788ce4 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 b0d0118ed9c5fc531039306d948b3e244e46e6b0..9dc9b7a1099a91b54ef723e8c442b4d9054e1aaf 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 f7afcc9a62b6c144c22dcc3b8c88614ce9db65ad..907fc63d8f56da3cb28349388dd28ca17a06d65b 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 fcc74391e085688334d66516e12fb4ae1aa5bdfc..0000000000000000000000000000000000000000 --- 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 aa23d79aee3bed06484f990ff3fe6a507eb03a82..0000000000000000000000000000000000000000 --- 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 335d11d711cc11f1b523dbce5add3303f46431f2..763bbf4bb795e957f9392d176141be38aa8ce338 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 9d9471f21b99543d36606a04c5b5509a3f8e0fdf..ac3fee99c4132cd98ab61d869d8ed8b7810a50d1 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 056e478c929aedf827aa51fa2a7adc1367900a77..31eab8d9bdac001ca6a59c99b7feb4675b4d52c0 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 e62318701783b21c83ac2eefbbced5b35cd7dd42..f5ffa882f5577684aeaa3e676c076d192e76f16e 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 aa002a2536b6e10f8e3714d69f78c45919887f9e..5ed26f59a1c590e0e529a847bc7ccfdcc9f0dfae 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 d972415507c63d6b2f445806d4583c290026e24e..8ecc2dc580127afbb574fe54c03b631d86e6229a 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