The word "tag" was overloaded, so from now on use "tag" for the

predefined tags in the protocol and serial components, and "IV" for
the encrypted IVs used to identify connections in the transport
component.
This commit is contained in:
akwizgran
2011-08-19 11:15:35 +02:00
parent 2411e2008b
commit 9dea4d0299
19 changed files with 239 additions and 250 deletions

View File

@@ -185,10 +185,10 @@ public class FileReadWriteTest extends TestCase {
testWriteFile();
InputStream in = new FileInputStream(file);
byte[] firstTag = new byte[16];
byte[] iv = new byte[16];
int offset = 0;
while(offset < 16) {
int read = in.read(firstTag, offset, firstTag.length - offset);
int read = in.read(iv, offset, iv.length - offset);
if(read == -1) break;
offset += read;
}

View File

@@ -29,21 +29,21 @@ public class CryptoComponentTest extends TestCase {
crypto.deriveOutgoingMacKey(bobSecret));
assertEquals(crypto.deriveIncomingFrameKey(aliceSecret),
crypto.deriveOutgoingFrameKey(bobSecret));
assertEquals(crypto.deriveIncomingTagKey(aliceSecret),
crypto.deriveOutgoingTagKey(bobSecret));
assertEquals(crypto.deriveIncomingIvKey(aliceSecret),
crypto.deriveOutgoingIvKey(bobSecret));
// Check that Alice's outgoing keys match Bob's incoming keys
assertEquals(crypto.deriveOutgoingMacKey(aliceSecret),
crypto.deriveIncomingMacKey(bobSecret));
assertEquals(crypto.deriveOutgoingFrameKey(aliceSecret),
crypto.deriveIncomingFrameKey(bobSecret));
assertEquals(crypto.deriveOutgoingTagKey(aliceSecret),
crypto.deriveIncomingTagKey(bobSecret));
assertEquals(crypto.deriveOutgoingIvKey(aliceSecret),
crypto.deriveIncomingIvKey(bobSecret));
// Check that Alice's incoming and outgoing keys are different
assertFalse(crypto.deriveIncomingMacKey(aliceSecret).equals(
crypto.deriveOutgoingMacKey(aliceSecret)));
assertFalse(crypto.deriveIncomingFrameKey(aliceSecret).equals(
crypto.deriveOutgoingFrameKey(aliceSecret)));
assertFalse(crypto.deriveIncomingTagKey(aliceSecret).equals(
crypto.deriveOutgoingTagKey(aliceSecret)));
assertFalse(crypto.deriveIncomingIvKey(aliceSecret).equals(
crypto.deriveOutgoingIvKey(aliceSecret)));
}
}

View File

@@ -1,6 +1,6 @@
package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
@@ -54,16 +54,16 @@ public class ConnectionDecrypterImplTest extends TestCase {
public void testDecryption() throws Exception {
// Calculate the expected plaintext for the first frame
byte[] ciphertext = new byte[123];
byte[] ivBytes = new byte[TAG_LENGTH];
TagEncoder.encodeTag(ivBytes, transportId, connection, 0L);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
frameCipher.init(Cipher.DECRYPT_MODE, frameKey, iv);
byte[] iv = new byte[IV_LENGTH];
IvEncoder.encodeIv(iv, transportId, connection, 0L);
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];
TagEncoder.encodeTag(ivBytes, transportId, connection, 1L);
iv = new IvParameterSpec(ivBytes);
frameCipher.init(Cipher.DECRYPT_MODE, frameKey, iv);
IvEncoder.encodeIv(iv, transportId, connection, 1L);
ivSpec = new IvParameterSpec(iv);
frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
byte[] plaintext1 = frameCipher.doFinal(ciphertext1);
assertEquals(ciphertext1.length, plaintext1.length);
// Concatenate the ciphertexts

View File

@@ -1,6 +1,6 @@
package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
@@ -22,8 +22,8 @@ public class ConnectionEncrypterImplTest extends TestCase {
private static final int MAC_LENGTH = 32;
private final Cipher tagCipher, frameCipher;
private final SecretKey tagKey, frameKey;
private final Cipher ivCipher, frameCipher;
private final SecretKey ivKey, frameKey;
private final int transportId = 1234;
private final long connection = 12345L;
@@ -31,9 +31,9 @@ public class ConnectionEncrypterImplTest extends TestCase {
super();
Injector i = Guice.createInjector(new CryptoModule());
CryptoComponent crypto = i.getInstance(CryptoComponent.class);
tagCipher = crypto.getTagCipher();
ivCipher = crypto.getIvCipher();
frameCipher = crypto.getFrameCipher();
tagKey = crypto.generateSecretKey();
ivKey = crypto.generateSecretKey();
frameKey = crypto.generateSecretKey();
}
@@ -41,27 +41,26 @@ public class ConnectionEncrypterImplTest extends TestCase {
public void testSingleByteFrame() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ConnectionEncrypter e = new ConnectionEncrypterImpl(out, transportId,
connection, tagCipher, frameCipher, tagKey, frameKey);
connection, ivCipher, frameCipher, ivKey, frameKey);
e.getOutputStream().write((byte) 0);
e.writeMac(new byte[MAC_LENGTH]);
assertEquals(TAG_LENGTH + 1 + MAC_LENGTH, out.toByteArray().length);
assertEquals(IV_LENGTH + 1 + MAC_LENGTH, out.toByteArray().length);
}
@Test
public void testEncryption() throws Exception {
// Calculate the expected ciphertext for the tag
byte[] plaintextTag = TagEncoder.encodeTag(transportId, connection);
assertEquals(TAG_LENGTH, plaintextTag.length);
tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
byte[] tag = tagCipher.doFinal(plaintextTag);
assertEquals(TAG_LENGTH, tag.length);
// Calculate the expected ciphertext for the IV
byte[] iv = IvEncoder.encodeIv(transportId, connection);
assertEquals(IV_LENGTH, iv.length);
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
byte[] encryptedIv = ivCipher.doFinal(iv);
assertEquals(IV_LENGTH, encryptedIv.length);
// Calculate the expected ciphertext for the first frame
byte[] plaintext = new byte[123];
byte[] plaintextMac = new byte[MAC_LENGTH];
byte[] ivBytes = new byte[TAG_LENGTH];
TagEncoder.encodeTag(ivBytes, transportId, connection, 0L);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, iv);
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];
int offset = frameCipher.update(plaintext, 0, plaintext.length,
ciphertext);
@@ -69,9 +68,9 @@ public class ConnectionEncrypterImplTest extends TestCase {
offset);
// Calculate the expected ciphertext for the second frame
byte[] plaintext1 = new byte[1234];
TagEncoder.encodeTag(ivBytes, transportId, connection, 1L);
iv = new IvParameterSpec(ivBytes);
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, iv);
IvEncoder.encodeIv(iv, transportId, connection, 1L);
ivSpec = new IvParameterSpec(iv);
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
byte[] ciphertext1 = new byte[plaintext1.length + plaintextMac.length];
offset = frameCipher.update(plaintext1, 0, plaintext1.length,
ciphertext1);
@@ -79,14 +78,14 @@ public class ConnectionEncrypterImplTest extends TestCase {
offset);
// Concatenate the ciphertexts
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write(tag);
out.write(encryptedIv);
out.write(ciphertext);
out.write(ciphertext1);
byte[] expected = out.toByteArray();
// Use a ConnectionEncrypter to encrypt the plaintext
out.reset();
ConnectionEncrypter e = new ConnectionEncrypterImpl(out, transportId,
connection, tagCipher, frameCipher, tagKey, frameKey);
connection, ivCipher, frameCipher, ivKey, frameKey);
e.getOutputStream().write(plaintext);
e.writeMac(plaintextMac);
e.getOutputStream().write(plaintext1);

View File

@@ -33,6 +33,8 @@ public class ConnectionReaderImplTest extends TestCase {
mac.init(crypto.generateSecretKey());
}
// FIXME: Test corner cases and corrupt frames
@Test
public void testSingleByteFrame() throws Exception {
// Six bytes for the header, one for the payload

View File

@@ -1,6 +1,6 @@
package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
import java.util.Collection;
import java.util.Collections;
@@ -41,7 +41,7 @@ public class ConnectionRecogniserImplTest extends TestCase {
}
@Test
public void testUnexpectedTag() throws Exception {
public void testUnexpectedIv() throws Exception {
Mockery context = new Mockery();
final DatabaseComponent db = context.mock(DatabaseComponent.class);
context.checking(new Expectations() {{
@@ -55,18 +55,18 @@ public class ConnectionRecogniserImplTest extends TestCase {
}});
final ConnectionRecogniserImpl c =
new ConnectionRecogniserImpl(transportId, crypto, db);
assertNull(c.acceptConnection(new byte[TAG_LENGTH]));
assertNull(c.acceptConnection(new byte[IV_LENGTH]));
context.assertIsSatisfied();
}
@Test
public void testExpectedTag() throws Exception {
// Calculate the expected tag for connection number 3
SecretKey tagKey = crypto.deriveIncomingTagKey(secret);
Cipher tagCipher = crypto.getTagCipher();
tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
byte[] tag = TagEncoder.encodeTag(transportId, 3L);
byte[] encryptedTag = tagCipher.doFinal(tag);
public void testExpectedIv() throws Exception {
// Calculate the expected IV for connection number 3
SecretKey ivKey = crypto.deriveIncomingIvKey(secret);
Cipher ivCipher = crypto.getIvCipher();
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
byte[] iv = IvEncoder.encodeIv(transportId, 3L);
byte[] encryptedIv = ivCipher.doFinal(iv);
Mockery context = new Mockery();
final DatabaseComponent db = context.mock(DatabaseComponent.class);
@@ -83,10 +83,10 @@ public class ConnectionRecogniserImplTest extends TestCase {
}});
final ConnectionRecogniserImpl c =
new ConnectionRecogniserImpl(transportId, crypto, db);
// First time - the tag should be expected
assertEquals(contactId, c.acceptConnection(encryptedTag));
// Second time - the tag should no longer be expected
assertNull(c.acceptConnection(encryptedTag));
// First time - the IV should be expected
assertEquals(contactId, c.acceptConnection(encryptedIv));
// Second time - the IV should no longer be expected
assertNull(c.acceptConnection(encryptedIv));
// The window should have advanced
assertEquals(4L, connectionWindow.getCentre());
Collection<Long> unseen = connectionWindow.getUnseenConnectionNumbers();

View File

@@ -30,6 +30,8 @@ public class ConnectionWriterImplTest extends TestCase {
mac.init(crypto.generateSecretKey());
}
// FIXME: Test corner cases
@Test
public void testSingleByteFrame() throws Exception {
// Six bytes for the header, one for the payload

View File

@@ -1,6 +1,6 @@
package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -27,8 +27,8 @@ import com.google.inject.Injector;
public class FrameReadWriteTest extends TestCase {
private final CryptoComponent crypto;
private final Cipher tagCipher, frameCipher;
private final SecretKey macKey, tagKey, frameKey;
private final Cipher ivCipher, frameCipher;
private final SecretKey ivKey, frameKey, macKey;
private final Mac mac;
private final Random random;
private final byte[] secret = new byte[100];
@@ -39,24 +39,24 @@ public class FrameReadWriteTest extends TestCase {
super();
Injector i = Guice.createInjector(new CryptoModule());
crypto = i.getInstance(CryptoComponent.class);
tagCipher = crypto.getTagCipher();
ivCipher = crypto.getIvCipher();
frameCipher = crypto.getFrameCipher();
// Since we're sending packets to ourselves, we only need outgoing keys
macKey = crypto.deriveOutgoingMacKey(secret);
tagKey = crypto.deriveOutgoingTagKey(secret);
// Since we're sending frames to ourselves, we only need outgoing keys
ivKey = crypto.deriveOutgoingIvKey(secret);
frameKey = crypto.deriveOutgoingFrameKey(secret);
macKey = crypto.deriveOutgoingMacKey(secret);
mac = crypto.getMac();
random = new Random();
}
@Test
public void testWriteAndRead() throws Exception {
// Calculate the expected ciphertext for the tag
byte[] plaintextTag = TagEncoder.encodeTag(transportId, connection);
assertEquals(TAG_LENGTH, plaintextTag.length);
tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
byte[] tag = tagCipher.doFinal(plaintextTag);
assertEquals(TAG_LENGTH, tag.length);
// Calculate the expected ciphertext for the IV
byte[] iv = IvEncoder.encodeIv(transportId, connection);
assertEquals(IV_LENGTH, iv.length);
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
byte[] encryptedIv = ivCipher.doFinal(iv);
assertEquals(IV_LENGTH, encryptedIv.length);
// Generate two random frames
byte[] frame = new byte[12345];
random.nextBytes(frame);
@@ -65,7 +65,7 @@ public class FrameReadWriteTest extends TestCase {
// Write the frames
ByteArrayOutputStream out = new ByteArrayOutputStream();
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
transportId, connection, tagCipher, frameCipher, tagKey,
transportId, connection, ivCipher, frameCipher, ivKey,
frameKey);
mac.init(macKey);
ConnectionWriter writer = new ConnectionWriterImpl(encrypter, mac);
@@ -76,9 +76,9 @@ public class FrameReadWriteTest extends TestCase {
out1.flush();
// Read the frames back
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
byte[] recoveredTag = new byte[TAG_LENGTH];
assertEquals(TAG_LENGTH, in.read(recoveredTag));
assertTrue(Arrays.equals(tag, recoveredTag));
byte[] recoveredIv = new byte[IV_LENGTH];
assertEquals(IV_LENGTH, in.read(recoveredIv));
assertTrue(Arrays.equals(encryptedIv, recoveredIv));
ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in,
transportId, connection, frameCipher, frameKey);
ConnectionReader reader = new ConnectionReaderImpl(decrypter, mac);