diff --git a/api/net/sf/briar/api/crypto/CryptoComponent.java b/api/net/sf/briar/api/crypto/CryptoComponent.java
index a8f3530f4..373daea80 100644
--- a/api/net/sf/briar/api/crypto/CryptoComponent.java
+++ b/api/net/sf/briar/api/crypto/CryptoComponent.java
@@ -10,11 +10,17 @@ import javax.crypto.SecretKey;
public interface CryptoComponent {
- SecretKey deriveMacKey(byte[] secret);
+ SecretKey deriveIncomingMacKey(byte[] secret);
- SecretKey derivePacketKey(byte[] secret);
+ SecretKey deriveIncomingPacketKey(byte[] secret);
- SecretKey deriveTagKey(byte[] secret);
+ SecretKey deriveIncomingTagKey(byte[] secret);
+
+ SecretKey deriveOutgoingMacKey(byte[] secret);
+
+ SecretKey deriveOutgoingPacketKey(byte[] secret);
+
+ SecretKey deriveOutgoingTagKey(byte[] secret);
KeyPair generateKeyPair();
diff --git a/components/net/sf/briar/crypto/CryptoComponentImpl.java b/components/net/sf/briar/crypto/CryptoComponentImpl.java
index 99cbe824d..366c37fd5 100644
--- a/components/net/sf/briar/crypto/CryptoComponentImpl.java
+++ b/components/net/sf/briar/crypto/CryptoComponentImpl.java
@@ -68,9 +68,13 @@ class CryptoComponentImpl implements CryptoComponent {
}
}
- public SecretKey deriveMacKey(byte[] secret) {
+ public SecretKey deriveIncomingMacKey(byte[] secret) {
SharedSecret s = new SharedSecret(secret);
- if(s.getAlice()) return deriveKey("MACA", s.getIv(), s.getCiphertext());
+ return deriveMacKey(s, !s.getAlice());
+ }
+
+ private SecretKey deriveMacKey(SharedSecret s, boolean alice) {
+ if(alice) return deriveKey("MACA", s.getIv(), s.getCiphertext());
else return deriveKey("MACB", s.getIv(), s.getCiphertext());
}
@@ -110,18 +114,41 @@ class CryptoComponentImpl implements CryptoComponent {
}
}
- public SecretKey derivePacketKey(byte[] secret) {
+ public SecretKey deriveIncomingPacketKey(byte[] secret) {
SharedSecret s = new SharedSecret(secret);
- if(s.getAlice()) return deriveKey("PKTA", s.getIv(), s.getCiphertext());
+ return derivePacketKey(s, !s.getAlice());
+ }
+
+ private SecretKey derivePacketKey(SharedSecret s, boolean alice) {
+ if(alice) return deriveKey("PKTA", s.getIv(), s.getCiphertext());
else return deriveKey("PKTB", s.getIv(), s.getCiphertext());
}
- public SecretKey deriveTagKey(byte[] secret) {
+ public SecretKey deriveIncomingTagKey(byte[] secret) {
SharedSecret s = new SharedSecret(secret);
- if(s.getAlice()) return deriveKey("TAGA", s.getIv(), s.getCiphertext());
+ return deriveTagKey(s, !s.getAlice());
+ }
+
+ private SecretKey deriveTagKey(SharedSecret s, boolean alice) {
+ if(alice) return deriveKey("TAGA", s.getIv(), s.getCiphertext());
else return deriveKey("TAGB", s.getIv(), s.getCiphertext());
}
+ public SecretKey deriveOutgoingMacKey(byte[] secret) {
+ SharedSecret s = new SharedSecret(secret);
+ return deriveMacKey(s, s.getAlice());
+ }
+
+ public SecretKey deriveOutgoingPacketKey(byte[] secret) {
+ SharedSecret s = new SharedSecret(secret);
+ return derivePacketKey(s, s.getAlice());
+ }
+
+ public SecretKey deriveOutgoingTagKey(byte[] secret) {
+ SharedSecret s = new SharedSecret(secret);
+ return deriveTagKey(s, s.getAlice());
+ }
+
public KeyPair generateKeyPair() {
return keyPairGenerator.generateKeyPair();
}
diff --git a/components/net/sf/briar/transport/ConnectionRecogniserImpl.java b/components/net/sf/briar/transport/ConnectionRecogniserImpl.java
index 4fcf5deff..77865ddfc 100644
--- a/components/net/sf/briar/transport/ConnectionRecogniserImpl.java
+++ b/components/net/sf/briar/transport/ConnectionRecogniserImpl.java
@@ -50,7 +50,8 @@ DatabaseListener {
for(ContactId c : db.getContacts()) {
try {
// Initialise and store the contact's tag cipher
- SecretKey tagKey = crypto.deriveTagKey(db.getSharedSecret(c));
+ byte[] secret = db.getSharedSecret(c);
+ SecretKey tagKey = crypto.deriveIncomingTagKey(secret);
Cipher cipher = crypto.getTagCipher();
try {
cipher.init(Cipher.ENCRYPT_MODE, tagKey);
diff --git a/components/net/sf/briar/transport/PacketReaderFactoryImpl.java b/components/net/sf/briar/transport/PacketReaderFactoryImpl.java
index 5e5a7f2bf..3d8ccbdaf 100644
--- a/components/net/sf/briar/transport/PacketReaderFactoryImpl.java
+++ b/components/net/sf/briar/transport/PacketReaderFactoryImpl.java
@@ -24,9 +24,9 @@ class PacketReaderFactoryImpl implements PacketReaderFactory {
public PacketReader createPacketReader(byte[] firstTag, InputStream in,
int transportId, long connection, byte[] secret) {
- SecretKey macKey = crypto.deriveMacKey(secret);
- SecretKey tagKey = crypto.deriveTagKey(secret);
- SecretKey packetKey = crypto.derivePacketKey(secret);
+ SecretKey macKey = crypto.deriveIncomingMacKey(secret);
+ SecretKey tagKey = crypto.deriveIncomingTagKey(secret);
+ SecretKey packetKey = crypto.deriveIncomingPacketKey(secret);
Cipher tagCipher = crypto.getTagCipher();
Cipher packetCipher = crypto.getPacketCipher();
Mac mac = crypto.getMac();
diff --git a/components/net/sf/briar/transport/PacketWriterFactoryImpl.java b/components/net/sf/briar/transport/PacketWriterFactoryImpl.java
index cf411c2e0..a59d201c4 100644
--- a/components/net/sf/briar/transport/PacketWriterFactoryImpl.java
+++ b/components/net/sf/briar/transport/PacketWriterFactoryImpl.java
@@ -24,9 +24,9 @@ class PacketWriterFactoryImpl implements PacketWriterFactory {
public PacketWriter createPacketWriter(OutputStream out, int transportId,
long connection, byte[] secret) {
- SecretKey macKey = crypto.deriveMacKey(secret);
- SecretKey tagKey = crypto.deriveTagKey(secret);
- SecretKey packetKey = crypto.derivePacketKey(secret);
+ SecretKey macKey = crypto.deriveOutgoingMacKey(secret);
+ SecretKey tagKey = crypto.deriveOutgoingTagKey(secret);
+ SecretKey packetKey = crypto.deriveOutgoingPacketKey(secret);
Cipher tagCipher = crypto.getTagCipher();
Cipher packetCipher = crypto.getPacketCipher();
Mac mac = crypto.getMac();
diff --git a/test/build.xml b/test/build.xml
index d12ada885..f63488bbf 100644
--- a/test/build.xml
+++ b/test/build.xml
@@ -16,6 +16,8 @@
+
+
diff --git a/test/net/sf/briar/FileReadWriteTest.java b/test/net/sf/briar/FileReadWriteTest.java
index 498850795..363710f53 100644
--- a/test/net/sf/briar/FileReadWriteTest.java
+++ b/test/net/sf/briar/FileReadWriteTest.java
@@ -71,7 +71,7 @@ public class FileReadWriteTest extends TestCase {
private final ProtocolReaderFactory protocolReaderFactory;
private final ProtocolWriterFactory protocolWriterFactory;
private final CryptoComponent crypto;
- private final byte[] secret = new byte[45];
+ private final byte[] aliceSecret, bobSecret;
private final int transportId = 123;
private final long connection = 234L;
private final Author author;
@@ -94,6 +94,10 @@ public class FileReadWriteTest extends TestCase {
crypto = i.getInstance(CryptoComponent.class);
assertEquals(crypto.getMessageDigest().getDigestLength(),
UniqueId.LENGTH);
+ // Create matching secrets: one for Alice, one for Bob
+ aliceSecret = new byte[45];
+ aliceSecret[16] = (byte) 1;
+ bobSecret = new byte[45];
// Create two groups: one restricted, one unrestricted
GroupFactory groupFactory = i.getInstance(GroupFactory.class);
group = groupFactory.createGroup("Unrestricted group", null);
@@ -129,8 +133,9 @@ public class FileReadWriteTest extends TestCase {
@Test
public void testWriteFile() throws Exception {
OutputStream out = new FileOutputStream(file);
+ // Use Alice's secret for writing
PacketWriter packetWriter = packetWriterFactory.createPacketWriter(out,
- transportId, connection, secret);
+ transportId, connection, aliceSecret);
out = packetWriter.getOutputStream();
AckWriter a = protocolWriterFactory.createAckWriter(out);
@@ -194,8 +199,9 @@ public class FileReadWriteTest extends TestCase {
offset += read;
}
assertEquals(16, offset);
+ // Use Bob's secret for reading
PacketReader packetReader = packetReaderFactory.createPacketReader(
- firstTag, in, transportId, connection, secret);
+ firstTag, in, transportId, connection, bobSecret);
in = packetReader.getInputStream();
ProtocolReader protocolReader =
protocolReaderFactory.createProtocolReader(in);
diff --git a/test/net/sf/briar/crypto/CryptoComponentTest.java b/test/net/sf/briar/crypto/CryptoComponentTest.java
new file mode 100644
index 000000000..d7dad93ed
--- /dev/null
+++ b/test/net/sf/briar/crypto/CryptoComponentTest.java
@@ -0,0 +1,49 @@
+package net.sf.briar.crypto;
+
+import junit.framework.TestCase;
+import net.sf.briar.api.crypto.CryptoComponent;
+
+import org.junit.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+public class CryptoComponentTest extends TestCase {
+
+ private final CryptoComponent crypto;
+
+ public CryptoComponentTest() {
+ super();
+ Injector i = Guice.createInjector(new CryptoModule());
+ crypto = i.getInstance(CryptoComponent.class);
+ }
+
+ @Test
+ public void testKeyDerivation() {
+ // Create matching secrets: one for Alice, one for Bob
+ byte[] aliceSecret = new byte[123];
+ aliceSecret[SharedSecret.IV_BYTES] = (byte) 1;
+ byte[] bobSecret = new byte[123];
+ // Check that Alice's incoming keys match Bob's outgoing keys
+ assertEquals(crypto.deriveIncomingMacKey(aliceSecret),
+ crypto.deriveOutgoingMacKey(bobSecret));
+ assertEquals(crypto.deriveIncomingPacketKey(aliceSecret),
+ crypto.deriveOutgoingPacketKey(bobSecret));
+ assertEquals(crypto.deriveIncomingTagKey(aliceSecret),
+ crypto.deriveOutgoingTagKey(bobSecret));
+ // Check that Alice's outgoing keys match Bob's incoming keys
+ assertEquals(crypto.deriveOutgoingMacKey(aliceSecret),
+ crypto.deriveIncomingMacKey(bobSecret));
+ assertEquals(crypto.deriveOutgoingPacketKey(aliceSecret),
+ crypto.deriveIncomingPacketKey(bobSecret));
+ assertEquals(crypto.deriveOutgoingTagKey(aliceSecret),
+ crypto.deriveIncomingTagKey(bobSecret));
+ // Check that Alice's incoming and outgoing keys are different
+ assertFalse(crypto.deriveIncomingMacKey(aliceSecret).equals(
+ crypto.deriveOutgoingMacKey(aliceSecret)));
+ assertFalse(crypto.deriveIncomingPacketKey(aliceSecret).equals(
+ crypto.deriveOutgoingPacketKey(aliceSecret)));
+ assertFalse(crypto.deriveIncomingTagKey(aliceSecret).equals(
+ crypto.deriveOutgoingTagKey(aliceSecret)));
+ }
+}
diff --git a/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java b/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java
index 948a7872a..c5009db87 100644
--- a/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java
@@ -60,7 +60,7 @@ public class ConnectionRecogniserImplTest extends TestCase {
@Test
public void testExpectedTag() throws Exception {
// Calculate the expected tag for connection number 3
- SecretKey tagKey = crypto.deriveTagKey(secret);
+ SecretKey tagKey = crypto.deriveIncomingTagKey(secret);
Cipher tagCipher = crypto.getTagCipher();
tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
byte[] tag = TagEncoder.encodeTag(transportId, 3L, 0);
diff --git a/test/net/sf/briar/transport/PacketReadWriteTest.java b/test/net/sf/briar/transport/PacketReadWriteTest.java
index a4f47e1bf..106dff792 100644
--- a/test/net/sf/briar/transport/PacketReadWriteTest.java
+++ b/test/net/sf/briar/transport/PacketReadWriteTest.java
@@ -39,9 +39,10 @@ public class PacketReadWriteTest extends TestCase {
crypto = i.getInstance(CryptoComponent.class);
tagCipher = crypto.getTagCipher();
packetCipher = crypto.getPacketCipher();
- macKey = crypto.deriveMacKey(secret);
- tagKey = crypto.deriveTagKey(secret);
- packetKey = crypto.derivePacketKey(secret);
+ // Since we're sending packets to ourselves, we only need outgoing keys
+ macKey = crypto.deriveOutgoingMacKey(secret);
+ tagKey = crypto.deriveOutgoingTagKey(secret);
+ packetKey = crypto.deriveOutgoingPacketKey(secret);
mac = crypto.getMac();
random = new Random();
}