From aabb8fb5b3495e5f87c53735827c5c75de3eb014 Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Thu, 19 Jan 2012 20:51:45 +0000 Subject: [PATCH] Split the functionality of ConnectionWriterImpl into layers. --- .../ConnectionReaderFactoryImpl.java | 24 ++++----- .../ConnectionWriterFactoryImpl.java | 34 ++++++++---- .../briar/transport/ConnectionWriterImpl.java | 34 ++---------- .../NullOutgoingReliabilityLayer.java | 24 +++++++++ .../OutgoingAuthenticationLayer.java | 15 ++++++ .../OutgoingAuthenticationLayerImpl.java | 52 +++++++++++++++++++ .../transport/OutgoingReliabilityLayer.java | 15 ++++++ .../transport/ConnectionReaderImplTest.java | 13 ++--- .../transport/ConnectionWriterImplTest.java | 43 +++++++-------- .../briar/transport/FrameReadWriteTest.java | 34 ++++++------ 10 files changed, 190 insertions(+), 98 deletions(-) create mode 100644 components/net/sf/briar/transport/NullOutgoingReliabilityLayer.java create mode 100644 components/net/sf/briar/transport/OutgoingAuthenticationLayer.java create mode 100644 components/net/sf/briar/transport/OutgoingAuthenticationLayerImpl.java create mode 100644 components/net/sf/briar/transport/OutgoingReliabilityLayer.java diff --git a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java index f587991f2d..95c0524571 100644 --- a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java +++ b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java @@ -44,18 +44,18 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory { // Create the decrypter Cipher tagCipher = crypto.getTagCipher(); Cipher segCipher = crypto.getSegmentCipher(); - IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, + IncomingEncryptionLayer encryption = new IncomingEncryptionLayerImpl(in, tagCipher, segCipher, tagKey, segKey, false, bufferedTag); // No error correction - IncomingErrorCorrectionLayer correcter = - new NullIncomingErrorCorrectionLayer(decrypter); + IncomingErrorCorrectionLayer correction = + new NullIncomingErrorCorrectionLayer(encryption); // Create the authenticator Mac mac = crypto.getMac(); - IncomingAuthenticationLayer authenticator = - new IncomingAuthenticationLayerImpl(correcter, mac, macKey); + IncomingAuthenticationLayer authentication = + new IncomingAuthenticationLayerImpl(correction, mac, macKey); // No reordering or retransmission IncomingReliabilityLayer reliability = - new NullIncomingReliabilityLayer(authenticator); + new NullIncomingReliabilityLayer(authentication); // Create the reader - don't tolerate errors return new ConnectionReaderImpl(reliability, false); } @@ -80,19 +80,19 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory { // Create the decrypter Cipher tagCipher = crypto.getTagCipher(); Cipher segCipher = crypto.getSegmentCipher(); - IncomingEncryptionLayer decrypter = + IncomingEncryptionLayer encryption = new IncomingSegmentedEncryptionLayer(in, tagCipher, segCipher, tagKey, segKey, false, bufferedSegment); // No error correction - IncomingErrorCorrectionLayer correcter = - new NullIncomingErrorCorrectionLayer(decrypter); + IncomingErrorCorrectionLayer correction = + new NullIncomingErrorCorrectionLayer(encryption); // Create the authenticator Mac mac = crypto.getMac(); - IncomingAuthenticationLayer authenticator = - new IncomingAuthenticationLayerImpl(correcter, mac, macKey); + IncomingAuthenticationLayer authentication = + new IncomingAuthenticationLayerImpl(correction, mac, macKey); // No reordering or retransmission IncomingReliabilityLayer reliability = - new NullIncomingReliabilityLayer(authenticator); + new NullIncomingReliabilityLayer(authentication); // Create the reader - don't tolerate errors return new ConnectionReaderImpl(reliability, false); } diff --git a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java index 067e041952..6382955245 100644 --- a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java +++ b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java @@ -33,14 +33,20 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory { // Create the encrypter Cipher tagCipher = crypto.getTagCipher(); Cipher segCipher = crypto.getSegmentCipher(); - OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out, - capacity, tagCipher, segCipher, tagKey, segKey, false); + OutgoingEncryptionLayer encryption = new OutgoingEncryptionLayerImpl( + out, capacity, tagCipher, segCipher, tagKey, segKey, false); // No error correction - OutgoingErrorCorrectionLayer correcter = - new NullOutgoingErrorCorrectionLayer(encrypter); - // Create the writer + OutgoingErrorCorrectionLayer correction = + new NullOutgoingErrorCorrectionLayer(encryption); + // Authentication Mac mac = crypto.getMac(); - return new ConnectionWriterImpl(correcter, mac, macKey); + OutgoingAuthenticationLayer authentication = + new OutgoingAuthenticationLayerImpl(correction, mac, macKey); + // No retransmission + OutgoingReliabilityLayer reliability = + new NullOutgoingReliabilityLayer(authentication); + // Create the writer + return new ConnectionWriterImpl(reliability); } public ConnectionWriter createConnectionWriter(SegmentSink out, @@ -53,14 +59,20 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory { // Create the encrypter Cipher tagCipher = crypto.getTagCipher(); Cipher segCipher = crypto.getSegmentCipher(); - OutgoingEncryptionLayer encrypter = + OutgoingEncryptionLayer encryption = new OutgoingSegmentedEncryptionLayer(out, capacity, tagCipher, segCipher, tagKey, segKey, false); // No error correction - OutgoingErrorCorrectionLayer correcter = - new NullOutgoingErrorCorrectionLayer(encrypter); - // Create the writer + OutgoingErrorCorrectionLayer correction = + new NullOutgoingErrorCorrectionLayer(encryption); + // Authentication Mac mac = crypto.getMac(); - return new ConnectionWriterImpl(correcter, mac, macKey); + OutgoingAuthenticationLayer authentication = + new OutgoingAuthenticationLayerImpl(correction, mac, macKey); + // No retransmission + OutgoingReliabilityLayer reliability = + new NullOutgoingReliabilityLayer(authentication); + // Create the writer + return new ConnectionWriterImpl(reliability); } } diff --git a/components/net/sf/briar/transport/ConnectionWriterImpl.java b/components/net/sf/briar/transport/ConnectionWriterImpl.java index 9a7ad2efca..d1fcbd7a0d 100644 --- a/components/net/sf/briar/transport/ConnectionWriterImpl.java +++ b/components/net/sf/briar/transport/ConnectionWriterImpl.java @@ -7,12 +7,7 @@ import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED; import java.io.IOException; import java.io.OutputStream; -import java.security.InvalidKeyException; -import javax.crypto.Mac; -import javax.crypto.ShortBufferException; - -import net.sf.briar.api.crypto.ErasableKey; import net.sf.briar.api.transport.ConnectionWriter; /** @@ -23,26 +18,14 @@ import net.sf.briar.api.transport.ConnectionWriter; */ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter { - private final OutgoingErrorCorrectionLayer out; - private final Mac mac; + private final OutgoingReliabilityLayer out; private final Frame frame; private int offset = FRAME_HEADER_LENGTH; private long frameNumber = 0L; - ConnectionWriterImpl(OutgoingErrorCorrectionLayer out, Mac mac, - ErasableKey macKey) { + ConnectionWriterImpl(OutgoingReliabilityLayer out) { this.out = out; - this.mac = mac; - // Initialise the MAC - try { - mac.init(macKey); - } catch(InvalidKeyException badKey) { - throw new IllegalArgumentException(badKey); - } - macKey.erase(); - if(mac.getMacLength() != MAC_LENGTH) - throw new IllegalArgumentException(); frame = new Frame(); } @@ -96,16 +79,9 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter { private void writeFrame() throws IOException { if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException(); - byte[] buf = frame.getBuffer(); - int payloadLength = offset - FRAME_HEADER_LENGTH; - assert payloadLength > 0; - HeaderEncoder.encodeHeader(buf, frameNumber, payloadLength, 0); - mac.update(buf, 0, offset); - try { - mac.doFinal(buf, offset); - } catch(ShortBufferException badMac) { - throw new RuntimeException(badMac); - } + int payload = offset - FRAME_HEADER_LENGTH; + assert payload > 0; + HeaderEncoder.encodeHeader(frame.getBuffer(), frameNumber, payload, 0); frame.setLength(offset + MAC_LENGTH); out.writeFrame(frame); offset = FRAME_HEADER_LENGTH; diff --git a/components/net/sf/briar/transport/NullOutgoingReliabilityLayer.java b/components/net/sf/briar/transport/NullOutgoingReliabilityLayer.java new file mode 100644 index 0000000000..a00a2e9c4e --- /dev/null +++ b/components/net/sf/briar/transport/NullOutgoingReliabilityLayer.java @@ -0,0 +1,24 @@ +package net.sf.briar.transport; + +import java.io.IOException; + +class NullOutgoingReliabilityLayer implements OutgoingReliabilityLayer { + + private final OutgoingAuthenticationLayer out; + + NullOutgoingReliabilityLayer(OutgoingAuthenticationLayer out) { + this.out = out; + } + + public void writeFrame(Frame f) throws IOException { + out.writeFrame(f); + } + + public void flush() throws IOException { + out.flush(); + } + + public long getRemainingCapacity() { + return out.getRemainingCapacity(); + } +} diff --git a/components/net/sf/briar/transport/OutgoingAuthenticationLayer.java b/components/net/sf/briar/transport/OutgoingAuthenticationLayer.java new file mode 100644 index 0000000000..e1b9b72b6d --- /dev/null +++ b/components/net/sf/briar/transport/OutgoingAuthenticationLayer.java @@ -0,0 +1,15 @@ +package net.sf.briar.transport; + +import java.io.IOException; + +interface OutgoingAuthenticationLayer { + + /** Writes the given frame. */ + void writeFrame(Frame f) throws IOException; + + /** Flushes the stack. */ + void flush() throws IOException; + + /** Returns the maximum number of bytes that can be written. */ + long getRemainingCapacity(); +} diff --git a/components/net/sf/briar/transport/OutgoingAuthenticationLayerImpl.java b/components/net/sf/briar/transport/OutgoingAuthenticationLayerImpl.java new file mode 100644 index 0000000000..c8cee560b4 --- /dev/null +++ b/components/net/sf/briar/transport/OutgoingAuthenticationLayerImpl.java @@ -0,0 +1,52 @@ +package net.sf.briar.transport; + +import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; + +import java.io.IOException; +import java.security.InvalidKeyException; + +import javax.crypto.Mac; +import javax.crypto.ShortBufferException; + +import net.sf.briar.api.crypto.ErasableKey; + +class OutgoingAuthenticationLayerImpl implements OutgoingAuthenticationLayer { + + private final OutgoingErrorCorrectionLayer out; + private final Mac mac; + + OutgoingAuthenticationLayerImpl(OutgoingErrorCorrectionLayer out, Mac mac, + ErasableKey macKey) { + this.out = out; + this.mac = mac; + // Initialise the MAC + try { + mac.init(macKey); + } catch(InvalidKeyException badKey) { + throw new IllegalArgumentException(badKey); + } + macKey.erase(); + if(mac.getMacLength() != MAC_LENGTH) + throw new IllegalArgumentException(); + } + + public void writeFrame(Frame f) throws IOException { + byte[] buf = f.getBuffer(); + int length = f.getLength() - MAC_LENGTH; + mac.update(buf, 0, length); + try { + mac.doFinal(buf, length); + } catch(ShortBufferException badMac) { + throw new RuntimeException(badMac); + } + out.writeFrame(f); + } + + public void flush() throws IOException { + out.flush(); + } + + public long getRemainingCapacity() { + return out.getRemainingCapacity(); + } +} diff --git a/components/net/sf/briar/transport/OutgoingReliabilityLayer.java b/components/net/sf/briar/transport/OutgoingReliabilityLayer.java new file mode 100644 index 0000000000..49aacb499a --- /dev/null +++ b/components/net/sf/briar/transport/OutgoingReliabilityLayer.java @@ -0,0 +1,15 @@ +package net.sf.briar.transport; + +import java.io.IOException; + +interface OutgoingReliabilityLayer { + + /** Writes the given frame. */ + void writeFrame(Frame f) throws IOException; + + /** Flushes the stack. */ + void flush() throws IOException; + + /** Returns the maximum number of bytes that can be written. */ + long getRemainingCapacity(); +} diff --git a/test/net/sf/briar/transport/ConnectionReaderImplTest.java b/test/net/sf/briar/transport/ConnectionReaderImplTest.java index d03330fa91..feaddea5ce 100644 --- a/test/net/sf/briar/transport/ConnectionReaderImplTest.java +++ b/test/net/sf/briar/transport/ConnectionReaderImplTest.java @@ -217,13 +217,14 @@ public class ConnectionReaderImplTest extends TransportTest { } private ConnectionReader createConnectionReader(InputStream in) { - IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in); - IncomingErrorCorrectionLayer correcter = - new NullIncomingErrorCorrectionLayer(decrypter); - IncomingAuthenticationLayer authenticator = - new IncomingAuthenticationLayerImpl(correcter, mac, macKey); + IncomingEncryptionLayer encryption = + new NullIncomingEncryptionLayer(in); + IncomingErrorCorrectionLayer correction = + new NullIncomingErrorCorrectionLayer(encryption); + IncomingAuthenticationLayer authentication = + new IncomingAuthenticationLayerImpl(correction, mac, macKey); IncomingReliabilityLayer reliability = - new NullIncomingReliabilityLayer(authenticator); + new NullIncomingReliabilityLayer(authentication); return new ConnectionReaderImpl(reliability, false); } } diff --git a/test/net/sf/briar/transport/ConnectionWriterImplTest.java b/test/net/sf/briar/transport/ConnectionWriterImplTest.java index 4259d717b5..225062ba19 100644 --- a/test/net/sf/briar/transport/ConnectionWriterImplTest.java +++ b/test/net/sf/briar/transport/ConnectionWriterImplTest.java @@ -12,6 +12,7 @@ import net.sf.briar.api.transport.ConnectionWriter; import org.junit.Test; +// FIXME: This test covers too many classes public class ConnectionWriterImplTest extends TransportTest { public ConnectionWriterImplTest() throws Exception { @@ -21,11 +22,7 @@ public class ConnectionWriterImplTest extends TransportTest { @Test public void testFlushWithoutWriteProducesNothing() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); - OutgoingEncryptionLayer encrypter = - new NullOutgoingEncryptionLayer(out); - OutgoingErrorCorrectionLayer correcter = - new NullOutgoingErrorCorrectionLayer(encrypter); - ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey); + ConnectionWriter w = createConnectionWriter(out); w.getOutputStream().flush(); w.getOutputStream().flush(); w.getOutputStream().flush(); @@ -44,11 +41,7 @@ public class ConnectionWriterImplTest extends TransportTest { mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength); // Check that the ConnectionWriter gets the same results ByteArrayOutputStream out = new ByteArrayOutputStream(); - OutgoingEncryptionLayer encrypter = - new NullOutgoingEncryptionLayer(out); - OutgoingErrorCorrectionLayer correcter = - new NullOutgoingErrorCorrectionLayer(encrypter); - ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey); + ConnectionWriter w = createConnectionWriter(out); w.getOutputStream().write(0); w.getOutputStream().flush(); assertArrayEquals(frame, out.toByteArray()); @@ -57,11 +50,7 @@ public class ConnectionWriterImplTest extends TransportTest { @Test public void testWriteByteToMaxLengthWritesFrame() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); - OutgoingEncryptionLayer encrypter = - new NullOutgoingEncryptionLayer(out); - OutgoingErrorCorrectionLayer correcter = - new NullOutgoingErrorCorrectionLayer(encrypter); - ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey); + ConnectionWriter w = createConnectionWriter(out); OutputStream out1 = w.getOutputStream(); // The first maxPayloadLength - 1 bytes should be buffered for(int i = 0; i < MAX_PAYLOAD_LENGTH - 1; i++) out1.write(0); @@ -74,11 +63,7 @@ public class ConnectionWriterImplTest extends TransportTest { @Test public void testWriteArrayToMaxLengthWritesFrame() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); - OutgoingEncryptionLayer encrypter = - new NullOutgoingEncryptionLayer(out); - OutgoingErrorCorrectionLayer correcter = - new NullOutgoingErrorCorrectionLayer(encrypter); - ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey); + ConnectionWriter w = createConnectionWriter(out); OutputStream out1 = w.getOutputStream(); // The first maxPayloadLength - 1 bytes should be buffered out1.write(new byte[MAX_PAYLOAD_LENGTH - 1]); @@ -112,11 +97,7 @@ public class ConnectionWriterImplTest extends TransportTest { byte[] expected = out.toByteArray(); // Check that the ConnectionWriter gets the same results out.reset(); - OutgoingEncryptionLayer encrypter = - new NullOutgoingEncryptionLayer(out); - OutgoingErrorCorrectionLayer correcter = - new NullOutgoingErrorCorrectionLayer(encrypter); - ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey); + ConnectionWriter w = createConnectionWriter(out); w.getOutputStream().write(new byte[123]); w.getOutputStream().flush(); w.getOutputStream().write(new byte[1234]); @@ -124,4 +105,16 @@ public class ConnectionWriterImplTest extends TransportTest { byte[] actual = out.toByteArray(); assertArrayEquals(expected, actual); } + + private ConnectionWriter createConnectionWriter(OutputStream out) { + OutgoingEncryptionLayer encryption = + new NullOutgoingEncryptionLayer(out); + OutgoingErrorCorrectionLayer correction = + new NullOutgoingErrorCorrectionLayer(encryption); + OutgoingAuthenticationLayer authentication = + new OutgoingAuthenticationLayerImpl(correction, mac, macKey); + OutgoingReliabilityLayer reliability = + new NullOutgoingReliabilityLayer(authentication); + return new ConnectionWriterImpl(reliability); + } } diff --git a/test/net/sf/briar/transport/FrameReadWriteTest.java b/test/net/sf/briar/transport/FrameReadWriteTest.java index ef0403f3a0..5ca1908782 100644 --- a/test/net/sf/briar/transport/FrameReadWriteTest.java +++ b/test/net/sf/briar/transport/FrameReadWriteTest.java @@ -74,13 +74,16 @@ public class FrameReadWriteTest extends BriarTestCase { ErasableKey macCopy = macKey.copy(); // Write the frames ByteArrayOutputStream out = new ByteArrayOutputStream(); - OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out, - Long.MAX_VALUE, tagCipher, segCipher, tagCopy, segCopy, + OutgoingEncryptionLayer encryptionOut = new OutgoingEncryptionLayerImpl( + out, Long.MAX_VALUE, tagCipher, segCipher, tagCopy, segCopy, false); - OutgoingErrorCorrectionLayer correcter = - new NullOutgoingErrorCorrectionLayer(encrypter); - ConnectionWriter writer = new ConnectionWriterImpl(correcter, mac, - macCopy); + OutgoingErrorCorrectionLayer correctionOut = + new NullOutgoingErrorCorrectionLayer(encryptionOut); + OutgoingAuthenticationLayer authenticationOut = + new OutgoingAuthenticationLayerImpl(correctionOut, mac, macCopy); + OutgoingReliabilityLayer reliabilityOut = + new NullOutgoingReliabilityLayer(authenticationOut); + ConnectionWriter writer = new ConnectionWriterImpl(reliabilityOut); OutputStream out1 = writer.getOutputStream(); out1.write(frame); out1.flush(); @@ -93,15 +96,16 @@ public class FrameReadWriteTest extends BriarTestCase { assertArrayEquals(tag, recoveredTag); assertEquals(0L, TagEncoder.decodeTag(tag, tagCipher, tagKey)); // Read the frames back - IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, - tagCipher, segCipher, tagKey, segKey, false, recoveredTag); - IncomingErrorCorrectionLayer correcter1 = - new NullIncomingErrorCorrectionLayer(decrypter); - IncomingAuthenticationLayer authenticator = - new IncomingAuthenticationLayerImpl(correcter1, mac, macKey); - IncomingReliabilityLayer reliability = - new NullIncomingReliabilityLayer(authenticator); - ConnectionReader reader = new ConnectionReaderImpl(reliability, false); + IncomingEncryptionLayer encryptionIn = new IncomingEncryptionLayerImpl( + in, tagCipher, segCipher, tagKey, segKey, false, recoveredTag); + IncomingErrorCorrectionLayer correctionIn = + new NullIncomingErrorCorrectionLayer(encryptionIn); + IncomingAuthenticationLayer authenticationIn = + new IncomingAuthenticationLayerImpl(correctionIn, mac, macKey); + IncomingReliabilityLayer reliabilityIn = + new NullIncomingReliabilityLayer(authenticationIn); + ConnectionReader reader = new ConnectionReaderImpl(reliabilityIn, + false); InputStream in1 = reader.getInputStream(); byte[] recovered = new byte[frame.length]; int offset = 0; -- GitLab