diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java index a1573ec7a9b88053f2366acb79f222c044c252c4..c6cd78c4cb8f36b0fc834cd6634b26d768351da3 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java @@ -10,8 +10,6 @@ public interface CryptoComponent { SecretKey generateSecretKey(); - MessageDigest getMessageDigest(); - PseudoRandom getPseudoRandom(int seed1, int seed2); SecureRandom getSecureRandom(); @@ -164,8 +162,17 @@ public interface CryptoComponent { /** * Returns the hash of the given inputs. The inputs are unambiguously * combined by prefixing each input with its length. + * + * @param label A label specific to this hash to ensure that hashes + * calculated for distinct purposes don't collide. + */ + byte[] hash(String label, byte[]... inputs); + + /** + * Returns the length of hashes produced by + * the {@link CryptoComponent#hash(String, byte[]...)} method. */ - byte[] hash(byte[]... inputs); + int getHashLength(); /** * Returns a message authentication code with the given key over the diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/MessageDigest.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/MessageDigest.java deleted file mode 100644 index f55e169d0ecc1ba86decdb87b46abc3a894479bd..0000000000000000000000000000000000000000 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/MessageDigest.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.briarproject.bramble.api.crypto; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; - -@NotNullByDefault -public interface MessageDigest { - - /** - * @see {@link java.security.MessageDigest#digest()} - */ - byte[] digest(); - - /** - * @see {@link java.security.MessageDigest#digest(byte[])} - */ - byte[] digest(byte[] input); - - /** - * @see {@link java.security.MessageDigest#digest(byte[], int, int)} - */ - int digest(byte[] buf, int offset, int len); - - /** - * @see {@link java.security.MessageDigest#getDigestLength()} - */ - int getDigestLength(); - - /** - * @see {@link java.security.MessageDigest#reset()} - */ - void reset(); - - /** - * @see {@link java.security.MessageDigest#update(byte)} - */ - void update(byte input); - - /** - * @see {@link java.security.MessageDigest#update(byte[])} - */ - void update(byte[] input); - - /** - * @see {@link java.security.MessageDigest#update(byte[], int, int)} - */ - void update(byte[] input, int offset, int len); -} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/identity/AuthorId.java b/bramble-api/src/main/java/org/briarproject/bramble/api/identity/AuthorId.java index c035a0ce089be9d014f70459125504c23750132e..0963e0049e20ca3fb3ac8dc14950e86c0dae3898 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/identity/AuthorId.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/identity/AuthorId.java @@ -3,8 +3,6 @@ package org.briarproject.bramble.api.identity; import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import java.nio.charset.Charset; - import javax.annotation.concurrent.ThreadSafe; /** @@ -18,8 +16,7 @@ public class AuthorId extends UniqueId { /** * Label for hashing authors to calculate their identities. */ - public static final byte[] LABEL = - "AUTHOR_ID".getBytes(Charset.forName("US-ASCII")); + public static final String LABEL = "org.briarproject.bramble.AUTHOR_ID"; public AuthorId(byte[] id) { super(id); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/GroupId.java b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/GroupId.java index bea1186f13768373d04af940dc445e4f79441160..cdd6b2d3fba5dd4ad95968e6e3360b1be120a695 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/GroupId.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/GroupId.java @@ -3,8 +3,6 @@ package org.briarproject.bramble.api.sync; import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import java.nio.charset.Charset; - import javax.annotation.concurrent.ThreadSafe; /** @@ -17,8 +15,7 @@ public class GroupId extends UniqueId { /** * Label for hashing groups to calculate their identifiers. */ - public static final byte[] LABEL = - "GROUP_ID".getBytes(Charset.forName("US-ASCII")); + public static final String LABEL = "org.briarproject.bramble.GROUP_ID"; public GroupId(byte[] id) { super(id); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/MessageId.java b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/MessageId.java index 3a1075dd9c77c1262fdf7a95c858d8d6a2095355..84389bbcc83371980d7e71a62ca5137079e011d3 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/MessageId.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/MessageId.java @@ -3,8 +3,6 @@ package org.briarproject.bramble.api.sync; import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import java.nio.charset.Charset; - import javax.annotation.concurrent.ThreadSafe; /** @@ -18,8 +16,7 @@ public class MessageId extends UniqueId { /** * Label for hashing messages to calculate their identifiers. */ - public static final byte[] LABEL = - "MESSAGE_ID".getBytes(Charset.forName("US-ASCII")); + public static final String LABEL = "org.briarproject.bramble.MESSAGE_ID"; public MessageId(byte[] id) { super(id); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java index 879ee259541f51fd42e45be70150527b718711fe..ae25da4e189bdeb559267f07fbdac4dbbbe90140 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java @@ -3,7 +3,6 @@ package org.briarproject.bramble.crypto; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.KeyPair; import org.briarproject.bramble.api.crypto.KeyParser; -import org.briarproject.bramble.api.crypto.MessageDigest; import org.briarproject.bramble.api.crypto.PrivateKey; import org.briarproject.bramble.api.crypto.PseudoRandom; import org.briarproject.bramble.api.crypto.PublicKey; @@ -58,6 +57,7 @@ class CryptoComponentImpl implements CryptoComponent { private static final int PBKDF_SALT_BYTES = 32; // 256 bits private static final int PBKDF_TARGET_MILLIS = 500; private static final int PBKDF_SAMPLES = 30; + private static final int HASH_SIZE = 256 / 8; private static byte[] ascii(String s) { return s.getBytes(Charset.forName("US-ASCII")); @@ -73,9 +73,11 @@ class CryptoComponentImpl implements CryptoComponent { private static final byte[] A_SIG_NONCE = ascii("ALICE_SIGNATURE_NONCE"); private static final byte[] B_SIG_NONCE = ascii("BOB_SIGNATURE_NONCE"); // Hash label for BQP public key commitment derivation - private static final byte[] COMMIT = ascii("COMMIT"); + private static final String COMMIT = + "org.briarproject.bramble.COMMIT"; // Hash label for shared secret derivation - private static final byte[] SHARED_SECRET = ascii("SHARED_SECRET"); + private static final String SHARED_SECRET = + "org.briarproject.bramble.SHARED_SECRET"; // KDF label for BQP confirmation key derivation private static final byte[] CONFIRMATION_KEY = ascii("CONFIRMATION_KEY"); // KDF label for master key derivation @@ -129,11 +131,6 @@ class CryptoComponentImpl implements CryptoComponent { return new SecretKey(b); } - @Override - public MessageDigest getMessageDigest() { - return new DigestWrapper(new Blake2sDigest()); - } - @Override public PseudoRandom getPseudoRandom(int seed1, int seed2) { return new PseudoRandomImpl(seed1, seed2); @@ -428,15 +425,26 @@ class CryptoComponentImpl implements CryptoComponent { } @Override - public byte[] hash(byte[]... inputs) { - MessageDigest digest = getMessageDigest(); + public byte[] hash(String label, byte[]... inputs) { + byte[] labelBytes = StringUtils.toUtf8(label); + Digest digest = new Blake2sDigest(); byte[] length = new byte[INT_32_BYTES]; + ByteUtils.writeUint32(labelBytes.length, length, 0); + digest.update(length, 0, length.length); + digest.update(labelBytes, 0, labelBytes.length); for (byte[] input : inputs) { ByteUtils.writeUint32(input.length, length, 0); - digest.update(length); - digest.update(input); + digest.update(length, 0, length.length); + digest.update(input, 0, input.length); } - return digest.digest(); + byte[] output = new byte[digest.getDigestSize()]; + digest.doFinal(output, 0); + return output; + } + + @Override + public int getHashLength() { + return HASH_SIZE; } @Override diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/DigestWrapper.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/DigestWrapper.java deleted file mode 100644 index 077a4012ad273a280992454899137bce15382af3..0000000000000000000000000000000000000000 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/DigestWrapper.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.briarproject.bramble.crypto; - -import org.briarproject.bramble.api.crypto.MessageDigest; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.spongycastle.crypto.Digest; - -import javax.annotation.concurrent.NotThreadSafe; - -@NotThreadSafe -@NotNullByDefault -class DigestWrapper implements MessageDigest { - - private final Digest digest; - - DigestWrapper(Digest digest) { - this.digest = digest; - } - - @Override - public byte[] digest() { - byte[] hash = new byte[digest.getDigestSize()]; - digest.doFinal(hash, 0); - return hash; - } - - @Override - public byte[] digest(byte[] input) { - update(input); - return digest(); - } - - @Override - public int digest(byte[] buf, int offset, int len) { - byte[] hash = digest(); - len = Math.min(len, hash.length); - System.arraycopy(hash, 0, buf, offset, len); - return len; - } - - @Override - public int getDigestLength() { - return digest.getDigestSize(); - } - - @Override - public void reset() { - digest.reset(); - } - - @Override - public void update(byte input) { - digest.update(input); - } - - @Override - public void update(byte[] input) { - digest.update(input, 0, input.length); - } - - @Override - public void update(byte[] input, int offset, int len) { - digest.update(input, offset, len); - } -} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/DoubleDigest.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/DoubleDigest.java index 3740472043e5b0f898136635187241f7786b184a..2bd71fa78a16fa9d5e60ef829a25d5d8ce657742 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/DoubleDigest.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/DoubleDigest.java @@ -1,6 +1,5 @@ package org.briarproject.bramble.crypto; -import org.briarproject.bramble.api.crypto.MessageDigest; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.spongycastle.crypto.Digest; @@ -17,7 +16,7 @@ import javax.annotation.concurrent.NotThreadSafe; */ @NotThreadSafe @NotNullByDefault -class DoubleDigest implements MessageDigest { +class DoubleDigest implements Digest { private final Digest delegate; @@ -25,8 +24,7 @@ class DoubleDigest implements MessageDigest { this.delegate = delegate; } - @Override - public byte[] digest() { + private byte[] digest() { byte[] digest = new byte[delegate.getDigestSize()]; delegate.doFinal(digest, 0); // h(m) delegate.update(digest, 0, digest.length); @@ -34,13 +32,6 @@ class DoubleDigest implements MessageDigest { return digest; } - @Override - public byte[] digest(byte[] input) { - delegate.update(input, 0, input.length); - return digest(); - } - - @Override public int digest(byte[] buf, int offset, int len) { byte[] digest = digest(); len = Math.min(len, digest.length); @@ -49,10 +40,15 @@ class DoubleDigest implements MessageDigest { } @Override - public int getDigestLength() { + public int getDigestSize() { return delegate.getDigestSize(); } + @Override + public String getAlgorithmName() { + return "Double " + delegate.getAlgorithmName(); + } + @Override public void reset() { delegate.reset(); @@ -63,7 +59,6 @@ class DoubleDigest implements MessageDigest { delegate.update(input); } - @Override public void update(byte[] input) { delegate.update(input, 0, input.length); } @@ -72,4 +67,10 @@ class DoubleDigest implements MessageDigest { public void update(byte[] input, int offset, int len) { delegate.update(input, offset, len); } + + @Override + public int doFinal(byte[] out, int outOff) { + return digest(out, outOff, delegate.getDigestSize()); + } + } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/FortunaGenerator.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/FortunaGenerator.java index 2c4ef3ef68584aece066a0d245e795523cf7357b..5c36a931fdc20ee390442b74c7eba46bd36664a9 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/FortunaGenerator.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/FortunaGenerator.java @@ -1,6 +1,5 @@ package org.briarproject.bramble.crypto; -import org.briarproject.bramble.api.crypto.MessageDigest; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.spongycastle.crypto.BlockCipher; import org.spongycastle.crypto.digests.SHA256Digest; @@ -27,7 +26,7 @@ class FortunaGenerator { private final Lock lock = new ReentrantLock(); // The following are locking: lock - private final MessageDigest digest = new DoubleDigest(new SHA256Digest()); + private final DoubleDigest digest = new DoubleDigest(new SHA256Digest()); private final BlockCipher cipher = new AESLightEngine(); private final byte[] key = new byte[KEY_BYTES]; private final byte[] counter = new byte[BLOCK_BYTES]; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/invitation/Connector.java b/bramble-core/src/main/java/org/briarproject/bramble/invitation/Connector.java index 0fb91aa8a4be140a266cf2bf4fab6b7fc5848525..4c1a63c6732e7996ab2e19466d6d7a9a4b023741 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/invitation/Connector.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/invitation/Connector.java @@ -5,7 +5,6 @@ import org.briarproject.bramble.api.contact.ContactExchangeTask; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.KeyPair; import org.briarproject.bramble.api.crypto.KeyParser; -import org.briarproject.bramble.api.crypto.MessageDigest; import org.briarproject.bramble.api.crypto.PseudoRandom; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.data.BdfReader; @@ -35,6 +34,8 @@ abstract class Connector extends Thread { private static final Logger LOG = Logger.getLogger(Connector.class.getName()); + private static final String LABEL_PUBLIC_KEY = + "org.briarproject.bramble.invitation.PUBLIC_KEY"; protected final CryptoComponent crypto; protected final BdfReaderFactory bdfReaderFactory; @@ -48,7 +49,6 @@ abstract class Connector extends Thread { private final KeyPair keyPair; private final KeyParser keyParser; - private final MessageDigest messageDigest; Connector(CryptoComponent crypto, BdfReaderFactory bdfReaderFactory, BdfWriterFactory bdfWriterFactory, @@ -66,7 +66,6 @@ abstract class Connector extends Thread { pluginName = plugin.getClass().getName(); keyPair = crypto.generateAgreementKeyPair(); keyParser = crypto.getAgreementKeyParser(); - messageDigest = crypto.getMessageDigest(); } @Nullable @@ -78,13 +77,15 @@ abstract class Connector extends Thread { } void sendPublicKeyHash(BdfWriter w) throws IOException { - w.writeRaw(messageDigest.digest(keyPair.getPublic().getEncoded())); + byte[] hash = + crypto.hash(LABEL_PUBLIC_KEY, keyPair.getPublic().getEncoded()); + w.writeRaw(hash); w.flush(); if (LOG.isLoggable(INFO)) LOG.info(pluginName + " sent hash"); } byte[] receivePublicKeyHash(BdfReader r) throws IOException { - int hashLength = messageDigest.getDigestLength(); + int hashLength = crypto.getHashLength(); byte[] b = r.readRaw(hashLength); if (b.length < hashLength) throw new FormatException(); if (LOG.isLoggable(INFO)) LOG.info(pluginName + " received hash"); @@ -109,7 +110,9 @@ abstract class Connector extends Thread { SecretKey deriveMasterSecret(byte[] hash, byte[] key, boolean alice) throws GeneralSecurityException { // Check that the hash matches the key - if (!Arrays.equals(hash, messageDigest.digest(key))) { + byte[] keyHash = + crypto.hash(LABEL_PUBLIC_KEY, keyPair.getPublic().getEncoded()); + if (!Arrays.equals(hash, keyHash)) { if (LOG.isLoggable(INFO)) LOG.info(pluginName + " hash does not match key"); throw new GeneralSecurityException(); diff --git a/briar-tests/src/org/briarproject/bramble/crypto/FortunaSecureRandomTest.java b/briar-tests/src/org/briarproject/bramble/crypto/FortunaSecureRandomTest.java index 86e302ec0c9958d5e94d3f6a7f69f74fd65e7508..6e789aa7fedb2c79b5eb0156a1956ea527a67536 100644 --- a/briar-tests/src/org/briarproject/bramble/crypto/FortunaSecureRandomTest.java +++ b/briar-tests/src/org/briarproject/bramble/crypto/FortunaSecureRandomTest.java @@ -1,7 +1,6 @@ package org.briarproject.bramble.crypto; import org.briarproject.BriarTestCase; -import org.briarproject.bramble.api.crypto.MessageDigest; import org.junit.Test; import org.spongycastle.crypto.BlockCipher; import org.spongycastle.crypto.digests.SHA256Digest; @@ -27,7 +26,7 @@ public class FortunaSecureRandomTest extends BriarTestCase { byte[] counter = new byte[16], output = new byte[16]; byte[] newKey = new byte[32]; // Calculate the initial key - MessageDigest digest = new DoubleDigest(new SHA256Digest()); + DoubleDigest digest = new DoubleDigest(new SHA256Digest()); digest.update(key); digest.update(seed); digest.digest(key, 0, 32);