mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 21:29:54 +01:00
Add key derivation for static keys.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.api.crypto;
|
package org.briarproject.bramble.api.crypto;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
|
import org.briarproject.bramble.api.transport.StaticTransportKeys;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,6 +26,23 @@ public interface TransportCrypto {
|
|||||||
*/
|
*/
|
||||||
TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod);
|
TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives static transport keys for the given transport in the given time
|
||||||
|
* period from the given root key.
|
||||||
|
*
|
||||||
|
* @param alice whether the keys are for use by Alice or Bob.
|
||||||
|
*/
|
||||||
|
StaticTransportKeys deriveStaticTransportKeys(TransportId t,
|
||||||
|
SecretKey rootKey, boolean alice, long timePeriod);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the given static transport keys to the given time period. If
|
||||||
|
* the keys are for the given period or any later period they are not
|
||||||
|
* updated.
|
||||||
|
*/
|
||||||
|
StaticTransportKeys updateTransportKeys(StaticTransportKeys k,
|
||||||
|
long timePeriod);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes the pseudo-random tag that is used to recognise a stream.
|
* Encodes the pseudo-random tag that is used to recognise a stream.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package org.briarproject.bramble.api.transport;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class StaticTransportKeys extends TransportKeys {
|
||||||
|
|
||||||
|
private final SecretKey rootKey;
|
||||||
|
private final boolean alice;
|
||||||
|
|
||||||
|
public StaticTransportKeys(TransportId transportId, IncomingKeys inPrev,
|
||||||
|
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr,
|
||||||
|
SecretKey rootKey, boolean alice) {
|
||||||
|
super(transportId, inPrev, inCurr, inNext, outCurr);
|
||||||
|
this.rootKey = rootKey;
|
||||||
|
this.alice = alice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecretKey getRootKey() {
|
||||||
|
return rootKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAlice() {
|
||||||
|
return alice;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -108,4 +108,27 @@ public interface TransportConstants {
|
|||||||
*/
|
*/
|
||||||
String ROTATE_LABEL = "org.briarproject.bramble.transport/ROTATE";
|
String ROTATE_LABEL = "org.briarproject.bramble.transport/ROTATE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label for deriving Alice's static tag key from the root key.
|
||||||
|
*/
|
||||||
|
String ALICE_STATIC_TAG_LABEL =
|
||||||
|
"org.briarproject.bramble.transport/ALICE_STATIC_TAG_KEY";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label for deriving Bob's static tag key from the root key.
|
||||||
|
*/
|
||||||
|
String BOB_STATIC_TAG_LABEL =
|
||||||
|
"org.briarproject.bramble.transport/BOB_STATIC_TAG_KEY";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label for deriving Alice's static header key from the root key.
|
||||||
|
*/
|
||||||
|
String ALICE_STATIC_HEADER_LABEL =
|
||||||
|
"org.briarproject.bramble.transport/ALICE_STATIC_HEADER_KEY";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label for deriving Bob's static header key from the root key.
|
||||||
|
*/
|
||||||
|
String BOB_STATIC_HEADER_LABEL =
|
||||||
|
"org.briarproject.bramble.transport/BOB_STATIC_HEADER_KEY";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,17 +6,21 @@ import org.briarproject.bramble.api.crypto.TransportCrypto;
|
|||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.bramble.api.transport.IncomingKeys;
|
import org.briarproject.bramble.api.transport.IncomingKeys;
|
||||||
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
||||||
|
import org.briarproject.bramble.api.transport.StaticTransportKeys;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
import org.spongycastle.crypto.Digest;
|
import org.spongycastle.crypto.Digest;
|
||||||
import org.spongycastle.crypto.digests.Blake2bDigest;
|
import org.spongycastle.crypto.digests.Blake2bDigest;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.lang.System.arraycopy;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_HEADER_LABEL;
|
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_HEADER_LABEL;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_STATIC_HEADER_LABEL;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_STATIC_TAG_LABEL;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_TAG_LABEL;
|
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_TAG_LABEL;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_HEADER_LABEL;
|
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_HEADER_LABEL;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_STATIC_HEADER_LABEL;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_STATIC_TAG_LABEL;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_TAG_LABEL;
|
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_TAG_LABEL;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.ROTATE_LABEL;
|
import static org.briarproject.bramble.api.transport.TransportConstants.ROTATE_LABEL;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
@@ -24,6 +28,9 @@ import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
|||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint16;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint64;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||||
|
|
||||||
class TransportCryptoImpl implements TransportCrypto {
|
class TransportCryptoImpl implements TransportCrypto {
|
||||||
|
|
||||||
@@ -90,24 +97,111 @@ class TransportCryptoImpl implements TransportCrypto {
|
|||||||
|
|
||||||
private SecretKey rotateKey(SecretKey k, long timePeriod) {
|
private SecretKey rotateKey(SecretKey k, long timePeriod) {
|
||||||
byte[] period = new byte[INT_64_BYTES];
|
byte[] period = new byte[INT_64_BYTES];
|
||||||
ByteUtils.writeUint64(timePeriod, period, 0);
|
writeUint64(timePeriod, period, 0);
|
||||||
return crypto.deriveKey(ROTATE_LABEL, k, period);
|
return crypto.deriveKey(ROTATE_LABEL, k, period);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey deriveTagKey(SecretKey master, TransportId t,
|
private SecretKey deriveTagKey(SecretKey master, TransportId t,
|
||||||
boolean alice) {
|
boolean alice) {
|
||||||
String label = alice ? ALICE_TAG_LABEL : BOB_TAG_LABEL;
|
String label = alice ? ALICE_TAG_LABEL : BOB_TAG_LABEL;
|
||||||
byte[] id = StringUtils.toUtf8(t.getString());
|
byte[] id = toUtf8(t.getString());
|
||||||
return crypto.deriveKey(label, master, id);
|
return crypto.deriveKey(label, master, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey deriveHeaderKey(SecretKey master, TransportId t,
|
private SecretKey deriveHeaderKey(SecretKey master, TransportId t,
|
||||||
boolean alice) {
|
boolean alice) {
|
||||||
String label = alice ? ALICE_HEADER_LABEL : BOB_HEADER_LABEL;
|
String label = alice ? ALICE_HEADER_LABEL : BOB_HEADER_LABEL;
|
||||||
byte[] id = StringUtils.toUtf8(t.getString());
|
byte[] id = toUtf8(t.getString());
|
||||||
return crypto.deriveKey(label, master, id);
|
return crypto.deriveKey(label, master, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StaticTransportKeys deriveStaticTransportKeys(TransportId t,
|
||||||
|
SecretKey rootKey, boolean alice, long timePeriod) {
|
||||||
|
if (timePeriod < 1) throw new IllegalArgumentException();
|
||||||
|
IncomingKeys inPrev = deriveStaticIncomingKeys(t, rootKey, alice,
|
||||||
|
timePeriod - 1);
|
||||||
|
IncomingKeys inCurr = deriveStaticIncomingKeys(t, rootKey, alice,
|
||||||
|
timePeriod);
|
||||||
|
IncomingKeys inNext = deriveStaticIncomingKeys(t, rootKey, alice,
|
||||||
|
timePeriod + 1);
|
||||||
|
OutgoingKeys outCurr = deriveStaticOutgoingKeys(t, rootKey, alice,
|
||||||
|
timePeriod);
|
||||||
|
return new StaticTransportKeys(t, inPrev, inCurr, inNext, outCurr,
|
||||||
|
rootKey, alice);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IncomingKeys deriveStaticIncomingKeys(TransportId t,
|
||||||
|
SecretKey rootKey, boolean alice, long timePeriod) {
|
||||||
|
SecretKey tag = deriveStaticTagKey(t, rootKey, !alice, timePeriod);
|
||||||
|
SecretKey header = deriveStaticHeaderKey(t, rootKey, !alice,
|
||||||
|
timePeriod);
|
||||||
|
return new IncomingKeys(tag, header, timePeriod);
|
||||||
|
}
|
||||||
|
|
||||||
|
private OutgoingKeys deriveStaticOutgoingKeys(TransportId t,
|
||||||
|
SecretKey rootKey, boolean alice, long timePeriod) {
|
||||||
|
SecretKey tag = deriveStaticTagKey(t, rootKey, alice, timePeriod);
|
||||||
|
SecretKey header = deriveStaticHeaderKey(t, rootKey, alice, timePeriod);
|
||||||
|
return new OutgoingKeys(tag, header, timePeriod, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SecretKey deriveStaticTagKey(TransportId t, SecretKey root,
|
||||||
|
boolean alice, long timePeriod) {
|
||||||
|
String label = alice ? ALICE_STATIC_TAG_LABEL : BOB_STATIC_TAG_LABEL;
|
||||||
|
byte[] id = toUtf8(t.getString());
|
||||||
|
byte[] period = new byte[INT_64_BYTES];
|
||||||
|
writeUint64(timePeriod, period, 0);
|
||||||
|
return crypto.deriveKey(label, root, id, period);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SecretKey deriveStaticHeaderKey(TransportId t, SecretKey root,
|
||||||
|
boolean alice, long timePeriod) {
|
||||||
|
String label =
|
||||||
|
alice ? ALICE_STATIC_HEADER_LABEL : BOB_STATIC_HEADER_LABEL;
|
||||||
|
byte[] id = toUtf8(t.getString());
|
||||||
|
byte[] period = new byte[INT_64_BYTES];
|
||||||
|
writeUint64(timePeriod, period, 0);
|
||||||
|
return crypto.deriveKey(label, root, id, period);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StaticTransportKeys updateTransportKeys(StaticTransportKeys k,
|
||||||
|
long timePeriod) {
|
||||||
|
long elapsed = timePeriod - k.getTimePeriod();
|
||||||
|
TransportId t = k.getTransportId();
|
||||||
|
SecretKey rootKey = k.getRootKey();
|
||||||
|
boolean alice = k.isAlice();
|
||||||
|
if (elapsed <= 0) {
|
||||||
|
// The keys are for the given period or later - don't update them
|
||||||
|
return k;
|
||||||
|
} else if (elapsed == 1) {
|
||||||
|
// The keys are one period old - shift by one period
|
||||||
|
IncomingKeys inPrev = k.getCurrentIncomingKeys();
|
||||||
|
IncomingKeys inCurr = k.getNextIncomingKeys();
|
||||||
|
IncomingKeys inNext = deriveStaticIncomingKeys(t, rootKey, alice,
|
||||||
|
timePeriod + 1);
|
||||||
|
OutgoingKeys outCurr = deriveStaticOutgoingKeys(t, rootKey, alice,
|
||||||
|
timePeriod);
|
||||||
|
return new StaticTransportKeys(t, inPrev, inCurr, inNext, outCurr,
|
||||||
|
rootKey, alice);
|
||||||
|
} else if (elapsed == 2) {
|
||||||
|
// The keys are two periods old - shift by two periods
|
||||||
|
IncomingKeys inPrev = k.getNextIncomingKeys();
|
||||||
|
IncomingKeys inCurr = deriveStaticIncomingKeys(t, rootKey, alice,
|
||||||
|
timePeriod);
|
||||||
|
IncomingKeys inNext = deriveStaticIncomingKeys(t, rootKey, alice,
|
||||||
|
timePeriod + 1);
|
||||||
|
OutgoingKeys outCurr = deriveStaticOutgoingKeys(t, rootKey, alice,
|
||||||
|
timePeriod);
|
||||||
|
return new StaticTransportKeys(t, inPrev, inCurr, inNext, outCurr,
|
||||||
|
rootKey, alice);
|
||||||
|
} else {
|
||||||
|
// The keys are more than two periods old - derive fresh keys
|
||||||
|
return deriveStaticTransportKeys(t, rootKey, alice, timePeriod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion,
|
public void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion,
|
||||||
long streamNumber) {
|
long streamNumber) {
|
||||||
@@ -124,14 +218,14 @@ class TransportCryptoImpl implements TransportCrypto {
|
|||||||
// The input is the protocol version as a 16-bit integer, followed by
|
// The input is the protocol version as a 16-bit integer, followed by
|
||||||
// the stream number as a 64-bit integer
|
// the stream number as a 64-bit integer
|
||||||
byte[] protocolVersionBytes = new byte[INT_16_BYTES];
|
byte[] protocolVersionBytes = new byte[INT_16_BYTES];
|
||||||
ByteUtils.writeUint16(protocolVersion, protocolVersionBytes, 0);
|
writeUint16(protocolVersion, protocolVersionBytes, 0);
|
||||||
prf.update(protocolVersionBytes, 0, protocolVersionBytes.length);
|
prf.update(protocolVersionBytes, 0, protocolVersionBytes.length);
|
||||||
byte[] streamNumberBytes = new byte[INT_64_BYTES];
|
byte[] streamNumberBytes = new byte[INT_64_BYTES];
|
||||||
ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0);
|
writeUint64(streamNumber, streamNumberBytes, 0);
|
||||||
prf.update(streamNumberBytes, 0, streamNumberBytes.length);
|
prf.update(streamNumberBytes, 0, streamNumberBytes.length);
|
||||||
byte[] mac = new byte[macLength];
|
byte[] mac = new byte[macLength];
|
||||||
prf.doFinal(mac, 0);
|
prf.doFinal(mac, 0);
|
||||||
// The output is the first TAG_LENGTH bytes of the MAC
|
// The output is the first TAG_LENGTH bytes of the MAC
|
||||||
System.arraycopy(mac, 0, tag, 0, TAG_LENGTH);
|
arraycopy(mac, 0, tag, 0, TAG_LENGTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
|||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class KeyDerivationTest extends BrambleTestCase {
|
public class KeyDerivationTest extends BrambleTestCase {
|
||||||
@@ -137,7 +138,7 @@ public class KeyDerivationTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testTransportIdAffectsOutput() {
|
public void testTransportIdAffectsOutput() {
|
||||||
TransportId transportId1 = getTransportId();
|
TransportId transportId1 = getTransportId();
|
||||||
assertFalse(transportId.getString().equals(transportId1.getString()));
|
assertNotEquals(transportId.getString(), transportId1.getString());
|
||||||
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
||||||
master, 123, true, true);
|
master, 123, true, true);
|
||||||
TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId1,
|
TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId1,
|
||||||
|
|||||||
Reference in New Issue
Block a user