diff --git a/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java b/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java index a4738b56ddaecff8f2de9430769a9015ddc173c8..a874314165b0e3b6de8b38c93c443136e0d928a0 100644 --- a/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java +++ b/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java @@ -1,27 +1,255 @@ package org.briarproject.crypto; +import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; +import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; +import static org.junit.Assert.assertArrayEquals; + +import java.io.ByteArrayOutputStream; +import java.util.Random; + import org.briarproject.BriarTestCase; +import org.briarproject.api.crypto.AuthenticatedCipher; +import org.briarproject.api.crypto.SecretKey; import org.junit.Test; public class StreamEncrypterImplTest extends BriarTestCase { + private final AuthenticatedCipher frameCipher; + private final SecretKey frameKey; + private final byte[] tag; + + public StreamEncrypterImplTest() { + frameCipher = new TestAuthenticatedCipher(); + frameKey = new SecretKey(new byte[32]); + tag = new byte[TAG_LENGTH]; + new Random().nextBytes(tag); + } + + @Test + public void testWriteUnpaddedNonFinalFrameWithTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); + int payloadLength = 123; + byte[] payload = new byte[payloadLength]; + new 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[TAG_LENGTH + HEADER_LENGTH + payloadLength + + MAC_LENGTH]; + 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()); + } + + @Test + public void testWriteUnpaddedFinalFrameWithTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); + int payloadLength = 123; + byte[] payload = new byte[payloadLength]; + new 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 + HEADER_LENGTH + payloadLength + + MAC_LENGTH]; + 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()); + } + + @Test + public void testWriteUnpaddedNonFinalFrameWithoutTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); + int payloadLength = 123; + byte[] payload = new byte[payloadLength]; + new 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[HEADER_LENGTH + payloadLength + MAC_LENGTH]; + System.arraycopy(header, 0, expected, 0, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength); + assertArrayEquals(expected, out.toByteArray()); + } + @Test - public void testEncryptionWithoutTag() throws Exception { - // FIXME + public void testWriteUnpaddedFinalFrameWithoutTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); + int payloadLength = 123; + byte[] payload = new byte[payloadLength]; + new 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[HEADER_LENGTH + payloadLength + MAC_LENGTH]; + System.arraycopy(header, 0, expected, 0, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength); + assertArrayEquals(expected, out.toByteArray()); } @Test - public void testEncryptionWithTag() throws Exception { - // FIXME + public void testWritePaddedNonFinalFrameWithTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); + int payloadLength = 123, paddingLength = 234; + byte[] payload = new byte[payloadLength]; + new 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 + HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH]; + 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()); + } + + @Test + public void testWritePaddedFinalFrameWithTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); + int payloadLength = 123, paddingLength = 234; + byte[] payload = new byte[payloadLength]; + new 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 + HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH]; + 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()); + } + + @Test + public void testWritePaddedNonFinalFrameWithoutTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); + int payloadLength = 123, paddingLength = 234; + byte[] payload = new byte[payloadLength]; + new 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[HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH]; + System.arraycopy(header, 0, expected, 0, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength); + assertArrayEquals(expected, out.toByteArray()); + } + + @Test + public void testWritePaddedFinalFrameWithoutTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); + int payloadLength = 123, paddingLength = 234; + byte[] payload = new byte[payloadLength]; + new 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[HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH]; + System.arraycopy(header, 0, expected, 0, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength); + assertArrayEquals(expected, out.toByteArray()); + } + + @Test + public void testWriteTwoFrames() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); + int payloadLength = 123, paddingLength = 234; + byte[] payload = new byte[payloadLength]; + new Random().nextBytes(payload); + int payloadLength1 = 345, paddingLength1 = 456; + byte[] payload1 = new byte[payloadLength1]; + new 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, + paddingLength1); + byte[] expected = new byte[HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH + + HEADER_LENGTH + payloadLength1 + + paddingLength1 + MAC_LENGTH]; + System.arraycopy(header, 0, expected, 0, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength); + System.arraycopy(header1, 0, expected, HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH, HEADER_LENGTH); + System.arraycopy(payload1, 0, expected, HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH + HEADER_LENGTH, payloadLength1); + assertArrayEquals(expected, out.toByteArray()); } @Test public void testFlushWritesTagIfNotAlreadyWritten() throws Exception { - // FIXME + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); + s.flush(); + assertArrayEquals(tag, out.toByteArray()); } @Test public void testFlushDoesNotWriteTagIfAlreadyWritten() throws Exception { - // FIXME + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); + s.flush(); + s.flush(); + assertArrayEquals(tag, out.toByteArray()); + } + + @Test + public void testFlushDoesNotWriteTagIfNull() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); + s.flush(); + assertEquals(0, out.size()); } } diff --git a/briar-tests/src/org/briarproject/crypto/TestAuthenticatedCipher.java b/briar-tests/src/org/briarproject/crypto/TestAuthenticatedCipher.java new file mode 100644 index 0000000000000000000000000000000000000000..0271975bd43f5b64368486dbfdb2c5f0d9f0f64e --- /dev/null +++ b/briar-tests/src/org/briarproject/crypto/TestAuthenticatedCipher.java @@ -0,0 +1,45 @@ +package org.briarproject.crypto; + +import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; + +import java.security.GeneralSecurityException; + +import org.briarproject.api.crypto.AuthenticatedCipher; +import org.briarproject.api.crypto.SecretKey; + +class TestAuthenticatedCipher implements AuthenticatedCipher { + + private static final int BLOCK_BYTES = 16; + + private boolean encrypt = false; + + public void init(boolean encrypt, SecretKey key, byte[] iv, byte[] aad) + throws GeneralSecurityException { + this.encrypt = encrypt; + } + + public int process(byte[] input, int inputOff, int len, byte[] output, + int outputOff) throws GeneralSecurityException { + if(encrypt) { + System.arraycopy(input, inputOff, output, outputOff, len); + for(int i = 0; i < MAC_LENGTH; i++) + output[outputOff + len + i] = 0; + return len + MAC_LENGTH; + } else { + for(int i = 0; i < MAC_LENGTH; i++) + if(input[inputOff + len - MAC_LENGTH + i] != 0) + throw new GeneralSecurityException(); + System.arraycopy(input, inputOff, output, outputOff, + len - MAC_LENGTH); + return len - MAC_LENGTH; + } + } + + public int getMacLength() { + return MAC_LENGTH; + } + + public int getBlockSize() { + return BLOCK_BYTES; + } +}