mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-20 22:59:54 +01:00
Derive separate keys for each direction.
This commit is contained in:
@@ -10,11 +10,17 @@ import javax.crypto.SecretKey;
|
|||||||
|
|
||||||
public interface CryptoComponent {
|
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();
|
KeyPair generateKeyPair();
|
||||||
|
|
||||||
|
|||||||
@@ -68,9 +68,13 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SecretKey deriveMacKey(byte[] secret) {
|
public SecretKey deriveIncomingMacKey(byte[] secret) {
|
||||||
SharedSecret s = new SharedSecret(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());
|
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);
|
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());
|
else return deriveKey("PKTB", s.getIv(), s.getCiphertext());
|
||||||
}
|
}
|
||||||
|
|
||||||
public SecretKey deriveTagKey(byte[] secret) {
|
public SecretKey deriveIncomingTagKey(byte[] secret) {
|
||||||
SharedSecret s = new SharedSecret(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());
|
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() {
|
public KeyPair generateKeyPair() {
|
||||||
return keyPairGenerator.generateKeyPair();
|
return keyPairGenerator.generateKeyPair();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ DatabaseListener {
|
|||||||
for(ContactId c : db.getContacts()) {
|
for(ContactId c : db.getContacts()) {
|
||||||
try {
|
try {
|
||||||
// Initialise and store the contact's tag cipher
|
// 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();
|
Cipher cipher = crypto.getTagCipher();
|
||||||
try {
|
try {
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, tagKey);
|
cipher.init(Cipher.ENCRYPT_MODE, tagKey);
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ class PacketReaderFactoryImpl implements PacketReaderFactory {
|
|||||||
|
|
||||||
public PacketReader createPacketReader(byte[] firstTag, InputStream in,
|
public PacketReader createPacketReader(byte[] firstTag, InputStream in,
|
||||||
int transportId, long connection, byte[] secret) {
|
int transportId, long connection, byte[] secret) {
|
||||||
SecretKey macKey = crypto.deriveMacKey(secret);
|
SecretKey macKey = crypto.deriveIncomingMacKey(secret);
|
||||||
SecretKey tagKey = crypto.deriveTagKey(secret);
|
SecretKey tagKey = crypto.deriveIncomingTagKey(secret);
|
||||||
SecretKey packetKey = crypto.derivePacketKey(secret);
|
SecretKey packetKey = crypto.deriveIncomingPacketKey(secret);
|
||||||
Cipher tagCipher = crypto.getTagCipher();
|
Cipher tagCipher = crypto.getTagCipher();
|
||||||
Cipher packetCipher = crypto.getPacketCipher();
|
Cipher packetCipher = crypto.getPacketCipher();
|
||||||
Mac mac = crypto.getMac();
|
Mac mac = crypto.getMac();
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ class PacketWriterFactoryImpl implements PacketWriterFactory {
|
|||||||
|
|
||||||
public PacketWriter createPacketWriter(OutputStream out, int transportId,
|
public PacketWriter createPacketWriter(OutputStream out, int transportId,
|
||||||
long connection, byte[] secret) {
|
long connection, byte[] secret) {
|
||||||
SecretKey macKey = crypto.deriveMacKey(secret);
|
SecretKey macKey = crypto.deriveOutgoingMacKey(secret);
|
||||||
SecretKey tagKey = crypto.deriveTagKey(secret);
|
SecretKey tagKey = crypto.deriveOutgoingTagKey(secret);
|
||||||
SecretKey packetKey = crypto.derivePacketKey(secret);
|
SecretKey packetKey = crypto.deriveOutgoingPacketKey(secret);
|
||||||
Cipher tagCipher = crypto.getTagCipher();
|
Cipher tagCipher = crypto.getTagCipher();
|
||||||
Cipher packetCipher = crypto.getPacketCipher();
|
Cipher packetCipher = crypto.getPacketCipher();
|
||||||
Mac mac = crypto.getMac();
|
Mac mac = crypto.getMac();
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
<test name='net.sf.briar.FileReadWriteTest'/>
|
<test name='net.sf.briar.FileReadWriteTest'/>
|
||||||
<test name='net.sf.briar.LockFairnessTest'/>
|
<test name='net.sf.briar.LockFairnessTest'/>
|
||||||
<test name='net.sf.briar.crypto.CounterModeTest'/>
|
<test name='net.sf.briar.crypto.CounterModeTest'/>
|
||||||
|
<test name='net.sf.briar.crypto.CryptoComponentTest'/>
|
||||||
|
<test name='net.sf.briar.crypto.SharedSecretTest'/>
|
||||||
<test name='net.sf.briar.db.BasicH2Test'/>
|
<test name='net.sf.briar.db.BasicH2Test'/>
|
||||||
<test name='net.sf.briar.db.DatabaseCleanerImplTest'/>
|
<test name='net.sf.briar.db.DatabaseCleanerImplTest'/>
|
||||||
<test name='net.sf.briar.db.H2DatabaseTest'/>
|
<test name='net.sf.briar.db.H2DatabaseTest'/>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public class FileReadWriteTest extends TestCase {
|
|||||||
private final ProtocolReaderFactory protocolReaderFactory;
|
private final ProtocolReaderFactory protocolReaderFactory;
|
||||||
private final ProtocolWriterFactory protocolWriterFactory;
|
private final ProtocolWriterFactory protocolWriterFactory;
|
||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
private final byte[] secret = new byte[45];
|
private final byte[] aliceSecret, bobSecret;
|
||||||
private final int transportId = 123;
|
private final int transportId = 123;
|
||||||
private final long connection = 234L;
|
private final long connection = 234L;
|
||||||
private final Author author;
|
private final Author author;
|
||||||
@@ -94,6 +94,10 @@ public class FileReadWriteTest extends TestCase {
|
|||||||
crypto = i.getInstance(CryptoComponent.class);
|
crypto = i.getInstance(CryptoComponent.class);
|
||||||
assertEquals(crypto.getMessageDigest().getDigestLength(),
|
assertEquals(crypto.getMessageDigest().getDigestLength(),
|
||||||
UniqueId.LENGTH);
|
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
|
// Create two groups: one restricted, one unrestricted
|
||||||
GroupFactory groupFactory = i.getInstance(GroupFactory.class);
|
GroupFactory groupFactory = i.getInstance(GroupFactory.class);
|
||||||
group = groupFactory.createGroup("Unrestricted group", null);
|
group = groupFactory.createGroup("Unrestricted group", null);
|
||||||
@@ -129,8 +133,9 @@ public class FileReadWriteTest extends TestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteFile() throws Exception {
|
public void testWriteFile() throws Exception {
|
||||||
OutputStream out = new FileOutputStream(file);
|
OutputStream out = new FileOutputStream(file);
|
||||||
|
// Use Alice's secret for writing
|
||||||
PacketWriter packetWriter = packetWriterFactory.createPacketWriter(out,
|
PacketWriter packetWriter = packetWriterFactory.createPacketWriter(out,
|
||||||
transportId, connection, secret);
|
transportId, connection, aliceSecret);
|
||||||
out = packetWriter.getOutputStream();
|
out = packetWriter.getOutputStream();
|
||||||
|
|
||||||
AckWriter a = protocolWriterFactory.createAckWriter(out);
|
AckWriter a = protocolWriterFactory.createAckWriter(out);
|
||||||
@@ -194,8 +199,9 @@ public class FileReadWriteTest extends TestCase {
|
|||||||
offset += read;
|
offset += read;
|
||||||
}
|
}
|
||||||
assertEquals(16, offset);
|
assertEquals(16, offset);
|
||||||
|
// Use Bob's secret for reading
|
||||||
PacketReader packetReader = packetReaderFactory.createPacketReader(
|
PacketReader packetReader = packetReaderFactory.createPacketReader(
|
||||||
firstTag, in, transportId, connection, secret);
|
firstTag, in, transportId, connection, bobSecret);
|
||||||
in = packetReader.getInputStream();
|
in = packetReader.getInputStream();
|
||||||
ProtocolReader protocolReader =
|
ProtocolReader protocolReader =
|
||||||
protocolReaderFactory.createProtocolReader(in);
|
protocolReaderFactory.createProtocolReader(in);
|
||||||
|
|||||||
49
test/net/sf/briar/crypto/CryptoComponentTest.java
Normal file
49
test/net/sf/briar/crypto/CryptoComponentTest.java
Normal file
@@ -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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,7 +60,7 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testExpectedTag() throws Exception {
|
public void testExpectedTag() throws Exception {
|
||||||
// Calculate the expected tag for connection number 3
|
// Calculate the expected tag for connection number 3
|
||||||
SecretKey tagKey = crypto.deriveTagKey(secret);
|
SecretKey tagKey = crypto.deriveIncomingTagKey(secret);
|
||||||
Cipher tagCipher = crypto.getTagCipher();
|
Cipher tagCipher = crypto.getTagCipher();
|
||||||
tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
|
tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
|
||||||
byte[] tag = TagEncoder.encodeTag(transportId, 3L, 0);
|
byte[] tag = TagEncoder.encodeTag(transportId, 3L, 0);
|
||||||
|
|||||||
@@ -39,9 +39,10 @@ public class PacketReadWriteTest extends TestCase {
|
|||||||
crypto = i.getInstance(CryptoComponent.class);
|
crypto = i.getInstance(CryptoComponent.class);
|
||||||
tagCipher = crypto.getTagCipher();
|
tagCipher = crypto.getTagCipher();
|
||||||
packetCipher = crypto.getPacketCipher();
|
packetCipher = crypto.getPacketCipher();
|
||||||
macKey = crypto.deriveMacKey(secret);
|
// Since we're sending packets to ourselves, we only need outgoing keys
|
||||||
tagKey = crypto.deriveTagKey(secret);
|
macKey = crypto.deriveOutgoingMacKey(secret);
|
||||||
packetKey = crypto.derivePacketKey(secret);
|
tagKey = crypto.deriveOutgoingTagKey(secret);
|
||||||
|
packetKey = crypto.deriveOutgoingPacketKey(secret);
|
||||||
mac = crypto.getMac();
|
mac = crypto.getMac();
|
||||||
random = new Random();
|
random = new Random();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user