diff --git a/api/net/sf/briar/api/plugins/Segment.java b/api/net/sf/briar/api/plugins/Segment.java index 61c0a3ed2dec6ae98f63b90948db7c0f55868af5..b0eacf91045e4a4f6717036e8f2de1eb8d4c1881 100644 --- a/api/net/sf/briar/api/plugins/Segment.java +++ b/api/net/sf/briar/api/plugins/Segment.java @@ -2,8 +2,6 @@ package net.sf.briar.api.plugins; public interface Segment { - void clear(); - byte[] getBuffer(); int getLength(); diff --git a/components/net/sf/briar/crypto/CryptoComponentImpl.java b/components/net/sf/briar/crypto/CryptoComponentImpl.java index b1ae497099ae6488de34edd564cd2bb858cd36ae..a12dfb2d7b0a28105f1d71516b1ce54f1ec68150 100644 --- a/components/net/sf/briar/crypto/CryptoComponentImpl.java +++ b/components/net/sf/briar/crypto/CryptoComponentImpl.java @@ -30,9 +30,10 @@ class CryptoComponentImpl implements CryptoComponent { private static final String CIPHER_ALGO = "AES/CTR/NoPadding"; private static final String SECRET_KEY_ALGO = "AES"; private static final int SECRET_KEY_BYTES = 32; // 256 bits + private static final int KEY_DERIVATION_IV_BYTES = 16; // 128 bits private static final String MAC_ALGO = "HMacSHA256"; private static final String SIGNATURE_ALGO = "ECDSA"; - private static final int KEY_DERIVATION_IV_BYTES = 16; // 128 bits + private static final String TAG_CIPHER_ALGO = "AES/ECB/NoPadding"; // Labels for key derivation, null-terminated private static final byte[] FRAME = { 'F', 'R', 'A', 'M', 'E', 0 }; @@ -176,7 +177,7 @@ class CryptoComponentImpl implements CryptoComponent { public Cipher getTagCipher() { try { - return Cipher.getInstance(CIPHER_ALGO, PROVIDER); + return Cipher.getInstance(TAG_CIPHER_ALGO, PROVIDER); } catch(GeneralSecurityException e) { throw new RuntimeException(e); } diff --git a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java index 350eef73a34deebd53c606cae5ca95feb367a919..6e0677abaf3fd9a9384ef8c683c9fe999dbe09f2 100644 --- a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java +++ b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java @@ -27,9 +27,9 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory { // Validate the tag Cipher tagCipher = crypto.getTagCipher(); ErasableKey tagKey = crypto.deriveTagKey(secret, true); - boolean valid = TagEncoder.validateTag(tag, 0, tagCipher, tagKey); + long segmentNumber = TagEncoder.decodeTag(tag, tagCipher, tagKey); tagKey.erase(); - if(!valid) throw new IllegalArgumentException(); + if(segmentNumber != 0) throw new IllegalArgumentException(); return createConnectionReader(in, true, secret); } @@ -51,7 +51,10 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory { Mac mac = crypto.getMac(); IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, tagCipher, frameCipher, tagKey, frameKey, false); + // No error correction + IncomingErrorCorrectionLayer correcter = + new NullIncomingErrorCorrectionLayer(decrypter); // Create the reader - return new ConnectionReaderImpl(decrypter, mac, macKey); + return new ConnectionReaderImpl(correcter, mac, macKey); } } diff --git a/components/net/sf/briar/transport/ConnectionReaderImpl.java b/components/net/sf/briar/transport/ConnectionReaderImpl.java index 1afa4ab3780fc26fa0815b849318192bc121c548..0241369d4559a5e3c005dad9fe18657bfc0ebb33 100644 --- a/components/net/sf/briar/transport/ConnectionReaderImpl.java +++ b/components/net/sf/briar/transport/ConnectionReaderImpl.java @@ -2,12 +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 net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED; import java.io.IOException; import java.io.InputStream; import java.security.InvalidKeyException; +import java.util.Collection; +import java.util.Collections; import javax.crypto.Mac; @@ -17,16 +18,16 @@ import net.sf.briar.api.transport.ConnectionReader; class ConnectionReaderImpl extends InputStream implements ConnectionReader { - private final IncomingEncryptionLayer decrypter; + private final IncomingErrorCorrectionLayer in; private final Mac mac; - private final byte[] buf; + private final Frame frame; - private long frame = 0L; + private long frameNumber = 0L; private int offset = 0, length = 0; - ConnectionReaderImpl(IncomingEncryptionLayer decrypter, Mac mac, + ConnectionReaderImpl(IncomingErrorCorrectionLayer in, Mac mac, ErasableKey macKey) { - this.decrypter = decrypter; + this.in = in; this.mac = mac; // Initialise the MAC try { @@ -37,7 +38,7 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader { macKey.erase(); if(mac.getMacLength() != MAC_LENGTH) throw new IllegalArgumentException(); - buf = new byte[MAX_FRAME_LENGTH]; + frame = new Frame(); } public InputStream getInputStream() { @@ -47,7 +48,7 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader { @Override public int read() throws IOException { while(length == 0) if(!readFrame()) return -1; - int b = buf[offset] & 0xff; + int b = frame.getBuffer()[offset] & 0xff; offset++; length--; return b; @@ -62,7 +63,7 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader { public int read(byte[] b, int off, int len) throws IOException { while(length == 0) if(!readFrame()) return -1; len = Math.min(len, length); - System.arraycopy(buf, offset, b, off, len); + System.arraycopy(frame.getBuffer(), offset, b, off, len); offset += len; length -= len; return len; @@ -71,17 +72,19 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader { private boolean readFrame() throws IOException { assert length == 0; // Don't allow more than 2^32 frames to be read - if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException(); + if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException(); // Read a frame - int frameLength = decrypter.readFrame(buf); - if(frameLength == -1) return false; + Collection<Long> window = Collections.singleton(frameNumber); + if(!in.readFrame(frame, window)) return false; // Check that the frame number is correct and the length is legal - if(!HeaderEncoder.validateHeader(buf, frame)) + byte[] buf = frame.getBuffer(); + if(!HeaderEncoder.validateHeader(buf, frameNumber)) throw new FormatException(); + // Check that the payload and padding lengths are correct int payload = HeaderEncoder.getPayloadLength(buf); int padding = HeaderEncoder.getPaddingLength(buf); - if(frameLength != FRAME_HEADER_LENGTH + payload + padding + MAC_LENGTH) - throw new FormatException(); + if(frame.getLength() != FRAME_HEADER_LENGTH + payload + padding + + MAC_LENGTH) throw new FormatException(); // Check that the padding is all zeroes int paddingStart = FRAME_HEADER_LENGTH + payload; for(int i = paddingStart; i < paddingStart + padding; i++) { @@ -96,7 +99,7 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader { } offset = FRAME_HEADER_LENGTH; length = payload; - frame++; + frameNumber++; return true; } } diff --git a/components/net/sf/briar/transport/ConnectionRecogniserImpl.java b/components/net/sf/briar/transport/ConnectionRecogniserImpl.java index d00a4efd1de1b187f0dda9dd150278efea0d3fdb..68cfe03cd6ad7b998a0a999c884dd95d35f0c243 100644 --- a/components/net/sf/briar/transport/ConnectionRecogniserImpl.java +++ b/components/net/sf/briar/transport/ConnectionRecogniserImpl.java @@ -103,7 +103,7 @@ DatabaseListener { private Bytes calculateTag(Context ctx, byte[] secret) { ErasableKey tagKey = crypto.deriveTagKey(secret, true); byte[] tag = new byte[TAG_LENGTH]; - TagEncoder.encodeTag(tag, 0, tagCipher, tagKey); + TagEncoder.encodeTag(tag, 0L, tagCipher, tagKey); tagKey.erase(); return new Bytes(tag); } diff --git a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java index 3af3e0a56ad096d252138843d5bfbf658d2599c7..85daf0053a42667e7286022b39473bbbfd617af4 100644 --- a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java +++ b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java @@ -29,12 +29,12 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory { public ConnectionWriter createConnectionWriter(OutputStream out, long capacity, byte[] secret, byte[] tag) { - // Decrypt the tag + // Validate the tag Cipher tagCipher = crypto.getTagCipher(); ErasableKey tagKey = crypto.deriveTagKey(secret, true); - boolean valid = TagEncoder.validateTag(tag, 0, tagCipher, tagKey); + long segmentNumber = TagEncoder.decodeTag(tag, tagCipher, tagKey); tagKey.erase(); - if(!valid) throw new IllegalArgumentException(); + if(segmentNumber != 0) throw new IllegalArgumentException(); return createConnectionWriter(out, capacity, false, secret); } diff --git a/components/net/sf/briar/transport/Frame.java b/components/net/sf/briar/transport/Frame.java new file mode 100644 index 0000000000000000000000000000000000000000..f9d3ca2d1ba346941847556dee5e8a08f9049bcf --- /dev/null +++ b/components/net/sf/briar/transport/Frame.java @@ -0,0 +1,25 @@ +package net.sf.briar.transport; + +import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; + +class Frame { + + private final byte[] buf = new byte[MAX_FRAME_LENGTH]; + + private int length = -1; + + public byte[] getBuffer() { + return buf; + } + + public int getLength() { + if(length == -1) throw new IllegalStateException(); + return length; + } + + public void setLength(int length) { + if(length < 0 || length > buf.length) + throw new IllegalArgumentException(); + this.length = length; + } +} diff --git a/components/net/sf/briar/transport/IncomingEncryptionLayer.java b/components/net/sf/briar/transport/IncomingEncryptionLayer.java index bd4bd19829a000454397d49badc2bd9e7ce14d9a..c93681130c13ec5191952c0ae19f323e7b87eb42 100644 --- a/components/net/sf/briar/transport/IncomingEncryptionLayer.java +++ b/components/net/sf/briar/transport/IncomingEncryptionLayer.java @@ -2,11 +2,13 @@ package net.sf.briar.transport; import java.io.IOException; +import net.sf.briar.api.plugins.Segment; + interface IncomingEncryptionLayer { /** - * Reads a frame into the given buffer and returns its length, or -1 if no - * more frames can be read. + * Reads a segment, excluding its tag, into the given buffer. Returns false + * if no more segments can be read from the connection. */ - int readFrame(byte[] b) throws IOException; + boolean readSegment(Segment s) throws IOException; } diff --git a/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java b/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java index 21d64a3744ee7629aa851e519b5d08200176d96b..cdfd11e99526281e2b9b46df6c13d90b13a8cd46 100644 --- a/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java +++ b/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java @@ -2,8 +2,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; import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH; -import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED; import java.io.EOFException; import java.io.IOException; @@ -15,6 +16,7 @@ import javax.crypto.spec.IvParameterSpec; import net.sf.briar.api.FormatException; import net.sf.briar.api.crypto.ErasableKey; +import net.sf.briar.api.plugins.Segment; class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer { @@ -22,10 +24,11 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer { private final Cipher tagCipher, frameCipher; private final ErasableKey tagKey, frameKey; private final int blockSize; - private final byte[] iv; + private final byte[] iv, ciphertext; private final boolean tagEverySegment; - private long frame = 0L; + private boolean firstSegment = true; + private long segmentNumber = 0L; IncomingEncryptionLayerImpl(InputStream in, Cipher tagCipher, Cipher frameCipher, ErasableKey tagKey, ErasableKey frameKey, @@ -40,71 +43,73 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer { if(blockSize < FRAME_HEADER_LENGTH) throw new IllegalArgumentException(); iv = IvEncoder.encodeIv(0, blockSize); + ciphertext = new byte[MAX_SEGMENT_LENGTH]; } - public int readFrame(byte[] b) throws IOException { - if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException(); - boolean tag = tagEverySegment && frame > 0; - // Clear the buffer before exposing it to the transport plugin - for(int i = 0; i < b.length; i++) b[i] = 0; + public boolean readSegment(Segment s) throws IOException { + boolean tag = tagEverySegment && !firstSegment; try { // If a tag is expected then read, decrypt and validate it if(tag) { int offset = 0; while(offset < TAG_LENGTH) { - int read = in.read(b, offset, TAG_LENGTH - offset); + int read = in.read(ciphertext, offset, TAG_LENGTH - offset); if(read == -1) { - if(offset == 0) return -1; + if(offset == 0) return false; throw new EOFException(); } offset += read; } - if(!TagEncoder.validateTag(b, frame, tagCipher, tagKey)) - throw new FormatException(); + long seg = TagEncoder.decodeTag(ciphertext, tagCipher, tagKey); + if(seg == -1) throw new FormatException(); + segmentNumber = seg; } - // Read the first block + // Read the first block of the frame/segment int offset = 0; while(offset < blockSize) { - int read = in.read(b, offset, blockSize - offset); + int read = in.read(ciphertext, offset, blockSize - offset); if(read == -1) { - if(offset == 0 && !tag) return -1; + if(offset == 0 && !tag && !firstSegment) return false; throw new EOFException(); } offset += read; } - // Decrypt the first block + // Decrypt the first block of the frame/segment + byte[] plaintext = s.getBuffer(); try { - IvEncoder.updateIv(iv, frame); + IvEncoder.updateIv(iv, segmentNumber); IvParameterSpec ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec); - int decrypted = frameCipher.update(b, 0, blockSize, b); + int decrypted = frameCipher.update(ciphertext, 0, blockSize, + plaintext); if(decrypted != blockSize) throw new RuntimeException(); } catch(GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } - // Validate and parse the header - if(!HeaderEncoder.validateHeader(b, frame)) - throw new FormatException(); - int payload = HeaderEncoder.getPayloadLength(b); - int padding = HeaderEncoder.getPaddingLength(b); + // Parse the frame header + int payload = HeaderEncoder.getPayloadLength(plaintext); + int padding = HeaderEncoder.getPaddingLength(plaintext); int length = FRAME_HEADER_LENGTH + payload + padding + MAC_LENGTH; - // Read the remainder of the frame + if(length > MAX_FRAME_LENGTH) throw new FormatException(); + // Read the remainder of the frame/segment while(offset < length) { - int read = in.read(b, offset, length - offset); + int read = in.read(ciphertext, offset, length - offset); if(read == -1) throw new EOFException(); offset += read; } - // Decrypt the remainder of the frame + // Decrypt the remainder of the frame/segment try { - int decrypted = frameCipher.doFinal(b, blockSize, - length - blockSize, b, blockSize); + int decrypted = frameCipher.doFinal(ciphertext, blockSize, + length - blockSize, plaintext, blockSize); if(decrypted != length - blockSize) throw new RuntimeException(); } catch(GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } - frame++; - return length; + s.setLength(length); + s.setSegmentNumber(segmentNumber++); + firstSegment = false; + return true; } catch(IOException e) { frameKey.erase(); tagKey.erase(); diff --git a/components/net/sf/briar/transport/IncomingErrorCorrectionLayer.java b/components/net/sf/briar/transport/IncomingErrorCorrectionLayer.java new file mode 100644 index 0000000000000000000000000000000000000000..446c7a3ef52d5f64beccf4574702f54eb36e2a7c --- /dev/null +++ b/components/net/sf/briar/transport/IncomingErrorCorrectionLayer.java @@ -0,0 +1,14 @@ +package net.sf.briar.transport; + +import java.io.IOException; +import java.util.Collection; + +interface IncomingErrorCorrectionLayer { + + /** + * Reads a frame into the given buffer. The frame number must be contained + * in the given window. Returns false if no more frames can be read from + * the connection. + */ + boolean readFrame(Frame f, Collection<Long> window) throws IOException; +} diff --git a/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java b/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java index 61af30b988eed27bc9a97dc7c3ca1a4c54db6b3d..00652bd49ebb15a6e27955f24857968bac90b282 100644 --- a/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java +++ b/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java @@ -4,7 +4,6 @@ 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 static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED; import java.io.IOException; import java.security.GeneralSecurityException; @@ -27,7 +26,8 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer { private final Segment segment; private final boolean tagEverySegment; - private long frame = 0L; + private boolean firstSegment = true; + private long segmentNumber = 0L; IncomingSegmentedEncryptionLayer(SegmentSource in, Cipher tagCipher, Cipher frameCipher, ErasableKey tagKey, ErasableKey frameKey, @@ -45,41 +45,37 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer { segment = new SegmentImpl(); } - public int readFrame(byte[] b) throws IOException { - if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException(); - boolean tag = tagEverySegment && frame > 0; - // Clear the buffer before exposing it to the transport plugin - segment.clear(); + public boolean readSegment(Segment s) throws IOException { + boolean tag = tagEverySegment && !firstSegment; try { // Read the segment - if(!in.readSegment(segment)) return -1; + if(!in.readSegment(segment)) return false; int offset = tag ? TAG_LENGTH : 0, length = segment.getLength(); if(length > MAX_SEGMENT_LENGTH) throw new FormatException(); if(length < offset + FRAME_HEADER_LENGTH + MAC_LENGTH) throw new FormatException(); - // If a tag is expected, decrypt and validate it - if(tag && !TagEncoder.validateTag(segment.getBuffer(), frame, - tagCipher, tagKey)) throw new FormatException(); - // Decrypt the frame + byte[] ciphertext = segment.getBuffer(); + // If a tag is expected then decrypt and validate it + if(tag) { + long seg = TagEncoder.decodeTag(ciphertext, tagCipher, tagKey); + if(seg == -1) throw new FormatException(); + segmentNumber = seg; + } + // Decrypt the segment try { - IvEncoder.updateIv(iv, frame); + IvEncoder.updateIv(iv, segmentNumber); IvParameterSpec ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec); - int decrypted = frameCipher.doFinal(segment.getBuffer(), offset, - length - offset, b); + int decrypted = frameCipher.doFinal(ciphertext, offset, + length - offset, s.getBuffer()); if(decrypted != length - offset) throw new RuntimeException(); } catch(GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } - // Validate and parse the header - if(!HeaderEncoder.validateHeader(b, frame)) - throw new FormatException(); - int payload = HeaderEncoder.getPayloadLength(b); - int padding = HeaderEncoder.getPaddingLength(b); - if(length != offset + FRAME_HEADER_LENGTH + payload + padding - + MAC_LENGTH) throw new FormatException(); - frame++; - return length - offset; + s.setLength(length - offset); + s.setSegmentNumber(segmentNumber++); + firstSegment = false; + return true; } catch(IOException e) { frameKey.erase(); tagKey.erase(); diff --git a/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java b/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java new file mode 100644 index 0000000000000000000000000000000000000000..cd97383c7c08bebd7f153bf0219d741756a6c47f --- /dev/null +++ b/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java @@ -0,0 +1,31 @@ +package net.sf.briar.transport; + +import java.io.IOException; +import java.util.Collection; + +import net.sf.briar.api.plugins.Segment; + +class NullIncomingErrorCorrectionLayer implements IncomingErrorCorrectionLayer { + + private final IncomingEncryptionLayer in; + private final Segment segment; + + NullIncomingErrorCorrectionLayer(IncomingEncryptionLayer in) { + this.in = in; + segment = new SegmentImpl(); + } + + public boolean readFrame(Frame f, Collection<Long> window) + throws IOException { + while(true) { + if(!in.readSegment(segment)) return false; + byte[] buf = segment.getBuffer(); + if(window.contains(HeaderEncoder.getFrameNumber(buf))) break; + } + int length = segment.getLength(); + // FIXME: Unnecessary copy + System.arraycopy(segment.getBuffer(), 0, f.getBuffer(), 0, length); + f.setLength(length); + return true; + } +} diff --git a/components/net/sf/briar/transport/SegmentImpl.java b/components/net/sf/briar/transport/SegmentImpl.java index 0ad809bdc0838e86bf82c0b89d3ba9e5ce4a4642..da3d4eab391387085857776978dc219a494b4fd9 100644 --- a/components/net/sf/briar/transport/SegmentImpl.java +++ b/components/net/sf/briar/transport/SegmentImpl.java @@ -11,12 +11,6 @@ class SegmentImpl implements Segment { private int length = -1; private long segmentNumber = -1; - public void clear() { - for(int i = 0; i < buf.length; i++) buf[i] = 0; - length = -1; - segmentNumber = -1; - } - public byte[] getBuffer() { return buf; } diff --git a/components/net/sf/briar/transport/TagEncoder.java b/components/net/sf/briar/transport/TagEncoder.java index 6afa2bead72d06f19190096c3dbc16bafae531e8..3ca17ea6208b8fb93771c3d117568a2a3bcdd0cd 100644 --- a/components/net/sf/briar/transport/TagEncoder.java +++ b/components/net/sf/briar/transport/TagEncoder.java @@ -6,28 +6,22 @@ import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED; import java.security.GeneralSecurityException; import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; import net.sf.briar.api.crypto.ErasableKey; import net.sf.briar.util.ByteUtils; class TagEncoder { - private static final byte[] BLANK = new byte[TAG_LENGTH]; - - static void encodeTag(byte[] tag, long frame, Cipher tagCipher, + static void encodeTag(byte[] tag, long segmentNumber, Cipher tagCipher, ErasableKey tagKey) { if(tag.length < TAG_LENGTH) throw new IllegalArgumentException(); - if(frame < 0 || frame > MAX_32_BIT_UNSIGNED) + if(segmentNumber < 0 || segmentNumber > MAX_32_BIT_UNSIGNED) throw new IllegalArgumentException(); - // Encode the frame number as a uint32 at the end of the IV - byte[] iv = new byte[tagCipher.getBlockSize()]; - if(iv.length != TAG_LENGTH) throw new IllegalArgumentException(); - ByteUtils.writeUint32(frame, iv, iv.length - 4); - IvParameterSpec ivSpec = new IvParameterSpec(iv); + // Encode the segment number as a uint32 at the end of the tag + ByteUtils.writeUint32(segmentNumber, tag, TAG_LENGTH - 4); try { - tagCipher.init(Cipher.ENCRYPT_MODE, tagKey, ivSpec); - int encrypted = tagCipher.doFinal(BLANK, 0, TAG_LENGTH, tag); + tagCipher.init(Cipher.ENCRYPT_MODE, tagKey); + int encrypted = tagCipher.doFinal(tag, 0, TAG_LENGTH, tag); if(encrypted != TAG_LENGTH) throw new IllegalArgumentException(); } catch(GeneralSecurityException e) { // Unsuitable cipher or key @@ -35,26 +29,18 @@ class TagEncoder { } } - static boolean validateTag(byte[] tag, long frame, Cipher tagCipher, - ErasableKey tagKey) { - if(frame < 0 || frame > MAX_32_BIT_UNSIGNED) - throw new IllegalArgumentException(); - if(tag.length < TAG_LENGTH) return false; - // Encode the frame number as a uint32 at the end of the IV - byte[] iv = new byte[tagCipher.getBlockSize()]; - if(iv.length != TAG_LENGTH) throw new IllegalArgumentException(); - ByteUtils.writeUint32(frame, iv, iv.length - 4); - IvParameterSpec ivSpec = new IvParameterSpec(iv); + static long decodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey) { + if(tag.length < TAG_LENGTH) throw new IllegalArgumentException(); try { - tagCipher.init(Cipher.DECRYPT_MODE, tagKey, ivSpec); + tagCipher.init(Cipher.DECRYPT_MODE, tagKey); byte[] plaintext = tagCipher.doFinal(tag, 0, TAG_LENGTH); if(plaintext.length != TAG_LENGTH) throw new IllegalArgumentException(); - // The plaintext should be blank - for(int i = 0; i < plaintext.length; i++) { - if(plaintext[i] != 0) return false; + // All but the last four bytes of the plaintext should be blank + for(int i = 0; i < TAG_LENGTH - 4; i++) { + if(plaintext[i] != 0) return -1; } - return true; + return ByteUtils.readUint32(plaintext, TAG_LENGTH - 4); } catch(GeneralSecurityException e) { // Unsuitable cipher or key throw new IllegalArgumentException(e); diff --git a/test/net/sf/briar/transport/ConnectionReaderImplTest.java b/test/net/sf/briar/transport/ConnectionReaderImplTest.java index 2eda0dc36597ae0d3c8eec7c82ed0348844a506e..344561e799c53a367719f71391c7fefdd35937f5 100644 --- a/test/net/sf/briar/transport/ConnectionReaderImplTest.java +++ b/test/net/sf/briar/transport/ConnectionReaderImplTest.java @@ -33,7 +33,9 @@ public class ConnectionReaderImplTest extends TransportTest { // Read the frame ByteArrayInputStream in = new ByteArrayInputStream(frame); IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in); - ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey); + IncomingErrorCorrectionLayer correcter = + new NullIncomingErrorCorrectionLayer(decrypter); + ConnectionReader r = new ConnectionReaderImpl(correcter, mac, macKey); // There should be no bytes available before EOF assertEquals(-1, r.getInputStream().read()); } @@ -51,7 +53,9 @@ public class ConnectionReaderImplTest extends TransportTest { // Read the frame ByteArrayInputStream in = new ByteArrayInputStream(frame); IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in); - ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey); + IncomingErrorCorrectionLayer correcter = + new NullIncomingErrorCorrectionLayer(decrypter); + ConnectionReader r = new ConnectionReaderImpl(correcter, mac, macKey); // There should be one byte available before EOF assertEquals(0, r.getInputStream().read()); assertEquals(-1, r.getInputStream().read()); @@ -77,7 +81,9 @@ public class ConnectionReaderImplTest extends TransportTest { // Read the first frame ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in); - ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey); + IncomingErrorCorrectionLayer correcter = + new NullIncomingErrorCorrectionLayer(decrypter); + ConnectionReader r = new ConnectionReaderImpl(correcter, mac, macKey); byte[] read = new byte[MAX_PAYLOAD_LENGTH]; TestUtils.readFully(r.getInputStream(), read); // Try to read the second frame @@ -111,7 +117,9 @@ public class ConnectionReaderImplTest extends TransportTest { // Read the first frame ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in); - ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey); + IncomingErrorCorrectionLayer correcter = + new NullIncomingErrorCorrectionLayer(decrypter); + ConnectionReader r = new ConnectionReaderImpl(correcter, mac, macKey); byte[] read = new byte[MAX_PAYLOAD_LENGTH - paddingLength]; TestUtils.readFully(r.getInputStream(), read); // Try to read the second frame @@ -137,7 +145,9 @@ public class ConnectionReaderImplTest extends TransportTest { // Read the frame ByteArrayInputStream in = new ByteArrayInputStream(frame); IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in); - ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey); + IncomingErrorCorrectionLayer correcter = + new NullIncomingErrorCorrectionLayer(decrypter); + ConnectionReader r = new ConnectionReaderImpl(correcter, mac, macKey); // The non-zero padding should be rejected try { r.getInputStream().read(); @@ -169,7 +179,9 @@ public class ConnectionReaderImplTest extends TransportTest { // Read the frames ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in); - ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey); + IncomingErrorCorrectionLayer correcter = + new NullIncomingErrorCorrectionLayer(decrypter); + ConnectionReader r = new ConnectionReaderImpl(correcter, mac, macKey); byte[] read = new byte[payloadLength]; TestUtils.readFully(r.getInputStream(), read); assertArrayEquals(new byte[payloadLength], read); @@ -193,7 +205,9 @@ public class ConnectionReaderImplTest extends TransportTest { // Try to read the frame - not a single byte should be read ByteArrayInputStream in = new ByteArrayInputStream(frame); IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in); - ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey); + IncomingErrorCorrectionLayer correcter = + new NullIncomingErrorCorrectionLayer(decrypter); + ConnectionReader r = new ConnectionReaderImpl(correcter, mac, macKey); try { r.getInputStream().read(); fail(); @@ -215,7 +229,9 @@ public class ConnectionReaderImplTest extends TransportTest { // Try to read the frame - not a single byte should be read ByteArrayInputStream in = new ByteArrayInputStream(frame); IncomingEncryptionLayer decrypter = new NullIncomingEncryptionLayer(in); - ConnectionReader r = new ConnectionReaderImpl(decrypter, mac, macKey); + IncomingErrorCorrectionLayer correcter = + new NullIncomingErrorCorrectionLayer(decrypter); + ConnectionReader r = new ConnectionReaderImpl(correcter, mac, macKey); try { r.getInputStream().read(); fail(); diff --git a/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java b/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java index a35279e54393359cb03e5085256811ec7033d561..a18f12b5be892295cb88813d2867c5d69e589337 100644 --- a/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java +++ b/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java @@ -618,7 +618,7 @@ public class ConnectionRecogniserImplTest extends BriarTestCase { ErasableKey tagKey = crypto.deriveTagKey(secret, true); Cipher tagCipher = crypto.getTagCipher(); byte[] tag = new byte[TAG_LENGTH]; - TagEncoder.encodeTag(tag, 0, tagCipher, tagKey); + TagEncoder.encodeTag(tag, 0L, tagCipher, tagKey); return tag; } } diff --git a/test/net/sf/briar/transport/FrameReadWriteTest.java b/test/net/sf/briar/transport/FrameReadWriteTest.java index 1646c8c36034d8dbb08e252d1b26a6e8d92cdcff..4699597f901a96b5aaff5fc151ed066853bdc078 100644 --- a/test/net/sf/briar/transport/FrameReadWriteTest.java +++ b/test/net/sf/briar/transport/FrameReadWriteTest.java @@ -62,7 +62,7 @@ public class FrameReadWriteTest extends BriarTestCase { private void testWriteAndRead(boolean initiator) throws Exception { // Encode the tag byte[] tag = new byte[TAG_LENGTH]; - TagEncoder.encodeTag(tag, 0, tagCipher, tagKey); + TagEncoder.encodeTag(tag, 0L, tagCipher, tagKey); // Generate two random frames byte[] frame = new byte[12345]; random.nextBytes(frame); @@ -89,11 +89,13 @@ public class FrameReadWriteTest extends BriarTestCase { byte[] recoveredTag = new byte[TAG_LENGTH]; assertEquals(TAG_LENGTH, in.read(recoveredTag)); assertArrayEquals(tag, recoveredTag); - assertTrue(TagEncoder.validateTag(tag, 0, tagCipher, tagKey)); + assertEquals(0L, TagEncoder.decodeTag(tag, tagCipher, tagKey)); // Read the frames back IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, tagCipher, frameCipher, tagKey, frameKey, false); - ConnectionReader reader = new ConnectionReaderImpl(decrypter, mac, + IncomingErrorCorrectionLayer correcter = + new NullIncomingErrorCorrectionLayer(decrypter); + ConnectionReader reader = new ConnectionReaderImpl(correcter, mac, macKey); InputStream in1 = reader.getInputStream(); byte[] recovered = new byte[frame.length]; diff --git a/test/net/sf/briar/transport/IncomingEncryptionLayerImplTest.java b/test/net/sf/briar/transport/IncomingEncryptionLayerImplTest.java index 62724afbb8c3e604c27365d5640de8cdb62ac140..4db4ed9297a28b9e957e464f3f4a0229db82d73e 100644 --- a/test/net/sf/briar/transport/IncomingEncryptionLayerImplTest.java +++ b/test/net/sf/briar/transport/IncomingEncryptionLayerImplTest.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.api.transport.TransportConstants.TAG_LENGTH; import java.io.ByteArrayInputStream; @@ -13,6 +12,7 @@ import javax.crypto.spec.IvParameterSpec; import net.sf.briar.BriarTestCase; import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.ErasableKey; +import net.sf.briar.api.plugins.Segment; import net.sf.briar.crypto.CryptoModule; import org.apache.commons.io.output.ByteArrayOutputStream; @@ -38,14 +38,14 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase { @Test public void testDecryptionWithFirstSegmentTagged() throws Exception { - // Calculate the ciphertext for the first frame + // Calculate the ciphertext for the first segment byte[] plaintext = new byte[FRAME_HEADER_LENGTH + 123 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext, 0L, 123, 0); byte[] iv = IvEncoder.encodeIv(0L, frameCipher.getBlockSize()); IvParameterSpec ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); byte[] ciphertext = frameCipher.doFinal(plaintext, 0, plaintext.length); - // Calculate the ciphertext for the second frame + // Calculate the ciphertext for the second segment byte[] plaintext1 = new byte[FRAME_HEADER_LENGTH + 1234 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext1, 1L, 1234, 0); IvEncoder.updateIv(iv, 1L); @@ -62,13 +62,19 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase { IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, tagCipher, frameCipher, tagKey, frameKey, false); // First frame - byte[] decrypted = new byte[MAX_FRAME_LENGTH]; - assertEquals(plaintext.length, decrypter.readFrame(decrypted)); + Segment s = new SegmentImpl(); + assertTrue(decrypter.readSegment(s)); + assertEquals(plaintext.length, s.getLength()); + assertEquals(0L, s.getSegmentNumber()); + byte[] decrypted = s.getBuffer(); for(int i = 0; i < plaintext.length; i++) { assertEquals(plaintext[i], decrypted[i]); } // Second frame - assertEquals(plaintext1.length, decrypter.readFrame(decrypted)); + assertTrue(decrypter.readSegment(s)); + assertEquals(plaintext1.length, s.getLength()); + assertEquals(1L, s.getSegmentNumber()); + decrypted = s.getBuffer(); for(int i = 0; i < plaintext1.length; i++) { assertEquals(plaintext1[i], decrypted[i]); } @@ -76,18 +82,18 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase { @Test public void testDecryptionWithEverySegmentTagged() throws Exception { - // Calculate the ciphertext for the first frame + // Calculate the ciphertext for the first segment byte[] plaintext = new byte[FRAME_HEADER_LENGTH + 123 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext, 0L, 123, 0); byte[] iv = IvEncoder.encodeIv(0L, frameCipher.getBlockSize()); IvParameterSpec ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); byte[] ciphertext = frameCipher.doFinal(plaintext, 0, plaintext.length); - // Calculate the ciphertext for the second frame, including its tag + // Calculate the ciphertext for the second segment, including its tag byte[] plaintext1 = new byte[FRAME_HEADER_LENGTH + 1234 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext1, 1L, 1234, 0); byte[] ciphertext1 = new byte[TAG_LENGTH + plaintext1.length]; - TagEncoder.encodeTag(ciphertext1, 1, tagCipher, tagKey); + TagEncoder.encodeTag(ciphertext1, 1L, tagCipher, tagKey); IvEncoder.updateIv(iv, 1L); ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); @@ -102,13 +108,19 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase { IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, tagCipher, frameCipher, tagKey, frameKey, true); // First frame - byte[] decrypted = new byte[MAX_FRAME_LENGTH]; - assertEquals(plaintext.length, decrypter.readFrame(decrypted)); + Segment s = new SegmentImpl(); + assertTrue(decrypter.readSegment(s)); + assertEquals(plaintext.length, s.getLength()); + assertEquals(0L, s.getSegmentNumber()); + byte[] decrypted = s.getBuffer(); for(int i = 0; i < plaintext.length; i++) { assertEquals(plaintext[i], decrypted[i]); } // Second frame - assertEquals(plaintext1.length, decrypter.readFrame(decrypted)); + assertTrue(decrypter.readSegment(s)); + assertEquals(plaintext1.length, s.getLength()); + assertEquals(1L, s.getSegmentNumber()); + decrypted = s.getBuffer(); for(int i = 0; i < plaintext1.length; i++) { assertEquals(plaintext1[i], decrypted[i]); } diff --git a/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java b/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java index f5c70be4d84074365a588f88588170fd366cf79c..fbcf8cc78c226dd2b7626e9dd7794a64830db845 100644 --- a/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java +++ b/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.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.api.transport.TransportConstants.TAG_LENGTH; import java.io.IOException; @@ -39,14 +38,14 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase { @Test public void testDecryptionWithFirstSegmentTagged() throws Exception { - // Calculate the ciphertext for the first frame + // Calculate the ciphertext for the first segment byte[] plaintext = new byte[FRAME_HEADER_LENGTH + 123 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext, 0L, 123, 0); byte[] iv = IvEncoder.encodeIv(0L, frameCipher.getBlockSize()); IvParameterSpec ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); byte[] ciphertext = frameCipher.doFinal(plaintext, 0, plaintext.length); - // Calculate the ciphertext for the second frame + // Calculate the ciphertext for the second segment byte[] plaintext1 = new byte[FRAME_HEADER_LENGTH + 1234 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext1, 1L, 1234, 0); IvEncoder.updateIv(iv, 1L); @@ -61,13 +60,19 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase { new IncomingSegmentedEncryptionLayer(in, tagCipher, frameCipher, tagKey, frameKey, false); // First frame - byte[] decrypted = new byte[MAX_FRAME_LENGTH]; - assertEquals(plaintext.length, decrypter.readFrame(decrypted)); + Segment s = new SegmentImpl(); + assertTrue(decrypter.readSegment(s)); + assertEquals(plaintext.length, s.getLength()); + assertEquals(0L, s.getSegmentNumber()); + byte[] decrypted = s.getBuffer(); for(int i = 0; i < plaintext.length; i++) { assertEquals(plaintext[i], decrypted[i]); } // Second frame - assertEquals(plaintext1.length, decrypter.readFrame(decrypted)); + assertTrue(decrypter.readSegment(s)); + assertEquals(plaintext1.length, s.getLength()); + assertEquals(1L, s.getSegmentNumber()); + decrypted = s.getBuffer(); for(int i = 0; i < plaintext1.length; i++) { assertEquals(plaintext1[i], decrypted[i]); } @@ -86,7 +91,7 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase { byte[] plaintext1 = new byte[FRAME_HEADER_LENGTH + 1234 + MAC_LENGTH]; HeaderEncoder.encodeHeader(plaintext1, 1L, 1234, 0); byte[] ciphertext1 = new byte[TAG_LENGTH + plaintext1.length]; - TagEncoder.encodeTag(ciphertext1, 1, tagCipher, tagKey); + TagEncoder.encodeTag(ciphertext1, 1L, tagCipher, tagKey); IvEncoder.updateIv(iv, 1L); ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); @@ -99,13 +104,19 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase { new IncomingSegmentedEncryptionLayer(in, tagCipher, frameCipher, tagKey, frameKey, true); // First frame - byte[] decrypted = new byte[MAX_FRAME_LENGTH]; - assertEquals(plaintext.length, decrypter.readFrame(decrypted)); + Segment s = new SegmentImpl(); + assertTrue(decrypter.readSegment(s)); + assertEquals(plaintext.length, s.getLength()); + assertEquals(0L, s.getSegmentNumber()); + byte[] decrypted = s.getBuffer(); for(int i = 0; i < plaintext.length; i++) { assertEquals(plaintext[i], decrypted[i]); } // Second frame - assertEquals(plaintext1.length, decrypter.readFrame(decrypted)); + assertTrue(decrypter.readSegment(s)); + assertEquals(plaintext1.length, s.getLength()); + assertEquals(1L, s.getSegmentNumber()); + decrypted = s.getBuffer(); for(int i = 0; i < plaintext1.length; i++) { assertEquals(plaintext1[i], decrypted[i]); } diff --git a/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java b/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java index 03892bdaf6d00900e73b8c655e418805f1f1c3ee..057bcea77bb6753f5cbacb900eaefc58bf76cedd 100644 --- a/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java +++ b/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java @@ -9,38 +9,44 @@ import java.io.IOException; import java.io.InputStream; import net.sf.briar.api.FormatException; +import net.sf.briar.api.plugins.Segment; /** An encryption layer that performs no encryption. */ class NullIncomingEncryptionLayer implements IncomingEncryptionLayer { private final InputStream in; + private long segmentNumber = 0L; + NullIncomingEncryptionLayer(InputStream in) { this.in = in; } - public int readFrame(byte[] b) throws IOException { - // Read the header to determine the frame length + public boolean readSegment(Segment s) throws IOException { + byte[] buf = s.getBuffer(); + // Read the frame header int offset = 0, length = FRAME_HEADER_LENGTH; while(offset < length) { - int read = in.read(b, offset, length - offset); + int read = in.read(buf, offset, length - offset); if(read == -1) { - if(offset == 0) return -1; + if(offset == 0) return false; throw new EOFException(); } offset += read; } - // Parse the header - int payload = HeaderEncoder.getPayloadLength(b); - int padding = HeaderEncoder.getPaddingLength(b); + // Parse the frame header + int payload = HeaderEncoder.getPayloadLength(buf); + int padding = HeaderEncoder.getPaddingLength(buf); length = FRAME_HEADER_LENGTH + payload + padding + MAC_LENGTH; if(length > MAX_FRAME_LENGTH) throw new FormatException(); - // Read the remainder of the frame + // Read the remainder of the frame/segment while(offset < length) { - int read = in.read(b, offset, length - offset); + int read = in.read(buf, offset, length - offset); if(read == -1) throw new EOFException(); offset += read; } - return length; + s.setLength(length); + s.setSegmentNumber(segmentNumber++); + return true; } } diff --git a/test/net/sf/briar/transport/OutgoingEncryptionLayerImplTest.java b/test/net/sf/briar/transport/OutgoingEncryptionLayerImplTest.java index 8aa93d68e8ddb87423717f4744eb8b4b16891d08..6e16d1aa7245e92424550d978b347e1b80c9b112 100644 --- a/test/net/sf/briar/transport/OutgoingEncryptionLayerImplTest.java +++ b/test/net/sf/briar/transport/OutgoingEncryptionLayerImplTest.java @@ -39,14 +39,14 @@ public class OutgoingEncryptionLayerImplTest extends BriarTestCase { public void testEncryptionWithFirstSegmentTagged() throws Exception { // Calculate the expected tag byte[] tag = new byte[TAG_LENGTH]; - TagEncoder.encodeTag(tag, 0, tagCipher, tagKey); - // Calculate the expected ciphertext for the first frame + TagEncoder.encodeTag(tag, 0L, tagCipher, tagKey); + // Calculate the expected ciphertext for the first segment byte[] iv = new byte[frameCipher.getBlockSize()]; byte[] plaintext = new byte[123 + MAC_LENGTH]; IvParameterSpec ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); byte[] ciphertext = frameCipher.doFinal(plaintext); - // Calculate the expected ciphertext for the second frame + // Calculate the expected ciphertext for the second segment byte[] plaintext1 = new byte[1234 + MAC_LENGTH]; IvEncoder.updateIv(iv, 1L); ivSpec = new IvParameterSpec(iv); @@ -76,17 +76,17 @@ public class OutgoingEncryptionLayerImplTest extends BriarTestCase { public void testEncryptionWithEverySegmentTagged() throws Exception { // Calculate the expected tag for the first segment byte[] tag = new byte[TAG_LENGTH]; - TagEncoder.encodeTag(tag, 0, tagCipher, tagKey); - // Calculate the expected ciphertext for the first frame + TagEncoder.encodeTag(tag, 0L, tagCipher, tagKey); + // Calculate the expected ciphertext for the first segment byte[] iv = new byte[frameCipher.getBlockSize()]; byte[] plaintext = new byte[123 + MAC_LENGTH]; IvParameterSpec ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); byte[] ciphertext = frameCipher.doFinal(plaintext); - // Calculate the expected tag for the second frame + // Calculate the expected tag for the second segment byte[] tag1 = new byte[TAG_LENGTH]; - TagEncoder.encodeTag(tag1, 1, tagCipher, tagKey); - // Calculate the expected ciphertext for the second frame + TagEncoder.encodeTag(tag1, 1L, tagCipher, tagKey); + // Calculate the expected ciphertext for the second segment byte[] plaintext1 = new byte[1234 + MAC_LENGTH]; IvEncoder.updateIv(iv, 1L); ivSpec = new IvParameterSpec(iv); diff --git a/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java b/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java index ecbbbc1c68ed981bbdd92fea0af047d25330ed95..0fa64f2c0cc711c3ef8471ecd10eaaf7623354a3 100644 --- a/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java +++ b/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java @@ -42,14 +42,14 @@ public class OutgoingSegmentedEncryptionLayerTest extends BriarTestCase { public void testEncryptionWithFirstSegmentTagged() throws Exception { // Calculate the expected tag byte[] tag = new byte[TAG_LENGTH]; - TagEncoder.encodeTag(tag, 0, tagCipher, tagKey); - // Calculate the expected ciphertext for the first frame + TagEncoder.encodeTag(tag, 0L, tagCipher, tagKey); + // Calculate the expected ciphertext for the first segment byte[] iv = new byte[frameCipher.getBlockSize()]; byte[] plaintext = new byte[123 + MAC_LENGTH]; IvParameterSpec ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); byte[] ciphertext = frameCipher.doFinal(plaintext); - // Calculate the expected ciphertext for the second frame + // Calculate the expected ciphertext for the second segment byte[] plaintext1 = new byte[1234 + MAC_LENGTH]; IvEncoder.updateIv(iv, 1L); ivSpec = new IvParameterSpec(iv); @@ -78,19 +78,19 @@ public class OutgoingSegmentedEncryptionLayerTest extends BriarTestCase { @Test public void testEncryptionWithEverySegmentTagged() throws Exception { - // Calculate the expected tag for the first frame + // Calculate the expected tag for the first segment byte[] tag = new byte[TAG_LENGTH]; - TagEncoder.encodeTag(tag, 0, tagCipher, tagKey); - // Calculate the expected ciphertext for the first frame + TagEncoder.encodeTag(tag, 0L, tagCipher, tagKey); + // Calculate the expected ciphertext for the first segment byte[] iv = new byte[frameCipher.getBlockSize()]; byte[] plaintext = new byte[123 + MAC_LENGTH]; IvParameterSpec ivSpec = new IvParameterSpec(iv); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); byte[] ciphertext = frameCipher.doFinal(plaintext); - // Calculate the expected tag for the second frame + // Calculate the expected tag for the second segment byte[] tag1 = new byte[TAG_LENGTH]; - TagEncoder.encodeTag(tag1, 1, tagCipher, tagKey); - // Calculate the expected ciphertext for the second frame + TagEncoder.encodeTag(tag1, 1L, tagCipher, tagKey); + // Calculate the expected ciphertext for the second segment byte[] plaintext1 = new byte[1234 + MAC_LENGTH]; IvEncoder.updateIv(iv, 1L); ivSpec = new IvParameterSpec(iv); diff --git a/test/net/sf/briar/transport/TransportTest.java b/test/net/sf/briar/transport/TransportTest.java index 3db6a202fdbbabc4fb144d1d0a9aad53d1c59ecd..c44e6fc2c76000ad8f8199168b9ea16e00f20f99 100644 --- a/test/net/sf/briar/transport/TransportTest.java +++ b/test/net/sf/briar/transport/TransportTest.java @@ -16,8 +16,8 @@ import com.google.inject.Injector; public abstract class TransportTest extends BriarTestCase { - static final int MAX_PAYLOAD_LENGTH - = MAX_FRAME_LENGTH - FRAME_HEADER_LENGTH - MAC_LENGTH; + static final int MAX_PAYLOAD_LENGTH = + MAX_FRAME_LENGTH - FRAME_HEADER_LENGTH - MAC_LENGTH; protected final Mac mac; protected final ErasableKey macKey;