From dbeb7a207e92d8b6da62a363a25d07c37fe8a58a Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Tue, 17 Jan 2012 20:21:26 +0000 Subject: [PATCH] Added factory methods for segmented connection readers. --- api/net/sf/briar/api/plugins/SegmentSink.java | 2 + .../sf/briar/api/plugins/SegmentSource.java | 2 + .../transport/ConnectionReaderFactory.java | 16 +++++ .../api/{plugins => transport}/Segment.java | 2 +- .../ConnectionReaderFactoryImpl.java | 47 +++++++++++---- .../transport/IncomingEncryptionLayer.java | 2 +- .../IncomingEncryptionLayerImpl.java | 47 +++++++++------ .../IncomingSegmentedEncryptionLayer.java | 28 ++++++--- .../NullIncomingErrorCorrectionLayer.java | 2 +- .../NullOutgoingErrorCorrectionLayer.java | 2 +- .../transport/OutgoingEncryptionLayer.java | 2 +- .../OutgoingEncryptionLayerImpl.java | 2 +- .../OutgoingSegmentedEncryptionLayer.java | 2 +- .../net/sf/briar/transport/SegmentImpl.java | 2 +- .../briar/transport/FrameReadWriteTest.java | 2 +- .../IncomingEncryptionLayerImplTest.java | 36 ++++++----- .../IncomingSegmentedEncryptionLayerTest.java | 59 +++++++++++-------- .../NullIncomingEncryptionLayer.java | 2 +- .../NullOutgoingEncryptionLayer.java | 2 +- .../OutgoingEncryptionLayerImplTest.java | 2 +- .../OutgoingSegmentedEncryptionLayerTest.java | 2 +- 21 files changed, 175 insertions(+), 88 deletions(-) rename api/net/sf/briar/api/{plugins => transport}/Segment.java (82%) diff --git a/api/net/sf/briar/api/plugins/SegmentSink.java b/api/net/sf/briar/api/plugins/SegmentSink.java index 8f017c96e2..55caa49340 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 bb5a92a18f..403659a0b1 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 a886826af4..ea079fb52f 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 b0eacf9104..da91745fa4 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 6e0677abaf..638ff48fba 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 c93681130c..84c8776c11 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 447656ab66..a0c7db71a9 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 21caee2ce6..6c396e79ec 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 cd97383c7c..53898dc9f9 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 9bf37eac52..c0719e2ead 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 fecc03d286..e3b11cfe2e 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 5a3ff9d092..c0aa5942ce 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 2bf1864454..e5c66522c9 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 da3d4eab39..8cd7acc549 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 465e85e3eb..37ec138af1 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 4db4ed9297..75bec7f4b5 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 fbcf8cc78c..9439a84820 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 057bcea77b..6be55a3a74 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 ed8ff5d559..574b404c1b 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 bd1246e965..c0f3a90369 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 4266801360..378b515d1d 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; -- GitLab