mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 03:39:05 +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:
@@ -135,7 +135,7 @@ public class FileReadWriteTest extends TestCase {
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
// Use Alice's secret for writing
|
||||
ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out,
|
||||
transportId, connection, aliceSecret);
|
||||
true, transportId, connection, aliceSecret);
|
||||
out = w.getOutputStream();
|
||||
|
||||
AckWriter a = protocolWriterFactory.createAckWriter(out);
|
||||
@@ -194,7 +194,7 @@ public class FileReadWriteTest extends TestCase {
|
||||
assertEquals(16, offset);
|
||||
// Use Bob's secret for reading
|
||||
ConnectionReader r = connectionReaderFactory.createConnectionReader(in,
|
||||
transportId, connection, bobSecret);
|
||||
true, transportId, connection, bobSecret);
|
||||
in = r.getInputStream();
|
||||
ProtocolReader protocolReader =
|
||||
protocolReaderFactory.createProtocolReader(in);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -43,25 +41,33 @@ public class ConnectionDecrypterImplTest extends TestCase {
|
||||
byte[] ciphertext = new byte[1 + MAC_LENGTH];
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
|
||||
// Check that one byte plus a MAC can be read
|
||||
ConnectionDecrypter d = new ConnectionDecrypterImpl(in, transportId,
|
||||
connection, frameCipher, frameKey);
|
||||
ConnectionDecrypter d = new ConnectionDecrypterImpl(in, true,
|
||||
transportId, connection, frameCipher, frameKey);
|
||||
assertFalse(d.getInputStream().read() == -1);
|
||||
d.readMac(new byte[MAC_LENGTH]);
|
||||
assertTrue(d.getInputStream().read() == -1);
|
||||
}
|
||||
|
||||
@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
|
||||
byte[] ciphertext = new byte[123];
|
||||
byte[] iv = new byte[IV_LENGTH];
|
||||
IvEncoder.encodeIv(iv, transportId, connection, 0L);
|
||||
byte[] iv = IvEncoder.encodeIv(initiator, transportId, connection);
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
|
||||
byte[] plaintext = frameCipher.doFinal(ciphertext);
|
||||
// Calculate the expected plaintext for the second frame
|
||||
byte[] ciphertext1 = new byte[1234];
|
||||
IvEncoder.encodeIv(iv, transportId, connection, 1L);
|
||||
IvEncoder.updateIv(iv, 1L);
|
||||
ivSpec = new IvParameterSpec(iv);
|
||||
frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
|
||||
byte[] plaintext1 = frameCipher.doFinal(ciphertext1);
|
||||
@@ -72,8 +78,8 @@ public class ConnectionDecrypterImplTest extends TestCase {
|
||||
out.write(ciphertext1);
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
// Use a ConnectionDecrypter to decrypt the ciphertext
|
||||
ConnectionDecrypter d = new ConnectionDecrypterImpl(in, transportId,
|
||||
connection, frameCipher, frameKey);
|
||||
ConnectionDecrypter d = new ConnectionDecrypterImpl(in, initiator,
|
||||
transportId, connection, frameCipher, frameKey);
|
||||
// First frame
|
||||
byte[] decrypted = new byte[plaintext.length - MAC_LENGTH];
|
||||
TestUtils.readFully(d.getInputStream(), decrypted);
|
||||
|
||||
@@ -40,17 +40,27 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
||||
@Test
|
||||
public void testSingleByteFrame() throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ConnectionEncrypter e = new ConnectionEncrypterImpl(out, transportId,
|
||||
connection, ivCipher, frameCipher, ivKey, frameKey);
|
||||
ConnectionEncrypter e = new ConnectionEncrypterImpl(out, true,
|
||||
transportId, connection, ivCipher, frameCipher, ivKey,
|
||||
frameKey);
|
||||
e.getOutputStream().write((byte) 0);
|
||||
e.writeMac(new byte[MAC_LENGTH]);
|
||||
assertEquals(IV_LENGTH + 1 + MAC_LENGTH, out.toByteArray().length);
|
||||
}
|
||||
|
||||
@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
|
||||
byte[] iv = IvEncoder.encodeIv(transportId, connection);
|
||||
byte[] iv = IvEncoder.encodeIv(initiator, transportId, connection);
|
||||
assertEquals(IV_LENGTH, iv.length);
|
||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
||||
byte[] encryptedIv = ivCipher.doFinal(iv);
|
||||
@@ -58,7 +68,6 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
||||
// Calculate the expected ciphertext for the first frame
|
||||
byte[] plaintext = new byte[123];
|
||||
byte[] plaintextMac = new byte[MAC_LENGTH];
|
||||
IvEncoder.encodeIv(iv, transportId, connection, 0L);
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
|
||||
byte[] ciphertext = new byte[plaintext.length + plaintextMac.length];
|
||||
@@ -68,7 +77,7 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
||||
offset);
|
||||
// Calculate the expected ciphertext for the second frame
|
||||
byte[] plaintext1 = new byte[1234];
|
||||
IvEncoder.encodeIv(iv, transportId, connection, 1L);
|
||||
IvEncoder.updateIv(iv, 1L);
|
||||
ivSpec = new IvParameterSpec(iv);
|
||||
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
|
||||
byte[] ciphertext1 = new byte[plaintext1.length + plaintextMac.length];
|
||||
@@ -84,8 +93,9 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
||||
byte[] expected = out.toByteArray();
|
||||
// Use a ConnectionEncrypter to encrypt the plaintext
|
||||
out.reset();
|
||||
ConnectionEncrypter e = new ConnectionEncrypterImpl(out, transportId,
|
||||
connection, ivCipher, frameCipher, ivKey, frameKey);
|
||||
ConnectionEncrypter e = new ConnectionEncrypterImpl(out, initiator,
|
||||
transportId, connection, ivCipher, frameCipher, ivKey,
|
||||
frameKey);
|
||||
e.getOutputStream().write(plaintext);
|
||||
e.writeMac(plaintextMac);
|
||||
e.getOutputStream().write(plaintext1);
|
||||
|
||||
@@ -65,7 +65,7 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
||||
SecretKey ivKey = crypto.deriveIncomingIvKey(secret);
|
||||
Cipher ivCipher = crypto.getIvCipher();
|
||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
||||
byte[] iv = IvEncoder.encodeIv(transportId, 3L);
|
||||
byte[] iv = IvEncoder.encodeIv(true, transportId, 3L);
|
||||
byte[] encryptedIv = ivCipher.doFinal(iv);
|
||||
|
||||
Mockery context = new Mockery();
|
||||
|
||||
@@ -50,9 +50,18 @@ public class FrameReadWriteTest extends TestCase {
|
||||
}
|
||||
|
||||
@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
|
||||
byte[] iv = IvEncoder.encodeIv(transportId, connection);
|
||||
byte[] iv = IvEncoder.encodeIv(initiator, transportId, connection);
|
||||
assertEquals(IV_LENGTH, iv.length);
|
||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
||||
byte[] encryptedIv = ivCipher.doFinal(iv);
|
||||
@@ -65,8 +74,8 @@ public class FrameReadWriteTest extends TestCase {
|
||||
// Write the frames
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
|
||||
transportId, connection, ivCipher, frameCipher, ivKey,
|
||||
frameKey);
|
||||
initiator, transportId, connection, ivCipher, frameCipher,
|
||||
ivKey, frameKey);
|
||||
mac.init(macKey);
|
||||
ConnectionWriter writer = new ConnectionWriterImpl(encrypter, mac);
|
||||
OutputStream out1 = writer.getOutputStream();
|
||||
@@ -80,7 +89,7 @@ public class FrameReadWriteTest extends TestCase {
|
||||
assertEquals(IV_LENGTH, in.read(recoveredIv));
|
||||
assertTrue(Arrays.equals(encryptedIv, recoveredIv));
|
||||
ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in,
|
||||
transportId, connection, frameCipher, frameKey);
|
||||
initiator, transportId, connection, frameCipher, frameKey);
|
||||
ConnectionReader reader = new ConnectionReaderImpl(decrypter, mac);
|
||||
InputStream in1 = reader.getInputStream();
|
||||
byte[] recovered = new byte[frame.length];
|
||||
|
||||
Reference in New Issue
Block a user