mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 21:29:54 +01:00
Converted the outgoing encryption layer from frames to segments.
This commit is contained in:
@@ -50,8 +50,11 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
|||||||
Cipher frameCipher = crypto.getFrameCipher();
|
Cipher frameCipher = crypto.getFrameCipher();
|
||||||
OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out,
|
OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out,
|
||||||
capacity, tagCipher, frameCipher, tagKey, frameKey, false);
|
capacity, tagCipher, frameCipher, tagKey, frameKey, false);
|
||||||
|
// No error correction
|
||||||
|
OutgoingErrorCorrectionLayer correcter =
|
||||||
|
new NullOutgoingErrorCorrectionLayer(encrypter);
|
||||||
// Create the writer
|
// Create the writer
|
||||||
Mac mac = crypto.getMac();
|
Mac mac = crypto.getMac();
|
||||||
return new ConnectionWriterImpl(encrypter, mac, macKey);
|
return new ConnectionWriterImpl(correcter, mac, macKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,16 +23,16 @@ import net.sf.briar.api.transport.ConnectionWriter;
|
|||||||
*/
|
*/
|
||||||
class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
|
class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
|
||||||
|
|
||||||
private final OutgoingEncryptionLayer encrypter;
|
private final OutgoingErrorCorrectionLayer out;
|
||||||
private final Mac mac;
|
private final Mac mac;
|
||||||
private final byte[] buf;
|
private final Frame frame;
|
||||||
|
|
||||||
private int length = FRAME_HEADER_LENGTH;
|
private int offset = FRAME_HEADER_LENGTH;
|
||||||
private long frame = 0L;
|
private long frameNumber = 0L;
|
||||||
|
|
||||||
ConnectionWriterImpl(OutgoingEncryptionLayer encrypter, Mac mac,
|
ConnectionWriterImpl(OutgoingErrorCorrectionLayer out, Mac mac,
|
||||||
ErasableKey macKey) {
|
ErasableKey macKey) {
|
||||||
this.encrypter = encrypter;
|
this.out = out;
|
||||||
this.mac = mac;
|
this.mac = mac;
|
||||||
// Initialise the MAC
|
// Initialise the MAC
|
||||||
try {
|
try {
|
||||||
@@ -43,7 +43,7 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
|
|||||||
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 OutputStream getOutputStream() {
|
public OutputStream getOutputStream() {
|
||||||
@@ -51,10 +51,10 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getRemainingCapacity() {
|
public long getRemainingCapacity() {
|
||||||
long capacity = encrypter.getRemainingCapacity();
|
long capacity = out.getRemainingCapacity();
|
||||||
// If there's any data buffered, subtract it and its overhead
|
// If there's any data buffered, subtract it and its overhead
|
||||||
if(length > FRAME_HEADER_LENGTH)
|
if(offset > FRAME_HEADER_LENGTH)
|
||||||
capacity -= length + MAC_LENGTH;
|
capacity -= offset + MAC_LENGTH;
|
||||||
// Subtract the overhead from the remaining capacity
|
// Subtract the overhead from the remaining capacity
|
||||||
long frames = (long) Math.ceil((double) capacity / MAX_FRAME_LENGTH);
|
long frames = (long) Math.ceil((double) capacity / MAX_FRAME_LENGTH);
|
||||||
int overheadPerFrame = FRAME_HEADER_LENGTH + MAC_LENGTH;
|
int overheadPerFrame = FRAME_HEADER_LENGTH + MAC_LENGTH;
|
||||||
@@ -63,14 +63,14 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
if(length > FRAME_HEADER_LENGTH) writeFrame();
|
if(offset > FRAME_HEADER_LENGTH) writeFrame();
|
||||||
encrypter.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(int b) throws IOException {
|
public void write(int b) throws IOException {
|
||||||
buf[length++] = (byte) b;
|
frame.getBuffer()[offset++] = (byte) b;
|
||||||
if(length + MAC_LENGTH == MAX_FRAME_LENGTH) writeFrame();
|
if(offset + MAC_LENGTH == MAX_FRAME_LENGTH) writeFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -80,32 +80,35 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(byte[] b, int off, int len) throws IOException {
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
int available = MAX_FRAME_LENGTH - length - MAC_LENGTH;
|
byte[] buf = frame.getBuffer();
|
||||||
|
int available = MAX_FRAME_LENGTH - offset - MAC_LENGTH;
|
||||||
while(available <= len) {
|
while(available <= len) {
|
||||||
System.arraycopy(b, off, buf, length, available);
|
System.arraycopy(b, off, buf, offset, available);
|
||||||
length += available;
|
offset += available;
|
||||||
writeFrame();
|
writeFrame();
|
||||||
off += available;
|
off += available;
|
||||||
len -= available;
|
len -= available;
|
||||||
available = MAX_FRAME_LENGTH - length - MAC_LENGTH;
|
available = MAX_FRAME_LENGTH - offset - MAC_LENGTH;
|
||||||
}
|
}
|
||||||
System.arraycopy(b, off, buf, length, len);
|
System.arraycopy(b, off, buf, offset, len);
|
||||||
length += len;
|
offset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeFrame() throws IOException {
|
private void writeFrame() throws IOException {
|
||||||
if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
|
if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
|
||||||
int payloadLength = length - FRAME_HEADER_LENGTH;
|
byte[] buf = frame.getBuffer();
|
||||||
|
int payloadLength = offset - FRAME_HEADER_LENGTH;
|
||||||
assert payloadLength > 0;
|
assert payloadLength > 0;
|
||||||
HeaderEncoder.encodeHeader(buf, frame, payloadLength, 0);
|
HeaderEncoder.encodeHeader(buf, frameNumber, payloadLength, 0);
|
||||||
mac.update(buf, 0, length);
|
mac.update(buf, 0, offset);
|
||||||
try {
|
try {
|
||||||
mac.doFinal(buf, length);
|
mac.doFinal(buf, offset);
|
||||||
} catch(ShortBufferException badMac) {
|
} catch(ShortBufferException badMac) {
|
||||||
throw new RuntimeException(badMac);
|
throw new RuntimeException(badMac);
|
||||||
}
|
}
|
||||||
encrypter.writeFrame(buf, length + MAC_LENGTH);
|
frame.setLength(offset + MAC_LENGTH);
|
||||||
length = FRAME_HEADER_LENGTH;
|
out.writeFrame(frame);
|
||||||
frame++;
|
offset = FRAME_HEADER_LENGTH;
|
||||||
|
frameNumber++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
|
|||||||
blockSize = frameCipher.getBlockSize();
|
blockSize = frameCipher.getBlockSize();
|
||||||
if(blockSize < FRAME_HEADER_LENGTH)
|
if(blockSize < FRAME_HEADER_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
iv = IvEncoder.encodeIv(0, blockSize);
|
iv = IvEncoder.encodeIv(0L, blockSize);
|
||||||
ciphertext = new byte[MAX_SEGMENT_LENGTH];
|
ciphertext = new byte[MAX_SEGMENT_LENGTH];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
|
|||||||
blockSize = frameCipher.getBlockSize();
|
blockSize = frameCipher.getBlockSize();
|
||||||
if(blockSize < FRAME_HEADER_LENGTH)
|
if(blockSize < FRAME_HEADER_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
iv = IvEncoder.encodeIv(0, blockSize);
|
iv = IvEncoder.encodeIv(0L, blockSize);
|
||||||
segment = new SegmentImpl();
|
segment = new SegmentImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
|
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import net.sf.briar.api.plugins.Segment;
|
||||||
|
|
||||||
|
class NullOutgoingErrorCorrectionLayer implements OutgoingErrorCorrectionLayer {
|
||||||
|
|
||||||
|
private final OutgoingEncryptionLayer out;
|
||||||
|
private final Segment segment;
|
||||||
|
|
||||||
|
private long segmentNumber = 0L;
|
||||||
|
|
||||||
|
public NullOutgoingErrorCorrectionLayer(OutgoingEncryptionLayer out) {
|
||||||
|
this.out = out;
|
||||||
|
segment = new SegmentImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFrame(Frame f) throws IOException {
|
||||||
|
if(segmentNumber > MAX_32_BIT_UNSIGNED)
|
||||||
|
throw new IllegalStateException();
|
||||||
|
int length = f.getLength();
|
||||||
|
// FIXME: Unnecessary copy
|
||||||
|
System.arraycopy(f.getBuffer(), 0, segment.getBuffer(), 0, length);
|
||||||
|
segment.setLength(length);
|
||||||
|
segment.setSegmentNumber(segmentNumber++);
|
||||||
|
out.writeSegment(segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() throws IOException {
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRemainingCapacity() {
|
||||||
|
return out.getRemainingCapacity();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,13 +2,14 @@ package net.sf.briar.transport;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/** Encrypts authenticated data to be sent over a connection. */
|
import net.sf.briar.api.plugins.Segment;
|
||||||
|
|
||||||
interface OutgoingEncryptionLayer {
|
interface OutgoingEncryptionLayer {
|
||||||
|
|
||||||
/** Writes the given frame. */
|
/** Writes the given segment. */
|
||||||
void writeFrame(byte[] b, int len) throws IOException;
|
void writeSegment(Segment s) throws IOException;
|
||||||
|
|
||||||
/** Flushes the output stream. */
|
/** Flushes the stack. */
|
||||||
void flush() throws IOException;
|
void flush() throws IOException;
|
||||||
|
|
||||||
/** Returns the maximum number of bytes that can be written. */
|
/** Returns the maximum number of bytes that can be written. */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package net.sf.briar.transport;
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
|
import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH;
|
||||||
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
import static 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.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@@ -11,6 +11,7 @@ import javax.crypto.Cipher;
|
|||||||
import javax.crypto.spec.IvParameterSpec;
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.ErasableKey;
|
||||||
|
import net.sf.briar.api.plugins.Segment;
|
||||||
|
|
||||||
class OutgoingEncryptionLayerImpl implements OutgoingEncryptionLayer {
|
class OutgoingEncryptionLayerImpl implements OutgoingEncryptionLayer {
|
||||||
|
|
||||||
@@ -18,13 +19,13 @@ class OutgoingEncryptionLayerImpl implements OutgoingEncryptionLayer {
|
|||||||
private final Cipher tagCipher, frameCipher;
|
private final Cipher tagCipher, frameCipher;
|
||||||
private final ErasableKey tagKey, frameKey;
|
private final ErasableKey tagKey, frameKey;
|
||||||
private final boolean tagEverySegment;
|
private final boolean tagEverySegment;
|
||||||
private final byte[] iv, tag;
|
private final byte[] iv, ciphertext;
|
||||||
|
|
||||||
private long capacity, frame = 0L;
|
private long capacity;
|
||||||
|
|
||||||
OutgoingEncryptionLayerImpl(OutputStream out, long capacity, Cipher tagCipher,
|
OutgoingEncryptionLayerImpl(OutputStream out, long capacity,
|
||||||
Cipher frameCipher, ErasableKey tagKey, ErasableKey frameKey,
|
Cipher tagCipher, Cipher frameCipher, ErasableKey tagKey,
|
||||||
boolean tagEverySegment) {
|
ErasableKey frameKey, boolean tagEverySegment) {
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
this.tagCipher = tagCipher;
|
this.tagCipher = tagCipher;
|
||||||
@@ -32,35 +33,37 @@ class OutgoingEncryptionLayerImpl implements OutgoingEncryptionLayer {
|
|||||||
this.tagKey = tagKey;
|
this.tagKey = tagKey;
|
||||||
this.frameKey = frameKey;
|
this.frameKey = frameKey;
|
||||||
this.tagEverySegment = tagEverySegment;
|
this.tagEverySegment = tagEverySegment;
|
||||||
iv = IvEncoder.encodeIv(0, frameCipher.getBlockSize());
|
iv = IvEncoder.encodeIv(0L, frameCipher.getBlockSize());
|
||||||
tag = new byte[TAG_LENGTH];
|
ciphertext = new byte[MAX_SEGMENT_LENGTH];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeFrame(byte[] b, int len) throws IOException {
|
public void writeSegment(Segment s) throws IOException {
|
||||||
if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
|
byte[] plaintext = s.getBuffer();
|
||||||
|
int length = s.getLength();
|
||||||
|
long segmentNumber = s.getSegmentNumber();
|
||||||
|
int offset = 0;
|
||||||
|
if(tagEverySegment || segmentNumber == 0) {
|
||||||
|
TagEncoder.encodeTag(ciphertext, segmentNumber, tagCipher, tagKey);
|
||||||
|
offset = TAG_LENGTH;
|
||||||
|
}
|
||||||
|
IvEncoder.updateIv(iv, segmentNumber);
|
||||||
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||||
try {
|
try {
|
||||||
if(tagEverySegment || frame == 0) {
|
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
|
||||||
TagEncoder.encodeTag(tag, frame, tagCipher, tagKey);
|
int encrypted = frameCipher.doFinal(plaintext, 0, length,
|
||||||
out.write(tag);
|
ciphertext, offset);
|
||||||
capacity -= tag.length;
|
if(encrypted != length) throw new RuntimeException();
|
||||||
}
|
} catch(GeneralSecurityException badCipher) {
|
||||||
IvEncoder.updateIv(iv, frame);
|
throw new RuntimeException(badCipher);
|
||||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
}
|
||||||
try {
|
try {
|
||||||
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
|
out.write(ciphertext, 0, offset + length);
|
||||||
int encrypted = frameCipher.doFinal(b, 0, len, b);
|
|
||||||
if(encrypted != len) throw new RuntimeException();
|
|
||||||
} catch(GeneralSecurityException badCipher) {
|
|
||||||
throw new RuntimeException(badCipher);
|
|
||||||
}
|
|
||||||
out.write(b, 0, len);
|
|
||||||
capacity -= len;
|
|
||||||
frame++;
|
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
frameKey.erase();
|
frameKey.erase();
|
||||||
tagKey.erase();
|
tagKey.erase();
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
capacity -= offset + length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
interface OutgoingErrorCorrectionLayer {
|
||||||
|
|
||||||
|
/** Writes the given frame. */
|
||||||
|
void writeFrame(Frame f) throws IOException;
|
||||||
|
|
||||||
|
/** Flushes the stack. */
|
||||||
|
void flush() throws IOException;
|
||||||
|
|
||||||
|
/** Returns the maximum number of bytes that can be written. */
|
||||||
|
long getRemainingCapacity();
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package net.sf.briar.transport;
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
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;
|
||||||
@@ -22,7 +21,7 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer {
|
|||||||
private final byte[] iv;
|
private final byte[] iv;
|
||||||
private final Segment segment;
|
private final Segment segment;
|
||||||
|
|
||||||
private long capacity, frame = 0L;
|
private long capacity;
|
||||||
|
|
||||||
OutgoingSegmentedEncryptionLayer(SegmentSink out, long capacity,
|
OutgoingSegmentedEncryptionLayer(SegmentSink out, long capacity,
|
||||||
Cipher tagCipher, Cipher frameCipher, ErasableKey tagKey,
|
Cipher tagCipher, Cipher frameCipher, ErasableKey tagKey,
|
||||||
@@ -34,29 +33,30 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer {
|
|||||||
this.tagKey = tagKey;
|
this.tagKey = tagKey;
|
||||||
this.frameKey = frameKey;
|
this.frameKey = frameKey;
|
||||||
this.tagEverySegment = tagEverySegment;
|
this.tagEverySegment = tagEverySegment;
|
||||||
iv = IvEncoder.encodeIv(0, frameCipher.getBlockSize());
|
iv = IvEncoder.encodeIv(0L, frameCipher.getBlockSize());
|
||||||
segment = new SegmentImpl();
|
segment = new SegmentImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeFrame(byte[] b, int len) throws IOException {
|
public void writeSegment(Segment s) throws IOException {
|
||||||
if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
|
byte[] plaintext = s.getBuffer(), ciphertext = segment.getBuffer();
|
||||||
|
int length = s.getLength();
|
||||||
|
long segmentNumber = s.getSegmentNumber();
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
if(tagEverySegment || frame == 0) {
|
if(tagEverySegment || segmentNumber == 0) {
|
||||||
TagEncoder.encodeTag(segment.getBuffer(), frame, tagCipher, tagKey);
|
TagEncoder.encodeTag(ciphertext, segmentNumber, tagCipher, tagKey);
|
||||||
offset = TAG_LENGTH;
|
offset = TAG_LENGTH;
|
||||||
capacity -= TAG_LENGTH;
|
|
||||||
}
|
}
|
||||||
IvEncoder.updateIv(iv, frame);
|
IvEncoder.updateIv(iv, segmentNumber);
|
||||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||||
try {
|
try {
|
||||||
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
|
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
|
||||||
int encrypted = frameCipher.doFinal(b, 0, len, segment.getBuffer(),
|
int encrypted = frameCipher.doFinal(plaintext, 0, length,
|
||||||
offset);
|
ciphertext, offset);
|
||||||
if(encrypted != len) throw new RuntimeException();
|
if(encrypted != length) throw new RuntimeException();
|
||||||
} catch(GeneralSecurityException badCipher) {
|
} catch(GeneralSecurityException badCipher) {
|
||||||
throw new RuntimeException(badCipher);
|
throw new RuntimeException(badCipher);
|
||||||
}
|
}
|
||||||
segment.setLength(offset + len);
|
segment.setLength(offset + length);
|
||||||
try {
|
try {
|
||||||
out.writeSegment(segment);
|
out.writeSegment(segment);
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
@@ -64,8 +64,7 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer {
|
|||||||
tagKey.erase();
|
tagKey.erase();
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
capacity -= len;
|
capacity -= offset + length;
|
||||||
frame++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flush() throws IOException {}
|
public void flush() throws IOException {}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ class TagEncoder {
|
|||||||
if(tag.length < TAG_LENGTH) throw new IllegalArgumentException();
|
if(tag.length < TAG_LENGTH) throw new IllegalArgumentException();
|
||||||
if(segmentNumber < 0 || segmentNumber > MAX_32_BIT_UNSIGNED)
|
if(segmentNumber < 0 || segmentNumber > MAX_32_BIT_UNSIGNED)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
|
// Clear the tag
|
||||||
|
for(int i = 0; i < TAG_LENGTH; i++) tag[i] = 0;
|
||||||
// Encode the segment number as a uint32 at the end of the tag
|
// Encode the segment number as a uint32 at the end of the tag
|
||||||
ByteUtils.writeUint32(segmentNumber, tag, TAG_LENGTH - 4);
|
ByteUtils.writeUint32(segmentNumber, tag, TAG_LENGTH - 4);
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -21,8 +21,11 @@ public class ConnectionWriterImplTest extends TransportTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testFlushWithoutWriteProducesNothing() throws Exception {
|
public void testFlushWithoutWriteProducesNothing() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
|
OutgoingEncryptionLayer encrypter =
|
||||||
ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
|
new NullOutgoingEncryptionLayer(out);
|
||||||
|
OutgoingErrorCorrectionLayer correcter =
|
||||||
|
new NullOutgoingErrorCorrectionLayer(encrypter);
|
||||||
|
ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey);
|
||||||
w.getOutputStream().flush();
|
w.getOutputStream().flush();
|
||||||
w.getOutputStream().flush();
|
w.getOutputStream().flush();
|
||||||
w.getOutputStream().flush();
|
w.getOutputStream().flush();
|
||||||
@@ -41,8 +44,11 @@ public class ConnectionWriterImplTest extends TransportTest {
|
|||||||
mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength);
|
mac.doFinal(frame, FRAME_HEADER_LENGTH + payloadLength);
|
||||||
// Check that the ConnectionWriter gets the same results
|
// Check that the ConnectionWriter gets the same results
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
|
OutgoingEncryptionLayer encrypter =
|
||||||
ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
|
new NullOutgoingEncryptionLayer(out);
|
||||||
|
OutgoingErrorCorrectionLayer correcter =
|
||||||
|
new NullOutgoingErrorCorrectionLayer(encrypter);
|
||||||
|
ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey);
|
||||||
w.getOutputStream().write(0);
|
w.getOutputStream().write(0);
|
||||||
w.getOutputStream().flush();
|
w.getOutputStream().flush();
|
||||||
assertArrayEquals(frame, out.toByteArray());
|
assertArrayEquals(frame, out.toByteArray());
|
||||||
@@ -51,8 +57,11 @@ public class ConnectionWriterImplTest extends TransportTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteByteToMaxLengthWritesFrame() throws Exception {
|
public void testWriteByteToMaxLengthWritesFrame() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
|
OutgoingEncryptionLayer encrypter =
|
||||||
ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
|
new NullOutgoingEncryptionLayer(out);
|
||||||
|
OutgoingErrorCorrectionLayer correcter =
|
||||||
|
new NullOutgoingErrorCorrectionLayer(encrypter);
|
||||||
|
ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey);
|
||||||
OutputStream out1 = w.getOutputStream();
|
OutputStream out1 = w.getOutputStream();
|
||||||
// The first maxPayloadLength - 1 bytes should be buffered
|
// The first maxPayloadLength - 1 bytes should be buffered
|
||||||
for(int i = 0; i < MAX_PAYLOAD_LENGTH - 1; i++) out1.write(0);
|
for(int i = 0; i < MAX_PAYLOAD_LENGTH - 1; i++) out1.write(0);
|
||||||
@@ -65,8 +74,11 @@ public class ConnectionWriterImplTest extends TransportTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteArrayToMaxLengthWritesFrame() throws Exception {
|
public void testWriteArrayToMaxLengthWritesFrame() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
|
OutgoingEncryptionLayer encrypter =
|
||||||
ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
|
new NullOutgoingEncryptionLayer(out);
|
||||||
|
OutgoingErrorCorrectionLayer correcter =
|
||||||
|
new NullOutgoingErrorCorrectionLayer(encrypter);
|
||||||
|
ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey);
|
||||||
OutputStream out1 = w.getOutputStream();
|
OutputStream out1 = w.getOutputStream();
|
||||||
// The first maxPayloadLength - 1 bytes should be buffered
|
// The first maxPayloadLength - 1 bytes should be buffered
|
||||||
out1.write(new byte[MAX_PAYLOAD_LENGTH - 1]);
|
out1.write(new byte[MAX_PAYLOAD_LENGTH - 1]);
|
||||||
@@ -100,8 +112,11 @@ public class ConnectionWriterImplTest extends TransportTest {
|
|||||||
byte[] expected = out.toByteArray();
|
byte[] expected = out.toByteArray();
|
||||||
// Check that the ConnectionWriter gets the same results
|
// Check that the ConnectionWriter gets the same results
|
||||||
out.reset();
|
out.reset();
|
||||||
OutgoingEncryptionLayer encrypter = new NullOutgoingEncryptionLayer(out);
|
OutgoingEncryptionLayer encrypter =
|
||||||
ConnectionWriter w = new ConnectionWriterImpl(encrypter, mac, macKey);
|
new NullOutgoingEncryptionLayer(out);
|
||||||
|
OutgoingErrorCorrectionLayer correcter =
|
||||||
|
new NullOutgoingErrorCorrectionLayer(encrypter);
|
||||||
|
ConnectionWriter w = new ConnectionWriterImpl(correcter, mac, macKey);
|
||||||
w.getOutputStream().write(new byte[123]);
|
w.getOutputStream().write(new byte[123]);
|
||||||
w.getOutputStream().flush();
|
w.getOutputStream().flush();
|
||||||
w.getOutputStream().write(new byte[1234]);
|
w.getOutputStream().write(new byte[1234]);
|
||||||
|
|||||||
@@ -77,7 +77,9 @@ public class FrameReadWriteTest extends BriarTestCase {
|
|||||||
OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out,
|
OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out,
|
||||||
Long.MAX_VALUE, tagCipher, frameCipher, tagCopy, frameCopy,
|
Long.MAX_VALUE, tagCipher, frameCipher, tagCopy, frameCopy,
|
||||||
false);
|
false);
|
||||||
ConnectionWriter writer = new ConnectionWriterImpl(encrypter, mac,
|
OutgoingErrorCorrectionLayer correcter =
|
||||||
|
new NullOutgoingErrorCorrectionLayer(encrypter);
|
||||||
|
ConnectionWriter writer = new ConnectionWriterImpl(correcter, mac,
|
||||||
macCopy);
|
macCopy);
|
||||||
OutputStream out1 = writer.getOutputStream();
|
OutputStream out1 = writer.getOutputStream();
|
||||||
out1.write(frame);
|
out1.write(frame);
|
||||||
@@ -93,9 +95,9 @@ public class FrameReadWriteTest extends BriarTestCase {
|
|||||||
// 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);
|
||||||
IncomingErrorCorrectionLayer correcter =
|
IncomingErrorCorrectionLayer correcter1 =
|
||||||
new NullIncomingErrorCorrectionLayer(decrypter);
|
new NullIncomingErrorCorrectionLayer(decrypter);
|
||||||
ConnectionReader reader = new ConnectionReaderImpl(correcter, mac,
|
ConnectionReader reader = new ConnectionReaderImpl(correcter1, mac,
|
||||||
macKey);
|
macKey);
|
||||||
InputStream in1 = reader.getInputStream();
|
InputStream in1 = reader.getInputStream();
|
||||||
byte[] recovered = new byte[frame.length];
|
byte[] recovered = new byte[frame.length];
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package net.sf.briar.transport;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import net.sf.briar.api.plugins.Segment;
|
||||||
|
|
||||||
/** An encryption layer that performs no encryption. */
|
/** An encryption layer that performs no encryption. */
|
||||||
class NullOutgoingEncryptionLayer implements OutgoingEncryptionLayer {
|
class NullOutgoingEncryptionLayer implements OutgoingEncryptionLayer {
|
||||||
|
|
||||||
@@ -20,9 +22,9 @@ class NullOutgoingEncryptionLayer implements OutgoingEncryptionLayer {
|
|||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeFrame(byte[] b, int len) throws IOException {
|
public void writeSegment(Segment s) throws IOException {
|
||||||
out.write(b, 0, len);
|
out.write(s.getBuffer(), 0, s.getLength());
|
||||||
capacity -= len;
|
capacity -= s.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
|
|||||||
@@ -11,6 +11,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.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -63,8 +64,15 @@ public class OutgoingEncryptionLayerImplTest extends BriarTestCase {
|
|||||||
OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out,
|
OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out,
|
||||||
Long.MAX_VALUE, tagCipher, frameCipher, tagKey, frameKey,
|
Long.MAX_VALUE, tagCipher, frameCipher, tagKey, frameKey,
|
||||||
false);
|
false);
|
||||||
encrypter.writeFrame(plaintext, plaintext.length);
|
Segment s = new SegmentImpl();
|
||||||
encrypter.writeFrame(plaintext1, plaintext1.length);
|
System.arraycopy(plaintext, 0, s.getBuffer(), 0, plaintext.length);
|
||||||
|
s.setLength(plaintext.length);
|
||||||
|
s.setSegmentNumber(0L);
|
||||||
|
encrypter.writeSegment(s);
|
||||||
|
System.arraycopy(plaintext1, 0, s.getBuffer(), 0, plaintext1.length);
|
||||||
|
s.setLength(plaintext1.length);
|
||||||
|
s.setSegmentNumber(1L);
|
||||||
|
encrypter.writeSegment(s);
|
||||||
byte[] actual = out.toByteArray();
|
byte[] actual = out.toByteArray();
|
||||||
// Check that the actual ciphertext matches the expected ciphertext
|
// Check that the actual ciphertext matches the expected ciphertext
|
||||||
assertArrayEquals(expected, actual);
|
assertArrayEquals(expected, actual);
|
||||||
@@ -103,8 +111,15 @@ public class OutgoingEncryptionLayerImplTest extends BriarTestCase {
|
|||||||
out.reset();
|
out.reset();
|
||||||
OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out,
|
OutgoingEncryptionLayer encrypter = new OutgoingEncryptionLayerImpl(out,
|
||||||
Long.MAX_VALUE, tagCipher, frameCipher, tagKey, frameKey, true);
|
Long.MAX_VALUE, tagCipher, frameCipher, tagKey, frameKey, true);
|
||||||
encrypter.writeFrame(plaintext, plaintext.length);
|
Segment s = new SegmentImpl();
|
||||||
encrypter.writeFrame(plaintext1, plaintext1.length);
|
System.arraycopy(plaintext, 0, s.getBuffer(), 0, plaintext.length);
|
||||||
|
s.setLength(plaintext.length);
|
||||||
|
s.setSegmentNumber(0L);
|
||||||
|
encrypter.writeSegment(s);
|
||||||
|
System.arraycopy(plaintext1, 0, s.getBuffer(), 0, plaintext1.length);
|
||||||
|
s.setLength(plaintext1.length);
|
||||||
|
s.setSegmentNumber(1L);
|
||||||
|
encrypter.writeSegment(s);
|
||||||
byte[] actual = out.toByteArray();
|
byte[] actual = out.toByteArray();
|
||||||
// Check that the actual ciphertext matches the expected ciphertext
|
// Check that the actual ciphertext matches the expected ciphertext
|
||||||
assertArrayEquals(expected, actual);
|
assertArrayEquals(expected, actual);
|
||||||
|
|||||||
@@ -66,9 +66,15 @@ public class OutgoingSegmentedEncryptionLayerTest extends BriarTestCase {
|
|||||||
OutgoingEncryptionLayer encrypter =
|
OutgoingEncryptionLayer encrypter =
|
||||||
new OutgoingSegmentedEncryptionLayer(sink, Long.MAX_VALUE,
|
new OutgoingSegmentedEncryptionLayer(sink, Long.MAX_VALUE,
|
||||||
tagCipher, frameCipher, tagKey, frameKey, false);
|
tagCipher, frameCipher, tagKey, frameKey, false);
|
||||||
// The first frame's buffer must have enough space for the tag
|
Segment s = new SegmentImpl();
|
||||||
encrypter.writeFrame(plaintext, plaintext.length);
|
System.arraycopy(plaintext, 0, s.getBuffer(), 0, plaintext.length);
|
||||||
encrypter.writeFrame(plaintext1, plaintext1.length);
|
s.setLength(plaintext.length);
|
||||||
|
s.setSegmentNumber(0L);
|
||||||
|
encrypter.writeSegment(s);
|
||||||
|
System.arraycopy(plaintext1, 0, s.getBuffer(), 0, plaintext1.length);
|
||||||
|
s.setLength(plaintext1.length);
|
||||||
|
s.setSegmentNumber(1L);
|
||||||
|
encrypter.writeSegment(s);
|
||||||
byte[] actual = out.toByteArray();
|
byte[] actual = out.toByteArray();
|
||||||
// Check that the actual ciphertext matches the expected ciphertext
|
// Check that the actual ciphertext matches the expected ciphertext
|
||||||
assertArrayEquals(expected, actual);
|
assertArrayEquals(expected, actual);
|
||||||
@@ -108,8 +114,15 @@ public class OutgoingSegmentedEncryptionLayerTest extends BriarTestCase {
|
|||||||
OutgoingEncryptionLayer encrypter =
|
OutgoingEncryptionLayer encrypter =
|
||||||
new OutgoingSegmentedEncryptionLayer(sink, Long.MAX_VALUE,
|
new OutgoingSegmentedEncryptionLayer(sink, Long.MAX_VALUE,
|
||||||
tagCipher, frameCipher, tagKey, frameKey, true);
|
tagCipher, frameCipher, tagKey, frameKey, true);
|
||||||
encrypter.writeFrame(plaintext, plaintext.length);
|
Segment s = new SegmentImpl();
|
||||||
encrypter.writeFrame(plaintext1, plaintext1.length);
|
System.arraycopy(plaintext, 0, s.getBuffer(), 0, plaintext.length);
|
||||||
|
s.setLength(plaintext.length);
|
||||||
|
s.setSegmentNumber(0L);
|
||||||
|
encrypter.writeSegment(s);
|
||||||
|
System.arraycopy(plaintext1, 0, s.getBuffer(), 0, plaintext1.length);
|
||||||
|
s.setLength(plaintext1.length);
|
||||||
|
s.setSegmentNumber(1L);
|
||||||
|
encrypter.writeSegment(s);
|
||||||
byte[] actual = out.toByteArray();
|
byte[] actual = out.toByteArray();
|
||||||
// Check that the actual ciphertext matches the expected ciphertext
|
// Check that the actual ciphertext matches the expected ciphertext
|
||||||
assertArrayEquals(expected, actual);
|
assertArrayEquals(expected, actual);
|
||||||
|
|||||||
Reference in New Issue
Block a user