mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 11:49:04 +01:00
Implement stream header for BTPv2. #111
This commit is contained in:
@@ -1,37 +1,226 @@
|
||||
package org.briarproject.crypto;
|
||||
|
||||
import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.TestUtils;
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
import org.briarproject.util.ByteUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class StreamDecrypterImplTest extends BriarTestCase {
|
||||
|
||||
private final AuthenticatedCipher cipher;
|
||||
private final SecretKey streamHeaderKey, frameKey;
|
||||
private final byte[] streamHeaderIv;
|
||||
private final Random random;
|
||||
|
||||
public StreamDecrypterImplTest() {
|
||||
cipher = new TestAuthenticatedCipher(); // Null cipher
|
||||
streamHeaderKey = TestUtils.createSecretKey();
|
||||
frameKey = TestUtils.createSecretKey();
|
||||
streamHeaderIv = new byte[STREAM_HEADER_IV_LENGTH];
|
||||
random = new Random();
|
||||
random.nextBytes(streamHeaderIv);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadValidFrames() throws Exception {
|
||||
// FIXME
|
||||
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
int payloadLength = 123, paddingLength = 234;
|
||||
FrameEncoder.encodeHeader(frameHeader, false, payloadLength,
|
||||
paddingLength);
|
||||
byte[] payload = new byte[payloadLength];
|
||||
random.nextBytes(payload);
|
||||
|
||||
byte[] frameHeader1 = new byte[FRAME_HEADER_LENGTH];
|
||||
int payloadLength1 = 345, paddingLength1 = 456;
|
||||
FrameEncoder.encodeHeader(frameHeader1, true, payloadLength1,
|
||||
paddingLength1);
|
||||
byte[] payload1 = new byte[payloadLength1];
|
||||
random.nextBytes(payload1);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(streamHeaderIv);
|
||||
out.write(frameKey.getBytes());
|
||||
out.write(new byte[MAC_LENGTH]);
|
||||
out.write(frameHeader);
|
||||
out.write(payload);
|
||||
out.write(new byte[paddingLength]);
|
||||
out.write(new byte[MAC_LENGTH]);
|
||||
out.write(frameHeader1);
|
||||
out.write(payload1);
|
||||
out.write(new byte[paddingLength1]);
|
||||
out.write(new byte[MAC_LENGTH]);
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
StreamDecrypterImpl s = new StreamDecrypterImpl(in, cipher,
|
||||
streamHeaderKey);
|
||||
|
||||
// Read the first frame
|
||||
byte[] buffer = new byte[MAX_PAYLOAD_LENGTH];
|
||||
assertEquals(payloadLength, s.readFrame(buffer));
|
||||
assertArrayStartsWith(payload, buffer, payloadLength);
|
||||
|
||||
// Read the second frame
|
||||
assertEquals(payloadLength1, s.readFrame(buffer));
|
||||
assertArrayStartsWith(payload1, buffer, payloadLength1);
|
||||
|
||||
// End of stream
|
||||
assertEquals(-1, s.readFrame(buffer));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncatedFrameThrowsException() throws Exception {
|
||||
// FIXME
|
||||
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
int payloadLength = 123, paddingLength = 234;
|
||||
FrameEncoder.encodeHeader(frameHeader, false, payloadLength,
|
||||
paddingLength);
|
||||
byte[] payload = new byte[payloadLength];
|
||||
random.nextBytes(payload);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(streamHeaderIv);
|
||||
out.write(frameKey.getBytes());
|
||||
out.write(new byte[MAC_LENGTH]);
|
||||
out.write(frameHeader);
|
||||
out.write(payload);
|
||||
out.write(new byte[paddingLength]);
|
||||
out.write(new byte[MAC_LENGTH - 1]); // Chop off the last byte
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
StreamDecrypterImpl s = new StreamDecrypterImpl(in, cipher,
|
||||
streamHeaderKey);
|
||||
|
||||
// Try to read the truncated frame
|
||||
byte[] buffer = new byte[MAX_PAYLOAD_LENGTH];
|
||||
try {
|
||||
s.readFrame(buffer);
|
||||
fail();
|
||||
} catch (IOException expected) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModifiedFrameThrowsException() throws Exception {
|
||||
// FIXME
|
||||
}
|
||||
public void testInvalidPayloadAndPaddingLengthThrowsException()
|
||||
throws Exception {
|
||||
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
// The payload length plus padding length is invalid
|
||||
int payloadLength = MAX_PAYLOAD_LENGTH - 1, paddingLength = 2;
|
||||
ByteUtils.writeUint16(payloadLength, frameHeader, 0);
|
||||
ByteUtils.writeUint16(paddingLength, frameHeader, 2);
|
||||
byte[] payload = new byte[payloadLength];
|
||||
random.nextBytes(payload);
|
||||
|
||||
@Test
|
||||
public void testInvalidPayloadLengthThrowsException() throws Exception {
|
||||
// FIXME
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(streamHeaderIv);
|
||||
out.write(frameKey.getBytes());
|
||||
out.write(new byte[MAC_LENGTH]);
|
||||
out.write(frameHeader);
|
||||
out.write(payload);
|
||||
out.write(new byte[paddingLength]);
|
||||
out.write(new byte[MAC_LENGTH]);
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
StreamDecrypterImpl s = new StreamDecrypterImpl(in, cipher,
|
||||
streamHeaderKey);
|
||||
|
||||
// Try to read the invalid frame
|
||||
byte[] buffer = new byte[MAX_PAYLOAD_LENGTH];
|
||||
try {
|
||||
s.readFrame(buffer);
|
||||
fail();
|
||||
} catch (IOException expected) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonZeroPaddingThrowsException() throws Exception {
|
||||
// FIXME
|
||||
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
int payloadLength = 123, paddingLength = 234;
|
||||
FrameEncoder.encodeHeader(frameHeader, false, payloadLength,
|
||||
paddingLength);
|
||||
byte[] payload = new byte[payloadLength];
|
||||
random.nextBytes(payload);
|
||||
// Set one of the padding bytes non-zero
|
||||
byte[] padding = new byte[paddingLength];
|
||||
padding[paddingLength - 1] = 1;
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(streamHeaderIv);
|
||||
out.write(frameKey.getBytes());
|
||||
out.write(new byte[MAC_LENGTH]);
|
||||
out.write(frameHeader);
|
||||
out.write(payload);
|
||||
out.write(padding);
|
||||
out.write(new byte[MAC_LENGTH]);
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
StreamDecrypterImpl s = new StreamDecrypterImpl(in, cipher,
|
||||
streamHeaderKey);
|
||||
|
||||
// Try to read the invalid frame
|
||||
byte[] buffer = new byte[MAX_PAYLOAD_LENGTH];
|
||||
try {
|
||||
s.readFrame(buffer);
|
||||
fail();
|
||||
} catch (IOException expected) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCannotReadBeyondFinalFrame() throws Exception {
|
||||
// FIXME
|
||||
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
int payloadLength = 123, paddingLength = 234;
|
||||
FrameEncoder.encodeHeader(frameHeader, true, payloadLength,
|
||||
paddingLength);
|
||||
byte[] payload = new byte[payloadLength];
|
||||
random.nextBytes(payload);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(streamHeaderIv);
|
||||
out.write(frameKey.getBytes());
|
||||
out.write(new byte[MAC_LENGTH]);
|
||||
out.write(frameHeader);
|
||||
out.write(payload);
|
||||
out.write(new byte[paddingLength]);
|
||||
out.write(new byte[MAC_LENGTH]);
|
||||
// Add some data beyond the final frame
|
||||
out.write(new byte[1024]);
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
StreamDecrypterImpl s = new StreamDecrypterImpl(in, cipher,
|
||||
streamHeaderKey);
|
||||
|
||||
// Read the first frame
|
||||
byte[] buffer = new byte[MAX_PAYLOAD_LENGTH];
|
||||
assertEquals(payloadLength, s.readFrame(buffer));
|
||||
assertArrayStartsWith(payload, buffer, payloadLength);
|
||||
|
||||
// End of stream
|
||||
assertEquals(-1, s.readFrame(buffer));
|
||||
|
||||
// Yup, definitely end of stream
|
||||
assertEquals(-1, s.readFrame(buffer));
|
||||
}
|
||||
|
||||
private static void assertArrayStartsWith(byte[] expected, byte[] actual,
|
||||
int len) {
|
||||
byte[] prefix = new byte[len];
|
||||
System.arraycopy(actual, 0, prefix, 0, len);
|
||||
assertArrayEquals(expected, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,261 +1,345 @@
|
||||
package org.briarproject.crypto;
|
||||
|
||||
import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.TestUtils;
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class StreamEncrypterImplTest extends BriarTestCase {
|
||||
|
||||
private final AuthenticatedCipher frameCipher;
|
||||
private final SecretKey frameKey;
|
||||
private final byte[] tag;
|
||||
private final AuthenticatedCipher cipher;
|
||||
private final SecretKey streamHeaderKey, frameKey;
|
||||
private final byte[] tag, streamHeaderIv;
|
||||
private final Random random;
|
||||
|
||||
public StreamEncrypterImplTest() {
|
||||
frameCipher = new TestAuthenticatedCipher();
|
||||
frameKey = new SecretKey(new byte[32]);
|
||||
cipher = new TestAuthenticatedCipher(); // Null cipher
|
||||
streamHeaderKey = TestUtils.createSecretKey();
|
||||
frameKey = TestUtils.createSecretKey();
|
||||
tag = new byte[TAG_LENGTH];
|
||||
new Random().nextBytes(tag);
|
||||
streamHeaderIv = new byte[STREAM_HEADER_IV_LENGTH];
|
||||
random = new Random();
|
||||
random.nextBytes(tag);
|
||||
random.nextBytes(streamHeaderIv);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteUnpaddedNonFinalFrameWithTag() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher,
|
||||
frameKey, tag);
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, tag,
|
||||
streamHeaderIv, streamHeaderKey, frameKey);
|
||||
int payloadLength = 123;
|
||||
byte[] payload = new byte[payloadLength];
|
||||
new Random().nextBytes(payload);
|
||||
random.nextBytes(payload);
|
||||
|
||||
s.writeFrame(payload, payloadLength, 0, false);
|
||||
|
||||
byte[] header = new byte[HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(header, false, payloadLength, 0);
|
||||
int frameLength = HEADER_LENGTH + payloadLength + MAC_LENGTH;
|
||||
byte[] expected = new byte[TAG_LENGTH + frameLength];
|
||||
System.arraycopy(tag, 0, expected, 0, TAG_LENGTH);
|
||||
System.arraycopy(header, 0, expected, TAG_LENGTH, HEADER_LENGTH);
|
||||
System.arraycopy(payload, 0, expected, TAG_LENGTH + HEADER_LENGTH,
|
||||
payloadLength);
|
||||
assertArrayEquals(expected, out.toByteArray());
|
||||
// Expect the tag, stream header, frame header, payload and MAC
|
||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||
expected.write(tag);
|
||||
expected.write(streamHeaderIv);
|
||||
expected.write(frameKey.getBytes());
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(expectedFrameHeader, false, payloadLength, 0);
|
||||
expected.write(expectedFrameHeader);
|
||||
expected.write(payload);
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
|
||||
assertArrayEquals(expected.toByteArray(), out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteUnpaddedFinalFrameWithTag() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher,
|
||||
frameKey, tag);
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, tag,
|
||||
streamHeaderIv, streamHeaderKey, frameKey);
|
||||
int payloadLength = 123;
|
||||
int frameLength = HEADER_LENGTH + payloadLength + MAC_LENGTH;
|
||||
byte[] payload = new byte[payloadLength];
|
||||
new Random().nextBytes(payload);
|
||||
random.nextBytes(payload);
|
||||
|
||||
s.writeFrame(payload, payloadLength, 0, true);
|
||||
|
||||
byte[] header = new byte[HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(header, true, payloadLength, 0);
|
||||
byte[] expected = new byte[TAG_LENGTH + frameLength];
|
||||
System.arraycopy(tag, 0, expected, 0, TAG_LENGTH);
|
||||
System.arraycopy(header, 0, expected, TAG_LENGTH, HEADER_LENGTH);
|
||||
System.arraycopy(payload, 0, expected, TAG_LENGTH + HEADER_LENGTH,
|
||||
payloadLength);
|
||||
assertArrayEquals(expected, out.toByteArray());
|
||||
// Expect the tag, stream header, frame header, payload and MAC
|
||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||
expected.write(tag);
|
||||
expected.write(streamHeaderIv);
|
||||
expected.write(frameKey.getBytes());
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(expectedFrameHeader, true, payloadLength, 0);
|
||||
expected.write(expectedFrameHeader);
|
||||
expected.write(payload);
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
|
||||
assertArrayEquals(expected.toByteArray(), out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteUnpaddedNonFinalFrameWithoutTag() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher,
|
||||
frameKey, null);
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, null,
|
||||
streamHeaderIv, streamHeaderKey, frameKey);
|
||||
int payloadLength = 123;
|
||||
int frameLength = HEADER_LENGTH + payloadLength + MAC_LENGTH;
|
||||
byte[] payload = new byte[payloadLength];
|
||||
new Random().nextBytes(payload);
|
||||
random.nextBytes(payload);
|
||||
|
||||
s.writeFrame(payload, payloadLength, 0, false);
|
||||
|
||||
byte[] header = new byte[HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(header, false, payloadLength, 0);
|
||||
byte[] expected = new byte[frameLength];
|
||||
System.arraycopy(header, 0, expected, 0, HEADER_LENGTH);
|
||||
System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength);
|
||||
assertArrayEquals(expected, out.toByteArray());
|
||||
// Expect the stream header, frame header, payload and MAC
|
||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||
expected.write(streamHeaderIv);
|
||||
expected.write(frameKey.getBytes());
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(expectedFrameHeader, false, payloadLength, 0);
|
||||
expected.write(expectedFrameHeader);
|
||||
expected.write(payload);
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
|
||||
assertArrayEquals(expected.toByteArray(), out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteUnpaddedFinalFrameWithoutTag() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher,
|
||||
frameKey, null);
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, null,
|
||||
streamHeaderIv, streamHeaderKey, frameKey);
|
||||
int payloadLength = 123;
|
||||
int frameLength = HEADER_LENGTH + payloadLength + MAC_LENGTH;
|
||||
byte[] payload = new byte[payloadLength];
|
||||
new Random().nextBytes(payload);
|
||||
random.nextBytes(payload);
|
||||
|
||||
s.writeFrame(payload, payloadLength, 0, true);
|
||||
|
||||
byte[] header = new byte[HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(header, true, payloadLength, 0);
|
||||
byte[] expected = new byte[frameLength];
|
||||
System.arraycopy(header, 0, expected, 0, HEADER_LENGTH);
|
||||
System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength);
|
||||
assertArrayEquals(expected, out.toByteArray());
|
||||
// Expect the stream header, frame header, payload and MAC
|
||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||
expected.write(streamHeaderIv);
|
||||
expected.write(frameKey.getBytes());
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(expectedFrameHeader, true, payloadLength, 0);
|
||||
expected.write(expectedFrameHeader);
|
||||
expected.write(payload);
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
|
||||
assertArrayEquals(expected.toByteArray(), out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWritePaddedNonFinalFrameWithTag() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher,
|
||||
frameKey, tag);
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, tag,
|
||||
streamHeaderIv, streamHeaderKey, frameKey);
|
||||
int payloadLength = 123, paddingLength = 234;
|
||||
int frameLength = HEADER_LENGTH + payloadLength + paddingLength
|
||||
+ MAC_LENGTH;
|
||||
byte[] payload = new byte[payloadLength];
|
||||
new Random().nextBytes(payload);
|
||||
random.nextBytes(payload);
|
||||
|
||||
s.writeFrame(payload, payloadLength, paddingLength, false);
|
||||
|
||||
byte[] header = new byte[HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(header, false, payloadLength, paddingLength);
|
||||
byte[] expected = new byte[TAG_LENGTH + frameLength];
|
||||
System.arraycopy(tag, 0, expected, 0, TAG_LENGTH);
|
||||
System.arraycopy(header, 0, expected, TAG_LENGTH, HEADER_LENGTH);
|
||||
System.arraycopy(payload, 0, expected, TAG_LENGTH + HEADER_LENGTH,
|
||||
payloadLength);
|
||||
assertArrayEquals(expected, out.toByteArray());
|
||||
// Expect the tag, stream header, frame header, payload, padding and MAC
|
||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||
expected.write(tag);
|
||||
expected.write(streamHeaderIv);
|
||||
expected.write(frameKey.getBytes());
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(expectedFrameHeader, false, payloadLength,
|
||||
paddingLength);
|
||||
expected.write(expectedFrameHeader);
|
||||
expected.write(payload);
|
||||
expected.write(new byte[paddingLength]);
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
|
||||
assertArrayEquals(expected.toByteArray(), out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWritePaddedFinalFrameWithTag() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher,
|
||||
frameKey, tag);
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, tag,
|
||||
streamHeaderIv, streamHeaderKey, frameKey);
|
||||
int payloadLength = 123, paddingLength = 234;
|
||||
int frameLength = HEADER_LENGTH + payloadLength + paddingLength
|
||||
+ MAC_LENGTH;
|
||||
byte[] payload = new byte[payloadLength];
|
||||
new Random().nextBytes(payload);
|
||||
random.nextBytes(payload);
|
||||
|
||||
s.writeFrame(payload, payloadLength, paddingLength, true);
|
||||
|
||||
byte[] header = new byte[HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(header, true, payloadLength, paddingLength);
|
||||
byte[] expected = new byte[TAG_LENGTH + frameLength];
|
||||
System.arraycopy(tag, 0, expected, 0, TAG_LENGTH);
|
||||
System.arraycopy(header, 0, expected, TAG_LENGTH, HEADER_LENGTH);
|
||||
System.arraycopy(payload, 0, expected, TAG_LENGTH + HEADER_LENGTH,
|
||||
payloadLength);
|
||||
assertArrayEquals(expected, out.toByteArray());
|
||||
// Expect the tag, stream header, frame header, payload, padding and MAC
|
||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||
expected.write(tag);
|
||||
expected.write(streamHeaderIv);
|
||||
expected.write(frameKey.getBytes());
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(expectedFrameHeader, true, payloadLength,
|
||||
paddingLength);
|
||||
expected.write(expectedFrameHeader);
|
||||
expected.write(payload);
|
||||
expected.write(new byte[paddingLength]);
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
|
||||
assertArrayEquals(expected.toByteArray(), out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWritePaddedNonFinalFrameWithoutTag() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher,
|
||||
frameKey, null);
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, null,
|
||||
streamHeaderIv, streamHeaderKey, frameKey);
|
||||
int payloadLength = 123, paddingLength = 234;
|
||||
int frameLength = HEADER_LENGTH + payloadLength + paddingLength
|
||||
+ MAC_LENGTH;
|
||||
byte[] payload = new byte[payloadLength];
|
||||
new Random().nextBytes(payload);
|
||||
random.nextBytes(payload);
|
||||
|
||||
s.writeFrame(payload, payloadLength, paddingLength, false);
|
||||
|
||||
byte[] header = new byte[HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(header, false, payloadLength, paddingLength);
|
||||
byte[] expected = new byte[frameLength];
|
||||
System.arraycopy(header, 0, expected, 0, HEADER_LENGTH);
|
||||
System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength);
|
||||
assertArrayEquals(expected, out.toByteArray());
|
||||
// Expect the stream header, frame header, payload, padding and MAC
|
||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||
expected.write(streamHeaderIv);
|
||||
expected.write(frameKey.getBytes());
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(expectedFrameHeader, false, payloadLength,
|
||||
paddingLength);
|
||||
expected.write(expectedFrameHeader);
|
||||
expected.write(payload);
|
||||
expected.write(new byte[paddingLength]);
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
|
||||
assertArrayEquals(expected.toByteArray(), out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWritePaddedFinalFrameWithoutTag() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher,
|
||||
frameKey, null);
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, null,
|
||||
streamHeaderIv, streamHeaderKey, frameKey);
|
||||
int payloadLength = 123, paddingLength = 234;
|
||||
int frameLength = HEADER_LENGTH + payloadLength + paddingLength
|
||||
+ MAC_LENGTH;
|
||||
byte[] payload = new byte[payloadLength];
|
||||
new Random().nextBytes(payload);
|
||||
random.nextBytes(payload);
|
||||
|
||||
s.writeFrame(payload, payloadLength, paddingLength, true);
|
||||
|
||||
byte[] header = new byte[HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(header, true, payloadLength, paddingLength);
|
||||
byte[] expected = new byte[frameLength];
|
||||
System.arraycopy(header, 0, expected, 0, HEADER_LENGTH);
|
||||
System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength);
|
||||
assertArrayEquals(expected, out.toByteArray());
|
||||
// Expect the stream header, frame header, payload, padding and MAC
|
||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||
expected.write(streamHeaderIv);
|
||||
expected.write(frameKey.getBytes());
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(expectedFrameHeader, true, payloadLength,
|
||||
paddingLength);
|
||||
expected.write(expectedFrameHeader);
|
||||
expected.write(payload);
|
||||
expected.write(new byte[paddingLength]);
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
|
||||
assertArrayEquals(expected.toByteArray(), out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteTwoFrames() throws Exception {
|
||||
public void testWriteTwoFramesWithTag() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher,
|
||||
frameKey, null);
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, tag,
|
||||
streamHeaderIv, streamHeaderKey, frameKey);
|
||||
int payloadLength = 123, paddingLength = 234;
|
||||
int frameLength = HEADER_LENGTH + payloadLength + paddingLength
|
||||
+ MAC_LENGTH;
|
||||
byte[] payload = new byte[payloadLength];
|
||||
new Random().nextBytes(payload);
|
||||
random.nextBytes(payload);
|
||||
int payloadLength1 = 345, paddingLength1 = 456;
|
||||
int frameLength1 = HEADER_LENGTH + payloadLength1 + paddingLength1
|
||||
+ MAC_LENGTH;
|
||||
byte[] payload1 = new byte[payloadLength1];
|
||||
new Random().nextBytes(payload1);
|
||||
random.nextBytes(payload1);
|
||||
|
||||
s.writeFrame(payload, payloadLength, paddingLength, false);
|
||||
s.writeFrame(payload1, payloadLength1, paddingLength1, true);
|
||||
|
||||
byte[] header = new byte[HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(header, false, payloadLength, paddingLength);
|
||||
byte[] header1 = new byte[HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(header1, true, payloadLength1,
|
||||
// Expect the tag, stream header, first frame header, payload, padding,
|
||||
// MAC, second frame header, payload, padding, MAC
|
||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||
expected.write(tag);
|
||||
expected.write(streamHeaderIv);
|
||||
expected.write(frameKey.getBytes());
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(expectedFrameHeader, false, payloadLength,
|
||||
paddingLength);
|
||||
expected.write(expectedFrameHeader);
|
||||
expected.write(payload);
|
||||
expected.write(new byte[paddingLength]);
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
byte[] expectedFrameHeader1 = new byte[FRAME_HEADER_LENGTH];
|
||||
FrameEncoder.encodeHeader(expectedFrameHeader1, true, payloadLength1,
|
||||
paddingLength1);
|
||||
byte[] expected = new byte[frameLength + frameLength1];
|
||||
System.arraycopy(header, 0, expected, 0, HEADER_LENGTH);
|
||||
System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength);
|
||||
System.arraycopy(header1, 0, expected, frameLength, HEADER_LENGTH);
|
||||
System.arraycopy(payload1, 0, expected, frameLength + HEADER_LENGTH,
|
||||
payloadLength1);
|
||||
assertArrayEquals(expected, out.toByteArray());
|
||||
expected.write(expectedFrameHeader1);
|
||||
expected.write(payload1);
|
||||
expected.write(new byte[paddingLength1]);
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
|
||||
assertArrayEquals(expected.toByteArray(), out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushWritesTagIfNotAlreadyWritten() throws Exception {
|
||||
public void testFlushWritesTagAndStreamHeaderIfNotAlreadyWritten()
|
||||
throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher,
|
||||
frameKey, tag);
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, tag,
|
||||
streamHeaderIv, streamHeaderKey, frameKey);
|
||||
|
||||
// Flush the stream once
|
||||
s.flush();
|
||||
assertArrayEquals(tag, out.toByteArray());
|
||||
|
||||
// Expect the tag and stream header
|
||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||
expected.write(tag);
|
||||
expected.write(streamHeaderIv);
|
||||
expected.write(frameKey.getBytes());
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
|
||||
assertArrayEquals(expected.toByteArray(), out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushDoesNotWriteTagIfAlreadyWritten() throws Exception {
|
||||
public void testFlushDoesNotWriteTagOrStreamHeaderIfAlreadyWritten()
|
||||
throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher,
|
||||
frameKey, tag);
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, tag,
|
||||
streamHeaderIv, streamHeaderKey, frameKey);
|
||||
|
||||
// Flush the stream twice
|
||||
s.flush();
|
||||
s.flush();
|
||||
assertArrayEquals(tag, out.toByteArray());
|
||||
|
||||
// Expect the tag and stream header
|
||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||
expected.write(tag);
|
||||
expected.write(streamHeaderIv);
|
||||
expected.write(frameKey.getBytes());
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
|
||||
assertArrayEquals(expected.toByteArray(), out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushDoesNotWriteTagIfNull() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher,
|
||||
frameKey, null);
|
||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, null,
|
||||
streamHeaderIv, streamHeaderKey, frameKey);
|
||||
|
||||
// Flush the stream once
|
||||
s.flush();
|
||||
assertEquals(0, out.size());
|
||||
|
||||
// Expect the stream header
|
||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||
expected.write(streamHeaderIv);
|
||||
expected.write(frameKey.getBytes());
|
||||
expected.write(new byte[MAC_LENGTH]);
|
||||
|
||||
assertArrayEquals(expected.toByteArray(), out.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||
|
||||
@@ -24,8 +24,8 @@ class TestStreamDecrypter implements StreamDecrypter {
|
||||
|
||||
public int readFrame(byte[] payload) throws IOException {
|
||||
int offset = 0;
|
||||
while (offset < HEADER_LENGTH) {
|
||||
int read = in.read(frame, offset, HEADER_LENGTH - offset);
|
||||
while (offset < FRAME_HEADER_LENGTH) {
|
||||
int read = in.read(frame, offset, FRAME_HEADER_LENGTH - offset);
|
||||
if (read == -1) throw new EOFException();
|
||||
offset += read;
|
||||
}
|
||||
@@ -37,9 +37,9 @@ class TestStreamDecrypter implements StreamDecrypter {
|
||||
offset += read;
|
||||
}
|
||||
if (!finalFrame && offset < frame.length) throw new EOFException();
|
||||
if (offset < HEADER_LENGTH + payloadLength + MAC_LENGTH)
|
||||
if (offset < FRAME_HEADER_LENGTH + payloadLength + MAC_LENGTH)
|
||||
throw new FormatException();
|
||||
System.arraycopy(frame, HEADER_LENGTH, payload, 0, payloadLength);
|
||||
System.arraycopy(frame, FRAME_HEADER_LENGTH, payload, 0, payloadLength);
|
||||
return payloadLength;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.briarproject.util.ByteUtils;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||
|
||||
@@ -31,11 +31,11 @@ class TestStreamEncrypter implements StreamEncrypter {
|
||||
}
|
||||
ByteUtils.writeUint16(payloadLength, frame, 0);
|
||||
if (finalFrame) frame[0] |= 0x80;
|
||||
System.arraycopy(payload, 0, frame, HEADER_LENGTH, payloadLength);
|
||||
for (int i = HEADER_LENGTH + payloadLength; i < frame.length; i++)
|
||||
System.arraycopy(payload, 0, frame, FRAME_HEADER_LENGTH, payloadLength);
|
||||
for (int i = FRAME_HEADER_LENGTH + payloadLength; i < frame.length; i++)
|
||||
frame[i] = 0;
|
||||
if (finalFrame)
|
||||
out.write(frame, 0, HEADER_LENGTH + payloadLength + MAC_LENGTH);
|
||||
out.write(frame, 0, FRAME_HEADER_LENGTH + payloadLength + MAC_LENGTH);
|
||||
else out.write(frame, 0, frame.length);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user