diff --git a/api/net/sf/briar/api/plugins/SegmentSink.java b/api/net/sf/briar/api/plugins/SegmentSink.java index 55caa493403d95c52e3f7d4599328ca095c44c8a..83eaa2f6ae62eca33535d184112ccbb8d6cdb8b5 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 403659a0b1fc831f865db2c4418a7676a7e1ab63..135d03f548a624962ff5ea3c2d674e4d4868d95a 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 581c026ce5875f396811515a0c4a25aa4b3286c1..1859eda8dca6aec5f2987257af8b3544310fb6d5 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 d1fcbd7a0d74a3fdd6843c1421837ab03a276dfb..e39de66619f253f1de7aa2c9fa99cf0abaa67998 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 64c8eeda9a94cf71b7752bde3c0498f3395742de..921e5ff23e6d1d553b06f09c4bdd67208a2d827b 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 22dd0df36510f5961c3cbc5012b66c5d204eabb1..33a6f20aa3e9590bc47c6390cb6d202aed00683b 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 c2332c74583aa9c2405e7735618464aeeffe9c33..5489a8ba9c50165a9f57e338a05a17fc8423389c 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 3521ce46e6b71dd8a8b00fe9eb4ed1be8da59a0d..08e903a28b6ed1810eb952c8041f80e1fe5c1f85 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 2f1bfb44e92a5842c69bd5d721d31385a32da184..b9c702b278de0cd5fc86ca60c458566f9fa9f1d8 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 e49e0cbb9fe5ca344c29459695ec31f8e66cd521..f909dcd606b0a46957643456e4da05a52e39138e 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 e20ac44d79a0f3a9211a848cfaaca947d2d2ffcc..ff1d2f89524966fdff4012288997b372b992a454 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 417a2525f199a747278252ddcd0f32ebb8a7b299..162a228c2dc99dd79f6cb3a5d0932a19ae213ab8 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 f2a2ad40a3ddda8e77b7c258355f6dce51d498b9..50dacb4485d2c24d847c967fda8666e0140d066d 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 54e1f04aec8821e127bc7ae4486da58cc6bed18b..1e5077d3c139d7377bd93ec8e7d620b699064f0d 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 25ddb59d24846c50ac99adc6c5d7b93b07c5dfcc..ecd871d22f27eef6474936eafe5be01a9874f917 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 c0719e2ead3745148f84945dd45d136be67fa332..6847697f9a59e0231dbd495a0652b8ed335d57d3 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 a00a2e9c4e0c1bd14ef356dee2a3ce41673440a5..650f245e54c0e9b84ae8119d62ce8329138a598d 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 e1b9b72b6d7ed61857b0c80cfe1714c2fdb6c0d1..21e41a9243aed1bbc5cd58444c61b2d634d83664 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 c8cee560b454b3e083cfd4e933061c15de204bfa..535ec4834a2a0af64d12da6616527b657f8d5ea7 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 e3b11cfe2ee0c25e3b6ff7d4786a56583e7e1eb2..e0e4b44023ae29e67cc6d3776dcb6a2397f0a5e6 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 4169eef5afb7232f703cbf1a159fb33cfa7477fd..6e9696b2060aef6f545b2bee480e61a29a9eef4f 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 206a594df3e0e9704e85e3e24b586ec38a8843c2..9dfd9eac37647014bb66dc871a41eedd18f5dffb 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 24168939b68b6cd511108e00aa8103a81561bb85..e7662d002e123b8b9cecefacdf5c43e754f12c11 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 49aacb499a883964f7d52a3b5057035fe89cd79f..ef6797d9a893fdfb6576bc53491130928593eb4f 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 1214dec4a8c49a2913c03ff824f60cf2bace0123..eb188ff608d8546c6ace6710dda8c8d45ef59e2a 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 991585457303b9c9c32644420c4cfcad5164827c..3c4552cf6159a48b30ad42fdc12251a504427c0e 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 9072b728b0a4e14e20546bc5a8ca4809137a06f3..f6f507bb55aad999f154cbce0374c6142464a9a2 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 7359cf515e7f48cf0bff18a2370140ca9879ddb4..13243605ed0a2ca9c1aa202f49b740f682a9cb80 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 def5509b8381ce1017533f5ecea85fdd6d527306..dd244eeaffc0a43b89cfdcac11d0ab8fa294b5e6 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 574b404c1b67067b942efd72f54e3c2478f8fc26..88921aff0321f7ca4ac996c0fc56972be0beb21e 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 398ca9cc5c433f5a6369f12ce4ccd5cee516f0a7..00d467e92c99d43ffc0861a21f5f14a23d6a9161 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 b361cc2d83371fbaceb9fc4d39a83a0c14dca175..f8a0b017fe67902c6650637407bac81e08c7f136 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 944610fcbeae3700f9ef429410095d0a8efa4480..43b66551b63ad0987778b260e1a53a256bce631b 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 e1ca00b3aecf356a9d4d1cee576ab13b232a8d04..af67c0b644d28c8536b95eac1054f900532cdcdd 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);