From 3a77ba9aaf84de2ee651601a387a1127428545e4 Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Fri, 20 Jan 2012 23:06:51 +0000 Subject: [PATCH] Allow the transport to specify the maximum segment length. --- api/net/sf/briar/api/plugins/SegmentSink.java | 5 ++++ .../sf/briar/api/plugins/SegmentSource.java | 5 ++++ .../briar/transport/ConnectionReaderImpl.java | 2 +- .../briar/transport/ConnectionWriterImpl.java | 13 +++++----- components/net/sf/briar/transport/Frame.java | 6 +++++ .../IncomingAuthenticationLayer.java | 3 +++ .../IncomingAuthenticationLayerImpl.java | 10 +++++--- .../transport/IncomingEncryptionLayer.java | 5 ++++ .../IncomingEncryptionLayerImpl.java | 6 ++++- .../IncomingErrorCorrectionLayer.java | 3 +++ .../IncomingErrorCorrectionLayerImpl.java | 12 +++++++-- .../transport/IncomingReliabilityLayer.java | 3 +++ .../IncomingSegmentedEncryptionLayer.java | 18 ++++++++++--- .../NullIncomingErrorCorrectionLayer.java | 8 +++++- .../NullIncomingReliabilityLayer.java | 6 +++++ .../NullOutgoingErrorCorrectionLayer.java | 8 +++++- .../NullOutgoingReliabilityLayer.java | 6 +++++ .../OutgoingAuthenticationLayer.java | 3 +++ .../OutgoingAuthenticationLayerImpl.java | 7 +++++- .../transport/OutgoingEncryptionLayer.java | 5 ++++ .../OutgoingEncryptionLayerImpl.java | 4 +++ .../OutgoingErrorCorrectionLayer.java | 3 +++ .../OutgoingErrorCorrectionLayerImpl.java | 12 +++++++-- .../transport/OutgoingReliabilityLayer.java | 3 +++ .../OutgoingSegmentedEncryptionLayer.java | 17 +++++++++++-- .../net/sf/briar/transport/SegmentImpl.java | 5 ++++ .../IncomingErrorCorrectionLayerImplTest.java | 4 +++ .../IncomingSegmentedEncryptionLayerTest.java | 5 ++++ .../NullIncomingEncryptionLayer.java | 6 +++++ .../NullOutgoingEncryptionLayer.java | 7 ++++++ .../OutgoingSegmentedEncryptionLayerTest.java | 5 ++++ .../briar/transport/XorErasureCodeTest.java | 2 +- .../transport/XorErasureDecoderTest.java | 2 +- .../transport/XorErasureEncoderTest.java | 25 +++++++++---------- 34 files changed, 195 insertions(+), 39 deletions(-) diff --git a/api/net/sf/briar/api/plugins/SegmentSink.java b/api/net/sf/briar/api/plugins/SegmentSink.java index 55caa49340..83eaa2f6ae 100644 --- a/api/net/sf/briar/api/plugins/SegmentSink.java +++ b/api/net/sf/briar/api/plugins/SegmentSink.java @@ -8,4 +8,9 @@ public interface SegmentSink { /** Writes the given segment. */ void writeSegment(Segment s) throws IOException; + + /** + * Returns the maximum length in bytes of the segments this sink accepts. + */ + int getMaxSegmentLength(); } diff --git a/api/net/sf/briar/api/plugins/SegmentSource.java b/api/net/sf/briar/api/plugins/SegmentSource.java index 403659a0b1..135d03f548 100644 --- a/api/net/sf/briar/api/plugins/SegmentSource.java +++ b/api/net/sf/briar/api/plugins/SegmentSource.java @@ -11,4 +11,9 @@ public interface SegmentSource { * segment was read, or false if no more segments can be read. */ boolean readSegment(Segment s) throws IOException; + + /** + * Returns the maximum length in bytes of the segments this source returns. + */ + int getMaxSegmentLength(); } diff --git a/components/net/sf/briar/transport/ConnectionReaderImpl.java b/components/net/sf/briar/transport/ConnectionReaderImpl.java index 581c026ce5..1859eda8dc 100644 --- a/components/net/sf/briar/transport/ConnectionReaderImpl.java +++ b/components/net/sf/briar/transport/ConnectionReaderImpl.java @@ -19,7 +19,7 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader { ConnectionReaderImpl(IncomingReliabilityLayer in, boolean tolerateErrors) { this.in = in; this.tolerateErrors = tolerateErrors; - frame = new Frame(); + frame = new Frame(in.getMaxFrameLength()); } public InputStream getInputStream() { diff --git a/components/net/sf/briar/transport/ConnectionWriterImpl.java b/components/net/sf/briar/transport/ConnectionWriterImpl.java index d1fcbd7a0d..e39de66619 100644 --- a/components/net/sf/briar/transport/ConnectionWriterImpl.java +++ b/components/net/sf/briar/transport/ConnectionWriterImpl.java @@ -2,7 +2,6 @@ package net.sf.briar.transport; import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; -import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED; import java.io.IOException; @@ -19,6 +18,7 @@ import net.sf.briar.api.transport.ConnectionWriter; class ConnectionWriterImpl extends OutputStream implements ConnectionWriter { private final OutgoingReliabilityLayer out; + private final int maxFrameLength; private final Frame frame; private int offset = FRAME_HEADER_LENGTH; @@ -26,7 +26,8 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter { ConnectionWriterImpl(OutgoingReliabilityLayer out) { this.out = out; - frame = new Frame(); + maxFrameLength = out.getMaxFrameLength(); + frame = new Frame(maxFrameLength); } public OutputStream getOutputStream() { @@ -39,7 +40,7 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter { if(offset > FRAME_HEADER_LENGTH) capacity -= offset + MAC_LENGTH; // Subtract the overhead from the remaining capacity - long frames = (long) Math.ceil((double) capacity / MAX_FRAME_LENGTH); + long frames = (long) Math.ceil((double) capacity / maxFrameLength); int overheadPerFrame = FRAME_HEADER_LENGTH + MAC_LENGTH; return Math.max(0L, capacity - frames * overheadPerFrame); } @@ -53,7 +54,7 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter { @Override public void write(int b) throws IOException { frame.getBuffer()[offset++] = (byte) b; - if(offset + MAC_LENGTH == MAX_FRAME_LENGTH) writeFrame(); + if(offset + MAC_LENGTH == maxFrameLength) writeFrame(); } @Override @@ -64,14 +65,14 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter { @Override public void write(byte[] b, int off, int len) throws IOException { byte[] buf = frame.getBuffer(); - int available = MAX_FRAME_LENGTH - offset - MAC_LENGTH; + int available = maxFrameLength - offset - MAC_LENGTH; while(available <= len) { System.arraycopy(b, off, buf, offset, available); offset += available; writeFrame(); off += available; len -= available; - available = MAX_FRAME_LENGTH - offset - MAC_LENGTH; + available = maxFrameLength - offset - MAC_LENGTH; } System.arraycopy(b, off, buf, offset, len); offset += len; diff --git a/components/net/sf/briar/transport/Frame.java b/components/net/sf/briar/transport/Frame.java index 64c8eeda9a..921e5ff23e 100644 --- a/components/net/sf/briar/transport/Frame.java +++ b/components/net/sf/briar/transport/Frame.java @@ -1,6 +1,9 @@ package net.sf.briar.transport; +import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH; +import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; +import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH; class Frame { @@ -13,6 +16,9 @@ class Frame { } Frame(int length) { + if(length < FRAME_HEADER_LENGTH + MAC_LENGTH) + throw new IllegalArgumentException(); + if(length > MAX_SEGMENT_LENGTH) throw new IllegalArgumentException(); buf = new byte[length]; } diff --git a/components/net/sf/briar/transport/IncomingAuthenticationLayer.java b/components/net/sf/briar/transport/IncomingAuthenticationLayer.java index 22dd0df365..33a6f20aa3 100644 --- a/components/net/sf/briar/transport/IncomingAuthenticationLayer.java +++ b/components/net/sf/briar/transport/IncomingAuthenticationLayer.java @@ -15,4 +15,7 @@ interface IncomingAuthenticationLayer { */ boolean readFrame(Frame f, FrameWindow window) throws IOException, InvalidDataException; + + /** Returns the maximum length in bytes of the frames this layer returns. */ + int getMaxFrameLength(); } diff --git a/components/net/sf/briar/transport/IncomingAuthenticationLayerImpl.java b/components/net/sf/briar/transport/IncomingAuthenticationLayerImpl.java index c2332c7458..5489a8ba9c 100644 --- a/components/net/sf/briar/transport/IncomingAuthenticationLayerImpl.java +++ b/components/net/sf/briar/transport/IncomingAuthenticationLayerImpl.java @@ -2,7 +2,6 @@ package net.sf.briar.transport; import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; -import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; import java.io.IOException; import java.security.InvalidKeyException; @@ -14,13 +13,13 @@ import net.sf.briar.api.crypto.ErasableKey; class IncomingAuthenticationLayerImpl implements IncomingAuthenticationLayer { private final IncomingErrorCorrectionLayer in; + private final int maxFrameLength; private final Mac mac; IncomingAuthenticationLayerImpl(IncomingErrorCorrectionLayer in, Mac mac, ErasableKey macKey) { this.in = in; this.mac = mac; - // Initialise the MAC try { mac.init(macKey); } catch(InvalidKeyException e) { @@ -29,6 +28,7 @@ class IncomingAuthenticationLayerImpl implements IncomingAuthenticationLayer { macKey.erase(); if(mac.getMacLength() != MAC_LENGTH) throw new IllegalArgumentException(); + maxFrameLength = in.getMaxFrameLength(); } public boolean readFrame(Frame f, FrameWindow window) throws IOException, @@ -39,7 +39,7 @@ class IncomingAuthenticationLayerImpl implements IncomingAuthenticationLayer { int length = f.getLength(); if(length < FRAME_HEADER_LENGTH + MAC_LENGTH) throw new InvalidDataException(); - if(length > MAX_FRAME_LENGTH) throw new InvalidDataException(); + if(length > maxFrameLength) throw new InvalidDataException(); // Check that the payload and padding lengths are correct byte[] buf = f.getBuffer(); int payload = HeaderEncoder.getPayloadLength(buf); @@ -61,4 +61,8 @@ class IncomingAuthenticationLayerImpl implements IncomingAuthenticationLayer { } return true; } + + public int getMaxFrameLength() { + return maxFrameLength; + } } diff --git a/components/net/sf/briar/transport/IncomingEncryptionLayer.java b/components/net/sf/briar/transport/IncomingEncryptionLayer.java index 3521ce46e6..08e903a28b 100644 --- a/components/net/sf/briar/transport/IncomingEncryptionLayer.java +++ b/components/net/sf/briar/transport/IncomingEncryptionLayer.java @@ -15,4 +15,9 @@ interface IncomingEncryptionLayer { * may choose whether to retry the read or close the connection. */ boolean readSegment(Segment s) throws IOException, InvalidDataException; + + /** + * Returns the maximum length in bytes of the segments this layer returns. + */ + int getMaxSegmentLength(); } diff --git a/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java b/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java index 2f1bfb44e9..b9c702b278 100644 --- a/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java +++ b/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java @@ -23,9 +23,9 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer { private final InputStream in; private final Cipher tagCipher, segCipher; private final ErasableKey tagKey, segKey; + private final boolean tagEverySegment; private final int blockSize; private final byte[] iv, ciphertext; - private final boolean tagEverySegment; private byte[] bufferedTag; private boolean firstSegment = true; @@ -128,4 +128,8 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer { throw e; } } + + public int getMaxSegmentLength() { + return MAX_SEGMENT_LENGTH - TAG_LENGTH; + } } \ No newline at end of file diff --git a/components/net/sf/briar/transport/IncomingErrorCorrectionLayer.java b/components/net/sf/briar/transport/IncomingErrorCorrectionLayer.java index e49e0cbb9f..f909dcd606 100644 --- a/components/net/sf/briar/transport/IncomingErrorCorrectionLayer.java +++ b/components/net/sf/briar/transport/IncomingErrorCorrectionLayer.java @@ -15,4 +15,7 @@ interface IncomingErrorCorrectionLayer { */ boolean readFrame(Frame f, FrameWindow window) throws IOException, InvalidDataException; + + /** Returns the maximum length in bytes of the frames this layer returns. */ + int getMaxFrameLength(); } diff --git a/components/net/sf/briar/transport/IncomingErrorCorrectionLayerImpl.java b/components/net/sf/briar/transport/IncomingErrorCorrectionLayerImpl.java index e20ac44d79..ff1d2f8952 100644 --- a/components/net/sf/briar/transport/IncomingErrorCorrectionLayerImpl.java +++ b/components/net/sf/briar/transport/IncomingErrorCorrectionLayerImpl.java @@ -1,5 +1,7 @@ package net.sf.briar.transport; +import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; + import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -14,7 +16,7 @@ class IncomingErrorCorrectionLayerImpl implements IncomingErrorCorrectionLayer { private final IncomingEncryptionLayer in; private final ErasureDecoder decoder; - private final int n, k; + private final int n, k, maxSegmentLength, maxFrameLength; private final Map<Long, Integer> discardCounts; private final Map<Long, Segment[]> segmentSets; private final ArrayList<Segment> freeSegments; @@ -25,6 +27,8 @@ class IncomingErrorCorrectionLayerImpl implements IncomingErrorCorrectionLayer { this.decoder = decoder; this.n = n; this.k = k; + maxSegmentLength = in.getMaxSegmentLength(); + maxFrameLength = Math.min(MAX_FRAME_LENGTH, maxSegmentLength * k); discardCounts = new HashMap<Long, Integer>(); segmentSets = new HashMap<Long, Segment[]>(); freeSegments = new ArrayList<Segment>(); @@ -47,7 +51,7 @@ class IncomingErrorCorrectionLayerImpl implements IncomingErrorCorrectionLayer { // Grab a free segment, or allocate one if necessary Segment s; int free = freeSegments.size(); - if(free == 0) s = new SegmentImpl(); + if(free == 0) s = new SegmentImpl(maxSegmentLength); else s = freeSegments.remove(free - 1); // Read segments until a frame can be decoded while(true) { @@ -74,6 +78,10 @@ class IncomingErrorCorrectionLayerImpl implements IncomingErrorCorrectionLayer { } } + public int getMaxFrameLength() { + return maxFrameLength; + } + private void countDiscard(long frameNumber) throws FormatException { Integer count = discardCounts.get(frameNumber); if(count == null) discardCounts.put(frameNumber, 1); diff --git a/components/net/sf/briar/transport/IncomingReliabilityLayer.java b/components/net/sf/briar/transport/IncomingReliabilityLayer.java index 417a2525f1..162a228c2d 100644 --- a/components/net/sf/briar/transport/IncomingReliabilityLayer.java +++ b/components/net/sf/briar/transport/IncomingReliabilityLayer.java @@ -13,4 +13,7 @@ interface IncomingReliabilityLayer { * may choose whether to retry the read or close the connection. */ boolean readFrame(Frame f) throws IOException, InvalidDataException; + + /** Returns the maximum length in bytes of the frames this layer returns. */ + int getMaxFrameLength(); } diff --git a/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java b/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java index f2a2ad40a3..50dacb4485 100644 --- a/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java +++ b/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java @@ -20,10 +20,10 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer { private final SegmentSource in; private final Cipher tagCipher, segCipher; private final ErasableKey tagKey, segKey; - private final int blockSize; - private final byte[] iv; private final boolean tagEverySegment; + private final int blockSize, maxSegmentLength; private final Segment segment; + private final byte[] iv; private Segment bufferedSegment; private boolean firstSegment = true; @@ -42,8 +42,13 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer { blockSize = segCipher.getBlockSize(); if(blockSize < FRAME_HEADER_LENGTH) throw new IllegalArgumentException(); + int length = in.getMaxSegmentLength(); + if(length < TAG_LENGTH + FRAME_HEADER_LENGTH + 1 + MAC_LENGTH) + throw new IllegalArgumentException(); + if(length > MAX_SEGMENT_LENGTH) throw new IllegalArgumentException(); + maxSegmentLength = length - TAG_LENGTH; + segment = new SegmentImpl(length); iv = IvEncoder.encodeIv(0L, blockSize); - segment = new SegmentImpl(); } public boolean readSegment(Segment s) throws IOException, @@ -62,9 +67,10 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer { } int offset = expectTag ? TAG_LENGTH : 0; int length = segment.getLength(); - if(length > MAX_SEGMENT_LENGTH) throw new InvalidDataException(); if(length < offset + FRAME_HEADER_LENGTH + MAC_LENGTH) throw new InvalidDataException(); + if(length > offset + maxSegmentLength) + throw new InvalidDataException(); byte[] ciphertext = segment.getBuffer(); // If a tag is expected then decrypt and validate it if(expectTag) { @@ -92,4 +98,8 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer { throw e; } } + + public int getMaxSegmentLength() { + return maxSegmentLength; + } } diff --git a/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java b/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java index 54e1f04aec..1e5077d3c1 100644 --- a/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java +++ b/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java @@ -7,11 +7,13 @@ import net.sf.briar.api.transport.Segment; class NullIncomingErrorCorrectionLayer implements IncomingErrorCorrectionLayer { private final IncomingEncryptionLayer in; + private final int maxFrameLength; private final Segment segment; NullIncomingErrorCorrectionLayer(IncomingEncryptionLayer in) { this.in = in; - segment = new SegmentImpl(); + maxFrameLength = in.getMaxSegmentLength(); + segment = new SegmentImpl(maxFrameLength); } public boolean readFrame(Frame f, FrameWindow window) throws IOException, @@ -28,4 +30,8 @@ class NullIncomingErrorCorrectionLayer implements IncomingErrorCorrectionLayer { f.setLength(length); return true; } + + public int getMaxFrameLength() { + return maxFrameLength; + } } diff --git a/components/net/sf/briar/transport/NullIncomingReliabilityLayer.java b/components/net/sf/briar/transport/NullIncomingReliabilityLayer.java index 25ddb59d24..ecd871d22f 100644 --- a/components/net/sf/briar/transport/NullIncomingReliabilityLayer.java +++ b/components/net/sf/briar/transport/NullIncomingReliabilityLayer.java @@ -5,10 +5,12 @@ import java.io.IOException; class NullIncomingReliabilityLayer implements IncomingReliabilityLayer { private final IncomingAuthenticationLayer in; + private final int maxFrameLength; private final FrameWindow window; NullIncomingReliabilityLayer(IncomingAuthenticationLayer in) { this.in = in; + maxFrameLength = in.getMaxFrameLength(); window = new NullFrameWindow(); } @@ -18,4 +20,8 @@ class NullIncomingReliabilityLayer implements IncomingReliabilityLayer { if(!window.remove(frameNumber)) throw new IllegalStateException(); return true; } + + public int getMaxFrameLength() { + return maxFrameLength; + } } diff --git a/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java b/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java index c0719e2ead..6847697f9a 100644 --- a/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java +++ b/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java @@ -9,13 +9,15 @@ import net.sf.briar.api.transport.Segment; class NullOutgoingErrorCorrectionLayer implements OutgoingErrorCorrectionLayer { private final OutgoingEncryptionLayer out; + private final int maxSegmentLength; private final Segment segment; private long segmentNumber = 0L; public NullOutgoingErrorCorrectionLayer(OutgoingEncryptionLayer out) { this.out = out; - segment = new SegmentImpl(); + maxSegmentLength = out.getMaxSegmentLength(); + segment = new SegmentImpl(maxSegmentLength); } public void writeFrame(Frame f) throws IOException { @@ -36,4 +38,8 @@ class NullOutgoingErrorCorrectionLayer implements OutgoingErrorCorrectionLayer { public long getRemainingCapacity() { return out.getRemainingCapacity(); } + + public int getMaxFrameLength() { + return maxSegmentLength; + } } diff --git a/components/net/sf/briar/transport/NullOutgoingReliabilityLayer.java b/components/net/sf/briar/transport/NullOutgoingReliabilityLayer.java index a00a2e9c4e..650f245e54 100644 --- a/components/net/sf/briar/transport/NullOutgoingReliabilityLayer.java +++ b/components/net/sf/briar/transport/NullOutgoingReliabilityLayer.java @@ -5,9 +5,11 @@ import java.io.IOException; class NullOutgoingReliabilityLayer implements OutgoingReliabilityLayer { private final OutgoingAuthenticationLayer out; + private final int maxFrameLength; NullOutgoingReliabilityLayer(OutgoingAuthenticationLayer out) { this.out = out; + maxFrameLength = out.getMaxFrameLength(); } public void writeFrame(Frame f) throws IOException { @@ -21,4 +23,8 @@ class NullOutgoingReliabilityLayer implements OutgoingReliabilityLayer { public long getRemainingCapacity() { return out.getRemainingCapacity(); } + + public int getMaxFrameLength() { + return maxFrameLength; + } } diff --git a/components/net/sf/briar/transport/OutgoingAuthenticationLayer.java b/components/net/sf/briar/transport/OutgoingAuthenticationLayer.java index e1b9b72b6d..21e41a9243 100644 --- a/components/net/sf/briar/transport/OutgoingAuthenticationLayer.java +++ b/components/net/sf/briar/transport/OutgoingAuthenticationLayer.java @@ -12,4 +12,7 @@ interface OutgoingAuthenticationLayer { /** Returns the maximum number of bytes that can be written. */ long getRemainingCapacity(); + + /** Returns the maximum length in bytes of the frames this layer accepts. */ + int getMaxFrameLength(); } diff --git a/components/net/sf/briar/transport/OutgoingAuthenticationLayerImpl.java b/components/net/sf/briar/transport/OutgoingAuthenticationLayerImpl.java index c8cee560b4..535ec4834a 100644 --- a/components/net/sf/briar/transport/OutgoingAuthenticationLayerImpl.java +++ b/components/net/sf/briar/transport/OutgoingAuthenticationLayerImpl.java @@ -14,12 +14,12 @@ class OutgoingAuthenticationLayerImpl implements OutgoingAuthenticationLayer { private final OutgoingErrorCorrectionLayer out; private final Mac mac; + private final int maxFrameLength; OutgoingAuthenticationLayerImpl(OutgoingErrorCorrectionLayer out, Mac mac, ErasableKey macKey) { this.out = out; this.mac = mac; - // Initialise the MAC try { mac.init(macKey); } catch(InvalidKeyException badKey) { @@ -28,6 +28,7 @@ class OutgoingAuthenticationLayerImpl implements OutgoingAuthenticationLayer { macKey.erase(); if(mac.getMacLength() != MAC_LENGTH) throw new IllegalArgumentException(); + maxFrameLength = out.getMaxFrameLength(); } public void writeFrame(Frame f) throws IOException { @@ -49,4 +50,8 @@ class OutgoingAuthenticationLayerImpl implements OutgoingAuthenticationLayer { public long getRemainingCapacity() { return out.getRemainingCapacity(); } + + public int getMaxFrameLength() { + return maxFrameLength; + } } diff --git a/components/net/sf/briar/transport/OutgoingEncryptionLayer.java b/components/net/sf/briar/transport/OutgoingEncryptionLayer.java index e3b11cfe2e..e0e4b44023 100644 --- a/components/net/sf/briar/transport/OutgoingEncryptionLayer.java +++ b/components/net/sf/briar/transport/OutgoingEncryptionLayer.java @@ -14,4 +14,9 @@ interface OutgoingEncryptionLayer { /** Returns the maximum number of bytes that can be written. */ long getRemainingCapacity(); + + /** + * Returns the maximum length in bytes of the segments this layer accepts. + */ + int getMaxSegmentLength(); } diff --git a/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java b/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java index 4169eef5af..6e9696b206 100644 --- a/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java +++ b/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java @@ -73,4 +73,8 @@ class OutgoingEncryptionLayerImpl implements OutgoingEncryptionLayer { public long getRemainingCapacity() { return capacity; } + + public int getMaxSegmentLength() { + return MAX_SEGMENT_LENGTH - TAG_LENGTH; + } } \ No newline at end of file diff --git a/components/net/sf/briar/transport/OutgoingErrorCorrectionLayer.java b/components/net/sf/briar/transport/OutgoingErrorCorrectionLayer.java index 206a594df3..9dfd9eac37 100644 --- a/components/net/sf/briar/transport/OutgoingErrorCorrectionLayer.java +++ b/components/net/sf/briar/transport/OutgoingErrorCorrectionLayer.java @@ -12,4 +12,7 @@ interface OutgoingErrorCorrectionLayer { /** Returns the maximum number of bytes that can be written. */ long getRemainingCapacity(); + + /** Returns the maximum length in bytes of the frames this layer accepts. */ + int getMaxFrameLength(); } diff --git a/components/net/sf/briar/transport/OutgoingErrorCorrectionLayerImpl.java b/components/net/sf/briar/transport/OutgoingErrorCorrectionLayerImpl.java index 24168939b6..e7662d002e 100644 --- a/components/net/sf/briar/transport/OutgoingErrorCorrectionLayerImpl.java +++ b/components/net/sf/briar/transport/OutgoingErrorCorrectionLayerImpl.java @@ -1,5 +1,7 @@ package net.sf.briar.transport; +import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; + import java.io.IOException; import net.sf.briar.api.transport.Segment; @@ -8,13 +10,15 @@ class OutgoingErrorCorrectionLayerImpl implements OutgoingErrorCorrectionLayer { private final OutgoingEncryptionLayer out; private final ErasureEncoder encoder; - private final int n; + private final int n, maxFrameLength; OutgoingErrorCorrectionLayerImpl(OutgoingEncryptionLayer out, - ErasureEncoder encoder, int n) { + ErasureEncoder encoder, int n, int k) { this.out = out; this.encoder = encoder; this.n = n; + maxFrameLength = Math.min(MAX_FRAME_LENGTH, + out.getMaxSegmentLength() * k); } public void writeFrame(Frame f) throws IOException { @@ -28,4 +32,8 @@ class OutgoingErrorCorrectionLayerImpl implements OutgoingErrorCorrectionLayer { public long getRemainingCapacity() { return out.getRemainingCapacity() / n; } + + public int getMaxFrameLength() { + return maxFrameLength; + } } diff --git a/components/net/sf/briar/transport/OutgoingReliabilityLayer.java b/components/net/sf/briar/transport/OutgoingReliabilityLayer.java index 49aacb499a..ef6797d9a8 100644 --- a/components/net/sf/briar/transport/OutgoingReliabilityLayer.java +++ b/components/net/sf/briar/transport/OutgoingReliabilityLayer.java @@ -12,4 +12,7 @@ interface OutgoingReliabilityLayer { /** Returns the maximum number of bytes that can be written. */ long getRemainingCapacity(); + + /** Returns the maximum length in bytes of the frames this layer accepts. */ + int getMaxFrameLength(); } diff --git a/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java b/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java index 1214dec4a8..eb188ff608 100644 --- a/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java +++ b/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java @@ -1,5 +1,8 @@ package net.sf.briar.transport; +import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH; +import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; +import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH; import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH; import java.io.IOException; @@ -18,8 +21,9 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer { private final Cipher tagCipher, segCipher; private final ErasableKey tagKey, segKey; private final boolean tagEverySegment; - private final byte[] iv; + private final int maxSegmentLength; private final Segment segment; + private final byte[] iv; private long capacity; @@ -33,8 +37,13 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer { this.tagKey = tagKey; this.segKey = segKey; this.tagEverySegment = tagEverySegment; + int length = out.getMaxSegmentLength(); + if(length < TAG_LENGTH + FRAME_HEADER_LENGTH + 1 + MAC_LENGTH) + throw new RuntimeException(); + if(length > MAX_SEGMENT_LENGTH) throw new RuntimeException(); + maxSegmentLength = length - MAC_LENGTH; + segment = new SegmentImpl(length); iv = IvEncoder.encodeIv(0L, segCipher.getBlockSize()); - segment = new SegmentImpl(); } public void writeSegment(Segment s) throws IOException { @@ -72,4 +81,8 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer { public long getRemainingCapacity() { return capacity; } + + public int getMaxSegmentLength() { + return maxSegmentLength; + } } \ No newline at end of file diff --git a/components/net/sf/briar/transport/SegmentImpl.java b/components/net/sf/briar/transport/SegmentImpl.java index 9915854573..3c4552cf61 100644 --- a/components/net/sf/briar/transport/SegmentImpl.java +++ b/components/net/sf/briar/transport/SegmentImpl.java @@ -1,5 +1,7 @@ package net.sf.briar.transport; +import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH; +import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH; import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED; import net.sf.briar.api.transport.Segment; @@ -16,6 +18,9 @@ class SegmentImpl implements Segment { } SegmentImpl(int length) { + if(length < FRAME_HEADER_LENGTH + MAC_LENGTH) + throw new IllegalArgumentException(); + if(length > MAX_SEGMENT_LENGTH) throw new IllegalArgumentException(); buf = new byte[length]; } diff --git a/test/net/sf/briar/transport/IncomingErrorCorrectionLayerImplTest.java b/test/net/sf/briar/transport/IncomingErrorCorrectionLayerImplTest.java index 9072b728b0..f6f507bb55 100644 --- a/test/net/sf/briar/transport/IncomingErrorCorrectionLayerImplTest.java +++ b/test/net/sf/briar/transport/IncomingErrorCorrectionLayerImplTest.java @@ -160,5 +160,9 @@ public class IncomingErrorCorrectionLayerImplTest extends BriarTestCase { s.setLength(length); return true; } + + public int getMaxSegmentLength() { + return length; + } } } diff --git a/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java b/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java index 7359cf515e..13243605ed 100644 --- a/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java +++ b/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java @@ -2,6 +2,7 @@ package net.sf.briar.transport; import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; +import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH; import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH; import java.io.IOException; @@ -149,5 +150,9 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase { s.setLength(segment.length); return true; } + + public int getMaxSegmentLength() { + return MAX_SEGMENT_LENGTH; + } } } diff --git a/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java b/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java index def5509b83..dd244eeaff 100644 --- a/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java +++ b/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java @@ -3,6 +3,8 @@ package net.sf.briar.transport; import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; +import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH; +import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH; import java.io.EOFException; import java.io.IOException; @@ -49,4 +51,8 @@ class NullIncomingEncryptionLayer implements IncomingEncryptionLayer { s.setSegmentNumber(segmentNumber++); return true; } + + public int getMaxSegmentLength() { + return MAX_SEGMENT_LENGTH - TAG_LENGTH; + } } diff --git a/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java b/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java index 574b404c1b..88921aff03 100644 --- a/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java +++ b/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java @@ -1,5 +1,8 @@ package net.sf.briar.transport; +import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH; +import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH; + import java.io.IOException; import java.io.OutputStream; @@ -34,4 +37,8 @@ class NullOutgoingEncryptionLayer implements OutgoingEncryptionLayer { public long getRemainingCapacity() { return capacity; } + + public int getMaxSegmentLength() { + return MAX_SEGMENT_LENGTH - TAG_LENGTH; + } } diff --git a/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java b/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java index 398ca9cc5c..00d467e92c 100644 --- a/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java +++ b/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java @@ -1,5 +1,6 @@ package net.sf.briar.transport; +import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH; import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH; import static org.junit.Assert.assertArrayEquals; @@ -136,5 +137,9 @@ public class OutgoingSegmentedEncryptionLayerTest extends BriarTestCase { public void writeSegment(Segment s) throws IOException { write(s.getBuffer(), 0, s.getLength()); } + + public int getMaxSegmentLength() { + return MAX_SEGMENT_LENGTH; + } } } diff --git a/test/net/sf/briar/transport/XorErasureCodeTest.java b/test/net/sf/briar/transport/XorErasureCodeTest.java index b361cc2d83..f8a0b017fe 100644 --- a/test/net/sf/briar/transport/XorErasureCodeTest.java +++ b/test/net/sf/briar/transport/XorErasureCodeTest.java @@ -2,13 +2,13 @@ package net.sf.briar.transport; import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; +import static org.junit.Assert.assertArrayEquals; import java.util.Random; import net.sf.briar.BriarTestCase; import net.sf.briar.api.transport.Segment; -import static org.junit.Assert.assertArrayEquals; import org.junit.Test; public class XorErasureCodeTest extends BriarTestCase { diff --git a/test/net/sf/briar/transport/XorErasureDecoderTest.java b/test/net/sf/briar/transport/XorErasureDecoderTest.java index 944610fcbe..43b66551b6 100644 --- a/test/net/sf/briar/transport/XorErasureDecoderTest.java +++ b/test/net/sf/briar/transport/XorErasureDecoderTest.java @@ -3,11 +3,11 @@ package net.sf.briar.transport; import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; +import static org.junit.Assert.assertArrayEquals; import net.sf.briar.BriarTestCase; import net.sf.briar.api.FormatException; import net.sf.briar.api.transport.Segment; -import static org.junit.Assert.assertArrayEquals; import org.junit.Test; public class XorErasureDecoderTest extends BriarTestCase { diff --git a/test/net/sf/briar/transport/XorErasureEncoderTest.java b/test/net/sf/briar/transport/XorErasureEncoderTest.java index e1ca00b3ae..af67c0b644 100644 --- a/test/net/sf/briar/transport/XorErasureEncoderTest.java +++ b/test/net/sf/briar/transport/XorErasureEncoderTest.java @@ -10,30 +10,29 @@ public class XorErasureEncoderTest extends BriarTestCase { @Test public void testEncoding() { - // Create a 100-byte frame + // Create a frame Frame f = new Frame(); - f.setLength(100); + f.setLength(200); byte[] b = f.getBuffer(); - for(int i = 0; i < 100; i++) b[i] = (byte) i; + for(int i = 0; i < 200; i++) b[i] = (byte) i; // Encode the frame XorErasureEncoder e = new XorErasureEncoder(4); Segment[] set = e.encodeFrame(f); - // There should be four pieces of 34 bytes each + // There should be four pieces of 67 bytes each assertEquals(4, set.length); - for(int i = 0; i < 4; i++) assertEquals(34, set[i].getLength()); - // The first three pieces should contain the data, plus two zero bytes + for(int i = 0; i < 4; i++) assertEquals(67, set[i].getLength()); + // The first three pieces should contain the data plus on padding byte byte[] b1 = set[0].getBuffer(); - for(int i = 0; i < 34; i++) assertEquals(i, b1[i]); + for(int i = 0; i < 67; i++) assertEquals((byte) i, b1[i]); byte[] b2 = set[1].getBuffer(); - for(int i = 0; i < 34; i++) assertEquals(i + 34, b2[i]); + for(int i = 0; i < 67; i++) assertEquals((byte) (i + 67), b2[i]); byte[] b3 = set[2].getBuffer(); - for(int i = 0; i < 32; i++) assertEquals(i + 68, b3[i]); - assertEquals(0, b3[32]); - assertEquals(0, b3[33]); + for(int i = 0; i < 66; i++) assertEquals((byte) (i + 134), b3[i]); + assertEquals(0, b3[66]); // The fourth piece should be the XOR of the other three byte[] b4 = set[3].getBuffer(); - byte[] expected = new byte[34]; - for(int i = 0; i < 34; i++) { + byte[] expected = new byte[67]; + for(int i = 0; i < 67; i++) { expected[i] = (byte) (b1[i] ^ b2[i] ^ b3[i]); } assertArrayEquals(expected, b4); -- GitLab