Added factory methods for segmented connection readers.

This commit is contained in:
akwizgran
2012-01-17 20:21:26 +00:00
parent 87e1c42bf8
commit dbeb7a207e
21 changed files with 175 additions and 88 deletions

View File

@@ -2,6 +2,8 @@ package net.sf.briar.api.plugins;
import java.io.IOException; import java.io.IOException;
import net.sf.briar.api.transport.Segment;
public interface SegmentSink { public interface SegmentSink {
/** Writes the given segment. */ /** Writes the given segment. */

View File

@@ -2,6 +2,8 @@ package net.sf.briar.api.plugins;
import java.io.IOException; import java.io.IOException;
import net.sf.briar.api.transport.Segment;
public interface SegmentSource { public interface SegmentSource {
/** /**

View File

@@ -2,6 +2,8 @@ package net.sf.briar.api.transport;
import java.io.InputStream; import java.io.InputStream;
import net.sf.briar.api.plugins.SegmentSource;
public interface ConnectionReaderFactory { public interface ConnectionReaderFactory {
/** /**
@@ -12,9 +14,23 @@ public interface ConnectionReaderFactory {
ConnectionReader createConnectionReader(InputStream in, byte[] secret, ConnectionReader createConnectionReader(InputStream in, byte[] secret,
byte[] tag); byte[] tag);
/**
* Creates a connection reader for a simplex connection or the initiator's
* side of a duplex connection. The secret is erased before this method
* returns.
*/
ConnectionReader createConnectionReader(SegmentSource in, byte[] secret,
Segment buffered);
/** /**
* Creates a connection reader for the responder's side of a duplex * Creates a connection reader for the responder's side of a duplex
* connection. The secret is erased before this method returns. * connection. The secret is erased before this method returns.
*/ */
ConnectionReader createConnectionReader(InputStream in, byte[] secret); ConnectionReader createConnectionReader(InputStream in, byte[] secret);
/**
* Creates a connection reader for the responder's side of a duplex
* connection. The secret is erased before this method returns.
*/
ConnectionReader createConnectionReader(SegmentSource in, byte[] secret);
} }

View File

@@ -1,4 +1,4 @@
package net.sf.briar.api.plugins; package net.sf.briar.api.transport;
public interface Segment { public interface Segment {

View File

@@ -7,8 +7,10 @@ import javax.crypto.Mac;
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.SegmentSource;
import net.sf.briar.api.transport.ConnectionReader; import net.sf.briar.api.transport.ConnectionReader;
import net.sf.briar.api.transport.ConnectionReaderFactory; import net.sf.briar.api.transport.ConnectionReaderFactory;
import net.sf.briar.api.transport.Segment;
import net.sf.briar.util.ByteUtils; import net.sf.briar.util.ByteUtils;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -24,22 +26,16 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
public ConnectionReader createConnectionReader(InputStream in, public ConnectionReader createConnectionReader(InputStream in,
byte[] secret, byte[] tag) { byte[] secret, byte[] tag) {
// Validate the tag return createConnectionReader(in, secret, tag, true);
Cipher tagCipher = crypto.getTagCipher();
ErasableKey tagKey = crypto.deriveTagKey(secret, true);
long segmentNumber = TagEncoder.decodeTag(tag, tagCipher, tagKey);
tagKey.erase();
if(segmentNumber != 0) throw new IllegalArgumentException();
return createConnectionReader(in, true, secret);
} }
public ConnectionReader createConnectionReader(InputStream in, public ConnectionReader createConnectionReader(InputStream in,
byte[] secret) { byte[] secret) {
return createConnectionReader(in, false, secret); return createConnectionReader(in, secret, null, false);
} }
private ConnectionReader createConnectionReader(InputStream in, private ConnectionReader createConnectionReader(InputStream in,
boolean initiator, byte[] secret) { byte[] secret, byte[] tag, boolean initiator) {
// Derive the keys and erase the secret // Derive the keys and erase the secret
ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator); ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
ErasableKey macKey = crypto.deriveMacKey(secret, initiator); ErasableKey macKey = crypto.deriveMacKey(secret, initiator);
@@ -50,7 +46,38 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
Cipher frameCipher = crypto.getFrameCipher(); Cipher frameCipher = crypto.getFrameCipher();
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, tag);
// No error correction
IncomingErrorCorrectionLayer correcter =
new NullIncomingErrorCorrectionLayer(decrypter);
// Create the reader
return new ConnectionReaderImpl(correcter, mac, macKey);
}
public ConnectionReader createConnectionReader(SegmentSource in,
byte[] secret, Segment buffered) {
return createConnectionReader(in, secret, buffered, true);
}
public ConnectionReader createConnectionReader(SegmentSource in,
byte[] secret) {
return createConnectionReader(in, secret, new SegmentImpl(), false);
}
private ConnectionReader createConnectionReader(SegmentSource in,
byte[] secret, Segment buffered, boolean initiator) {
// Derive the keys and erase the secret
ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
ErasableKey macKey = crypto.deriveMacKey(secret, initiator);
ErasableKey tagKey = crypto.deriveTagKey(secret, initiator);
ByteUtils.erase(secret);
// Create the decrypter
Cipher tagCipher = crypto.getTagCipher();
Cipher frameCipher = crypto.getFrameCipher();
Mac mac = crypto.getMac();
IncomingEncryptionLayer decrypter =
new IncomingSegmentedEncryptionLayer(in, tagCipher, frameCipher,
tagKey, frameKey, false, buffered);
// No error correction // No error correction
IncomingErrorCorrectionLayer correcter = IncomingErrorCorrectionLayer correcter =
new NullIncomingErrorCorrectionLayer(decrypter); new NullIncomingErrorCorrectionLayer(decrypter);

View File

@@ -2,7 +2,7 @@ package net.sf.briar.transport;
import java.io.IOException; import java.io.IOException;
import net.sf.briar.api.plugins.Segment; import net.sf.briar.api.transport.Segment;
interface IncomingEncryptionLayer { interface IncomingEncryptionLayer {

View File

@@ -16,7 +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; import net.sf.briar.api.transport.Segment;
class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer { class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
@@ -27,18 +27,20 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
private final byte[] iv, ciphertext; private final byte[] iv, ciphertext;
private final boolean tagEverySegment; private final boolean tagEverySegment;
private byte[] bufferedTag;
private boolean firstSegment = true; private boolean firstSegment = true;
private long segmentNumber = 0L; 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,
boolean tagEverySegment) { boolean tagEverySegment, byte[] bufferedTag) {
this.in = in; this.in = in;
this.tagCipher = tagCipher; this.tagCipher = tagCipher;
this.frameCipher = frameCipher; this.frameCipher = frameCipher;
this.tagKey = tagKey; this.tagKey = tagKey;
this.frameKey = frameKey; this.frameKey = frameKey;
this.tagEverySegment = tagEverySegment; this.tagEverySegment = tagEverySegment;
this.bufferedTag = bufferedTag;
blockSize = frameCipher.getBlockSize(); blockSize = frameCipher.getBlockSize();
if(blockSize < FRAME_HEADER_LENGTH) if(blockSize < FRAME_HEADER_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
@@ -47,29 +49,41 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
} }
public boolean readSegment(Segment s) throws IOException { public boolean readSegment(Segment s) throws IOException {
boolean tag = tagEverySegment && !firstSegment; boolean expectTag = tagEverySegment || firstSegment;
firstSegment = false;
try { try {
// If a tag is expected then read, decrypt and validate it if(expectTag) {
if(tag) { // Read the tag if we don't have one buffered
int offset = 0; if(bufferedTag == null) {
while(offset < TAG_LENGTH) { int offset = 0;
int read = in.read(ciphertext, offset, TAG_LENGTH - offset); while(offset < TAG_LENGTH) {
if(read == -1) { int read = in.read(ciphertext, offset,
if(offset == 0) return false; TAG_LENGTH - offset);
throw new EOFException(); if(read == -1) {
if(offset == 0) return false;
throw new EOFException();
}
offset += read;
} }
offset += read; long seg = TagEncoder.decodeTag(ciphertext, tagCipher,
tagKey);
if(seg == -1) throw new FormatException();
segmentNumber = seg;
} else {
System.out.println("Buffered tag");
long seg = TagEncoder.decodeTag(bufferedTag, tagCipher,
tagKey);
bufferedTag = null;
if(seg == -1) throw new FormatException();
segmentNumber = seg;
} }
long seg = TagEncoder.decodeTag(ciphertext, tagCipher, tagKey);
if(seg == -1) throw new FormatException();
segmentNumber = seg;
} }
// Read the first block of the frame/segment // Read the first block of the frame/segment
int offset = 0; int offset = 0;
while(offset < blockSize) { while(offset < blockSize) {
int read = in.read(ciphertext, offset, blockSize - offset); int read = in.read(ciphertext, offset, blockSize - offset);
if(read == -1) { if(read == -1) {
if(offset == 0 && !tag && !firstSegment) return false; if(offset == 0 && !expectTag) return false;
throw new EOFException(); throw new EOFException();
} }
offset += read; offset += read;
@@ -108,7 +122,6 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
} }
s.setLength(length); s.setLength(length);
s.setSegmentNumber(segmentNumber++); s.setSegmentNumber(segmentNumber++);
firstSegment = false;
return true; return true;
} catch(IOException e) { } catch(IOException e) {
frameKey.erase(); frameKey.erase();

View File

@@ -13,8 +13,8 @@ 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;
import net.sf.briar.api.plugins.SegmentSource; import net.sf.briar.api.plugins.SegmentSource;
import net.sf.briar.api.transport.Segment;
class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer { class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
@@ -23,15 +23,16 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
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;
private final Segment segment;
private final boolean tagEverySegment; private final boolean tagEverySegment;
private final Segment segment;
private Segment bufferedSegment;
private boolean firstSegment = true; private boolean firstSegment = true;
private long segmentNumber = 0L; 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,
boolean tagEverySegment) { boolean tagEverySegment, Segment s) {
this.in = in; this.in = in;
this.tagCipher = tagCipher; this.tagCipher = tagCipher;
this.frameCipher = frameCipher; this.frameCipher = frameCipher;
@@ -43,20 +44,30 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
iv = IvEncoder.encodeIv(0L, blockSize); iv = IvEncoder.encodeIv(0L, blockSize);
segment = new SegmentImpl(); segment = new SegmentImpl();
bufferedSegment = s;
} }
public boolean readSegment(Segment s) throws IOException { public boolean readSegment(Segment s) throws IOException {
boolean tag = tagEverySegment && !firstSegment; boolean expectTag = tagEverySegment || firstSegment;
firstSegment = false;
try { try {
// Read the segment // Read the segment, unless we have one buffered
if(!in.readSegment(segment)) return false; Segment segment;
int offset = tag ? TAG_LENGTH : 0, length = segment.getLength(); if(bufferedSegment == null) {
segment = this.segment;
if(!in.readSegment(segment)) return false;
} else {
segment = bufferedSegment;
bufferedSegment = null;
}
int offset = expectTag ? TAG_LENGTH : 0;
int 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();
byte[] ciphertext = segment.getBuffer(); byte[] ciphertext = segment.getBuffer();
// If a tag is expected then decrypt and validate it // If a tag is expected then decrypt and validate it
if(tag) { if(expectTag) {
long seg = TagEncoder.decodeTag(ciphertext, tagCipher, tagKey); long seg = TagEncoder.decodeTag(ciphertext, tagCipher, tagKey);
if(seg == -1) throw new FormatException(); if(seg == -1) throw new FormatException();
segmentNumber = seg; segmentNumber = seg;
@@ -74,7 +85,6 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
} }
s.setLength(length - offset); s.setLength(length - offset);
s.setSegmentNumber(segmentNumber++); s.setSegmentNumber(segmentNumber++);
firstSegment = false;
return true; return true;
} catch(IOException e) { } catch(IOException e) {
frameKey.erase(); frameKey.erase();

View File

@@ -3,7 +3,7 @@ package net.sf.briar.transport;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import net.sf.briar.api.plugins.Segment; import net.sf.briar.api.transport.Segment;
class NullIncomingErrorCorrectionLayer implements IncomingErrorCorrectionLayer { class NullIncomingErrorCorrectionLayer implements IncomingErrorCorrectionLayer {

View File

@@ -4,7 +4,7 @@ import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
import java.io.IOException; import java.io.IOException;
import net.sf.briar.api.plugins.Segment; import net.sf.briar.api.transport.Segment;
class NullOutgoingErrorCorrectionLayer implements OutgoingErrorCorrectionLayer { class NullOutgoingErrorCorrectionLayer implements OutgoingErrorCorrectionLayer {

View File

@@ -2,7 +2,7 @@ package net.sf.briar.transport;
import java.io.IOException; import java.io.IOException;
import net.sf.briar.api.plugins.Segment; import net.sf.briar.api.transport.Segment;
interface OutgoingEncryptionLayer { interface OutgoingEncryptionLayer {

View File

@@ -11,7 +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; import net.sf.briar.api.transport.Segment;
class OutgoingEncryptionLayerImpl implements OutgoingEncryptionLayer { class OutgoingEncryptionLayerImpl implements OutgoingEncryptionLayer {

View File

@@ -9,8 +9,8 @@ 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;
import net.sf.briar.api.plugins.SegmentSink; import net.sf.briar.api.plugins.SegmentSink;
import net.sf.briar.api.transport.Segment;
class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer { class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer {

View File

@@ -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.MAX_SEGMENT_LENGTH;
import net.sf.briar.api.plugins.Segment; import net.sf.briar.api.transport.Segment;
import net.sf.briar.util.ByteUtils; import net.sf.briar.util.ByteUtils;
class SegmentImpl implements Segment { class SegmentImpl implements Segment {

View File

@@ -94,7 +94,7 @@ public class FrameReadWriteTest extends BriarTestCase {
assertEquals(0L, TagEncoder.decodeTag(tag, 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, recoveredTag);
IncomingErrorCorrectionLayer correcter1 = IncomingErrorCorrectionLayer correcter1 =
new NullIncomingErrorCorrectionLayer(decrypter); new NullIncomingErrorCorrectionLayer(decrypter);
ConnectionReader reader = new ConnectionReaderImpl(correcter1, mac, ConnectionReader reader = new ConnectionReaderImpl(correcter1, mac,

View File

@@ -12,7 +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.api.transport.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,6 +38,9 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase {
@Test @Test
public void testDecryptionWithFirstSegmentTagged() throws Exception { public void testDecryptionWithFirstSegmentTagged() throws Exception {
// Calculate the tag for the first segment
byte[] tag = new byte[TAG_LENGTH];
TagEncoder.encodeTag(tag, 0L, tagCipher, tagKey);
// Calculate the ciphertext for the first segment // 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);
@@ -53,15 +56,15 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase {
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
byte[] ciphertext1 = frameCipher.doFinal(plaintext1, 0, byte[] ciphertext1 = frameCipher.doFinal(plaintext1, 0,
plaintext1.length); plaintext1.length);
// Concatenate the ciphertexts // Concatenate the ciphertexts, excluding the first tag
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write(ciphertext); out.write(ciphertext);
out.write(ciphertext1); out.write(ciphertext1);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
// Use the encryption layer to decrypt the ciphertext // Use the encryption layer to decrypt the ciphertext
IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in,
tagCipher, frameCipher, tagKey, frameKey, false); tagCipher, frameCipher, tagKey, frameKey, false, tag);
// First frame // First segment
Segment s = new SegmentImpl(); Segment s = new SegmentImpl();
assertTrue(decrypter.readSegment(s)); assertTrue(decrypter.readSegment(s));
assertEquals(plaintext.length, s.getLength()); assertEquals(plaintext.length, s.getLength());
@@ -70,7 +73,7 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase {
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 segment
assertTrue(decrypter.readSegment(s)); assertTrue(decrypter.readSegment(s));
assertEquals(plaintext1.length, s.getLength()); assertEquals(plaintext1.length, s.getLength());
assertEquals(1L, s.getSegmentNumber()); assertEquals(1L, s.getSegmentNumber());
@@ -82,6 +85,9 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase {
@Test @Test
public void testDecryptionWithEverySegmentTagged() throws Exception { public void testDecryptionWithEverySegmentTagged() throws Exception {
// Calculate the tag for the first segment
byte[] tag = new byte[TAG_LENGTH];
TagEncoder.encodeTag(tag, 0L, tagCipher, tagKey);
// Calculate the ciphertext for the first segment // 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);
@@ -89,25 +95,27 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase {
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 segment, including its tag // Calculate the tag for the second segment
byte[] tag1 = new byte[TAG_LENGTH];
TagEncoder.encodeTag(tag1, 1L, tagCipher, tagKey);
// 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);
byte[] ciphertext1 = new byte[TAG_LENGTH + plaintext1.length];
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);
frameCipher.doFinal(plaintext1, 0, plaintext1.length, ciphertext1, byte[] ciphertext1 = frameCipher.doFinal(plaintext1, 0,
TAG_LENGTH); plaintext1.length);
// Concatenate the ciphertexts // Concatenate the ciphertexts, excluding the first tag
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write(ciphertext); out.write(ciphertext);
out.write(tag1);
out.write(ciphertext1); out.write(ciphertext1);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
// Use the encryption layer to decrypt the ciphertext // Use the encryption layer to decrypt the ciphertext
IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in, IncomingEncryptionLayer decrypter = new IncomingEncryptionLayerImpl(in,
tagCipher, frameCipher, tagKey, frameKey, true); tagCipher, frameCipher, tagKey, frameKey, true, tag);
// First frame // First segment
Segment s = new SegmentImpl(); Segment s = new SegmentImpl();
assertTrue(decrypter.readSegment(s)); assertTrue(decrypter.readSegment(s));
assertEquals(plaintext.length, s.getLength()); assertEquals(plaintext.length, s.getLength());
@@ -116,7 +124,7 @@ public class IncomingEncryptionLayerImplTest extends BriarTestCase {
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 segment
assertTrue(decrypter.readSegment(s)); assertTrue(decrypter.readSegment(s));
assertEquals(plaintext1.length, s.getLength()); assertEquals(plaintext1.length, s.getLength());
assertEquals(1L, s.getSegmentNumber()); assertEquals(1L, s.getSegmentNumber());

View File

@@ -12,8 +12,8 @@ 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.api.plugins.SegmentSource; import net.sf.briar.api.plugins.SegmentSource;
import net.sf.briar.api.transport.Segment;
import net.sf.briar.crypto.CryptoModule; import net.sf.briar.crypto.CryptoModule;
import org.junit.Test; import org.junit.Test;
@@ -38,13 +38,16 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase {
@Test @Test
public void testDecryptionWithFirstSegmentTagged() throws Exception { public void testDecryptionWithFirstSegmentTagged() throws Exception {
// Calculate the ciphertext for the first segment // Calculate the ciphertext for the first segment, including its tag
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[] ciphertext = new byte[TAG_LENGTH + plaintext.length];
TagEncoder.encodeTag(ciphertext, 0L, tagCipher, tagKey);
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); frameCipher.doFinal(plaintext, 0, plaintext.length, ciphertext,
TAG_LENGTH);
// Calculate the ciphertext for the second segment // 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);
@@ -53,13 +56,17 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase {
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
byte[] ciphertext1 = frameCipher.doFinal(plaintext1, 0, byte[] ciphertext1 = frameCipher.doFinal(plaintext1, 0,
plaintext1.length); plaintext1.length);
// Buffer the first segment and create a source for the second
Segment buffered = new SegmentImpl();
System.arraycopy(ciphertext, 0, buffered.getBuffer(), 0,
ciphertext.length);
buffered.setLength(ciphertext.length);
SegmentSource in = new ByteArraySegmentSource(ciphertext1);
// Use the encryption layer to decrypt the ciphertext // Use the encryption layer to decrypt the ciphertext
byte[][] frames = new byte[][] { ciphertext, ciphertext1 };
SegmentSource in = new ByteArraySegmentSource(frames);
IncomingEncryptionLayer decrypter = IncomingEncryptionLayer decrypter =
new IncomingSegmentedEncryptionLayer(in, tagCipher, frameCipher, new IncomingSegmentedEncryptionLayer(in, tagCipher, frameCipher,
tagKey, frameKey, false); tagKey, frameKey, false, buffered);
// First frame // First segment
Segment s = new SegmentImpl(); Segment s = new SegmentImpl();
assertTrue(decrypter.readSegment(s)); assertTrue(decrypter.readSegment(s));
assertEquals(plaintext.length, s.getLength()); assertEquals(plaintext.length, s.getLength());
@@ -68,7 +75,7 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase {
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 segment
assertTrue(decrypter.readSegment(s)); assertTrue(decrypter.readSegment(s));
assertEquals(plaintext1.length, s.getLength()); assertEquals(plaintext1.length, s.getLength());
assertEquals(1L, s.getSegmentNumber()); assertEquals(1L, s.getSegmentNumber());
@@ -80,13 +87,16 @@ public class IncomingSegmentedEncryptionLayerTest 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, including its tag
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[] ciphertext = new byte[TAG_LENGTH + plaintext.length];
TagEncoder.encodeTag(ciphertext, 0L, tagCipher, tagKey);
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); frameCipher.doFinal(plaintext, 0, plaintext.length, ciphertext,
TAG_LENGTH);
// Calculate the ciphertext for the second frame, including its tag // Calculate the ciphertext for the second frame, 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);
@@ -97,13 +107,17 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase {
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec); frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
frameCipher.doFinal(plaintext1, 0, plaintext1.length, ciphertext1, frameCipher.doFinal(plaintext1, 0, plaintext1.length, ciphertext1,
TAG_LENGTH); TAG_LENGTH);
// Buffer the first segment and create a source for the second
Segment buffered = new SegmentImpl();
System.arraycopy(ciphertext, 0, buffered.getBuffer(), 0,
ciphertext.length);
buffered.setLength(ciphertext.length);
SegmentSource in = new ByteArraySegmentSource(ciphertext1);
// Use the encryption layer to decrypt the ciphertext // Use the encryption layer to decrypt the ciphertext
byte[][] frames = new byte[][] { ciphertext, ciphertext1 };
SegmentSource in = new ByteArraySegmentSource(frames);
IncomingEncryptionLayer decrypter = IncomingEncryptionLayer decrypter =
new IncomingSegmentedEncryptionLayer(in, tagCipher, frameCipher, new IncomingSegmentedEncryptionLayer(in, tagCipher, frameCipher,
tagKey, frameKey, true); tagKey, frameKey, true, buffered);
// First frame // First segment
Segment s = new SegmentImpl(); Segment s = new SegmentImpl();
assertTrue(decrypter.readSegment(s)); assertTrue(decrypter.readSegment(s));
assertEquals(plaintext.length, s.getLength()); assertEquals(plaintext.length, s.getLength());
@@ -112,7 +126,7 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase {
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 segment
assertTrue(decrypter.readSegment(s)); assertTrue(decrypter.readSegment(s));
assertEquals(plaintext1.length, s.getLength()); assertEquals(plaintext1.length, s.getLength());
assertEquals(1L, s.getSegmentNumber()); assertEquals(1L, s.getSegmentNumber());
@@ -124,20 +138,15 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase {
private static class ByteArraySegmentSource implements SegmentSource { private static class ByteArraySegmentSource implements SegmentSource {
private final byte[][] segments; private final byte[] segment;
private int segmentNumber = 0; private ByteArraySegmentSource(byte[] segment) {
this.segment = segment;
private ByteArraySegmentSource(byte[][] frames) {
this.segments = frames;
} }
public boolean readSegment(Segment s) throws IOException { public boolean readSegment(Segment s) throws IOException {
if(segmentNumber == segments.length) return false; System.arraycopy(segment, 0, s.getBuffer(), 0, segment.length);
byte[] src = segments[segmentNumber]; s.setLength(segment.length);
System.arraycopy(src, 0, s.getBuffer(), 0, src.length);
s.setLength(src.length);
segmentNumber++;
return true; return true;
} }
} }

View File

@@ -9,7 +9,7 @@ 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; import net.sf.briar.api.transport.Segment;
/** An encryption layer that performs no encryption. */ /** An encryption layer that performs no encryption. */
class NullIncomingEncryptionLayer implements IncomingEncryptionLayer { class NullIncomingEncryptionLayer implements IncomingEncryptionLayer {

View File

@@ -3,7 +3,7 @@ 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; import net.sf.briar.api.transport.Segment;
/** An encryption layer that performs no encryption. */ /** An encryption layer that performs no encryption. */
class NullOutgoingEncryptionLayer implements OutgoingEncryptionLayer { class NullOutgoingEncryptionLayer implements OutgoingEncryptionLayer {

View File

@@ -11,7 +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.api.transport.Segment;
import net.sf.briar.crypto.CryptoModule; import net.sf.briar.crypto.CryptoModule;
import org.junit.Test; import org.junit.Test;

View File

@@ -12,8 +12,8 @@ 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.api.plugins.SegmentSink; import net.sf.briar.api.plugins.SegmentSink;
import net.sf.briar.api.transport.Segment;
import net.sf.briar.crypto.CryptoModule; import net.sf.briar.crypto.CryptoModule;
import org.junit.Test; import org.junit.Test;