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