mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 13:49:53 +01:00
Fixed key derivation issues, moved tag encoding into crypto component.
This commit is contained in:
@@ -53,6 +53,10 @@ public interface CryptoComponent {
|
|||||||
*/
|
*/
|
||||||
byte[] deriveNextSecret(byte[] secret, long period);
|
byte[] deriveNextSecret(byte[] secret, long period);
|
||||||
|
|
||||||
|
/** Encodes the pseudo-random tag that is used to recognise a connection. */
|
||||||
|
void encodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey,
|
||||||
|
long connection);
|
||||||
|
|
||||||
KeyPair generateAgreementKeyPair();
|
KeyPair generateAgreementKeyPair();
|
||||||
|
|
||||||
KeyPair generateSignatureKeyPair();
|
KeyPair generateSignatureKeyPair();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ public class TemporarySecret extends ContactTransport {
|
|||||||
private final long period, outgoing, centre;
|
private final long period, outgoing, centre;
|
||||||
private final byte[] secret, bitmap;
|
private final byte[] secret, bitmap;
|
||||||
|
|
||||||
|
/** Creates a temporary secret with the given connection window. */
|
||||||
public TemporarySecret(ContactId contactId, TransportId transportId,
|
public TemporarySecret(ContactId contactId, TransportId transportId,
|
||||||
long epoch, long clockDiff, long latency, boolean alice,
|
long epoch, long clockDiff, long latency, boolean alice,
|
||||||
long period, byte[] secret, long outgoing, long centre,
|
long period, byte[] secret, long outgoing, long centre,
|
||||||
@@ -21,14 +22,19 @@ public class TemporarySecret extends ContactTransport {
|
|||||||
this.bitmap = bitmap;
|
this.bitmap = bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Creates a temporary secret with a new connection window. */
|
||||||
|
public TemporarySecret(ContactId contactId, TransportId transportId,
|
||||||
|
long epoch, long clockDiff, long latency, boolean alice,
|
||||||
|
long period, byte[] secret) {
|
||||||
|
this(contactId, transportId, epoch, clockDiff, latency, alice, period,
|
||||||
|
secret, 0L, 0L, new byte[CONNECTION_WINDOW_SIZE / 8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a temporary secret derived from the given temporary secret. */
|
||||||
public TemporarySecret(TemporarySecret old, long period, byte[] secret) {
|
public TemporarySecret(TemporarySecret old, long period, byte[] secret) {
|
||||||
super(old.getContactId(), old.getTransportId(), old.getEpoch(),
|
this(old.getContactId(), old.getTransportId(), old.getEpoch(),
|
||||||
old.getClockDifference(), old.getLatency(), old.getAlice());
|
old.getClockDifference(), old.getLatency(), old.getAlice(),
|
||||||
this.period = period;
|
period, secret);
|
||||||
this.secret = secret;
|
|
||||||
outgoing = 0L;
|
|
||||||
centre = 0L;
|
|
||||||
bitmap = new byte[CONNECTION_WINDOW_SIZE / 8];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getPeriod() {
|
public long getPeriod() {
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ public interface ConnectionReaderFactory {
|
|||||||
* Creates a connection reader for one side of a connection.
|
* Creates a connection reader for one side of a connection.
|
||||||
*/
|
*/
|
||||||
ConnectionReader createConnectionReader(InputStream in,
|
ConnectionReader createConnectionReader(InputStream in,
|
||||||
ConnectionContext ctx, boolean initiator);
|
ConnectionContext ctx, boolean incoming, boolean initiator);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ public interface ConnectionWriterFactory {
|
|||||||
* Creates a connection writer for one side of a connection.
|
* Creates a connection writer for one side of a connection.
|
||||||
*/
|
*/
|
||||||
ConnectionWriter createConnectionWriter(OutputStream out, long capacity,
|
ConnectionWriter createConnectionWriter(OutputStream out, long capacity,
|
||||||
ConnectionContext ctx, boolean initiator);
|
ConnectionContext ctx, boolean incoming, boolean initiator);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package net.sf.briar.crypto;
|
package net.sf.briar.crypto;
|
||||||
|
|
||||||
|
import static javax.crypto.Cipher.ENCRYPT_MODE;
|
||||||
import static net.sf.briar.api.plugins.InvitationConstants.CODE_BITS;
|
import static net.sf.briar.api.plugins.InvitationConstants.CODE_BITS;
|
||||||
|
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
@@ -210,6 +212,23 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
return counterModeKdf(secret, ROTATE, period);
|
return counterModeKdf(secret, ROTATE, period);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void encodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey,
|
||||||
|
long connection) {
|
||||||
|
if(tag.length < TAG_LENGTH) throw new IllegalArgumentException();
|
||||||
|
if(connection < 0 || connection > MAX_32_BIT_UNSIGNED)
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
for(int i = 0; i < TAG_LENGTH; i++) tag[i] = 0;
|
||||||
|
ByteUtils.writeUint32(connection, tag, 0);
|
||||||
|
try {
|
||||||
|
tagCipher.init(ENCRYPT_MODE, tagKey);
|
||||||
|
int encrypted = tagCipher.doFinal(tag, 0, TAG_LENGTH, tag);
|
||||||
|
if(encrypted != TAG_LENGTH) throw new IllegalArgumentException();
|
||||||
|
} catch(GeneralSecurityException e) {
|
||||||
|
// Unsuitable cipher or key
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int generateInvitationCode() {
|
public int generateInvitationCode() {
|
||||||
int codeBytes = (int) Math.ceil(CODE_BITS / 8.0);
|
int codeBytes = (int) Math.ceil(CODE_BITS / 8.0);
|
||||||
byte[] random = new byte[codeBytes];
|
byte[] random = new byte[codeBytes];
|
||||||
|
|||||||
@@ -34,12 +34,12 @@ class IncomingDuplexConnection extends DuplexConnection {
|
|||||||
@Override
|
@Override
|
||||||
protected ConnectionReader createConnectionReader() throws IOException {
|
protected ConnectionReader createConnectionReader() throws IOException {
|
||||||
return connReaderFactory.createConnectionReader(
|
return connReaderFactory.createConnectionReader(
|
||||||
transport.getInputStream(), ctx, true);
|
transport.getInputStream(), ctx, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ConnectionWriter createConnectionWriter() throws IOException {
|
protected ConnectionWriter createConnectionWriter() throws IOException {
|
||||||
return connWriterFactory.createConnectionWriter(
|
return connWriterFactory.createConnectionWriter(
|
||||||
transport.getOutputStream(), Long.MAX_VALUE, ctx, false);
|
transport.getOutputStream(), Long.MAX_VALUE, ctx, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,12 +34,12 @@ class OutgoingDuplexConnection extends DuplexConnection {
|
|||||||
@Override
|
@Override
|
||||||
protected ConnectionReader createConnectionReader() throws IOException {
|
protected ConnectionReader createConnectionReader() throws IOException {
|
||||||
return connReaderFactory.createConnectionReader(
|
return connReaderFactory.createConnectionReader(
|
||||||
transport.getInputStream(), ctx, false);
|
transport.getInputStream(), ctx, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ConnectionWriter createConnectionWriter() throws IOException {
|
protected ConnectionWriter createConnectionWriter() throws IOException {
|
||||||
return connWriterFactory.createConnectionWriter(
|
return connWriterFactory.createConnectionWriter(
|
||||||
transport.getOutputStream(), Long.MAX_VALUE, ctx, true);
|
transport.getOutputStream(), Long.MAX_VALUE, ctx, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class IncomingSimplexConnection {
|
|||||||
connRegistry.registerConnection(contactId, transportId);
|
connRegistry.registerConnection(contactId, transportId);
|
||||||
try {
|
try {
|
||||||
ConnectionReader conn = connFactory.createConnectionReader(
|
ConnectionReader conn = connFactory.createConnectionReader(
|
||||||
transport.getInputStream(), ctx, true);
|
transport.getInputStream(), ctx, true, true);
|
||||||
InputStream in = conn.getInputStream();
|
InputStream in = conn.getInputStream();
|
||||||
ProtocolReader reader = protoFactory.createProtocolReader(in);
|
ProtocolReader reader = protoFactory.createProtocolReader(in);
|
||||||
// Read packets until EOF
|
// Read packets until EOF
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class OutgoingSimplexConnection {
|
|||||||
try {
|
try {
|
||||||
ConnectionWriter conn = connFactory.createConnectionWriter(
|
ConnectionWriter conn = connFactory.createConnectionWriter(
|
||||||
transport.getOutputStream(), transport.getCapacity(),
|
transport.getOutputStream(), transport.getCapacity(),
|
||||||
ctx, true);
|
ctx, false, true);
|
||||||
OutputStream out = conn.getOutputStream();
|
OutputStream out = conn.getOutputStream();
|
||||||
ProtocolWriter writer = protoFactory.createProtocolWriter(out,
|
ProtocolWriter writer = protoFactory.createProtocolWriter(out,
|
||||||
transport.shouldFlush());
|
transport.shouldFlush());
|
||||||
|
|||||||
@@ -22,12 +22,13 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ConnectionReader createConnectionReader(InputStream in,
|
public ConnectionReader createConnectionReader(InputStream in,
|
||||||
ConnectionContext ctx, boolean initiator) {
|
ConnectionContext ctx, boolean incoming, boolean initiator) {
|
||||||
byte[] secret = ctx.getSecret();
|
byte[] secret = ctx.getSecret();
|
||||||
long connection = ctx.getConnectionNumber();
|
long connection = ctx.getConnectionNumber();
|
||||||
boolean alice = ctx.getAlice();
|
boolean weAreAlice = ctx.getAlice();
|
||||||
ErasableKey frameKey = crypto.deriveFrameKey(secret, connection, alice,
|
boolean initiatorIsAlice = incoming ? !weAreAlice : weAreAlice;
|
||||||
initiator);
|
ErasableKey frameKey = crypto.deriveFrameKey(secret, connection,
|
||||||
|
initiatorIsAlice, initiator);
|
||||||
FrameReader encryption = new IncomingEncryptionLayer(in,
|
FrameReader encryption = new IncomingEncryptionLayer(in,
|
||||||
crypto.getFrameCipher(), frameKey, MAX_FRAME_LENGTH);
|
crypto.getFrameCipher(), frameKey, MAX_FRAME_LENGTH);
|
||||||
return new ConnectionReaderImpl(encryption, MAX_FRAME_LENGTH);
|
return new ConnectionReaderImpl(encryption, MAX_FRAME_LENGTH);
|
||||||
|
|||||||
@@ -26,18 +26,20 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ConnectionWriter createConnectionWriter(OutputStream out,
|
public ConnectionWriter createConnectionWriter(OutputStream out,
|
||||||
long capacity, ConnectionContext ctx, boolean initiator) {
|
long capacity, ConnectionContext ctx, boolean incoming,
|
||||||
|
boolean initiator) {
|
||||||
byte[] secret = ctx.getSecret();
|
byte[] secret = ctx.getSecret();
|
||||||
long connection = ctx.getConnectionNumber();
|
long connection = ctx.getConnectionNumber();
|
||||||
boolean alice = ctx.getAlice();
|
boolean weAreAlice = ctx.getAlice();
|
||||||
ErasableKey frameKey = crypto.deriveFrameKey(secret, connection, alice,
|
boolean initiatorIsAlice = incoming ? !weAreAlice : weAreAlice;
|
||||||
initiator);
|
ErasableKey frameKey = crypto.deriveFrameKey(secret, connection,
|
||||||
|
initiatorIsAlice, initiator);
|
||||||
FrameWriter encryption;
|
FrameWriter encryption;
|
||||||
if(initiator) {
|
if(initiator) {
|
||||||
byte[] tag = new byte[TAG_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
Cipher tagCipher = crypto.getTagCipher();
|
Cipher tagCipher = crypto.getTagCipher();
|
||||||
ErasableKey tagKey = crypto.deriveTagKey(secret, alice);
|
ErasableKey tagKey = crypto.deriveTagKey(secret, initiatorIsAlice);
|
||||||
TagEncoder.encodeTag(tag, tagCipher, tagKey, connection);
|
crypto.encodeTag(tag, tagCipher, tagKey, connection);
|
||||||
encryption = new OutgoingEncryptionLayer(out, capacity,
|
encryption = new OutgoingEncryptionLayer(out, capacity,
|
||||||
crypto.getFrameCipher(), frameKey, MAX_FRAME_LENGTH, tag);
|
crypto.getFrameCipher(), frameKey, MAX_FRAME_LENGTH, tag);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
package net.sf.briar.transport;
|
|
||||||
|
|
||||||
import static javax.crypto.Cipher.ENCRYPT_MODE;
|
|
||||||
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
|
||||||
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
|
||||||
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
|
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
|
||||||
import net.sf.briar.util.ByteUtils;
|
|
||||||
|
|
||||||
class TagEncoder {
|
|
||||||
|
|
||||||
static void encodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey,
|
|
||||||
long connection) {
|
|
||||||
if(tag.length < TAG_LENGTH) throw new IllegalArgumentException();
|
|
||||||
if(connection < 0 || connection > MAX_32_BIT_UNSIGNED)
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
for(int i = 0; i < TAG_LENGTH; i++) tag[i] = 0;
|
|
||||||
ByteUtils.writeUint32(connection, tag, 0);
|
|
||||||
try {
|
|
||||||
tagCipher.init(ENCRYPT_MODE, tagKey);
|
|
||||||
int encrypted = tagCipher.doFinal(tag, 0, TAG_LENGTH, tag);
|
|
||||||
if(encrypted != TAG_LENGTH) throw new IllegalArgumentException();
|
|
||||||
} catch(GeneralSecurityException e) {
|
|
||||||
// Unsuitable cipher or key
|
|
||||||
throw new IllegalArgumentException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -51,10 +51,10 @@ class TransportConnectionRecogniser {
|
|||||||
boolean alice = ctx.getAlice();
|
boolean alice = ctx.getAlice();
|
||||||
// Update the connection window and the expected tags
|
// Update the connection window and the expected tags
|
||||||
Cipher cipher = crypto.getTagCipher();
|
Cipher cipher = crypto.getTagCipher();
|
||||||
ErasableKey key = crypto.deriveTagKey(secret, alice);
|
ErasableKey key = crypto.deriveTagKey(secret, !alice);
|
||||||
for(long connection1 : window.setSeen(connection)) {
|
for(long connection1 : window.setSeen(connection)) {
|
||||||
byte[] tag1 = new byte[TAG_LENGTH];
|
byte[] tag1 = new byte[TAG_LENGTH];
|
||||||
TagEncoder.encodeTag(tag1, cipher, key, connection1);
|
crypto.encodeTag(tag1, cipher, key, connection1);
|
||||||
if(connection1 <= connection) {
|
if(connection1 <= connection) {
|
||||||
WindowContext old = tagMap.remove(new Bytes(tag1));
|
WindowContext old = tagMap.remove(new Bytes(tag1));
|
||||||
assert old != null;
|
assert old != null;
|
||||||
@@ -84,11 +84,11 @@ class TransportConnectionRecogniser {
|
|||||||
byte[] bitmap = s.getWindowBitmap();
|
byte[] bitmap = s.getWindowBitmap();
|
||||||
// Create the connection window and the expected tags
|
// Create the connection window and the expected tags
|
||||||
Cipher cipher = crypto.getTagCipher();
|
Cipher cipher = crypto.getTagCipher();
|
||||||
ErasableKey key = crypto.deriveTagKey(secret, alice);
|
ErasableKey key = crypto.deriveTagKey(secret, !alice);
|
||||||
ConnectionWindow window = new ConnectionWindow(centre, bitmap);
|
ConnectionWindow window = new ConnectionWindow(centre, bitmap);
|
||||||
for(long connection : window.getUnseen()) {
|
for(long connection : window.getUnseen()) {
|
||||||
byte[] tag = new byte[TAG_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
TagEncoder.encodeTag(tag, cipher, key, connection);
|
crypto.encodeTag(tag, cipher, key, connection);
|
||||||
ConnectionContext ctx = new ConnectionContext(contactId,
|
ConnectionContext ctx = new ConnectionContext(contactId,
|
||||||
transportId, secret.clone(), connection, alice);
|
transportId, secret.clone(), connection, alice);
|
||||||
WindowContext wctx = new WindowContext(window, ctx, period);
|
WindowContext wctx = new WindowContext(window, ctx, period);
|
||||||
@@ -113,10 +113,10 @@ class TransportConnectionRecogniser {
|
|||||||
private void removeSecret(RemovalContext rctx) {
|
private void removeSecret(RemovalContext rctx) {
|
||||||
// Remove the expected tags
|
// Remove the expected tags
|
||||||
Cipher cipher = crypto.getTagCipher();
|
Cipher cipher = crypto.getTagCipher();
|
||||||
ErasableKey key = crypto.deriveTagKey(rctx.secret, rctx.alice);
|
ErasableKey key = crypto.deriveTagKey(rctx.secret, !rctx.alice);
|
||||||
byte[] tag = new byte[TAG_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
for(long connection : rctx.window.getUnseen()) {
|
for(long connection : rctx.window.getUnseen()) {
|
||||||
TagEncoder.encodeTag(tag, cipher, key, connection);
|
crypto.encodeTag(tag, cipher, key, connection);
|
||||||
WindowContext old = tagMap.remove(new Bytes(tag));
|
WindowContext old = tagMap.remove(new Bytes(tag));
|
||||||
assert old != null;
|
assert old != null;
|
||||||
ByteUtils.erase(old.context.getSecret());
|
ByteUtils.erase(old.context.getSecret());
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ public class ProtocolIntegrationTest extends BriarTestCase {
|
|||||||
ConnectionContext ctx = new ConnectionContext(contactId, transportId,
|
ConnectionContext ctx = new ConnectionContext(contactId, transportId,
|
||||||
secret.clone(), 0L, true);
|
secret.clone(), 0L, true);
|
||||||
ConnectionWriter conn = connectionWriterFactory.createConnectionWriter(
|
ConnectionWriter conn = connectionWriterFactory.createConnectionWriter(
|
||||||
out, Long.MAX_VALUE, ctx, true);
|
out, Long.MAX_VALUE, ctx, false, true);
|
||||||
OutputStream out1 = conn.getOutputStream();
|
OutputStream out1 = conn.getOutputStream();
|
||||||
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out1,
|
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out1,
|
||||||
false);
|
false);
|
||||||
@@ -191,9 +191,9 @@ public class ProtocolIntegrationTest extends BriarTestCase {
|
|||||||
assertEquals(TAG_LENGTH, in.read(tag, 0, TAG_LENGTH));
|
assertEquals(TAG_LENGTH, in.read(tag, 0, TAG_LENGTH));
|
||||||
// FIXME: Check that the expected tag was received
|
// FIXME: Check that the expected tag was received
|
||||||
ConnectionContext ctx = new ConnectionContext(contactId, transportId,
|
ConnectionContext ctx = new ConnectionContext(contactId, transportId,
|
||||||
secret.clone(), 0L, true);
|
secret.clone(), 0L, false);
|
||||||
ConnectionReader conn = connectionReaderFactory.createConnectionReader(
|
ConnectionReader conn = connectionReaderFactory.createConnectionReader(
|
||||||
in, ctx, true);
|
in, ctx, true, true);
|
||||||
InputStream in1 = conn.getInputStream();
|
InputStream in1 = conn.getInputStream();
|
||||||
ProtocolReader reader = protocolReaderFactory.createProtocolReader(in1);
|
ProtocolReader reader = protocolReaderFactory.createProtocolReader(in1);
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ import net.sf.briar.BriarTestCase;
|
|||||||
import net.sf.briar.TestDatabaseModule;
|
import net.sf.briar.TestDatabaseModule;
|
||||||
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.KeyManager;
|
||||||
import net.sf.briar.api.db.DatabaseComponent;
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
|
import net.sf.briar.api.db.TemporarySecret;
|
||||||
import net.sf.briar.api.db.event.DatabaseEvent;
|
import net.sf.briar.api.db.event.DatabaseEvent;
|
||||||
import net.sf.briar.api.db.event.DatabaseListener;
|
import net.sf.briar.api.db.event.DatabaseListener;
|
||||||
import net.sf.briar.api.db.event.MessagesAddedEvent;
|
import net.sf.briar.api.db.event.MessagesAddedEvent;
|
||||||
@@ -48,11 +50,15 @@ import com.google.inject.Injector;
|
|||||||
|
|
||||||
public class SimplexProtocolIntegrationTest extends BriarTestCase {
|
public class SimplexProtocolIntegrationTest extends BriarTestCase {
|
||||||
|
|
||||||
|
private static final long CLOCK_DIFFERENCE = 60 * 1000L;
|
||||||
|
private static final long LATENCY = 60 * 1000L;
|
||||||
|
|
||||||
private final File testDir = TestUtils.getTestDirectory();
|
private final File testDir = TestUtils.getTestDirectory();
|
||||||
private final File aliceDir = new File(testDir, "alice");
|
private final File aliceDir = new File(testDir, "alice");
|
||||||
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 byte[] aliceToBobSecret, bobToAliceSecret;
|
private final byte[] secret;
|
||||||
|
private final long epoch;
|
||||||
|
|
||||||
private Injector alice, bob;
|
private Injector alice, bob;
|
||||||
|
|
||||||
@@ -60,11 +66,10 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase {
|
|||||||
super();
|
super();
|
||||||
transportId = new TransportId(TestUtils.getRandomId());
|
transportId = new TransportId(TestUtils.getRandomId());
|
||||||
// Create matching secrets for Alice and Bob
|
// Create matching secrets for Alice and Bob
|
||||||
Random r = new Random();
|
secret = new byte[32];
|
||||||
aliceToBobSecret = new byte[32];
|
new Random().nextBytes(secret);
|
||||||
r.nextBytes(aliceToBobSecret);
|
long rotationPeriod = 2 * CLOCK_DIFFERENCE + LATENCY;
|
||||||
bobToAliceSecret = new byte[32];
|
epoch = System.currentTimeMillis() - 2 * rotationPeriod;
|
||||||
r.nextBytes(bobToAliceSecret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -98,14 +103,22 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase {
|
|||||||
// Open Alice's database
|
// Open Alice's database
|
||||||
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
|
||||||
ContactId contactId = db.addContact();
|
ContactId contactId = db.addContact();
|
||||||
|
TemporarySecret s = new TemporarySecret(contactId, transportId, epoch,
|
||||||
|
CLOCK_DIFFERENCE, LATENCY, true, 0L, secret);
|
||||||
|
db.addContactTransport(s);
|
||||||
|
db.addSecrets(Collections.singletonList(s));
|
||||||
|
// Start Alice's key manager
|
||||||
|
KeyManager km = alice.getInstance(KeyManager.class);
|
||||||
|
km.start();
|
||||||
|
// Send Bob a message
|
||||||
String subject = "Hello";
|
String subject = "Hello";
|
||||||
byte[] body = "Hi Bob!".getBytes("UTF-8");
|
byte[] body = "Hi Bob!".getBytes("UTF-8");
|
||||||
MessageFactory messageFactory = alice.getInstance(MessageFactory.class);
|
MessageFactory messageFactory = alice.getInstance(MessageFactory.class);
|
||||||
Message message = messageFactory.createMessage(null, subject, body);
|
Message message = messageFactory.createMessage(null, subject, body);
|
||||||
db.addLocalPrivateMessage(message, contactId);
|
db.addLocalPrivateMessage(message, contactId);
|
||||||
// Create an outgoing batch connection
|
// Create an outgoing simplex connection
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
ConnectionRegistry connRegistry =
|
ConnectionRegistry connRegistry =
|
||||||
alice.getInstance(ConnectionRegistry.class);
|
alice.getInstance(ConnectionRegistry.class);
|
||||||
@@ -115,17 +128,18 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase {
|
|||||||
alice.getInstance(ProtocolWriterFactory.class);
|
alice.getInstance(ProtocolWriterFactory.class);
|
||||||
TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
|
TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
|
||||||
out, Long.MAX_VALUE, false);
|
out, Long.MAX_VALUE, false);
|
||||||
ConnectionContext ctx = new ConnectionContext(contactId, transportId,
|
ConnectionContext ctx = km.getConnectionContext(contactId, transportId);
|
||||||
aliceToBobSecret, 0L, true);
|
assertNotNull(ctx);
|
||||||
OutgoingSimplexConnection simplex = new OutgoingSimplexConnection(db,
|
OutgoingSimplexConnection simplex = new OutgoingSimplexConnection(db,
|
||||||
connRegistry, connFactory, protoFactory, ctx, transport);
|
connRegistry, connFactory, protoFactory, ctx, transport);
|
||||||
// Write whatever needs to be written
|
// Write whatever needs to be written
|
||||||
simplex.write();
|
simplex.write();
|
||||||
assertTrue(transport.getDisposed());
|
assertTrue(transport.getDisposed());
|
||||||
assertFalse(transport.getException());
|
assertFalse(transport.getException());
|
||||||
// Close Alice's database
|
// Clean up
|
||||||
|
km.stop();
|
||||||
db.close();
|
db.close();
|
||||||
// Return the contents of the batch connection
|
// Return the contents of the simplex connection
|
||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,6 +152,13 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase {
|
|||||||
db.addListener(listener);
|
db.addListener(listener);
|
||||||
// Add Alice as a contact
|
// Add Alice as a contact
|
||||||
ContactId contactId = db.addContact();
|
ContactId contactId = db.addContact();
|
||||||
|
TemporarySecret s = new TemporarySecret(contactId, transportId, epoch,
|
||||||
|
CLOCK_DIFFERENCE, LATENCY, false, 0L, secret);
|
||||||
|
db.addContactTransport(s);
|
||||||
|
db.addSecrets(Collections.singletonList(s));
|
||||||
|
// Start Bob's key manager
|
||||||
|
KeyManager km = bob.getInstance(KeyManager.class);
|
||||||
|
km.start();
|
||||||
// Fake a transport update from Alice
|
// Fake a transport update from Alice
|
||||||
TransportUpdate transportUpdate = new TransportUpdate() {
|
TransportUpdate transportUpdate = new TransportUpdate() {
|
||||||
|
|
||||||
@@ -159,7 +180,6 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase {
|
|||||||
assertEquals(tag.length, read);
|
assertEquals(tag.length, read);
|
||||||
ConnectionContext ctx = rec.acceptConnection(transportId, tag);
|
ConnectionContext ctx = rec.acceptConnection(transportId, tag);
|
||||||
assertNotNull(ctx);
|
assertNotNull(ctx);
|
||||||
assertEquals(contactId, ctx.getContactId());
|
|
||||||
// Create an incoming simplex connection
|
// Create an incoming simplex connection
|
||||||
ConnectionRegistry connRegistry =
|
ConnectionRegistry connRegistry =
|
||||||
bob.getInstance(ConnectionRegistry.class);
|
bob.getInstance(ConnectionRegistry.class);
|
||||||
@@ -181,7 +201,8 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase {
|
|||||||
assertTrue(transport.getRecognised());
|
assertTrue(transport.getRecognised());
|
||||||
// The private message from Alice should have been added
|
// The private message from Alice should have been added
|
||||||
assertTrue(listener.messagesAdded);
|
assertTrue(listener.messagesAdded);
|
||||||
// Close Bob's database
|
// Clean up
|
||||||
|
km.stop();
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ public class TransportIntegrationTest extends BriarTestCase {
|
|||||||
ConnectionContext ctx = new ConnectionContext(contactId, transportId,
|
ConnectionContext ctx = new ConnectionContext(contactId, transportId,
|
||||||
secret, 0L, true);
|
secret, 0L, true);
|
||||||
ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out,
|
ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out,
|
||||||
MIN_CONNECTION_LENGTH, ctx, true);
|
MIN_CONNECTION_LENGTH, ctx, false, true);
|
||||||
// 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);
|
||||||
@@ -157,7 +157,7 @@ public class TransportIntegrationTest extends BriarTestCase {
|
|||||||
ConnectionContext ctx = new ConnectionContext(contactId, transportId,
|
ConnectionContext ctx = new ConnectionContext(contactId, transportId,
|
||||||
secret, 0L, true);
|
secret, 0L, true);
|
||||||
ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out,
|
ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out,
|
||||||
MIN_CONNECTION_LENGTH, ctx, false);
|
MIN_CONNECTION_LENGTH, ctx, false, false);
|
||||||
// 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);
|
||||||
|
|||||||
Reference in New Issue
Block a user