mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 21:59:54 +01:00
Massive refactoring to merge handling of simplex and duplex connections.
This commit is contained in:
@@ -25,8 +25,6 @@ public class OutgoingEncryptionLayerTest extends BriarTestCase {
|
||||
// FIXME: This is an integration test, not a unit test
|
||||
|
||||
private static final int FRAME_LENGTH = 1024;
|
||||
private static final int MAX_PAYLOAD_LENGTH =
|
||||
FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH;
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
private final AuthenticatedCipher frameCipher;
|
||||
@@ -56,7 +54,7 @@ public class OutgoingEncryptionLayerTest extends BriarTestCase {
|
||||
// Check that the actual tag and ciphertext match what's expected
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out,
|
||||
10 * FRAME_LENGTH, frameCipher, frameKey, FRAME_LENGTH, tag);
|
||||
frameCipher, frameKey, FRAME_LENGTH, tag);
|
||||
o.writeFrame(new byte[FRAME_LENGTH - MAC_LENGTH], payloadLength, false);
|
||||
byte[] actual = out.toByteArray();
|
||||
assertEquals(TAG_LENGTH + FRAME_LENGTH, actual.length);
|
||||
@@ -67,93 +65,14 @@ public class OutgoingEncryptionLayerTest extends BriarTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitiatorClosesConnectionWithoutWriting() throws Exception {
|
||||
public void testCloseConnectionWithoutWriting() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
// Initiator's constructor
|
||||
OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out,
|
||||
10 * FRAME_LENGTH, frameCipher, crypto.generateSecretKey(),
|
||||
FRAME_LENGTH, tag);
|
||||
frameCipher, crypto.generateSecretKey(), FRAME_LENGTH, tag);
|
||||
// Write an empty final frame without having written any other frames
|
||||
o.writeFrame(new byte[FRAME_LENGTH - MAC_LENGTH], 0, true);
|
||||
// The tag and the empty frame should be written to the output stream
|
||||
assertEquals(TAG_LENGTH + HEADER_LENGTH + MAC_LENGTH, out.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponderClosesConnectionWithoutWriting() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
// Responder's constructor
|
||||
OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out,
|
||||
10 * FRAME_LENGTH, frameCipher, crypto.generateSecretKey(),
|
||||
FRAME_LENGTH);
|
||||
// Write an empty final frame without having written any other frames
|
||||
o.writeFrame(new byte[FRAME_LENGTH - MAC_LENGTH], 0, true);
|
||||
// An empty final frame should be written to the output stream
|
||||
assertEquals(HEADER_LENGTH + MAC_LENGTH, out.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemainingCapacityWithTag() throws Exception {
|
||||
int MAX_PAYLOAD_LENGTH = FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
// Initiator's constructor
|
||||
OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out,
|
||||
10 * FRAME_LENGTH, frameCipher, crypto.generateSecretKey(),
|
||||
FRAME_LENGTH, tag);
|
||||
// There should be space for nine full frames and one partial frame
|
||||
byte[] frame = new byte[FRAME_LENGTH - MAC_LENGTH];
|
||||
assertEquals(10 * MAX_PAYLOAD_LENGTH - TAG_LENGTH,
|
||||
o.getRemainingCapacity());
|
||||
// Write nine frames, each containing a partial payload
|
||||
for(int i = 0; i < 9; i++) {
|
||||
o.writeFrame(frame, 123, false);
|
||||
assertEquals((9 - i) * MAX_PAYLOAD_LENGTH - TAG_LENGTH,
|
||||
o.getRemainingCapacity());
|
||||
}
|
||||
// Write the final frame, which will not be padded
|
||||
o.writeFrame(frame, 123, true);
|
||||
int finalFrameLength = HEADER_LENGTH + 123 + MAC_LENGTH;
|
||||
assertEquals(MAX_PAYLOAD_LENGTH - TAG_LENGTH - finalFrameLength,
|
||||
o.getRemainingCapacity());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemainingCapacityWithoutTag() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
// Responder's constructor
|
||||
OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out,
|
||||
10 * FRAME_LENGTH, frameCipher, crypto.generateSecretKey(),
|
||||
FRAME_LENGTH);
|
||||
// There should be space for ten full frames
|
||||
assertEquals(10 * MAX_PAYLOAD_LENGTH, o.getRemainingCapacity());
|
||||
// Write nine frames, each containing a partial payload
|
||||
byte[] frame = new byte[FRAME_LENGTH - MAC_LENGTH];
|
||||
for(int i = 0; i < 9; i++) {
|
||||
o.writeFrame(frame, 123, false);
|
||||
assertEquals((9 - i) * MAX_PAYLOAD_LENGTH,
|
||||
o.getRemainingCapacity());
|
||||
}
|
||||
// Write the final frame, which will not be padded
|
||||
o.writeFrame(frame, 123, true);
|
||||
int finalFrameLength = HEADER_LENGTH + 123 + MAC_LENGTH;
|
||||
assertEquals(MAX_PAYLOAD_LENGTH - finalFrameLength,
|
||||
o.getRemainingCapacity());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemainingCapacityLimitedByFrameNumbers() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
// The connection has plenty of space so we're limited by frame numbers
|
||||
OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out,
|
||||
Long.MAX_VALUE, frameCipher, crypto.generateSecretKey(),
|
||||
FRAME_LENGTH);
|
||||
// There should be enough frame numbers for 2^32 frames
|
||||
assertEquals((1L << 32) * MAX_PAYLOAD_LENGTH, o.getRemainingCapacity());
|
||||
// Write a frame containing a partial payload
|
||||
byte[] frame = new byte[FRAME_LENGTH - MAC_LENGTH];
|
||||
o.writeFrame(frame, 123, false);
|
||||
// There should be enough frame numbers for 2^32 - 1 frames
|
||||
assertEquals(((1L << 32) - 1) * MAX_PAYLOAD_LENGTH,
|
||||
o.getRemainingCapacity());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package org.briarproject.transport;
|
||||
|
||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.MIN_STREAM_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Random;
|
||||
@@ -14,13 +13,9 @@ import java.util.Random;
|
||||
import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.TestLifecycleModule;
|
||||
import org.briarproject.TestSystemModule;
|
||||
import org.briarproject.api.ContactId;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.crypto.AuthenticatedCipher;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
import org.briarproject.api.transport.StreamContext;
|
||||
import org.briarproject.api.transport.StreamWriter;
|
||||
import org.briarproject.api.transport.StreamWriterFactory;
|
||||
import org.briarproject.crypto.CryptoModule;
|
||||
import org.junit.Test;
|
||||
@@ -35,13 +30,10 @@ public class TransportIntegrationTest extends BriarTestCase {
|
||||
private final int FRAME_LENGTH = 2048;
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
private final StreamWriterFactory streamWriterFactory;
|
||||
private final ContactId contactId;
|
||||
private final TransportId transportId;
|
||||
private final AuthenticatedCipher frameCipher;
|
||||
private final Random random;
|
||||
private final byte[] secret;
|
||||
private final SecretKey frameKey;
|
||||
private final SecretKey tagKey, frameKey;
|
||||
|
||||
public TransportIntegrationTest() {
|
||||
Module testModule = new AbstractModule() {
|
||||
@@ -54,15 +46,13 @@ public class TransportIntegrationTest extends BriarTestCase {
|
||||
Injector i = Guice.createInjector(testModule, new CryptoModule(),
|
||||
new TestLifecycleModule(), new TestSystemModule());
|
||||
crypto = i.getInstance(CryptoComponent.class);
|
||||
streamWriterFactory = i.getInstance(StreamWriterFactory.class);
|
||||
contactId = new ContactId(234);
|
||||
transportId = new TransportId("id");
|
||||
frameCipher = crypto.getFrameCipher();
|
||||
random = new Random();
|
||||
// Since we're sending frames to ourselves, we only need outgoing keys
|
||||
secret = new byte[32];
|
||||
random.nextBytes(secret);
|
||||
frameKey = crypto.deriveFrameKey(secret, 0, true, true);
|
||||
tagKey = crypto.deriveTagKey(secret, true);
|
||||
frameKey = crypto.deriveFrameKey(secret, 0, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -76,6 +66,9 @@ public class TransportIntegrationTest extends BriarTestCase {
|
||||
}
|
||||
|
||||
private void testWriteAndRead(boolean initiator) throws Exception {
|
||||
// Encode the tag
|
||||
byte[] tag = new byte[TAG_LENGTH];
|
||||
crypto.encodeTag(tag, tagKey, 0);
|
||||
// Generate two random frames
|
||||
byte[] frame = new byte[1234];
|
||||
random.nextBytes(frame);
|
||||
@@ -83,87 +76,46 @@ public class TransportIntegrationTest extends BriarTestCase {
|
||||
random.nextBytes(frame1);
|
||||
// Copy the frame key - the copy will be erased
|
||||
SecretKey frameCopy = frameKey.copy();
|
||||
// Write the frames
|
||||
// Write the tag and the frames
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
FrameWriter encryptionOut = new OutgoingEncryptionLayer(out,
|
||||
Long.MAX_VALUE, frameCipher, frameCopy, FRAME_LENGTH);
|
||||
StreamWriterImpl writer = new StreamWriterImpl(encryptionOut,
|
||||
FrameWriter frameWriter = new OutgoingEncryptionLayer(out,
|
||||
frameCipher, frameCopy, FRAME_LENGTH, tag);
|
||||
StreamWriterImpl streamWriter = new StreamWriterImpl(frameWriter,
|
||||
FRAME_LENGTH);
|
||||
OutputStream out1 = writer.getOutputStream();
|
||||
OutputStream out1 = streamWriter.getOutputStream();
|
||||
out1.write(frame);
|
||||
out1.flush();
|
||||
out1.write(frame1);
|
||||
out1.flush();
|
||||
byte[] output = out.toByteArray();
|
||||
assertEquals(FRAME_LENGTH * 2, output.length);
|
||||
// Read the tag and the frames back
|
||||
assertEquals(TAG_LENGTH + FRAME_LENGTH * 2, output.length);
|
||||
// Read the tag back
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(output);
|
||||
FrameReader encryptionIn = new IncomingEncryptionLayer(in, frameCipher,
|
||||
byte[] recoveredTag = new byte[tag.length];
|
||||
read(in, recoveredTag);
|
||||
assertArrayEquals(tag, recoveredTag);
|
||||
// Read the frames back
|
||||
FrameReader frameReader = new IncomingEncryptionLayer(in, frameCipher,
|
||||
frameKey, FRAME_LENGTH);
|
||||
StreamReaderImpl reader = new StreamReaderImpl(encryptionIn,
|
||||
StreamReaderImpl streamReader = new StreamReaderImpl(frameReader,
|
||||
FRAME_LENGTH);
|
||||
InputStream in1 = reader.getInputStream();
|
||||
byte[] recovered = new byte[frame.length];
|
||||
InputStream in1 = streamReader.getInputStream();
|
||||
byte[] recoveredFrame = new byte[frame.length];
|
||||
read(in1, recoveredFrame);
|
||||
assertArrayEquals(frame, recoveredFrame);
|
||||
byte[] recoveredFrame1 = new byte[frame1.length];
|
||||
read(in1, recoveredFrame1);
|
||||
assertArrayEquals(frame1, recoveredFrame1);
|
||||
streamWriter.close();
|
||||
streamReader.close();
|
||||
}
|
||||
|
||||
private void read(InputStream in, byte[] dest) throws IOException {
|
||||
int offset = 0;
|
||||
while(offset < recovered.length) {
|
||||
int read = in1.read(recovered, offset, recovered.length - offset);
|
||||
while(offset < dest.length) {
|
||||
int read = in.read(dest, offset, dest.length - offset);
|
||||
if(read == -1) break;
|
||||
offset += read;
|
||||
}
|
||||
assertEquals(recovered.length, offset);
|
||||
assertArrayEquals(frame, recovered);
|
||||
byte[] recovered1 = new byte[frame1.length];
|
||||
offset = 0;
|
||||
while(offset < recovered1.length) {
|
||||
int read = in1.read(recovered1, offset, recovered1.length - offset);
|
||||
if(read == -1) break;
|
||||
offset += read;
|
||||
}
|
||||
assertEquals(recovered1.length, offset);
|
||||
assertArrayEquals(frame1, recovered1);
|
||||
writer.close();
|
||||
reader.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverheadWithTag() throws Exception {
|
||||
ByteArrayOutputStream out =
|
||||
new ByteArrayOutputStream(MIN_STREAM_LENGTH);
|
||||
StreamContext ctx = new StreamContext(contactId, transportId,
|
||||
secret, 0, true);
|
||||
StreamWriter w = streamWriterFactory.createStreamWriter(out,
|
||||
MAX_FRAME_LENGTH, MIN_STREAM_LENGTH, ctx, false, true);
|
||||
// Check that the connection writer thinks there's room for a packet
|
||||
long capacity = w.getRemainingCapacity();
|
||||
assertTrue(capacity > MAX_PACKET_LENGTH);
|
||||
assertTrue(capacity < MIN_STREAM_LENGTH);
|
||||
// Check that there really is room for a packet
|
||||
byte[] payload = new byte[MAX_PACKET_LENGTH];
|
||||
w.getOutputStream().write(payload);
|
||||
w.getOutputStream().close();
|
||||
long used = out.size();
|
||||
assertTrue(used > MAX_PACKET_LENGTH);
|
||||
assertTrue(used <= MIN_STREAM_LENGTH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverheadWithoutTag() throws Exception {
|
||||
ByteArrayOutputStream out =
|
||||
new ByteArrayOutputStream(MIN_STREAM_LENGTH);
|
||||
StreamContext ctx = new StreamContext(contactId, transportId,
|
||||
secret, 0, true);
|
||||
StreamWriter w = streamWriterFactory.createStreamWriter(out,
|
||||
MAX_FRAME_LENGTH, MIN_STREAM_LENGTH, ctx, false, false);
|
||||
// Check that the connection writer thinks there's room for a packet
|
||||
long capacity = w.getRemainingCapacity();
|
||||
assertTrue(capacity > MAX_PACKET_LENGTH);
|
||||
assertTrue(capacity < MIN_STREAM_LENGTH);
|
||||
// Check that there really is room for a packet
|
||||
byte[] payload = new byte[MAX_PACKET_LENGTH];
|
||||
w.getOutputStream().write(payload);
|
||||
w.getOutputStream().close();
|
||||
long used = out.size();
|
||||
assertTrue(used > MAX_PACKET_LENGTH);
|
||||
assertTrue(used <= MIN_STREAM_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user