mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 03:39:05 +01:00
Include the frame number in the header.
This ensures the frame number is covered by the MAC, cleanly separating encryption from authentication (previously we depended on the encryption layer to garble frames if they were reordered).
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||
import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
@@ -21,12 +22,13 @@ public class ConnectionReaderImplTest extends TransportTest {
|
||||
@Test
|
||||
public void testLengthZero() throws Exception {
|
||||
int payloadLength = 0;
|
||||
byte[] frame = new byte[headerLength + payloadLength + macLength];
|
||||
writeHeader(frame, payloadLength, 0);
|
||||
byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
|
||||
+ macLength];
|
||||
HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
|
||||
// Calculate the MAC
|
||||
mac.init(macKey);
|
||||
mac.update(frame, 0, headerLength + payloadLength);
|
||||
mac.doFinal(frame, headerLength + payloadLength);
|
||||
mac.update(frame, 0, FRAME_HEADER_LENGTH + payloadLength);
|
||||
mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength);
|
||||
// Read the frame
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(frame);
|
||||
ConnectionDecrypter d = new NullConnectionDecrypter(in);
|
||||
@@ -40,12 +42,13 @@ public class ConnectionReaderImplTest extends TransportTest {
|
||||
@Test
|
||||
public void testLengthOne() throws Exception {
|
||||
int payloadLength = 1;
|
||||
byte[] frame = new byte[headerLength + payloadLength + macLength];
|
||||
writeHeader(frame, payloadLength, 0);
|
||||
byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
|
||||
+ macLength];
|
||||
HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
|
||||
// Calculate the MAC
|
||||
mac.init(macKey);
|
||||
mac.update(frame, 0, headerLength + payloadLength);
|
||||
mac.doFinal(frame, headerLength + payloadLength);
|
||||
mac.update(frame, 0, FRAME_HEADER_LENGTH + payloadLength);
|
||||
mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength);
|
||||
// Read the frame
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(frame);
|
||||
ConnectionDecrypter d = new NullConnectionDecrypter(in);
|
||||
@@ -59,15 +62,15 @@ public class ConnectionReaderImplTest extends TransportTest {
|
||||
public void testMaxLength() throws Exception {
|
||||
// First frame: max payload length
|
||||
byte[] frame = new byte[MAX_FRAME_LENGTH];
|
||||
writeHeader(frame, maxPayloadLength, 0);
|
||||
HeaderEncoder.encodeHeader(frame, 0, maxPayloadLength, 0);
|
||||
mac.init(macKey);
|
||||
mac.update(frame, 0, headerLength + maxPayloadLength);
|
||||
mac.doFinal(frame, headerLength + maxPayloadLength);
|
||||
mac.update(frame, 0, FRAME_HEADER_LENGTH + maxPayloadLength);
|
||||
mac.doFinal(frame, FRAME_HEADER_LENGTH + maxPayloadLength);
|
||||
// Second frame: max payload length plus one
|
||||
byte[] frame1 = new byte[MAX_FRAME_LENGTH + 1];
|
||||
writeHeader(frame1, maxPayloadLength + 1, 0);
|
||||
mac.update(frame1, 0, headerLength + maxPayloadLength + 1);
|
||||
mac.doFinal(frame1, headerLength + maxPayloadLength + 1);
|
||||
HeaderEncoder.encodeHeader(frame1, 1, maxPayloadLength + 1, 0);
|
||||
mac.update(frame1, 0, FRAME_HEADER_LENGTH + maxPayloadLength + 1);
|
||||
mac.doFinal(frame1, FRAME_HEADER_LENGTH + maxPayloadLength + 1);
|
||||
// Concatenate the frames
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(frame);
|
||||
@@ -91,16 +94,17 @@ public class ConnectionReaderImplTest extends TransportTest {
|
||||
int paddingLength = 10;
|
||||
// First frame: max payload length, including padding
|
||||
byte[] frame = new byte[MAX_FRAME_LENGTH];
|
||||
writeHeader(frame, maxPayloadLength - paddingLength, paddingLength);
|
||||
HeaderEncoder.encodeHeader(frame, 0, maxPayloadLength - paddingLength,
|
||||
paddingLength);
|
||||
mac.init(macKey);
|
||||
mac.update(frame, 0, headerLength + maxPayloadLength);
|
||||
mac.doFinal(frame, headerLength + maxPayloadLength);
|
||||
mac.update(frame, 0, FRAME_HEADER_LENGTH + maxPayloadLength);
|
||||
mac.doFinal(frame, FRAME_HEADER_LENGTH + maxPayloadLength);
|
||||
// Second frame: max payload length plus one, including padding
|
||||
byte[] frame1 = new byte[MAX_FRAME_LENGTH + 1];
|
||||
writeHeader(frame1, maxPayloadLength + 1 - paddingLength,
|
||||
paddingLength);
|
||||
mac.update(frame1, 0, headerLength + maxPayloadLength + 1);
|
||||
mac.doFinal(frame1, headerLength + maxPayloadLength + 1);
|
||||
HeaderEncoder.encodeHeader(frame1, 1,
|
||||
maxPayloadLength + 1 - paddingLength, paddingLength);
|
||||
mac.update(frame1, 0, FRAME_HEADER_LENGTH + maxPayloadLength + 1);
|
||||
mac.doFinal(frame1, FRAME_HEADER_LENGTH + maxPayloadLength + 1);
|
||||
// Concatenate the frames
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(frame);
|
||||
@@ -122,16 +126,20 @@ public class ConnectionReaderImplTest extends TransportTest {
|
||||
@Test
|
||||
public void testMultipleFrames() throws Exception {
|
||||
// First frame: 123-byte payload
|
||||
byte[] frame = new byte[headerLength + 123 + mac.getMacLength()];
|
||||
writeHeader(frame, 123, 0);
|
||||
int payloadLength = 123;
|
||||
byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
|
||||
+ macLength];
|
||||
HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
|
||||
mac.init(macKey);
|
||||
mac.update(frame, 0, headerLength + 123);
|
||||
mac.doFinal(frame, headerLength + 123);
|
||||
mac.update(frame, 0, FRAME_HEADER_LENGTH + payloadLength);
|
||||
mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength);
|
||||
// Second frame: 1234-byte payload
|
||||
byte[] frame1 = new byte[headerLength + 1234 + mac.getMacLength()];
|
||||
writeHeader(frame1, 1234, 0);
|
||||
mac.update(frame1, 0, headerLength + 1234);
|
||||
mac.doFinal(frame1, headerLength + 1234);
|
||||
int payloadLength1 = 1234;
|
||||
byte[] frame1 = new byte[FRAME_HEADER_LENGTH + payloadLength1
|
||||
+ macLength];
|
||||
HeaderEncoder.encodeHeader(frame1, 1, payloadLength1, 0);
|
||||
mac.update(frame1, 0, FRAME_HEADER_LENGTH + payloadLength1);
|
||||
mac.doFinal(frame1, FRAME_HEADER_LENGTH + payloadLength1);
|
||||
// Concatenate the frames
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(frame);
|
||||
@@ -140,23 +148,24 @@ public class ConnectionReaderImplTest extends TransportTest {
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
ConnectionDecrypter d = new NullConnectionDecrypter(in);
|
||||
ConnectionReader r = new ConnectionReaderImpl(d, mac, macKey);
|
||||
byte[] read = new byte[123];
|
||||
byte[] read = new byte[payloadLength];
|
||||
TestUtils.readFully(r.getInputStream(), read);
|
||||
assertArrayEquals(new byte[123], read);
|
||||
byte[] read1 = new byte[1234];
|
||||
assertArrayEquals(new byte[payloadLength], read);
|
||||
byte[] read1 = new byte[payloadLength1];
|
||||
TestUtils.readFully(r.getInputStream(), read1);
|
||||
assertArrayEquals(new byte[1234], read1);
|
||||
assertArrayEquals(new byte[payloadLength1], read1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorruptPayload() throws Exception {
|
||||
int payloadLength = 8;
|
||||
byte[] frame = new byte[headerLength + payloadLength + macLength];
|
||||
writeHeader(frame, payloadLength, 0);
|
||||
byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
|
||||
+ macLength];
|
||||
HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
|
||||
// Calculate the MAC
|
||||
mac.init(macKey);
|
||||
mac.update(frame, 0, headerLength + payloadLength);
|
||||
mac.doFinal(frame, headerLength + payloadLength);
|
||||
mac.update(frame, 0, FRAME_HEADER_LENGTH + payloadLength);
|
||||
mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength);
|
||||
// Modify the payload
|
||||
frame[12] ^= 1;
|
||||
// Try to read the frame - not a single byte should be read
|
||||
@@ -172,12 +181,13 @@ public class ConnectionReaderImplTest extends TransportTest {
|
||||
@Test
|
||||
public void testCorruptMac() throws Exception {
|
||||
int payloadLength = 8;
|
||||
byte[] frame = new byte[headerLength + payloadLength + macLength];
|
||||
writeHeader(frame, payloadLength, 0);
|
||||
byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
|
||||
+ macLength];
|
||||
HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
|
||||
// Calculate the MAC
|
||||
mac.init(macKey);
|
||||
mac.update(frame, 0, headerLength + payloadLength);
|
||||
mac.doFinal(frame, headerLength + payloadLength);
|
||||
mac.update(frame, 0, FRAME_HEADER_LENGTH + payloadLength);
|
||||
mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength);
|
||||
// Modify the MAC
|
||||
frame[17] ^= 1;
|
||||
// Try to read the frame - not a single byte should be read
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||
import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
@@ -30,12 +31,13 @@ public class ConnectionWriterImplTest extends TransportTest {
|
||||
@Test
|
||||
public void testSingleByteFrame() throws Exception {
|
||||
int payloadLength = 1;
|
||||
byte[] frame = new byte[headerLength + payloadLength + macLength];
|
||||
writeHeader(frame, payloadLength, 0);
|
||||
byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
|
||||
+ macLength];
|
||||
HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
|
||||
// Calculate the MAC
|
||||
mac.init(macKey);
|
||||
mac.update(frame, 0, headerLength + payloadLength);
|
||||
mac.doFinal(frame, headerLength + payloadLength);
|
||||
mac.update(frame, 0, FRAME_HEADER_LENGTH + payloadLength);
|
||||
mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength);
|
||||
// Check that the ConnectionWriter gets the same results
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ConnectionEncrypter e = new NullConnectionEncrypter(out);
|
||||
@@ -76,16 +78,20 @@ public class ConnectionWriterImplTest extends TransportTest {
|
||||
@Test
|
||||
public void testMultipleFrames() throws Exception {
|
||||
// First frame: 123-byte payload
|
||||
byte[] frame = new byte[headerLength + 123 + macLength];
|
||||
writeHeader(frame, 123, 0);
|
||||
int payloadLength = 123;
|
||||
byte[] frame = new byte[FRAME_HEADER_LENGTH + payloadLength
|
||||
+ macLength];
|
||||
HeaderEncoder.encodeHeader(frame, 0, payloadLength, 0);
|
||||
mac.init(macKey);
|
||||
mac.update(frame, 0, headerLength + 123);
|
||||
mac.doFinal(frame, headerLength + 123);
|
||||
mac.update(frame, 0, FRAME_HEADER_LENGTH + payloadLength);
|
||||
mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength);
|
||||
// Second frame: 1234-byte payload
|
||||
byte[] frame1 = new byte[headerLength + 1234 + macLength];
|
||||
writeHeader(frame1, 1234, 0);
|
||||
mac.update(frame1, 0, headerLength + 1234);
|
||||
mac.doFinal(frame1, headerLength + 1234);
|
||||
int payloadLength1 = 1234;
|
||||
byte[] frame1 = new byte[FRAME_HEADER_LENGTH + payloadLength1
|
||||
+ macLength];
|
||||
HeaderEncoder.encodeHeader(frame1, 1, payloadLength1, 0);
|
||||
mac.update(frame1, 0, FRAME_HEADER_LENGTH + 1234);
|
||||
mac.doFinal(frame1, FRAME_HEADER_LENGTH + 1234);
|
||||
// Concatenate the frames
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(frame);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||
import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import net.sf.briar.api.crypto.ErasableKey;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.crypto.ErasableKey;
|
||||
import net.sf.briar.crypto.CryptoModule;
|
||||
import net.sf.briar.util.ByteUtils;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
@@ -17,7 +17,7 @@ public abstract class TransportTest extends TestCase {
|
||||
|
||||
protected final Mac mac;
|
||||
protected final ErasableKey macKey;
|
||||
protected final int headerLength = 4, macLength, maxPayloadLength;
|
||||
protected final int macLength, maxPayloadLength;
|
||||
|
||||
public TransportTest() throws Exception {
|
||||
super();
|
||||
@@ -26,11 +26,6 @@ public abstract class TransportTest extends TestCase {
|
||||
mac = crypto.getMac();
|
||||
macKey = crypto.generateTestKey();
|
||||
macLength = mac.getMacLength();
|
||||
maxPayloadLength = MAX_FRAME_LENGTH - headerLength - macLength;
|
||||
}
|
||||
|
||||
static void writeHeader(byte[] b, int payload, int padding) {
|
||||
ByteUtils.writeUint16(payload, b, 0);
|
||||
ByteUtils.writeUint16(padding, b, 2);
|
||||
maxPayloadLength = MAX_FRAME_LENGTH - FRAME_HEADER_LENGTH - macLength;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user