Store the incoming and outgoing secrets separately.

This commit is contained in:
akwizgran
2011-11-15 16:07:14 +00:00
parent f41d48eb9f
commit 6a15c03e81
26 changed files with 200 additions and 336 deletions

View File

@@ -9,20 +9,16 @@ import javax.crypto.Mac;
public interface CryptoComponent { 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 deriveMacKey(byte[] source, boolean initiator);
ErasableKey deriveOutgoingFrameKey(byte[] secret);
ErasableKey deriveOutgoingIvKey(byte[] secret);
ErasableKey deriveOutgoingMacKey(byte[] secret);
KeyPair generateKeyPair(); KeyPair generateKeyPair();
ErasableKey generateTestKey();
Cipher getFrameCipher(); Cipher getFrameCipher();
Cipher getIvCipher(); Cipher getIvCipher();
@@ -36,6 +32,4 @@ public interface CryptoComponent {
SecureRandom getSecureRandom(); SecureRandom getSecureRandom();
Signature getSignature(); Signature getSignature();
ErasableKey generateTestKey();
} }

View File

@@ -53,10 +53,11 @@ public interface DatabaseComponent {
void removeListener(DatabaseListener d); 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. * 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. */ /** Adds a locally generated group message to the database. */
void addLocalGroupMessage(Message m) throws DbException; void addLocalGroupMessage(Message m) throws DbException;
@@ -158,7 +159,7 @@ public interface DatabaseComponent {
throws DbException; throws DbException;
/** Returns the secret shared with the given contact. */ /** 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. */ /** Returns the set of groups to which the user subscribes. */
Collection<Group> getSubscriptions() throws DbException; Collection<Group> getSubscriptions() throws DbException;

View File

@@ -8,14 +8,15 @@ public interface ConnectionReaderFactory {
/** /**
* Creates a connection reader for a batch-mode connection or the * 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, ConnectionReader createConnectionReader(InputStream in, TransportIndex i,
byte[] encryptedIv, byte[] secret); byte[] encryptedIv, byte[] secret);
/** /**
* Creates a connection reader for the responder's side of a stream-mode * 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, ConnectionReader createConnectionReader(InputStream in, TransportIndex i,
long connection, byte[] secret); long connection, byte[] secret);

View File

@@ -8,14 +8,15 @@ public interface ConnectionWriterFactory {
/** /**
* Creates a connection writer for a batch-mode connection or the * 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, ConnectionWriter createConnectionWriter(OutputStream out, long capacity,
TransportIndex i, long connection, byte[] secret); TransportIndex i, long connection, byte[] secret);
/** /**
* Creates a connection writer for the responder's side of a stream-mode * 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, ConnectionWriter createConnectionWriter(OutputStream out, long capacity,
TransportIndex i, byte[] encryptedIv, byte[] secret); TransportIndex i, byte[] encryptedIv, byte[] secret);

View File

@@ -53,17 +53,22 @@ class CryptoComponentImpl implements CryptoComponent {
} }
} }
public ErasableKey deriveIncomingFrameKey(byte[] secret) { public ErasableKey deriveFrameKey(byte[] source, boolean initiator) {
SharedSecret s = new SharedSecret(secret); if(initiator) return deriveKey("FRAME_I", source);
return deriveFrameKey(s, !s.getAlice()); else return deriveKey("FRAME_R", source);
} }
private ErasableKey deriveFrameKey(SharedSecret s, boolean alice) { public ErasableKey deriveIvKey(byte[] source, boolean initiator) {
if(alice) return deriveKey("F_A", s.getSecret()); if(initiator) return deriveKey("IV_I", source);
else return deriveKey("F_B", s.getSecret()); 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(); MessageDigest digest = getMessageDigest();
assert digest.getDigestLength() == SECRET_KEY_BYTES; assert digest.getDigestLength() == SECRET_KEY_BYTES;
try { try {
@@ -71,49 +76,20 @@ class CryptoComponentImpl implements CryptoComponent {
} catch(UnsupportedEncodingException e) { } catch(UnsupportedEncodingException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
digest.update(secret); digest.update(source);
return new ErasableKeyImpl(digest.digest(), SECRET_KEY_ALGO); 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() { public KeyPair generateKeyPair() {
return keyPairGenerator.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() { public Cipher getFrameCipher() {
try { try {
return Cipher.getInstance(FRAME_CIPHER_ALGO, PROVIDER); return Cipher.getInstance(FRAME_CIPHER_ALGO, PROVIDER);
@@ -177,10 +153,4 @@ class CryptoComponentImpl implements CryptoComponent {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public ErasableKey generateTestKey() {
byte[] b = new byte[SECRET_KEY_BYTES];
getSecureRandom().nextBytes(b);
return new ErasableKeyImpl(b, SECRET_KEY_ALGO);
}
} }

View File

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

View File

@@ -80,12 +80,13 @@ interface Database<T> {
void addBatchToAck(T txn, ContactId c, BatchId b) throws DbException; 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. * ID for the contact.
* <p> * <p>
* Locking: contact write. * 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 * Returns false if the given message is already in the database. Otherwise
@@ -376,7 +377,8 @@ interface Database<T> {
* <p> * <p>
* Locking: contact read. * 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. * Returns true if the given message has been starred.

View File

@@ -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"); if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding contact");
ContactId c; ContactId c;
contactLock.writeLock().lock(); contactLock.writeLock().lock();
try { try {
T txn = db.startTransaction(); T txn = db.startTransaction();
try { try {
c = db.addContact(txn, secret); c = db.addContact(txn, incomingSecret, outgoingSecret);
db.commitTransaction(txn); db.commitTransaction(txn);
if(LOG.isLoggable(Level.FINE)) LOG.fine("Added contact " + c); if(LOG.isLoggable(Level.FINE)) LOG.fine("Added contact " + c);
} catch(DbException e) { } 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(); contactLock.readLock().lock();
try { try {
if(!containsContact(c)) throw new NoSuchContactException(); if(!containsContact(c)) throw new NoSuchContactException();
T txn = db.startTransaction(); T txn = db.startTransaction();
try { try {
byte[] secret = db.getSharedSecret(txn, c); byte[] secret = db.getSharedSecret(txn, c, incoming);
db.commitTransaction(txn); db.commitTransaction(txn);
return secret; return secret;
} catch(DbException e) { } catch(DbException e) {

View File

@@ -56,7 +56,8 @@ abstract class JdbcDatabase implements Database<Connection> {
private static final String CREATE_CONTACTS = private static final String CREATE_CONTACTS =
"CREATE TABLE contacts" "CREATE TABLE contacts"
+ " (contactId COUNTER," + " (contactId COUNTER,"
+ " secret BINARY NOT NULL," + " incomingSecret BINARY NOT NULL,"
+ " outgoingSecret BINARY NOT NULL,"
+ " PRIMARY KEY (contactId))"; + " PRIMARY KEY (contactId))";
private static final String CREATE_MESSAGES = private static final String CREATE_MESSAGES =
@@ -509,15 +510,17 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
public ContactId addContact(Connection txn, byte[] secret) public ContactId addContact(Connection txn, byte[] incomingSecret,
throws DbException { byte[] outgoingSecret) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
// Create a new contact row // 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 = txn.prepareStatement(sql);
ps.setBytes(1, secret); ps.setBytes(1, incomingSecret);
ps.setBytes(2, outgoingSecret);
int affected = ps.executeUpdate(); int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException(); if(affected != 1) throw new DbStateException();
ps.close(); 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 { throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { 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 = txn.prepareStatement(sql);
ps.setInt(1, c.getInt()); ps.setInt(1, c.getInt());
rs = ps.executeQuery(); rs = ps.executeQuery();

View File

@@ -29,7 +29,7 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
TransportIndex i, byte[] encryptedIv, byte[] secret) { TransportIndex i, byte[] encryptedIv, byte[] secret) {
// Decrypt the IV // Decrypt the IV
Cipher ivCipher = crypto.getIvCipher(); Cipher ivCipher = crypto.getIvCipher();
ErasableKey ivKey = crypto.deriveIncomingIvKey(secret); ErasableKey ivKey = crypto.deriveIvKey(secret, true);
byte[] iv; byte[] iv;
try { try {
ivCipher.init(Cipher.DECRYPT_MODE, ivKey); ivCipher.init(Cipher.DECRYPT_MODE, ivKey);
@@ -57,15 +57,17 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
private ConnectionReader createConnectionReader(InputStream in, private ConnectionReader createConnectionReader(InputStream in,
boolean initiator, TransportIndex i, long connection, boolean initiator, TransportIndex i, long connection,
byte[] secret) { 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 // Create the decrypter
byte[] iv = IvEncoder.encodeIv(initiator, i, connection);
Cipher frameCipher = crypto.getFrameCipher(); Cipher frameCipher = crypto.getFrameCipher();
ErasableKey frameKey = crypto.deriveIncomingFrameKey(secret);
ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in, iv, ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in, iv,
frameCipher, frameKey); frameCipher, frameKey);
// Create the reader // Create the reader
Mac mac = crypto.getMac(); Mac mac = crypto.getMac();
ErasableKey macKey = crypto.deriveIncomingMacKey(secret);
return new ConnectionReaderImpl(decrypter, mac, macKey); return new ConnectionReaderImpl(decrypter, mac, macKey);
} }
} }

View File

@@ -75,7 +75,9 @@ DatabaseListener {
} }
private synchronized void calculateIvs(ContactId c) throws DbException { 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) { for(TransportId t : localTransportIds) {
TransportIndex i = db.getRemoteIndex(c, t); TransportIndex i = db.getRemoteIndex(c, t);
if(i != null) { if(i != null) {
@@ -131,7 +133,9 @@ DatabaseListener {
TransportIndex i1 = ctx1.getTransportIndex(); TransportIndex i1 = ctx1.getTransportIndex();
if(c1.equals(c) && i1.equals(i)) it.remove(); 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); calculateIvs(c, ctx.getTransportId(), i, ivKey, w);
} catch(NoSuchContactException e) { } catch(NoSuchContactException e) {
// The contact was removed - clean up when we get the event // The contact was removed - clean up when we get the event
@@ -181,8 +185,9 @@ DatabaseListener {
private synchronized void calculateIvs(TransportId t) throws DbException { private synchronized void calculateIvs(TransportId t) throws DbException {
for(ContactId c : db.getContacts()) { for(ContactId c : db.getContacts()) {
try { try {
byte[] secret = db.getSharedSecret(c); byte[] secret = db.getSharedSecret(c, true);
ErasableKey ivKey = crypto.deriveIncomingIvKey(secret); ErasableKey ivKey = crypto.deriveIvKey(secret, true);
for(int i = 0; i < secret.length; i++) secret[i] = 0;
TransportIndex i = db.getRemoteIndex(c, t); TransportIndex i = db.getRemoteIndex(c, t);
if(i != null) { if(i != null) {
ConnectionWindow w = db.getConnectionWindow(c, i); ConnectionWindow w = db.getConnectionWindow(c, i);

View File

@@ -36,7 +36,7 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
byte[] secret) { byte[] secret) {
// Decrypt the IV // Decrypt the IV
Cipher ivCipher = crypto.getIvCipher(); Cipher ivCipher = crypto.getIvCipher();
ErasableKey ivKey = crypto.deriveIncomingIvKey(secret); ErasableKey ivKey = crypto.deriveIvKey(secret, true);
byte[] iv; byte[] iv;
try { try {
ivCipher.init(Cipher.DECRYPT_MODE, ivKey); ivCipher.init(Cipher.DECRYPT_MODE, ivKey);
@@ -60,17 +60,19 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
private ConnectionWriter createConnectionWriter(OutputStream out, private ConnectionWriter createConnectionWriter(OutputStream out,
long capacity, boolean initiator, TransportIndex i, long connection, long capacity, boolean initiator, TransportIndex i, long connection,
byte[] secret) { 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 // Create the encrypter
Cipher ivCipher = crypto.getIvCipher(); Cipher ivCipher = crypto.getIvCipher();
Cipher frameCipher = crypto.getFrameCipher(); Cipher frameCipher = crypto.getFrameCipher();
ErasableKey ivKey = crypto.deriveOutgoingIvKey(secret);
ErasableKey frameKey = crypto.deriveOutgoingFrameKey(secret);
byte[] iv = IvEncoder.encodeIv(initiator, i, connection); byte[] iv = IvEncoder.encodeIv(initiator, i, connection);
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out, ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
capacity, iv, ivCipher, frameCipher, ivKey, frameKey); capacity, iv, ivCipher, frameCipher, ivKey, frameKey);
// Create the writer // Create the writer
Mac mac = crypto.getMac(); Mac mac = crypto.getMac();
ErasableKey macKey = crypto.deriveOutgoingMacKey(secret);
return new ConnectionWriterImpl(encrypter, mac, macKey); return new ConnectionWriterImpl(encrypter, mac, macKey);
} }
} }

View File

@@ -47,7 +47,7 @@ class IncomingBatchConnection {
void read() { void read() {
try { try {
byte[] secret = db.getSharedSecret(contactId); byte[] secret = db.getSharedSecret(contactId, true);
ConnectionReader conn = connFactory.createConnectionReader( ConnectionReader conn = connFactory.createConnectionReader(
reader.getInputStream(), transportIndex, encryptedIv, reader.getInputStream(), transportIndex, encryptedIv,
secret); secret);

View File

@@ -46,7 +46,7 @@ class OutgoingBatchConnection {
void write() { void write() {
try { try {
byte[] secret = db.getSharedSecret(contactId); byte[] secret = db.getSharedSecret(contactId, false);
long connection = db.getConnectionNumber(contactId, transportIndex); long connection = db.getConnectionNumber(contactId, transportIndex);
ConnectionWriter conn = connFactory.createConnectionWriter( ConnectionWriter conn = connFactory.createConnectionWriter(
writer.getOutputStream(), writer.getCapacity(), writer.getOutputStream(), writer.getCapacity(),

View File

@@ -33,7 +33,7 @@ public class IncomingStreamConnection extends StreamConnection {
@Override @Override
protected ConnectionReader createConnectionReader() throws DbException, protected ConnectionReader createConnectionReader() throws DbException,
IOException { IOException {
byte[] secret = db.getSharedSecret(contactId); byte[] secret = db.getSharedSecret(contactId, true);
return connReaderFactory.createConnectionReader( return connReaderFactory.createConnectionReader(
connection.getInputStream(), transportIndex, encryptedIv, connection.getInputStream(), transportIndex, encryptedIv,
secret); secret);
@@ -42,7 +42,7 @@ public class IncomingStreamConnection extends StreamConnection {
@Override @Override
protected ConnectionWriter createConnectionWriter() throws DbException, protected ConnectionWriter createConnectionWriter() throws DbException,
IOException { IOException {
byte[] secret = db.getSharedSecret(contactId); byte[] secret = db.getSharedSecret(contactId, false);
return connWriterFactory.createConnectionWriter( return connWriterFactory.createConnectionWriter(
connection.getOutputStream(), Long.MAX_VALUE, transportIndex, connection.getOutputStream(), Long.MAX_VALUE, transportIndex,
encryptedIv, secret); encryptedIv, secret);

View File

@@ -37,7 +37,7 @@ public class OutgoingStreamConnection extends StreamConnection {
transportIndex); transportIndex);
} }
} }
byte[] secret = db.getSharedSecret(contactId); byte[] secret = db.getSharedSecret(contactId, true);
return connReaderFactory.createConnectionReader( return connReaderFactory.createConnectionReader(
connection.getInputStream(), transportIndex, connectionNum, connection.getInputStream(), transportIndex, connectionNum,
secret); secret);
@@ -52,7 +52,7 @@ public class OutgoingStreamConnection extends StreamConnection {
transportIndex); transportIndex);
} }
} }
byte[] secret = db.getSharedSecret(contactId); byte[] secret = db.getSharedSecret(contactId, false);
return connWriterFactory.createConnectionWriter( return connWriterFactory.createConnectionWriter(
connection.getOutputStream(), Long.MAX_VALUE, transportIndex, connection.getOutputStream(), Long.MAX_VALUE, transportIndex,
connectionNum, secret); connectionNum, secret);

View File

@@ -17,8 +17,6 @@
<test name='net.sf.briar.LockFairnessTest'/> <test name='net.sf.briar.LockFairnessTest'/>
<test name='net.sf.briar.ProtocolIntegrationTest'/> <test name='net.sf.briar.ProtocolIntegrationTest'/>
<test name='net.sf.briar.crypto.CounterModeTest'/> <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.BasicH2Test'/>
<test name='net.sf.briar.db.DatabaseCleanerImplTest'/> <test name='net.sf.briar.db.DatabaseCleanerImplTest'/>
<test name='net.sf.briar.db.DatabaseComponentImplTest'/> <test name='net.sf.briar.db.DatabaseComponentImplTest'/>

View File

@@ -13,6 +13,7 @@ import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Random;
import junit.framework.TestCase; import junit.framework.TestCase;
import net.sf.briar.api.crypto.CryptoComponent; 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.batch.TransportBatchModule;
import net.sf.briar.transport.stream.TransportStreamModule; import net.sf.briar.transport.stream.TransportStreamModule;
import org.bouncycastle.util.Arrays;
import org.junit.Test; import org.junit.Test;
import com.google.inject.Guice; import com.google.inject.Guice;
@@ -71,7 +73,7 @@ public class ProtocolIntegrationTest extends TestCase {
private final ProtocolReaderFactory protocolReaderFactory; private final ProtocolReaderFactory protocolReaderFactory;
private final ProtocolWriterFactory protocolWriterFactory; private final ProtocolWriterFactory protocolWriterFactory;
private final CryptoComponent crypto; private final CryptoComponent crypto;
private final byte[] aliceSecret, bobSecret; private final byte[] aliceToBobSecret;
private final TransportIndex transportIndex = new TransportIndex(13); private final TransportIndex transportIndex = new TransportIndex(13);
private final long connection = 12345L; private final long connection = 12345L;
private final Author author; private final Author author;
@@ -96,10 +98,9 @@ public class ProtocolIntegrationTest extends TestCase {
crypto = i.getInstance(CryptoComponent.class); crypto = i.getInstance(CryptoComponent.class);
assertEquals(crypto.getMessageDigest().getDigestLength(), assertEquals(crypto.getMessageDigest().getDigestLength(),
UniqueId.LENGTH); UniqueId.LENGTH);
// Create matching secrets: one for Alice, one for Bob Random r = new Random();
aliceSecret = new byte[123]; aliceToBobSecret = new byte[123];
aliceSecret[0] = (byte) 1; r.nextBytes(aliceToBobSecret);
bobSecret = new byte[123];
// Create two groups: one restricted, one unrestricted // Create two groups: one restricted, one unrestricted
GroupFactory groupFactory = i.getInstance(GroupFactory.class); GroupFactory groupFactory = i.getInstance(GroupFactory.class);
group = groupFactory.createGroup("Unrestricted group", null); group = groupFactory.createGroup("Unrestricted group", null);
@@ -138,9 +139,9 @@ public class ProtocolIntegrationTest extends TestCase {
private byte[] write() throws Exception { private byte[] write() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
// Use Alice's secret for writing byte[] copyOfSecret = Arrays.clone(aliceToBobSecret);
ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out, ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out,
Long.MAX_VALUE, transportIndex, connection, aliceSecret); Long.MAX_VALUE, transportIndex, connection, copyOfSecret);
OutputStream out1 = w.getOutputStream(); OutputStream out1 = w.getOutputStream();
AckWriter a = protocolWriterFactory.createAckWriter(out1); AckWriter a = protocolWriterFactory.createAckWriter(out1);
@@ -193,9 +194,9 @@ public class ProtocolIntegrationTest extends TestCase {
offset += read; offset += read;
} }
assertEquals(16, offset); assertEquals(16, offset);
// Use Bob's secret for reading byte[] copyOfSecret = Arrays.clone(aliceToBobSecret);
ConnectionReader r = connectionReaderFactory.createConnectionReader(in, ConnectionReader r = connectionReaderFactory.createConnectionReader(in,
transportIndex, encryptedIv, bobSecret); transportIndex, encryptedIv, copyOfSecret);
in = r.getInputStream(); in = r.getInputStream();
ProtocolReader protocolReader = ProtocolReader protocolReader =
protocolReaderFactory.createProtocolReader(in); protocolReaderFactory.createProtocolReader(in);

View File

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

View File

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

View File

@@ -5,6 +5,7 @@ import java.util.BitSet;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Random;
import junit.framework.TestCase; import junit.framework.TestCase;
import net.sf.briar.TestUtils; import net.sf.briar.TestUtils;
@@ -46,6 +47,7 @@ import net.sf.briar.api.transport.ConnectionWindow;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.jmock.Mockery; import org.jmock.Mockery;
import static org.junit.Assert.assertArrayEquals;
import org.junit.Test; import org.junit.Test;
public abstract class DatabaseComponentTest extends TestCase { public abstract class DatabaseComponentTest extends TestCase {
@@ -66,7 +68,7 @@ public abstract class DatabaseComponentTest extends TestCase {
private final TransportIndex localIndex, remoteIndex; private final TransportIndex localIndex, remoteIndex;
private final Collection<Transport> transports; private final Collection<Transport> transports;
private final Map<ContactId, TransportProperties> remoteProperties; private final Map<ContactId, TransportProperties> remoteProperties;
private final byte[] secret; private final byte[] inSecret, outSecret;
public DatabaseComponentTest() { public DatabaseComponentTest() {
super(); super();
@@ -94,7 +96,11 @@ public abstract class DatabaseComponentTest extends TestCase {
Transport transport = new Transport(transportId, localIndex, Transport transport = new Transport(transportId, localIndex,
properties); properties);
transports = Collections.singletonList(transport); 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( protected abstract <T> DatabaseComponent createDatabaseComponent(
@@ -132,7 +138,7 @@ public abstract class DatabaseComponentTest extends TestCase {
oneOf(database).setRating(txn, authorId, Rating.GOOD); oneOf(database).setRating(txn, authorId, Rating.GOOD);
will(returnValue(Rating.GOOD)); will(returnValue(Rating.GOOD));
// addContact() // addContact()
oneOf(database).addContact(txn, secret); oneOf(database).addContact(txn, inSecret, outSecret);
will(returnValue(contactId)); will(returnValue(contactId));
oneOf(listener).eventOccurred(with(any(ContactAddedEvent.class))); oneOf(listener).eventOccurred(with(any(ContactAddedEvent.class)));
// getContacts() // getContacts()
@@ -143,11 +149,16 @@ public abstract class DatabaseComponentTest extends TestCase {
will(returnValue(true)); will(returnValue(true));
oneOf(database).getConnectionWindow(txn, contactId, remoteIndex); oneOf(database).getConnectionWindow(txn, contactId, remoteIndex);
will(returnValue(connectionWindow)); will(returnValue(connectionWindow));
// getSharedSecret(contactId) // getSharedSecret(contactId, true)
oneOf(database).containsContact(txn, contactId); oneOf(database).containsContact(txn, contactId);
will(returnValue(true)); will(returnValue(true));
oneOf(database).getSharedSecret(txn, contactId); oneOf(database).getSharedSecret(txn, contactId, true);
will(returnValue(secret)); 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) // getTransportProperties(transportId)
oneOf(database).getRemoteProperties(txn, transportId); oneOf(database).getRemoteProperties(txn, transportId);
will(returnValue(remoteProperties)); will(returnValue(remoteProperties));
@@ -198,11 +209,12 @@ public abstract class DatabaseComponentTest extends TestCase {
assertEquals(Rating.UNRATED, db.getRating(authorId)); assertEquals(Rating.UNRATED, db.getRating(authorId));
db.setRating(authorId, Rating.GOOD); // First time - listeners called db.setRating(authorId, Rating.GOOD); // First time - listeners called
db.setRating(authorId, Rating.GOOD); // Second time - not 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(Collections.singletonList(contactId), db.getContacts());
assertEquals(connectionWindow, assertEquals(connectionWindow,
db.getConnectionWindow(contactId, remoteIndex)); 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)); assertEquals(remoteProperties, db.getRemoteProperties(transportId));
db.subscribe(group); // First time - listeners called db.subscribe(group); // First time - listeners called
db.subscribe(group); // Second time - not called db.subscribe(group); // Second time - not called
@@ -564,7 +576,7 @@ public abstract class DatabaseComponentTest extends TestCase {
} catch(NoSuchContactException expected) {} } catch(NoSuchContactException expected) {}
try { try {
db.getSharedSecret(contactId); db.getSharedSecret(contactId, true);
fail(); fail();
} catch(NoSuchContactException expected) {} } catch(NoSuchContactException expected) {}

View File

@@ -85,7 +85,7 @@ public class H2DatabaseTest extends TestCase {
private final Map<ContactId, TransportProperties> remoteProperties; private final Map<ContactId, TransportProperties> remoteProperties;
private final Collection<Transport> remoteTransports; private final Collection<Transport> remoteTransports;
private final Map<Group, Long> subscriptions; private final Map<Group, Long> subscriptions;
private final byte[] secret; private final byte[] inSecret, outSecret;
public H2DatabaseTest() throws Exception { public H2DatabaseTest() throws Exception {
super(); super();
@@ -122,7 +122,11 @@ public class H2DatabaseTest extends TestCase {
properties); properties);
remoteTransports = Collections.singletonList(remoteTransport); remoteTransports = Collections.singletonList(remoteTransport);
subscriptions = Collections.singletonMap(group, 0L); 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 @Before
@@ -136,7 +140,8 @@ public class H2DatabaseTest extends TestCase {
Database<Connection> db = open(false); Database<Connection> db = open(false);
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
assertFalse(db.containsContact(txn, contactId)); assertFalse(db.containsContact(txn, contactId));
assertEquals(contactId, db.addContact(txn, secret)); assertEquals(contactId,
db.addContact(txn, inSecret, outSecret));
assertTrue(db.containsContact(txn, contactId)); assertTrue(db.containsContact(txn, contactId));
assertFalse(db.containsSubscription(txn, groupId)); assertFalse(db.containsSubscription(txn, groupId));
db.addSubscription(txn, group); db.addSubscription(txn, group);
@@ -192,20 +197,20 @@ public class H2DatabaseTest extends TestCase {
// Create three contacts // Create three contacts
assertFalse(db.containsContact(txn, contactId)); assertFalse(db.containsContact(txn, contactId));
assertEquals(contactId, db.addContact(txn, secret)); assertEquals(contactId, db.addContact(txn, inSecret, outSecret));
assertTrue(db.containsContact(txn, contactId)); assertTrue(db.containsContact(txn, contactId));
assertFalse(db.containsContact(txn, contactId1)); assertFalse(db.containsContact(txn, contactId1));
assertEquals(contactId1, db.addContact(txn, secret)); assertEquals(contactId1, db.addContact(txn, inSecret, outSecret));
assertTrue(db.containsContact(txn, contactId1)); assertTrue(db.containsContact(txn, contactId1));
assertFalse(db.containsContact(txn, contactId2)); assertFalse(db.containsContact(txn, contactId2));
assertEquals(contactId2, db.addContact(txn, secret)); assertEquals(contactId2, db.addContact(txn, inSecret, outSecret));
assertTrue(db.containsContact(txn, contactId2)); assertTrue(db.containsContact(txn, contactId2));
// Delete the contact with the highest ID // Delete the contact with the highest ID
db.removeContact(txn, contactId2); db.removeContact(txn, contactId2);
assertFalse(db.containsContact(txn, contactId2)); assertFalse(db.containsContact(txn, contactId2));
// Add another contact - a new ID should be created // Add another contact - a new ID should be created
assertFalse(db.containsContact(txn, contactId3)); assertFalse(db.containsContact(txn, contactId3));
assertEquals(contactId3, db.addContact(txn, secret)); assertEquals(contactId3, db.addContact(txn, inSecret, outSecret));
assertTrue(db.containsContact(txn, contactId3)); assertTrue(db.containsContact(txn, contactId3));
db.commitTransaction(txn); db.commitTransaction(txn);
@@ -252,7 +257,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and store a private message // 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.addPrivateMessage(txn, privateMessage, contactId);
// Removing the contact should remove the message // Removing the contact should remove the message
@@ -271,7 +276,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and store a private message // 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.addPrivateMessage(txn, privateMessage, contactId);
// The message has no status yet, so it should not be sendable // 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(); Connection txn = db.startTransaction();
// Add a contact and store a private message // 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.addPrivateMessage(txn, privateMessage, contactId);
db.setStatus(txn, contactId, privateMessageId, Status.NEW); db.setStatus(txn, contactId, privateMessageId, Status.NEW);
@@ -338,7 +343,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setVisibility(txn, groupId, Collections.singletonList(contactId));
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
@@ -376,7 +381,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setVisibility(txn, groupId, Collections.singletonList(contactId));
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
@@ -418,7 +423,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setVisibility(txn, groupId, Collections.singletonList(contactId));
db.addGroupMessage(txn, message); db.addGroupMessage(txn, message);
@@ -457,7 +462,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setVisibility(txn, groupId, Collections.singletonList(contactId));
db.addGroupMessage(txn, message); db.addGroupMessage(txn, message);
@@ -492,7 +497,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setVisibility(txn, groupId, Collections.singletonList(contactId));
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
@@ -523,7 +528,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
db.addGroupMessage(txn, message); db.addGroupMessage(txn, message);
@@ -556,7 +561,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and some batches to ack // 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, batchId);
db.addBatchToAck(txn, contactId, batchId1); db.addBatchToAck(txn, contactId, batchId1);
@@ -583,7 +588,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and receive the same batch twice // 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);
db.addBatchToAck(txn, contactId, batchId); db.addBatchToAck(txn, contactId, batchId);
@@ -609,7 +614,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.addGroupMessage(txn, message); db.addGroupMessage(txn, message);
@@ -634,8 +639,8 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add two contacts, subscribe to a group and store a message // Add two contacts, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, secret)); assertEquals(contactId, db.addContact(txn, inSecret, outSecret));
ContactId contactId1 = db.addContact(txn, secret); ContactId contactId1 = db.addContact(txn, inSecret, outSecret);
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.addGroupMessage(txn, message); db.addGroupMessage(txn, message);
@@ -657,7 +662,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setVisibility(txn, groupId, Collections.singletonList(contactId));
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
@@ -696,7 +701,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setVisibility(txn, groupId, Collections.singletonList(contactId));
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
@@ -741,7 +746,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact // Add a contact
assertEquals(contactId, db.addContact(txn, secret)); assertEquals(contactId, db.addContact(txn, inSecret, outSecret));
// Add some outstanding batches, a few ms apart // Add some outstanding batches, a few ms apart
for(int i = 0; i < ids.length; i++) { for(int i = 0; i < ids.length; i++) {
@@ -781,7 +786,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact // Add a contact
assertEquals(contactId, db.addContact(txn, secret)); assertEquals(contactId, db.addContact(txn, inSecret, outSecret));
// Add some outstanding batches, a few ms apart // Add some outstanding batches, a few ms apart
for(int i = 0; i < ids.length; i++) { for(int i = 0; i < ids.length; i++) {
@@ -1001,7 +1006,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact with a transport // 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); db.setTransports(txn, contactId, remoteTransports, 1);
assertEquals(remoteProperties, assertEquals(remoteProperties,
db.getRemoteProperties(txn, transportId)); db.getRemoteProperties(txn, transportId));
@@ -1094,7 +1099,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact with a transport // 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); db.setTransports(txn, contactId, remoteTransports, 1);
assertEquals(remoteProperties, assertEquals(remoteProperties,
db.getRemoteProperties(txn, transportId)); db.getRemoteProperties(txn, transportId));
@@ -1138,7 +1143,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact with some subscriptions // 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); db.setSubscriptions(txn, contactId, subscriptions, 1);
assertEquals(Collections.singletonList(group), assertEquals(Collections.singletonList(group),
db.getSubscriptions(txn, contactId)); db.getSubscriptions(txn, contactId));
@@ -1163,7 +1168,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact with some subscriptions // 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); db.setSubscriptions(txn, contactId, subscriptions, 2);
assertEquals(Collections.singletonList(group), assertEquals(Collections.singletonList(group),
db.getSubscriptions(txn, contactId)); db.getSubscriptions(txn, contactId));
@@ -1187,7 +1192,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and subscribe to a group // 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.addSubscription(txn, group);
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
@@ -1205,7 +1210,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
db.addGroupMessage(txn, message); db.addGroupMessage(txn, message);
@@ -1228,7 +1233,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
db.addGroupMessage(txn, message); db.addGroupMessage(txn, message);
@@ -1251,7 +1256,7 @@ public class H2DatabaseTest extends TestCase {
// Add a contact, subscribe to a group and store a message - // Add a contact, subscribe to a group and store a message -
// the message is older than the contact's subscription // 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.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setVisibility(txn, groupId, Collections.singletonList(contactId));
Map<Group, Long> subs = Collections.singletonMap(group, timestamp + 1); Map<Group, Long> subs = Collections.singletonMap(group, timestamp + 1);
@@ -1275,7 +1280,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setVisibility(txn, groupId, Collections.singletonList(contactId));
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
@@ -1300,7 +1305,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and subscribe to a group // 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.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setVisibility(txn, groupId, Collections.singletonList(contactId));
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
@@ -1319,7 +1324,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact with a subscription // 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); db.setSubscriptions(txn, contactId, subscriptions, 1);
// There's no local subscription for the group // There's no local subscription for the group
@@ -1336,7 +1341,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.addGroupMessage(txn, message); db.addGroupMessage(txn, message);
db.setStatus(txn, contactId, messageId, Status.NEW); db.setStatus(txn, contactId, messageId, Status.NEW);
@@ -1355,7 +1360,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.addGroupMessage(txn, message); db.addGroupMessage(txn, message);
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
@@ -1375,7 +1380,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setVisibility(txn, groupId, Collections.singletonList(contactId));
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
@@ -1397,7 +1402,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // 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.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singletonList(contactId)); db.setVisibility(txn, groupId, Collections.singletonList(contactId));
db.setSubscriptions(txn, contactId, subscriptions, 1); db.setSubscriptions(txn, contactId, subscriptions, 1);
@@ -1418,7 +1423,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and subscribe to a group // 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.addSubscription(txn, group);
// The group should not be visible to the contact // The group should not be visible to the contact
assertEquals(Collections.emptyList(), db.getVisibility(txn, groupId)); assertEquals(Collections.emptyList(), db.getVisibility(txn, groupId));
@@ -1441,7 +1446,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact // Add a contact
assertEquals(contactId, db.addContact(txn, secret)); assertEquals(contactId, db.addContact(txn, inSecret, outSecret));
// Get the connection window for a new index // Get the connection window for a new index
ConnectionWindow w = db.getConnectionWindow(txn, contactId, ConnectionWindow w = db.getConnectionWindow(txn, contactId,
remoteIndex); remoteIndex);
@@ -1460,7 +1465,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact // Add a contact
assertEquals(contactId, db.addContact(txn, secret)); assertEquals(contactId, db.addContact(txn, inSecret, outSecret));
// Get the connection window for a new index // Get the connection window for a new index
ConnectionWindow w = db.getConnectionWindow(txn, contactId, ConnectionWindow w = db.getConnectionWindow(txn, contactId,
remoteIndex); remoteIndex);
@@ -1564,7 +1569,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and subscribe to a group // 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.addSubscription(txn, group);
// A message with a private parent should return null // A message with a private parent should return null
@@ -1613,7 +1618,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact // 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 // The subscription and transport timestamps should be initialised to 0
assertEquals(0L, db.getSubscriptionsModified(txn, contactId)); assertEquals(0L, db.getSubscriptionsModified(txn, contactId));
@@ -1644,7 +1649,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and subscribe to a group // 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.addSubscription(txn, group);
// Store a couple of messages // Store a couple of messages

View File

@@ -4,14 +4,15 @@ import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Random;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import net.sf.briar.api.crypto.ErasableKey;
import junit.framework.TestCase; import junit.framework.TestCase;
import net.sf.briar.TestUtils; import net.sf.briar.TestUtils;
import net.sf.briar.api.ContactId; import net.sf.briar.api.ContactId;
import net.sf.briar.api.crypto.CryptoComponent; 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.db.DatabaseComponent;
import net.sf.briar.api.protocol.Transport; import net.sf.briar.api.protocol.Transport;
import net.sf.briar.api.protocol.TransportId; import net.sf.briar.api.protocol.TransportId;
@@ -31,7 +32,7 @@ public class ConnectionRecogniserImplTest extends TestCase {
private final CryptoComponent crypto; private final CryptoComponent crypto;
private final ContactId contactId; private final ContactId contactId;
private final byte[] secret; private final byte[] inSecret;
private final TransportId transportId; private final TransportId transportId;
private final TransportIndex localIndex, remoteIndex; private final TransportIndex localIndex, remoteIndex;
private final Collection<Transport> transports; private final Collection<Transport> transports;
@@ -42,7 +43,8 @@ public class ConnectionRecogniserImplTest extends TestCase {
Injector i = Guice.createInjector(new CryptoModule()); Injector i = Guice.createInjector(new CryptoModule());
crypto = i.getInstance(CryptoComponent.class); crypto = i.getInstance(CryptoComponent.class);
contactId = new ContactId(1); contactId = new ContactId(1);
secret = new byte[18]; inSecret = new byte[123];
new Random().nextBytes(inSecret);
transportId = new TransportId(TestUtils.getRandomId()); transportId = new TransportId(TestUtils.getRandomId());
localIndex = new TransportIndex(13); localIndex = new TransportIndex(13);
remoteIndex = new TransportIndex(7); remoteIndex = new TransportIndex(7);
@@ -63,8 +65,8 @@ public class ConnectionRecogniserImplTest extends TestCase {
will(returnValue(transports)); will(returnValue(transports));
oneOf(db).getContacts(); oneOf(db).getContacts();
will(returnValue(Collections.singletonList(contactId))); will(returnValue(Collections.singletonList(contactId)));
oneOf(db).getSharedSecret(contactId); oneOf(db).getSharedSecret(contactId, true);
will(returnValue(secret)); will(returnValue(inSecret));
oneOf(db).getRemoteIndex(contactId, transportId); oneOf(db).getRemoteIndex(contactId, transportId);
will(returnValue(remoteIndex)); will(returnValue(remoteIndex));
oneOf(db).getConnectionWindow(contactId, remoteIndex); oneOf(db).getConnectionWindow(contactId, remoteIndex);
@@ -79,7 +81,7 @@ public class ConnectionRecogniserImplTest extends TestCase {
@Test @Test
public void testExpectedIv() throws Exception { public void testExpectedIv() throws Exception {
// Calculate the expected IV for connection number 3 // Calculate the expected IV for connection number 3
ErasableKey ivKey = crypto.deriveIncomingIvKey(secret); ErasableKey ivKey = crypto.deriveIvKey(inSecret, true);
Cipher ivCipher = crypto.getIvCipher(); Cipher ivCipher = crypto.getIvCipher();
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey); ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
byte[] iv = IvEncoder.encodeIv(true, remoteIndex, 3L); byte[] iv = IvEncoder.encodeIv(true, remoteIndex, 3L);
@@ -94,8 +96,8 @@ public class ConnectionRecogniserImplTest extends TestCase {
will(returnValue(transports)); will(returnValue(transports));
oneOf(db).getContacts(); oneOf(db).getContacts();
will(returnValue(Collections.singletonList(contactId))); will(returnValue(Collections.singletonList(contactId)));
oneOf(db).getSharedSecret(contactId); oneOf(db).getSharedSecret(contactId, true);
will(returnValue(secret)); will(returnValue(inSecret));
oneOf(db).getRemoteIndex(contactId, transportId); oneOf(db).getRemoteIndex(contactId, transportId);
will(returnValue(remoteIndex)); will(returnValue(remoteIndex));
oneOf(db).getConnectionWindow(contactId, remoteIndex); oneOf(db).getConnectionWindow(contactId, remoteIndex);
@@ -105,8 +107,8 @@ public class ConnectionRecogniserImplTest extends TestCase {
will(returnValue(connectionWindow)); will(returnValue(connectionWindow));
oneOf(db).setConnectionWindow(contactId, remoteIndex, oneOf(db).setConnectionWindow(contactId, remoteIndex,
connectionWindow); connectionWindow);
oneOf(db).getSharedSecret(contactId); oneOf(db).getSharedSecret(contactId, true);
will(returnValue(secret)); will(returnValue(inSecret));
}}); }});
final ConnectionRecogniserImpl c = final ConnectionRecogniserImpl c =
new ConnectionRecogniserImpl(crypto, db); new ConnectionRecogniserImpl(crypto, db);

View File

@@ -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 static net.sf.briar.api.transport.TransportConstants.MIN_CONNECTION_LENGTH;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.util.Random;
import junit.framework.TestCase; import junit.framework.TestCase;
import net.sf.briar.TestDatabaseModule; import net.sf.briar.TestDatabaseModule;
@@ -26,7 +27,7 @@ import com.google.inject.Injector;
public class ConnectionWriterTest extends TestCase { public class ConnectionWriterTest extends TestCase {
private final ConnectionWriterFactory connectionWriterFactory; private final ConnectionWriterFactory connectionWriterFactory;
private final byte[] secret = new byte[100]; private final byte[] outSecret;
private final TransportIndex transportIndex = new TransportIndex(13); private final TransportIndex transportIndex = new TransportIndex(13);
private final long connection = 12345L; private final long connection = 12345L;
@@ -38,6 +39,8 @@ public class ConnectionWriterTest extends TestCase {
new TestDatabaseModule(), new TransportBatchModule(), new TestDatabaseModule(), new TransportBatchModule(),
new TransportModule(), new TransportStreamModule()); new TransportModule(), new TransportStreamModule());
connectionWriterFactory = i.getInstance(ConnectionWriterFactory.class); connectionWriterFactory = i.getInstance(ConnectionWriterFactory.class);
outSecret = new byte[123];
new Random().nextBytes(outSecret);
} }
@Test @Test
@@ -45,7 +48,7 @@ public class ConnectionWriterTest extends TestCase {
ByteArrayOutputStream out = ByteArrayOutputStream out =
new ByteArrayOutputStream(MIN_CONNECTION_LENGTH); new ByteArrayOutputStream(MIN_CONNECTION_LENGTH);
ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out, 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 // Check that the connection writer thinks there's room for a packet
long capacity = w.getRemainingCapacity(); long capacity = w.getRemainingCapacity();
assertTrue(capacity >= MAX_PACKET_LENGTH); assertTrue(capacity >= MAX_PACKET_LENGTH);

View File

@@ -29,10 +29,10 @@ public class FrameReadWriteTest extends TestCase {
private final CryptoComponent crypto; private final CryptoComponent crypto;
private final Cipher ivCipher, frameCipher; private final Cipher ivCipher, frameCipher;
private final Random random;
private final byte[] outSecret;
private final ErasableKey ivKey, frameKey, macKey; private final ErasableKey ivKey, frameKey, macKey;
private final Mac mac; private final Mac mac;
private final Random random;
private final byte[] secret = new byte[100];
private final TransportIndex transportIndex = new TransportIndex(13); private final TransportIndex transportIndex = new TransportIndex(13);
private final long connection = 12345L; private final long connection = 12345L;
@@ -42,12 +42,14 @@ public class FrameReadWriteTest extends TestCase {
crypto = i.getInstance(CryptoComponent.class); crypto = i.getInstance(CryptoComponent.class);
ivCipher = crypto.getIvCipher(); ivCipher = crypto.getIvCipher();
frameCipher = crypto.getFrameCipher(); frameCipher = crypto.getFrameCipher();
// Since we're sending frames to ourselves, we only need outgoing keys
ivKey = crypto.deriveOutgoingIvKey(secret);
frameKey = crypto.deriveOutgoingFrameKey(secret);
macKey = crypto.deriveOutgoingMacKey(secret);
mac = crypto.getMac();
random = new Random(); random = new Random();
// Since we're sending frames to ourselves, we only need outgoing keys
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();
} }
@Test @Test

View File

@@ -9,6 +9,7 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Random;
import junit.framework.TestCase; import junit.framework.TestCase;
import net.sf.briar.TestDatabaseModule; import net.sf.briar.TestDatabaseModule;
@@ -54,7 +55,7 @@ public class BatchConnectionReadWriteTest extends TestCase {
private final File bobDir = new File(testDir, "bob"); private final File bobDir = new File(testDir, "bob");
private final TransportId transportId; private final TransportId transportId;
private final TransportIndex transportIndex; private final TransportIndex transportIndex;
private final byte[] aliceSecret, bobSecret; private final byte[] aliceToBobSecret, bobToAliceSecret;
private Injector alice, bob; private Injector alice, bob;
@@ -63,9 +64,11 @@ public class BatchConnectionReadWriteTest extends TestCase {
transportId = new TransportId(TestUtils.getRandomId()); transportId = new TransportId(TestUtils.getRandomId());
transportIndex = new TransportIndex(1); transportIndex = new TransportIndex(1);
// Create matching secrets for Alice and Bob // Create matching secrets for Alice and Bob
aliceSecret = new byte[123]; Random r = new Random();
aliceSecret[0] = (byte) 1; aliceToBobSecret = new byte[123];
bobSecret = new byte[123]; r.nextBytes(aliceToBobSecret);
bobToAliceSecret = new byte[123];
r.nextBytes(bobToAliceSecret);
} }
@Before @Before
@@ -102,7 +105,7 @@ public class BatchConnectionReadWriteTest extends TestCase {
DatabaseComponent db = alice.getInstance(DatabaseComponent.class); DatabaseComponent db = alice.getInstance(DatabaseComponent.class);
db.open(false); db.open(false);
// Add Bob as a contact and send him a message // Add Bob as a contact and send him a message
ContactId contactId = db.addContact(aliceSecret); ContactId contactId = db.addContact(bobToAliceSecret, aliceToBobSecret);
String subject = "Hello"; String subject = "Hello";
byte[] messageBody = "Hi Bob!".getBytes("UTF-8"); byte[] messageBody = "Hi Bob!".getBytes("UTF-8");
MessageEncoder encoder = alice.getInstance(MessageEncoder.class); MessageEncoder encoder = alice.getInstance(MessageEncoder.class);
@@ -134,7 +137,7 @@ public class BatchConnectionReadWriteTest extends TestCase {
MessageListener listener = new MessageListener(); MessageListener listener = new MessageListener();
db.addListener(listener); db.addListener(listener);
// Add Alice as a contact // Add Alice as a contact
ContactId contactId = db.addContact(bobSecret); ContactId contactId = db.addContact(aliceToBobSecret, bobToAliceSecret);
// Add the transport // Add the transport
assertEquals(transportIndex, db.addTransport(transportId)); assertEquals(transportIndex, db.addTransport(transportId));
// Fake a transport update from Alice // Fake a transport update from Alice