diff --git a/api/net/sf/briar/api/plugins/SegmentSink.java b/api/net/sf/briar/api/plugins/SegmentSink.java index 8f017c96e27647a472a54fd2033475c76b428393..55caa493403d95c52e3f7d4599328ca095c44c8a 100644 --- a/api/net/sf/briar/api/plugins/SegmentSink.java +++ b/api/net/sf/briar/api/plugins/SegmentSink.java @@ -2,6 +2,8 @@ package net.sf.briar.api.plugins; import java.io.IOException; +import net.sf.briar.api.transport.Segment; + public interface SegmentSink { /** Writes the given segment. */ diff --git a/api/net/sf/briar/api/plugins/SegmentSource.java b/api/net/sf/briar/api/plugins/SegmentSource.java index bb5a92a18faddad1698425a62b4176749a711dd1..403659a0b1fc831f865db2c4418a7676a7e1ab63 100644 --- a/api/net/sf/briar/api/plugins/SegmentSource.java +++ b/api/net/sf/briar/api/plugins/SegmentSource.java @@ -2,6 +2,8 @@ package net.sf.briar.api.plugins; import java.io.IOException; +import net.sf.briar.api.transport.Segment; + public interface SegmentSource { /** diff --git a/api/net/sf/briar/api/transport/ConnectionReaderFactory.java b/api/net/sf/briar/api/transport/ConnectionReaderFactory.java index a886826af4bc076371b24004d50c93160702f391..ea079fb52f088c576a0ccaa83d5f1dbde63f17c4 100644 --- a/api/net/sf/briar/api/transport/ConnectionReaderFactory.java +++ b/api/net/sf/briar/api/transport/ConnectionReaderFactory.java @@ -2,6 +2,8 @@ package net.sf.briar.api.transport; import java.io.InputStream; +import net.sf.briar.api.plugins.SegmentSource; + public interface ConnectionReaderFactory { /** @@ -12,9 +14,23 @@ public interface ConnectionReaderFactory { ConnectionReader createConnectionReader(InputStream in, byte[] secret, byte[] tag); + /** + * Creates a connection reader for a simplex connection or the initiator's + * side of a duplex connection. The secret is erased before this method + * returns. + */ + ConnectionReader createConnectionReader(SegmentSource in, byte[] secret, + Segment buffered); + /** * Creates a connection reader for the responder's side of a duplex * connection. The secret is erased before this method returns. */ ConnectionReader createConnectionReader(InputStream in, byte[] secret); + + /** + * Creates a connection reader for the responder's side of a duplex + * connection. The secret is erased before this method returns. + */ + ConnectionReader createConnectionReader(SegmentSource in, byte[] secret); } diff --git a/api/net/sf/briar/api/plugins/Segment.java b/api/net/sf/briar/api/transport/Segment.java similarity index 82% rename from api/net/sf/briar/api/plugins/Segment.java rename to api/net/sf/briar/api/transport/Segment.java index b0eacf91045e4a4f6717036e8f2de1eb8d4c1881..da91745fa4140d803c2372774a9a835360edd503 100644 --- a/api/net/sf/briar/api/plugins/Segment.java +++ b/api/net/sf/briar/api/transport/Segment.java @@ -1,4 +1,4 @@ -package net.sf.briar.api.plugins; +package net.sf.briar.api.transport; public interface Segment { diff --git a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java index 6e0677abaf3fd9a9384ef8c683c9fe999dbe09f2..638ff48fba74098a75997df517fc76f4105454ff 100644 --- a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java +++ b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java @@ -7,8 +7,10 @@ import javax.crypto.Mac; import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.ErasableKey; +import net.sf.briar.api.plugins.SegmentSource; import net.sf.briar.api.transport.ConnectionReader; import net.sf.briar.api.transport.ConnectionReaderFactory; +import net.sf.briar.api.transport.Segment; import net.sf.briar.util.ByteUtils; import com.google.inject.Inject; @@ -24,22 +26,16 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory { public ConnectionReader createConnectionReader(InputStream in, byte[] secret, byte[] tag) { - // Validate the tag - Cipher tagCipher = crypto.getTagCipher(); - ErasableKey tagKey = crypto.deriveTagKey(secret, true); - long segmentNumber = TagEncoder.decodeTag(tag, tagCipher, tagKey); - tagKey.erase(); - if(segmentNumber != 0) throw new IllegalArgumentException(); - return createConnectionReader(in, true, secret); + return createConnectionReader(in, secret, tag, true); } public ConnectionReader createConnectionReader(InputStream in, byte[] secret) { - return createConnectionReader(in, false, secret); + return createConnectionReader(in, secret, null, false); } private ConnectionReader createConnectionReader(InputStream in, - boolean initiator, byte[] secret) { + byte[] secret, byte[] tag, boolean initiator) { // Derive the keys and erase the secret ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator); ErasableKey macKey = crypto.deriveMacKey(secret, initiator); @@ -50,7 +46,38 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory { Cipher frameCipher = crypto.getFrameCipher(); Mac mac = crypto.getMac(); IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, - tagCipher, frameCipher, tagKey, frameKey, false); + tagCipher, frameCipher, tagKey, frameKey, false, tag); + // No error correction + IncomingErrorCorrectionLayer correcter = + new NullIncomingErrorCorrectionLayer(decrypter); + // Create the reader + return new ConnectionReaderImpl(correcter, mac, macKey); + } + + public ConnectionReader createConnectionReader(SegmentSource in, + byte[] secret, Segment buffered) { + return createConnectionReader(in, secret, buffered, true); + } + + public ConnectionReader createConnectionReader(SegmentSource in, + byte[] secret) { + return createConnectionReader(in, secret, new SegmentImpl(), false); + } + + private ConnectionReader createConnectionReader(SegmentSource in, + byte[] secret, Segment buffered, boolean initiator) { + // Derive the keys and erase the secret + ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator); + ErasableKey macKey = crypto.deriveMacKey(secret, initiator); + ErasableKey tagKey = crypto.deriveTagKey(secret, initiator); + ByteUtils.erase(secret); + // Create the decrypter + Cipher tagCipher = crypto.getTagCipher(); + Cipher frameCipher = crypto.getFrameCipher(); + Mac mac = crypto.getMac(); + IncomingEncryptionLayer decrypter = + new IncomingSegmentedEncryptionLayer(in, tagCipher, frameCipher, + tagKey, frameKey, false, buffered); // No error correction IncomingErrorCorrectionLayer correcter = new NullIncomingErrorCorrectionLayer(decrypter); diff --git a/components/net/sf/briar/transport/IncomingEncryptionLayer.java b/components/net/sf/briar/transport/IncomingEncryptionLayer.java index c93681130c13ec5191952c0ae19f323e7b87eb42..84c8776c1164a99a91f27404c4e3a741c6422616 100644 --- a/components/net/sf/briar/transport/IncomingEncryptionLayer.java +++ b/components/net/sf/briar/transport/IncomingEncryptionLayer.java @@ -2,7 +2,7 @@ package net.sf.briar.transport; import java.io.IOException; -import net.sf.briar.api.plugins.Segment; +import net.sf.briar.api.transport.Segment; interface IncomingEncryptionLayer { diff --git a/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java b/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java index 447656ab66aa1b5b9bcb2b13365b636252ceb058..a0c7db71a99292d02d04f2619d6ff0c2c50319cd 100644 --- a/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java +++ b/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java @@ -16,7 +16,7 @@ import javax.crypto.spec.IvParameterSpec; import net.sf.briar.api.FormatException; import net.sf.briar.api.crypto.ErasableKey; -import net.sf.briar.api.plugins.Segment; +import net.sf.briar.api.transport.Segment; class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer { @@ -27,18 +27,20 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer { private final byte[] iv, ciphertext; private final boolean tagEverySegment; + private byte[] bufferedTag; private boolean firstSegment = true; private long segmentNumber = 0L; IncomingEncryptionLayerImpl(InputStream in, Cipher tagCipher, Cipher frameCipher, ErasableKey tagKey, ErasableKey frameKey, - boolean tagEverySegment) { + boolean tagEverySegment, byte[] bufferedTag) { this.in = in; this.tagCipher = tagCipher; this.frameCipher = frameCipher; this.tagKey = tagKey; this.frameKey = frameKey; this.tagEverySegment = tagEverySegment; + this.bufferedTag = bufferedTag; blockSize = frameCipher.getBlockSize(); if(blockSize < FRAME_HEADER_LENGTH) throw new IllegalArgumentException(); @@ -47,29 +49,41 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer { } public boolean readSegment(Segment s) throws IOException { - boolean tag = tagEverySegment && !firstSegment; + boolean expectTag = tagEverySegment || firstSegment; + firstSegment = false; try { - // If a tag is expected then read, decrypt and validate it - if(tag) { - int offset = 0; - while(offset < TAG_LENGTH) { - int read = in.read(ciphertext, offset, TAG_LENGTH - offset); - if(read == -1) { - if(offset == 0) return false; - throw new EOFException(); + if(expectTag) { + // Read the tag if we don't have one buffered + if(bufferedTag == null) { + int offset = 0; + while(offset < TAG_LENGTH) { + int read = in.read(ciphertext, offset, + TAG_LENGTH - offset); + if(read == -1) { + if(offset == 0) return false; + throw new EOFException(); + } + offset += read; } - offset += read; + long seg = TagEncoder.decodeTag(ciphertext, tagCipher, + tagKey); + if(seg == -1) throw new FormatException(); + segmentNumber = seg; + } else { + System.out.println("Buffered tag"); + long seg = TagEncoder.decodeTag(bufferedTag, tagCipher, + tagKey); + bufferedTag = null; + if(seg == -1) throw new FormatException(); + segmentNumber = seg; } - long seg = TagEncoder.decodeTag(ciphertext, tagCipher, tagKey); - if(seg == -1) throw new FormatException(); - segmentNumber = seg; } // Read the first block of the frame/segment int offset = 0; while(offset < blockSize) { int read = in.read(ciphertext, offset, blockSize - offset); if(read == -1) { - if(offset == 0 && !tag && !firstSegment) return false; + if(offset == 0 && !expectTag) return false; throw new EOFException(); } offset += read; @@ -108,7 +122,6 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer { } s.setLength(length); s.setSegmentNumber(segmentNumber++); - firstSegment = false; return true; } catch(IOException e) { frameKey.erase(); diff --git a/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java b/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java index 21caee2ce62e915b11bcc53ad437947660840b82..6c396e79ec400f9ef485eb6e8e6d7b2823bad168 100644 --- a/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java +++ b/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java @@ -13,8 +13,8 @@ import javax.crypto.spec.IvParameterSpec; import net.sf.briar.api.FormatException; import net.sf.briar.api.crypto.ErasableKey; -import net.sf.briar.api.plugins.Segment; import net.sf.briar.api.plugins.SegmentSource; +import net.sf.briar.api.transport.Segment; class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer { @@ -23,15 +23,16 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer { private final ErasableKey tagKey, frameKey; private final int blockSize; private final byte[] iv; - private final Segment segment; private final boolean tagEverySegment; + private final Segment segment; + private Segment bufferedSegment; private boolean firstSegment = true; private long segmentNumber = 0L; IncomingSegmentedEncryptionLayer(SegmentSource in, Cipher tagCipher, Cipher frameCipher, ErasableKey tagKey, ErasableKey frameKey, - boolean tagEverySegment) { + boolean tagEverySegment, Segment s) { this.in = in; this.tagCipher = tagCipher; this.frameCipher = frameCipher; @@ -43,20 +44,30 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer { throw new IllegalArgumentException(); iv = IvEncoder.encodeIv(0L, blockSize); segment = new SegmentImpl(); + bufferedSegment = s; } public boolean readSegment(Segment s) throws IOException { - boolean tag = tagEverySegment && !firstSegment; + boolean expectTag = tagEverySegment || firstSegment; + firstSegment = false; try { - // Read the segment - if(!in.readSegment(segment)) return false; - int offset = tag ? TAG_LENGTH : 0, length = segment.getLength(); + // Read the segment, unless we have one buffered + Segment segment; + if(bufferedSegment == null) { + segment = this.segment; + if(!in.readSegment(segment)) return false; + } else { + segment = bufferedSegment; + bufferedSegment = null; + } + int offset = expectTag ? TAG_LENGTH : 0; + int length = segment.getLength(); if(length > MAX_SEGMENT_LENGTH) throw new FormatException(); if(length < offset + FRAME_HEADER_LENGTH + MAC_LENGTH) throw new FormatException(); byte[] ciphertext = segment.getBuffer(); // If a tag is expected then decrypt and validate it - if(tag) { + if(expectTag) { long seg = TagEncoder.decodeTag(ciphertext, tagCipher, tagKey); if(seg == -1) throw new FormatException(); segmentNumber = seg; @@ -74,7 +85,6 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer { } s.setLength(length - offset); s.setSegmentNumber(segmentNumber++); - firstSegment = false; return true; } catch(IOException e) { frameKey.erase(); diff --git a/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java b/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java index cd97383c7c08bebd7f153bf0219d741756a6c47f..53898dc9f953dd40d7522082ca70e5d87c0db7fa 100644 --- a/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java +++ b/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java @@ -3,7 +3,7 @@ package net.sf.briar.transport; import java.io.IOException; import java.util.Collection; -import net.sf.briar.api.plugins.Segment; +import net.sf.briar.api.transport.Segment; class NullIncomingErrorCorrectionLayer implements IncomingErrorCorrectionLayer { diff --git a/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java b/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java index 9bf37eac5253a85a8d649128e7907c2ebb55fd57..c0719e2ead3745148f84945dd45d136be67fa332 100644 --- a/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java +++ b/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java @@ -4,7 +4,7 @@ import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED; import java.io.IOException; -import net.sf.briar.api.plugins.Segment; +import net.sf.briar.api.transport.Segment; class NullOutgoingErrorCorrectionLayer implements OutgoingErrorCorrectionLayer { diff --git a/components/net/sf/briar/transport/OutgoingEncryptionLayer.java b/components/net/sf/briar/transport/OutgoingEncryptionLayer.java index fecc03d286118d8f86ef08b4b0fc99f7a8649d20..e3b11cfe2ee0c25e3b6ff7d4786a56583e7e1eb2 100644 --- a/components/net/sf/briar/transport/OutgoingEncryptionLayer.java +++ b/components/net/sf/briar/transport/OutgoingEncryptionLayer.java @@ -2,7 +2,7 @@ package net.sf.briar.transport; import java.io.IOException; -import net.sf.briar.api.plugins.Segment; +import net.sf.briar.api.transport.Segment; interface OutgoingEncryptionLayer { diff --git a/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java b/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java index 5a3ff9d0927b9148fd5d153a068cb7bb3641eeaf..c0aa5942ceaa0b749c1c36e53fc668b2118e7369 100644 --- a/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java +++ b/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java @@ -11,7 +11,7 @@ import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import net.sf.briar.api.crypto.ErasableKey; -import net.sf.briar.api.plugins.Segment; +import net.sf.briar.api.transport.Segment; class OutgoingEncryptionLayerImpl implements OutgoingEncryptionLayer { diff --git a/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java b/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java index 2bf1864454a209019cd261376ff3c8f4d80482d3..e5c66522c939980d96cdc89582f4011a283510f1 100644 --- a/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java +++ b/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java @@ -9,8 +9,8 @@ import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import net.sf.briar.api.crypto.ErasableKey; -import net.sf.briar.api.plugins.Segment; import net.sf.briar.api.plugins.SegmentSink; +import net.sf.briar.api.transport.Segment; class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer { diff --git a/components/net/sf/briar/transport/SegmentImpl.java b/components/net/sf/briar/transport/SegmentImpl.java index da3d4eab391387085857776978dc219a494b4fd9..8cd7acc549b924109a2fd9a35567f7c4647eea1c 100644 --- a/components/net/sf/briar/transport/SegmentImpl.java +++ b/components/net/sf/briar/transport/SegmentImpl.java @@ -1,7 +1,7 @@ package net.sf.briar.transport; import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH; -import net.sf.briar.api.plugins.Segment; +import net.sf.briar.api.transport.Segment; import net.sf.briar.util.ByteUtils; class SegmentImpl implements Segment { diff --git a/test/net/sf/briar/transport/FrameReadWriteTest.java b/test/net/sf/briar/transport/FrameReadWriteTest.java index 465e85e3ebcf87ef4ac97e2618af0774cacc913c..37ec138af12afc45a03e16e7d91e2414c670d321 100644 --- a/test/net/sf/briar/transport/FrameReadWriteTest.java +++ b/test/net/sf/briar/transport/FrameReadWriteTest.java @@ -94,7 +94,7 @@ public class FrameReadWriteTest extends BriarTestCase { assertEquals(0L, TagEncoder.decodeTag(tag, tagCipher, tagKey)); // Read the frames back IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, - tagCipher, frameCipher, tagKey, frameKey, false); + tagCipher, frameCipher, tagKey, frameKey, false, recoveredTag); IncomingErrorCorrectionLayer correcter1 = new NullIncomingErrorCorrectionLayer(decrypter); ConnectionReader reader = new ConnectionReaderImpl(correcter1, mac, diff --git a/test/net/sf/briar/transport/IncomingEncryptionLayerImplTest.java b/test/net/sf/briar/transport/IncomingEncryptionLayerImplTest.java index 4db4ed9297a28b9e957e464f3f4a0229db82d73e..75bec7f4b5f9f56de5ba5b166757169e31354c5c 100644 --- a/test/net/sf/briar/transport/IncomingEncryptionLayerImplTest.java +++ b/test/net/sf/briar/transport/IncomingEncryptionLayerImplTest.java @@ -12,7 +12,7 @@ import javax.crypto.spec.IvParameterSpec; import net.sf.briar.BriarTestCase; import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.ErasableKey; -import net.sf.briar.api.plugins.Segment; +import net.sf.briar.api.transport.Segment; import net.sf.briar.crypto.CryptoModule; import org.apache.commons.io.output.ByteArrayOutputStream; @@ -38,6 +38,9 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase { @Test public void testDecryptionWithFirstSegmentTagged() throws Exception { + // Calculate the tag for the first segment + byte[] tag = new byte[TAG_LENGTH]; + TagEncoder.encodeTag(tag, 0L, tagCipher, tagKey); // Calculate the ciphertext for the first segment byte[] plaintext = new byte[FRAME_HEADER_LENGTH + 123 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext, 0L, 123, 0); @@ -53,15 +56,15 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase { frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); byte[] ciphertext1 = frameCipher.doFinal(plaintext1, 0, plaintext1.length); - // Concatenate the ciphertexts + // Concatenate the ciphertexts, excluding the first tag ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write(ciphertext); out.write(ciphertext1); ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); // Use the encryption layer to decrypt the ciphertext IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, - tagCipher, frameCipher, tagKey, frameKey, false); - // First frame + tagCipher, frameCipher, tagKey, frameKey, false, tag); + // First segment Segment s = new SegmentImpl(); assertTrue(decrypter.readSegment(s)); assertEquals(plaintext.length, s.getLength()); @@ -70,7 +73,7 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase { for(int i = 0; i < plaintext.length; i++) { assertEquals(plaintext[i], decrypted[i]); } - // Second frame + // Second segment assertTrue(decrypter.readSegment(s)); assertEquals(plaintext1.length, s.getLength()); assertEquals(1L, s.getSegmentNumber()); @@ -82,6 +85,9 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase { @Test public void testDecryptionWithEverySegmentTagged() throws Exception { + // Calculate the tag for the first segment + byte[] tag = new byte[TAG_LENGTH]; + TagEncoder.encodeTag(tag, 0L, tagCipher, tagKey); // Calculate the ciphertext for the first segment byte[] plaintext = new byte[FRAME_HEADER_LENGTH + 123 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext, 0L, 123, 0); @@ -89,25 +95,27 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase { IvParameterSpec ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); byte[] ciphertext = frameCipher.doFinal(plaintext, 0, plaintext.length); - // Calculate the ciphertext for the second segment, including its tag + // Calculate the tag for the second segment + byte[] tag1 = new byte[TAG_LENGTH]; + TagEncoder.encodeTag(tag1, 1L, tagCipher, tagKey); + // Calculate the ciphertext for the second segment byte[] plaintext1 = new byte[FRAME_HEADER_LENGTH + 1234 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext1, 1L, 1234, 0); - byte[] ciphertext1 = new byte[TAG_LENGTH + plaintext1.length]; - TagEncoder.encodeTag(ciphertext1, 1L, tagCipher, tagKey); IvEncoder.updateIv(iv, 1L); ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); - frameCipher.doFinal(plaintext1, 0, plaintext1.length, ciphertext1, - TAG_LENGTH); - // Concatenate the ciphertexts + byte[] ciphertext1 = frameCipher.doFinal(plaintext1, 0, + plaintext1.length); + // Concatenate the ciphertexts, excluding the first tag ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write(ciphertext); + out.write(tag1); out.write(ciphertext1); ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); // Use the encryption layer to decrypt the ciphertext IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, - tagCipher, frameCipher, tagKey, frameKey, true); - // First frame + tagCipher, frameCipher, tagKey, frameKey, true, tag); + // First segment Segment s = new SegmentImpl(); assertTrue(decrypter.readSegment(s)); assertEquals(plaintext.length, s.getLength()); @@ -116,7 +124,7 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase { for(int i = 0; i < plaintext.length; i++) { assertEquals(plaintext[i], decrypted[i]); } - // Second frame + // Second segment assertTrue(decrypter.readSegment(s)); assertEquals(plaintext1.length, s.getLength()); assertEquals(1L, s.getSegmentNumber()); diff --git a/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java b/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java index fbcf8cc78c226dd2b7626e9dd7794a64830db845..9439a8482013f019a44ecd7701a8112dffae2ded 100644 --- a/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java +++ b/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java @@ -12,8 +12,8 @@ import javax.crypto.spec.IvParameterSpec; import net.sf.briar.BriarTestCase; import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.ErasableKey; -import net.sf.briar.api.plugins.Segment; import net.sf.briar.api.plugins.SegmentSource; +import net.sf.briar.api.transport.Segment; import net.sf.briar.crypto.CryptoModule; import org.junit.Test; @@ -38,13 +38,16 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase { @Test public void testDecryptionWithFirstSegmentTagged() throws Exception { - // Calculate the ciphertext for the first segment + // Calculate the ciphertext for the first segment, including its tag byte[] plaintext = new byte[FRAME_HEADER_LENGTH + 123 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext, 0L, 123, 0); + byte[] ciphertext = new byte[TAG_LENGTH + plaintext.length]; + TagEncoder.encodeTag(ciphertext, 0L, tagCipher, tagKey); byte[] iv = IvEncoder.encodeIv(0L, frameCipher.getBlockSize()); IvParameterSpec ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); - byte[] ciphertext = frameCipher.doFinal(plaintext, 0, plaintext.length); + frameCipher.doFinal(plaintext, 0, plaintext.length, ciphertext, + TAG_LENGTH); // Calculate the ciphertext for the second segment byte[] plaintext1 = new byte[FRAME_HEADER_LENGTH + 1234 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext1, 1L, 1234, 0); @@ -53,13 +56,17 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase { frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); byte[] ciphertext1 = frameCipher.doFinal(plaintext1, 0, plaintext1.length); + // Buffer the first segment and create a source for the second + Segment buffered = new SegmentImpl(); + System.arraycopy(ciphertext, 0, buffered.getBuffer(), 0, + ciphertext.length); + buffered.setLength(ciphertext.length); + SegmentSource in = new ByteArraySegmentSource(ciphertext1); // Use the encryption layer to decrypt the ciphertext - byte[][] frames = new byte[][] { ciphertext, ciphertext1 }; - SegmentSource in = new ByteArraySegmentSource(frames); IncomingEncryptionLayer decrypter = new IncomingSegmentedEncryptionLayer(in, tagCipher, frameCipher, - tagKey, frameKey, false); - // First frame + tagKey, frameKey, false, buffered); + // First segment Segment s = new SegmentImpl(); assertTrue(decrypter.readSegment(s)); assertEquals(plaintext.length, s.getLength()); @@ -68,7 +75,7 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase { for(int i = 0; i < plaintext.length; i++) { assertEquals(plaintext[i], decrypted[i]); } - // Second frame + // Second segment assertTrue(decrypter.readSegment(s)); assertEquals(plaintext1.length, s.getLength()); assertEquals(1L, s.getSegmentNumber()); @@ -80,13 +87,16 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase { @Test public void testDecryptionWithEverySegmentTagged() throws Exception { - // Calculate the ciphertext for the first frame + // Calculate the ciphertext for the first segment, including its tag byte[] plaintext = new byte[FRAME_HEADER_LENGTH + 123 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext, 0L, 123, 0); + byte[] ciphertext = new byte[TAG_LENGTH + plaintext.length]; + TagEncoder.encodeTag(ciphertext, 0L, tagCipher, tagKey); byte[] iv = IvEncoder.encodeIv(0L, frameCipher.getBlockSize()); IvParameterSpec ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); - byte[] ciphertext = frameCipher.doFinal(plaintext, 0, plaintext.length); + frameCipher.doFinal(plaintext, 0, plaintext.length, ciphertext, + TAG_LENGTH); // Calculate the ciphertext for the second frame, including its tag byte[] plaintext1 = new byte[FRAME_HEADER_LENGTH + 1234 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext1, 1L, 1234, 0); @@ -97,13 +107,17 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase { frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); frameCipher.doFinal(plaintext1, 0, plaintext1.length, ciphertext1, TAG_LENGTH); + // Buffer the first segment and create a source for the second + Segment buffered = new SegmentImpl(); + System.arraycopy(ciphertext, 0, buffered.getBuffer(), 0, + ciphertext.length); + buffered.setLength(ciphertext.length); + SegmentSource in = new ByteArraySegmentSource(ciphertext1); // Use the encryption layer to decrypt the ciphertext - byte[][] frames = new byte[][] { ciphertext, ciphertext1 }; - SegmentSource in = new ByteArraySegmentSource(frames); IncomingEncryptionLayer decrypter = new IncomingSegmentedEncryptionLayer(in, tagCipher, frameCipher, - tagKey, frameKey, true); - // First frame + tagKey, frameKey, true, buffered); + // First segment Segment s = new SegmentImpl(); assertTrue(decrypter.readSegment(s)); assertEquals(plaintext.length, s.getLength()); @@ -112,7 +126,7 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase { for(int i = 0; i < plaintext.length; i++) { assertEquals(plaintext[i], decrypted[i]); } - // Second frame + // Second segment assertTrue(decrypter.readSegment(s)); assertEquals(plaintext1.length, s.getLength()); assertEquals(1L, s.getSegmentNumber()); @@ -124,20 +138,15 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase { private static class ByteArraySegmentSource implements SegmentSource { - private final byte[][] segments; - - private int segmentNumber = 0; + private final byte[] segment; - private ByteArraySegmentSource(byte[][] frames) { - this.segments = frames; + private ByteArraySegmentSource(byte[] segment) { + this.segment = segment; } public boolean readSegment(Segment s) throws IOException { - if(segmentNumber == segments.length) return false; - byte[] src = segments[segmentNumber]; - System.arraycopy(src, 0, s.getBuffer(), 0, src.length); - s.setLength(src.length); - segmentNumber++; + System.arraycopy(segment, 0, s.getBuffer(), 0, segment.length); + s.setLength(segment.length); return true; } } diff --git a/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java b/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java index 057bcea77bb6753f5cbacb900eaefc58bf76cedd..6be55a3a74ec8080643d7a3a93d00083fe6e2b5f 100644 --- a/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java +++ b/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java @@ -9,7 +9,7 @@ import java.io.IOException; import java.io.InputStream; import net.sf.briar.api.FormatException; -import net.sf.briar.api.plugins.Segment; +import net.sf.briar.api.transport.Segment; /** An encryption layer that performs no encryption. */ class NullIncomingEncryptionLayer implements IncomingEncryptionLayer { diff --git a/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java b/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java index ed8ff5d55956654d62973fb027ba9b4ae7de3aa5..574b404c1b67067b942efd72f54e3c2478f8fc26 100644 --- a/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java +++ b/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java @@ -3,7 +3,7 @@ package net.sf.briar.transport; import java.io.IOException; import java.io.OutputStream; -import net.sf.briar.api.plugins.Segment; +import net.sf.briar.api.transport.Segment; /** An encryption layer that performs no encryption. */ class NullOutgoingEncryptionLayer implements OutgoingEncryptionLayer { diff --git a/test/net/sf/briar/transport/OutgoingEncryptionLayerImplTest.java b/test/net/sf/briar/transport/OutgoingEncryptionLayerImplTest.java index bd1246e965560f5434b5bf48cf7284e3097712bc..c0f3a903697bd6ed8b994bf11e2fef939bde5753 100644 --- a/test/net/sf/briar/transport/OutgoingEncryptionLayerImplTest.java +++ b/test/net/sf/briar/transport/OutgoingEncryptionLayerImplTest.java @@ -11,7 +11,7 @@ import javax.crypto.spec.IvParameterSpec; import net.sf.briar.BriarTestCase; import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.ErasableKey; -import net.sf.briar.api.plugins.Segment; +import net.sf.briar.api.transport.Segment; import net.sf.briar.crypto.CryptoModule; import org.junit.Test; diff --git a/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java b/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java index 42668013602ebd52c02c1bab33d215fbfd19b261..378b515d1d09505029d1a0a90808419ff87cb6fa 100644 --- a/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java +++ b/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java @@ -12,8 +12,8 @@ import javax.crypto.spec.IvParameterSpec; import net.sf.briar.BriarTestCase; import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.ErasableKey; -import net.sf.briar.api.plugins.Segment; import net.sf.briar.api.plugins.SegmentSink; +import net.sf.briar.api.transport.Segment; import net.sf.briar.crypto.CryptoModule; import org.junit.Test;