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:
akwizgran
2011-12-02 13:37:44 +00:00
parent 14d5e6fe64
commit 51d58fadad
9 changed files with 144 additions and 80 deletions

View File

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

View File

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

View File

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