mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 06:09:55 +01:00
Added an initiator flag (bit 31) to the IV.
The flag is used to distinguish between the initiator and responder directions of a stream-mode connection, allowing them to use the same connection number without risking IV reuse. The flag is also raised for batch-mode connections, which only have one direction.
This commit is contained in:
@@ -4,6 +4,6 @@ import java.io.InputStream;
|
|||||||
|
|
||||||
public interface ConnectionReaderFactory {
|
public interface ConnectionReaderFactory {
|
||||||
|
|
||||||
ConnectionReader createConnectionReader(InputStream in, int transportId,
|
ConnectionReader createConnectionReader(InputStream in, boolean initiator,
|
||||||
long connection, byte[] secret);
|
int transportId, long connection, byte[] secret);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ import java.io.OutputStream;
|
|||||||
|
|
||||||
public interface ConnectionWriterFactory {
|
public interface ConnectionWriterFactory {
|
||||||
|
|
||||||
ConnectionWriter createConnectionWriter(OutputStream out, int transportId,
|
ConnectionWriter createConnectionWriter(OutputStream out, boolean initiator,
|
||||||
long connection, byte[] secret);
|
int transportId, long connection, byte[] secret);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import javax.crypto.spec.IvParameterSpec;
|
|||||||
class ConnectionDecrypterImpl extends FilterInputStream
|
class ConnectionDecrypterImpl extends FilterInputStream
|
||||||
implements ConnectionDecrypter {
|
implements ConnectionDecrypter {
|
||||||
|
|
||||||
private final int transportId;
|
|
||||||
private final long connection;
|
|
||||||
private final Cipher frameCipher;
|
private final Cipher frameCipher;
|
||||||
private final SecretKey frameKey;
|
private final SecretKey frameKey;
|
||||||
private final byte[] buf, iv;
|
private final byte[] buf, iv;
|
||||||
@@ -30,15 +28,13 @@ implements ConnectionDecrypter {
|
|||||||
private long frame = 0L;
|
private long frame = 0L;
|
||||||
private boolean betweenFrames = true;
|
private boolean betweenFrames = true;
|
||||||
|
|
||||||
ConnectionDecrypterImpl(InputStream in, int transportId, long connection,
|
ConnectionDecrypterImpl(InputStream in, boolean initiator, int transportId,
|
||||||
Cipher frameCipher, SecretKey frameKey) {
|
long connection, Cipher frameCipher, SecretKey frameKey) {
|
||||||
super(in);
|
super(in);
|
||||||
this.transportId = transportId;
|
|
||||||
this.connection = connection;
|
|
||||||
this.frameCipher = frameCipher;
|
this.frameCipher = frameCipher;
|
||||||
this.frameKey = frameKey;
|
this.frameKey = frameKey;
|
||||||
buf = new byte[IV_LENGTH];
|
buf = new byte[IV_LENGTH];
|
||||||
iv = new byte[IV_LENGTH];
|
iv = IvEncoder.encodeIv(initiator, transportId, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getInputStream() {
|
public InputStream getInputStream() {
|
||||||
@@ -132,8 +128,7 @@ implements ConnectionDecrypter {
|
|||||||
private void initialiseCipher() {
|
private void initialiseCipher() {
|
||||||
assert betweenFrames;
|
assert betweenFrames;
|
||||||
if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
|
if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
|
||||||
IvEncoder.encodeIv(iv, transportId, connection, frame);
|
IvEncoder.updateIv(iv, frame);
|
||||||
// Use the plaintext IV to initialise the frame cipher
|
|
||||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||||
try {
|
try {
|
||||||
frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
|
frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
|
||||||
|
|||||||
@@ -18,25 +18,21 @@ import javax.crypto.spec.IvParameterSpec;
|
|||||||
class ConnectionEncrypterImpl extends FilterOutputStream
|
class ConnectionEncrypterImpl extends FilterOutputStream
|
||||||
implements ConnectionEncrypter {
|
implements ConnectionEncrypter {
|
||||||
|
|
||||||
private final int transportId;
|
|
||||||
private final long connection;
|
|
||||||
private final Cipher ivCipher, frameCipher;
|
private final Cipher ivCipher, frameCipher;
|
||||||
private final SecretKey frameKey;
|
private final SecretKey frameKey;
|
||||||
private final byte[] iv;
|
private final byte[] iv;
|
||||||
|
|
||||||
private long frame = 0L;
|
private long frame = 0L;
|
||||||
private boolean started = false, betweenFrames = false;
|
private boolean ivWritten = false, betweenFrames = false;
|
||||||
|
|
||||||
ConnectionEncrypterImpl(OutputStream out, int transportId,
|
ConnectionEncrypterImpl(OutputStream out, boolean initiator,
|
||||||
long connection, Cipher ivCipher, Cipher frameCipher,
|
int transportId, long connection, Cipher ivCipher,
|
||||||
SecretKey ivKey, SecretKey frameKey) {
|
Cipher frameCipher, SecretKey ivKey, SecretKey frameKey) {
|
||||||
super(out);
|
super(out);
|
||||||
this.transportId = transportId;
|
|
||||||
this.connection = connection;
|
|
||||||
this.ivCipher = ivCipher;
|
this.ivCipher = ivCipher;
|
||||||
this.frameCipher = frameCipher;
|
this.frameCipher = frameCipher;
|
||||||
this.frameKey = frameKey;
|
this.frameKey = frameKey;
|
||||||
iv = new byte[IV_LENGTH];
|
iv = IvEncoder.encodeIv(initiator, transportId, connection);
|
||||||
try {
|
try {
|
||||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
||||||
} catch(InvalidKeyException badKey) {
|
} catch(InvalidKeyException badKey) {
|
||||||
@@ -51,7 +47,7 @@ implements ConnectionEncrypter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void writeMac(byte[] mac) throws IOException {
|
public void writeMac(byte[] mac) throws IOException {
|
||||||
if(!started || betweenFrames) throw new IllegalStateException();
|
if(!ivWritten || betweenFrames) throw new IllegalStateException();
|
||||||
try {
|
try {
|
||||||
out.write(frameCipher.doFinal(mac));
|
out.write(frameCipher.doFinal(mac));
|
||||||
} catch(BadPaddingException badCipher) {
|
} catch(BadPaddingException badCipher) {
|
||||||
@@ -64,7 +60,7 @@ implements ConnectionEncrypter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(int b) throws IOException {
|
public void write(int b) throws IOException {
|
||||||
if(!started) writeIv();
|
if(!ivWritten) writeIv();
|
||||||
if(betweenFrames) initialiseCipher();
|
if(betweenFrames) initialiseCipher();
|
||||||
byte[] ciphertext = frameCipher.update(new byte[] {(byte) b});
|
byte[] ciphertext = frameCipher.update(new byte[] {(byte) b});
|
||||||
if(ciphertext != null) out.write(ciphertext);
|
if(ciphertext != null) out.write(ciphertext);
|
||||||
@@ -77,16 +73,15 @@ implements ConnectionEncrypter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(byte[] b, int off, int len) throws IOException {
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
if(!started) writeIv();
|
if(!ivWritten) writeIv();
|
||||||
if(betweenFrames) initialiseCipher();
|
if(betweenFrames) initialiseCipher();
|
||||||
byte[] ciphertext = frameCipher.update(b, off, len);
|
byte[] ciphertext = frameCipher.update(b, off, len);
|
||||||
if(ciphertext != null) out.write(ciphertext);
|
if(ciphertext != null) out.write(ciphertext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeIv() throws IOException {
|
private void writeIv() throws IOException {
|
||||||
assert !started;
|
assert !ivWritten;
|
||||||
assert !betweenFrames;
|
assert !betweenFrames;
|
||||||
IvEncoder.encodeIv(iv, transportId, connection, 0L);
|
|
||||||
try {
|
try {
|
||||||
out.write(ivCipher.doFinal(iv));
|
out.write(ivCipher.doFinal(iv));
|
||||||
} catch(BadPaddingException badCipher) {
|
} catch(BadPaddingException badCipher) {
|
||||||
@@ -94,15 +89,15 @@ implements ConnectionEncrypter {
|
|||||||
} catch(IllegalBlockSizeException badCipher) {
|
} catch(IllegalBlockSizeException badCipher) {
|
||||||
throw new RuntimeException(badCipher);
|
throw new RuntimeException(badCipher);
|
||||||
}
|
}
|
||||||
started = true;
|
ivWritten = true;
|
||||||
betweenFrames = true;
|
betweenFrames = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialiseCipher() {
|
private void initialiseCipher() {
|
||||||
assert started;
|
assert ivWritten;
|
||||||
assert betweenFrames;
|
assert betweenFrames;
|
||||||
if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
|
if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
|
||||||
IvEncoder.encodeIv(iv, transportId, connection, frame);
|
IvEncoder.updateIv(iv, frame);
|
||||||
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);
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ConnectionReader createConnectionReader(InputStream in,
|
public ConnectionReader createConnectionReader(InputStream in,
|
||||||
int transportId, long connection, byte[] secret) {
|
boolean initiator, int transportId, long connection,
|
||||||
|
byte[] secret) {
|
||||||
SecretKey macKey = crypto.deriveIncomingMacKey(secret);
|
SecretKey macKey = crypto.deriveIncomingMacKey(secret);
|
||||||
SecretKey frameKey = crypto.deriveIncomingFrameKey(secret);
|
SecretKey frameKey = crypto.deriveIncomingFrameKey(secret);
|
||||||
Cipher frameCipher = crypto.getFrameCipher();
|
Cipher frameCipher = crypto.getFrameCipher();
|
||||||
@@ -34,7 +35,7 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
|
|||||||
throw new IllegalArgumentException(e);
|
throw new IllegalArgumentException(e);
|
||||||
}
|
}
|
||||||
ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in,
|
ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in,
|
||||||
transportId, connection, frameCipher, frameKey);
|
initiator, transportId, connection, frameCipher, frameKey);
|
||||||
return new ConnectionReaderImpl(decrypter, mac);
|
return new ConnectionReaderImpl(decrypter, mac);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ DatabaseListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private synchronized byte[] encryptIv(ContactId c, long connection) {
|
private synchronized byte[] encryptIv(ContactId c, long connection) {
|
||||||
byte[] iv = IvEncoder.encodeIv(transportId, connection);
|
byte[] iv = IvEncoder.encodeIv(true, transportId, connection);
|
||||||
Cipher cipher = contactToCipher.get(c);
|
Cipher cipher = contactToCipher.get(c);
|
||||||
assert cipher != null;
|
assert cipher != null;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ConnectionWriter createConnectionWriter(OutputStream out,
|
public ConnectionWriter createConnectionWriter(OutputStream out,
|
||||||
int transportId, long connection, byte[] secret) {
|
boolean initiator, int transportId, long connection,
|
||||||
|
byte[] secret) {
|
||||||
SecretKey macKey = crypto.deriveOutgoingMacKey(secret);
|
SecretKey macKey = crypto.deriveOutgoingMacKey(secret);
|
||||||
SecretKey ivKey = crypto.deriveOutgoingIvKey(secret);
|
SecretKey ivKey = crypto.deriveOutgoingIvKey(secret);
|
||||||
SecretKey frameKey = crypto.deriveOutgoingFrameKey(secret);
|
SecretKey frameKey = crypto.deriveOutgoingFrameKey(secret);
|
||||||
@@ -36,8 +37,8 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
|||||||
throw new IllegalArgumentException(badKey);
|
throw new IllegalArgumentException(badKey);
|
||||||
}
|
}
|
||||||
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
|
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
|
||||||
transportId, connection, ivCipher, frameCipher, ivKey,
|
initiator, transportId, connection, ivCipher, frameCipher,
|
||||||
frameKey);
|
ivKey, frameKey);
|
||||||
return new ConnectionWriterImpl(encrypter, mac);
|
return new ConnectionWriterImpl(encrypter, mac);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,11 @@ import net.sf.briar.util.ByteUtils;
|
|||||||
|
|
||||||
class IvEncoder {
|
class IvEncoder {
|
||||||
|
|
||||||
static byte[] encodeIv(int transportId, long connection) {
|
static byte[] encodeIv(boolean initiator, int transportId,
|
||||||
|
long connection) {
|
||||||
byte[] iv = new byte[IV_LENGTH];
|
byte[] iv = new byte[IV_LENGTH];
|
||||||
|
// Bit 31 is the initiator flag
|
||||||
|
if(initiator) iv[3] = 1;
|
||||||
// Encode the transport identifier as an unsigned 16-bit integer
|
// Encode the transport identifier as an unsigned 16-bit integer
|
||||||
ByteUtils.writeUint16(transportId, iv, 4);
|
ByteUtils.writeUint16(transportId, iv, 4);
|
||||||
// Encode the connection number as an unsigned 32-bit integer
|
// Encode the connection number as an unsigned 32-bit integer
|
||||||
@@ -14,20 +17,9 @@ class IvEncoder {
|
|||||||
return iv;
|
return iv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void encodeIv(byte[] iv, int transportId, long connection,
|
static void updateIv(byte[] iv, long frame) {
|
||||||
long frame) {
|
|
||||||
if(iv.length != IV_LENGTH) throw new IllegalArgumentException();
|
if(iv.length != IV_LENGTH) throw new IllegalArgumentException();
|
||||||
// The first 16 bits of the IV must be zero (reserved)
|
|
||||||
iv[0] = 0;
|
|
||||||
iv[1] = 0;
|
|
||||||
// Encode the transport identifier as an unsigned 16-bit integer
|
|
||||||
ByteUtils.writeUint16(transportId, iv, 4);
|
|
||||||
// Encode the connection number as an unsigned 32-bit integer
|
|
||||||
ByteUtils.writeUint32(connection, iv, 6);
|
|
||||||
// Encode the frame number as an unsigned 32-bit integer
|
// Encode the frame number as an unsigned 32-bit integer
|
||||||
ByteUtils.writeUint32(frame, iv, 10);
|
ByteUtils.writeUint32(frame, iv, 10);
|
||||||
// The last 16 bits of the IV must be zero (block number)
|
|
||||||
iv[14] = 0;
|
|
||||||
iv[15] = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ public class FileReadWriteTest extends TestCase {
|
|||||||
OutputStream out = new FileOutputStream(file);
|
OutputStream out = new FileOutputStream(file);
|
||||||
// Use Alice's secret for writing
|
// Use Alice's secret for writing
|
||||||
ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out,
|
ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out,
|
||||||
transportId, connection, aliceSecret);
|
true, transportId, connection, aliceSecret);
|
||||||
out = w.getOutputStream();
|
out = w.getOutputStream();
|
||||||
|
|
||||||
AckWriter a = protocolWriterFactory.createAckWriter(out);
|
AckWriter a = protocolWriterFactory.createAckWriter(out);
|
||||||
@@ -194,7 +194,7 @@ public class FileReadWriteTest extends TestCase {
|
|||||||
assertEquals(16, offset);
|
assertEquals(16, offset);
|
||||||
// Use Bob's secret for reading
|
// Use Bob's secret for reading
|
||||||
ConnectionReader r = connectionReaderFactory.createConnectionReader(in,
|
ConnectionReader r = connectionReaderFactory.createConnectionReader(in,
|
||||||
transportId, connection, bobSecret);
|
true, transportId, connection, bobSecret);
|
||||||
in = r.getInputStream();
|
in = r.getInputStream();
|
||||||
ProtocolReader protocolReader =
|
ProtocolReader protocolReader =
|
||||||
protocolReaderFactory.createProtocolReader(in);
|
protocolReaderFactory.createProtocolReader(in);
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package net.sf.briar.transport;
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@@ -43,25 +41,33 @@ public class ConnectionDecrypterImplTest extends TestCase {
|
|||||||
byte[] ciphertext = new byte[1 + MAC_LENGTH];
|
byte[] ciphertext = new byte[1 + MAC_LENGTH];
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
|
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
|
||||||
// Check that one byte plus a MAC can be read
|
// Check that one byte plus a MAC can be read
|
||||||
ConnectionDecrypter d = new ConnectionDecrypterImpl(in, transportId,
|
ConnectionDecrypter d = new ConnectionDecrypterImpl(in, true,
|
||||||
connection, frameCipher, frameKey);
|
transportId, connection, frameCipher, frameKey);
|
||||||
assertFalse(d.getInputStream().read() == -1);
|
assertFalse(d.getInputStream().read() == -1);
|
||||||
d.readMac(new byte[MAC_LENGTH]);
|
d.readMac(new byte[MAC_LENGTH]);
|
||||||
assertTrue(d.getInputStream().read() == -1);
|
assertTrue(d.getInputStream().read() == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDecryption() throws Exception {
|
public void testInitiatorDecryption() throws Exception {
|
||||||
|
testDecryption(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResponderDecryption() throws Exception {
|
||||||
|
testDecryption(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testDecryption(boolean initiator) throws Exception {
|
||||||
// Calculate the expected plaintext for the first frame
|
// Calculate the expected plaintext for the first frame
|
||||||
byte[] ciphertext = new byte[123];
|
byte[] ciphertext = new byte[123];
|
||||||
byte[] iv = new byte[IV_LENGTH];
|
byte[] iv = IvEncoder.encodeIv(initiator, transportId, connection);
|
||||||
IvEncoder.encodeIv(iv, transportId, connection, 0L);
|
|
||||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||||
frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
|
frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
|
||||||
byte[] plaintext = frameCipher.doFinal(ciphertext);
|
byte[] plaintext = frameCipher.doFinal(ciphertext);
|
||||||
// Calculate the expected plaintext for the second frame
|
// Calculate the expected plaintext for the second frame
|
||||||
byte[] ciphertext1 = new byte[1234];
|
byte[] ciphertext1 = new byte[1234];
|
||||||
IvEncoder.encodeIv(iv, transportId, connection, 1L);
|
IvEncoder.updateIv(iv, 1L);
|
||||||
ivSpec = new IvParameterSpec(iv);
|
ivSpec = new IvParameterSpec(iv);
|
||||||
frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
|
frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
|
||||||
byte[] plaintext1 = frameCipher.doFinal(ciphertext1);
|
byte[] plaintext1 = frameCipher.doFinal(ciphertext1);
|
||||||
@@ -72,8 +78,8 @@ public class ConnectionDecrypterImplTest extends TestCase {
|
|||||||
out.write(ciphertext1);
|
out.write(ciphertext1);
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
// Use a ConnectionDecrypter to decrypt the ciphertext
|
// Use a ConnectionDecrypter to decrypt the ciphertext
|
||||||
ConnectionDecrypter d = new ConnectionDecrypterImpl(in, transportId,
|
ConnectionDecrypter d = new ConnectionDecrypterImpl(in, initiator,
|
||||||
connection, frameCipher, frameKey);
|
transportId, connection, frameCipher, frameKey);
|
||||||
// First frame
|
// First frame
|
||||||
byte[] decrypted = new byte[plaintext.length - MAC_LENGTH];
|
byte[] decrypted = new byte[plaintext.length - MAC_LENGTH];
|
||||||
TestUtils.readFully(d.getInputStream(), decrypted);
|
TestUtils.readFully(d.getInputStream(), decrypted);
|
||||||
|
|||||||
@@ -40,17 +40,27 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testSingleByteFrame() throws Exception {
|
public void testSingleByteFrame() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
ConnectionEncrypter e = new ConnectionEncrypterImpl(out, transportId,
|
ConnectionEncrypter e = new ConnectionEncrypterImpl(out, true,
|
||||||
connection, ivCipher, frameCipher, ivKey, frameKey);
|
transportId, connection, ivCipher, frameCipher, ivKey,
|
||||||
|
frameKey);
|
||||||
e.getOutputStream().write((byte) 0);
|
e.getOutputStream().write((byte) 0);
|
||||||
e.writeMac(new byte[MAC_LENGTH]);
|
e.writeMac(new byte[MAC_LENGTH]);
|
||||||
assertEquals(IV_LENGTH + 1 + MAC_LENGTH, out.toByteArray().length);
|
assertEquals(IV_LENGTH + 1 + MAC_LENGTH, out.toByteArray().length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncryption() throws Exception {
|
public void testInitiatorEncryption() throws Exception {
|
||||||
|
testEncryption(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResponderEncryption() throws Exception {
|
||||||
|
testEncryption(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testEncryption(boolean initiator) throws Exception {
|
||||||
// Calculate the expected ciphertext for the IV
|
// Calculate the expected ciphertext for the IV
|
||||||
byte[] iv = IvEncoder.encodeIv(transportId, connection);
|
byte[] iv = IvEncoder.encodeIv(initiator, transportId, connection);
|
||||||
assertEquals(IV_LENGTH, iv.length);
|
assertEquals(IV_LENGTH, iv.length);
|
||||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
||||||
byte[] encryptedIv = ivCipher.doFinal(iv);
|
byte[] encryptedIv = ivCipher.doFinal(iv);
|
||||||
@@ -58,7 +68,6 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
|||||||
// Calculate the expected ciphertext for the first frame
|
// Calculate the expected ciphertext for the first frame
|
||||||
byte[] plaintext = new byte[123];
|
byte[] plaintext = new byte[123];
|
||||||
byte[] plaintextMac = new byte[MAC_LENGTH];
|
byte[] plaintextMac = new byte[MAC_LENGTH];
|
||||||
IvEncoder.encodeIv(iv, transportId, connection, 0L);
|
|
||||||
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 = new byte[plaintext.length + plaintextMac.length];
|
byte[] ciphertext = new byte[plaintext.length + plaintextMac.length];
|
||||||
@@ -68,7 +77,7 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
|||||||
offset);
|
offset);
|
||||||
// Calculate the expected ciphertext for the second frame
|
// Calculate the expected ciphertext for the second frame
|
||||||
byte[] plaintext1 = new byte[1234];
|
byte[] plaintext1 = new byte[1234];
|
||||||
IvEncoder.encodeIv(iv, transportId, connection, 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);
|
||||||
byte[] ciphertext1 = new byte[plaintext1.length + plaintextMac.length];
|
byte[] ciphertext1 = new byte[plaintext1.length + plaintextMac.length];
|
||||||
@@ -84,8 +93,9 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
|||||||
byte[] expected = out.toByteArray();
|
byte[] expected = out.toByteArray();
|
||||||
// Use a ConnectionEncrypter to encrypt the plaintext
|
// Use a ConnectionEncrypter to encrypt the plaintext
|
||||||
out.reset();
|
out.reset();
|
||||||
ConnectionEncrypter e = new ConnectionEncrypterImpl(out, transportId,
|
ConnectionEncrypter e = new ConnectionEncrypterImpl(out, initiator,
|
||||||
connection, ivCipher, frameCipher, ivKey, frameKey);
|
transportId, connection, ivCipher, frameCipher, ivKey,
|
||||||
|
frameKey);
|
||||||
e.getOutputStream().write(plaintext);
|
e.getOutputStream().write(plaintext);
|
||||||
e.writeMac(plaintextMac);
|
e.writeMac(plaintextMac);
|
||||||
e.getOutputStream().write(plaintext1);
|
e.getOutputStream().write(plaintext1);
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
SecretKey ivKey = crypto.deriveIncomingIvKey(secret);
|
SecretKey ivKey = crypto.deriveIncomingIvKey(secret);
|
||||||
Cipher ivCipher = crypto.getIvCipher();
|
Cipher ivCipher = crypto.getIvCipher();
|
||||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
||||||
byte[] iv = IvEncoder.encodeIv(transportId, 3L);
|
byte[] iv = IvEncoder.encodeIv(true, transportId, 3L);
|
||||||
byte[] encryptedIv = ivCipher.doFinal(iv);
|
byte[] encryptedIv = ivCipher.doFinal(iv);
|
||||||
|
|
||||||
Mockery context = new Mockery();
|
Mockery context = new Mockery();
|
||||||
|
|||||||
@@ -50,9 +50,18 @@ public class FrameReadWriteTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteAndRead() throws Exception {
|
public void testInitiatorWriteAndRead() throws Exception {
|
||||||
|
testWriteAndRead(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResponderWriteAndRead() throws Exception {
|
||||||
|
testWriteAndRead(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testWriteAndRead(boolean initiator) throws Exception {
|
||||||
// Calculate the expected ciphertext for the IV
|
// Calculate the expected ciphertext for the IV
|
||||||
byte[] iv = IvEncoder.encodeIv(transportId, connection);
|
byte[] iv = IvEncoder.encodeIv(initiator, transportId, connection);
|
||||||
assertEquals(IV_LENGTH, iv.length);
|
assertEquals(IV_LENGTH, iv.length);
|
||||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
||||||
byte[] encryptedIv = ivCipher.doFinal(iv);
|
byte[] encryptedIv = ivCipher.doFinal(iv);
|
||||||
@@ -65,8 +74,8 @@ public class FrameReadWriteTest extends TestCase {
|
|||||||
// Write the frames
|
// Write the frames
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
|
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
|
||||||
transportId, connection, ivCipher, frameCipher, ivKey,
|
initiator, transportId, connection, ivCipher, frameCipher,
|
||||||
frameKey);
|
ivKey, frameKey);
|
||||||
mac.init(macKey);
|
mac.init(macKey);
|
||||||
ConnectionWriter writer = new ConnectionWriterImpl(encrypter, mac);
|
ConnectionWriter writer = new ConnectionWriterImpl(encrypter, mac);
|
||||||
OutputStream out1 = writer.getOutputStream();
|
OutputStream out1 = writer.getOutputStream();
|
||||||
@@ -80,7 +89,7 @@ public class FrameReadWriteTest extends TestCase {
|
|||||||
assertEquals(IV_LENGTH, in.read(recoveredIv));
|
assertEquals(IV_LENGTH, in.read(recoveredIv));
|
||||||
assertTrue(Arrays.equals(encryptedIv, recoveredIv));
|
assertTrue(Arrays.equals(encryptedIv, recoveredIv));
|
||||||
ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in,
|
ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in,
|
||||||
transportId, connection, frameCipher, frameKey);
|
initiator, transportId, connection, frameCipher, frameKey);
|
||||||
ConnectionReader reader = new ConnectionReaderImpl(decrypter, mac);
|
ConnectionReader reader = new ConnectionReaderImpl(decrypter, mac);
|
||||||
InputStream in1 = reader.getInputStream();
|
InputStream in1 = reader.getInputStream();
|
||||||
byte[] recovered = new byte[frame.length];
|
byte[] recovered = new byte[frame.length];
|
||||||
|
|||||||
Reference in New Issue
Block a user