Require a label for hashing

* Add a string label argument to CryptoComponent#hash()
* Convert DoubleDigest from implementing MessageDigest
  to implementing org.spongycastle.crypto.Digest
  (we need to keep DoubleDigest for FortunaGenerator)
* Convert all other uses of MessageDigest to CryptoComponent#hash()
* Remove CryptoComponent#getMessageDigest(), MessageDigest and DigestWrapper
This commit is contained in:
Torsten Grote
2016-12-02 18:44:24 -02:00
parent 9c22ea8434
commit 062ed4ef4b
11 changed files with 59 additions and 162 deletions

View File

@@ -10,8 +10,6 @@ public interface CryptoComponent {
SecretKey generateSecretKey(); SecretKey generateSecretKey();
MessageDigest getMessageDigest();
PseudoRandom getPseudoRandom(int seed1, int seed2); PseudoRandom getPseudoRandom(int seed1, int seed2);
SecureRandom getSecureRandom(); SecureRandom getSecureRandom();
@@ -164,8 +162,17 @@ public interface CryptoComponent {
/** /**
* Returns the hash of the given inputs. The inputs are unambiguously * Returns the hash of the given inputs. The inputs are unambiguously
* combined by prefixing each input with its length. * 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(byte[]... inputs); byte[] hash(String label, byte[]... inputs);
/**
* Returns the length of hashes produced by
* the {@link CryptoComponent#hash(String, byte[]...)} method.
*/
int getHashLength();
/** /**
* Returns a message authentication code with the given key over the * Returns a message authentication code with the given key over the

View File

@@ -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);
}

View File

@@ -3,8 +3,6 @@ package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.nio.charset.Charset;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
/** /**
@@ -18,8 +16,7 @@ public class AuthorId extends UniqueId {
/** /**
* Label for hashing authors to calculate their identities. * Label for hashing authors to calculate their identities.
*/ */
public static final byte[] LABEL = public static final String LABEL = "org.briarproject.bramble.AUTHOR_ID";
"AUTHOR_ID".getBytes(Charset.forName("US-ASCII"));
public AuthorId(byte[] id) { public AuthorId(byte[] id) {
super(id); super(id);

View File

@@ -3,8 +3,6 @@ package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.nio.charset.Charset;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
/** /**
@@ -17,8 +15,7 @@ public class GroupId extends UniqueId {
/** /**
* Label for hashing groups to calculate their identifiers. * Label for hashing groups to calculate their identifiers.
*/ */
public static final byte[] LABEL = public static final String LABEL = "org.briarproject.bramble.GROUP_ID";
"GROUP_ID".getBytes(Charset.forName("US-ASCII"));
public GroupId(byte[] id) { public GroupId(byte[] id) {
super(id); super(id);

View File

@@ -3,8 +3,6 @@ package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.nio.charset.Charset;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
/** /**
@@ -18,8 +16,7 @@ public class MessageId extends UniqueId {
/** /**
* Label for hashing messages to calculate their identifiers. * Label for hashing messages to calculate their identifiers.
*/ */
public static final byte[] LABEL = public static final String LABEL = "org.briarproject.bramble.MESSAGE_ID";
"MESSAGE_ID".getBytes(Charset.forName("US-ASCII"));
public MessageId(byte[] id) { public MessageId(byte[] id) {
super(id); super(id);

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyPair; import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.KeyParser; 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.PrivateKey;
import org.briarproject.bramble.api.crypto.PseudoRandom; import org.briarproject.bramble.api.crypto.PseudoRandom;
import org.briarproject.bramble.api.crypto.PublicKey; 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_SALT_BYTES = 32; // 256 bits
private static final int PBKDF_TARGET_MILLIS = 500; private static final int PBKDF_TARGET_MILLIS = 500;
private static final int PBKDF_SAMPLES = 30; private static final int PBKDF_SAMPLES = 30;
private static final int HASH_SIZE = 256 / 8;
private static byte[] ascii(String s) { private static byte[] ascii(String s) {
return s.getBytes(Charset.forName("US-ASCII")); 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[] A_SIG_NONCE = ascii("ALICE_SIGNATURE_NONCE");
private static final byte[] B_SIG_NONCE = ascii("BOB_SIGNATURE_NONCE"); private static final byte[] B_SIG_NONCE = ascii("BOB_SIGNATURE_NONCE");
// Hash label for BQP public key commitment derivation // 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 // 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 // KDF label for BQP confirmation key derivation
private static final byte[] CONFIRMATION_KEY = ascii("CONFIRMATION_KEY"); private static final byte[] CONFIRMATION_KEY = ascii("CONFIRMATION_KEY");
// KDF label for master key derivation // KDF label for master key derivation
@@ -129,11 +131,6 @@ class CryptoComponentImpl implements CryptoComponent {
return new SecretKey(b); return new SecretKey(b);
} }
@Override
public MessageDigest getMessageDigest() {
return new DigestWrapper(new Blake2sDigest());
}
@Override @Override
public PseudoRandom getPseudoRandom(int seed1, int seed2) { public PseudoRandom getPseudoRandom(int seed1, int seed2) {
return new PseudoRandomImpl(seed1, seed2); return new PseudoRandomImpl(seed1, seed2);
@@ -428,15 +425,26 @@ class CryptoComponentImpl implements CryptoComponent {
} }
@Override @Override
public byte[] hash(byte[]... inputs) { public byte[] hash(String label, byte[]... inputs) {
MessageDigest digest = getMessageDigest(); byte[] labelBytes = StringUtils.toUtf8(label);
Digest digest = new Blake2sDigest();
byte[] length = new byte[INT_32_BYTES]; 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) { for (byte[] input : inputs) {
ByteUtils.writeUint32(input.length, length, 0); ByteUtils.writeUint32(input.length, length, 0);
digest.update(length); digest.update(length, 0, length.length);
digest.update(input); 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 @Override

View File

@@ -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);
}
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.crypto; package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.crypto.MessageDigest;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.spongycastle.crypto.Digest; import org.spongycastle.crypto.Digest;
@@ -17,7 +16,7 @@ import javax.annotation.concurrent.NotThreadSafe;
*/ */
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
class DoubleDigest implements MessageDigest { class DoubleDigest implements Digest {
private final Digest delegate; private final Digest delegate;
@@ -25,8 +24,7 @@ class DoubleDigest implements MessageDigest {
this.delegate = delegate; this.delegate = delegate;
} }
@Override private byte[] digest() {
public byte[] digest() {
byte[] digest = new byte[delegate.getDigestSize()]; byte[] digest = new byte[delegate.getDigestSize()];
delegate.doFinal(digest, 0); // h(m) delegate.doFinal(digest, 0); // h(m)
delegate.update(digest, 0, digest.length); delegate.update(digest, 0, digest.length);
@@ -34,13 +32,6 @@ class DoubleDigest implements MessageDigest {
return digest; 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) { public int digest(byte[] buf, int offset, int len) {
byte[] digest = digest(); byte[] digest = digest();
len = Math.min(len, digest.length); len = Math.min(len, digest.length);
@@ -49,10 +40,15 @@ class DoubleDigest implements MessageDigest {
} }
@Override @Override
public int getDigestLength() { public int getDigestSize() {
return delegate.getDigestSize(); return delegate.getDigestSize();
} }
@Override
public String getAlgorithmName() {
return "Double " + delegate.getAlgorithmName();
}
@Override @Override
public void reset() { public void reset() {
delegate.reset(); delegate.reset();
@@ -63,7 +59,6 @@ class DoubleDigest implements MessageDigest {
delegate.update(input); delegate.update(input);
} }
@Override
public void update(byte[] input) { public void update(byte[] input) {
delegate.update(input, 0, input.length); delegate.update(input, 0, input.length);
} }
@@ -72,4 +67,10 @@ class DoubleDigest implements MessageDigest {
public void update(byte[] input, int offset, int len) { public void update(byte[] input, int offset, int len) {
delegate.update(input, offset, len); delegate.update(input, offset, len);
} }
@Override
public int doFinal(byte[] out, int outOff) {
return digest(out, outOff, delegate.getDigestSize());
}
} }

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.crypto; package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.crypto.MessageDigest;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.spongycastle.crypto.BlockCipher; import org.spongycastle.crypto.BlockCipher;
import org.spongycastle.crypto.digests.SHA256Digest; import org.spongycastle.crypto.digests.SHA256Digest;
@@ -27,7 +26,7 @@ class FortunaGenerator {
private final Lock lock = new ReentrantLock(); private final Lock lock = new ReentrantLock();
// The following are locking: lock // 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 BlockCipher cipher = new AESLightEngine();
private final byte[] key = new byte[KEY_BYTES]; private final byte[] key = new byte[KEY_BYTES];
private final byte[] counter = new byte[BLOCK_BYTES]; private final byte[] counter = new byte[BLOCK_BYTES];

View File

@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.contact.ContactExchangeTask;
import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyPair; import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.KeyParser; 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.PseudoRandom;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.data.BdfReader; import org.briarproject.bramble.api.data.BdfReader;
@@ -35,6 +34,8 @@ abstract class Connector extends Thread {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(Connector.class.getName()); Logger.getLogger(Connector.class.getName());
private static final String LABEL_PUBLIC_KEY =
"org.briarproject.bramble.invitation.PUBLIC_KEY";
protected final CryptoComponent crypto; protected final CryptoComponent crypto;
protected final BdfReaderFactory bdfReaderFactory; protected final BdfReaderFactory bdfReaderFactory;
@@ -48,7 +49,6 @@ abstract class Connector extends Thread {
private final KeyPair keyPair; private final KeyPair keyPair;
private final KeyParser keyParser; private final KeyParser keyParser;
private final MessageDigest messageDigest;
Connector(CryptoComponent crypto, BdfReaderFactory bdfReaderFactory, Connector(CryptoComponent crypto, BdfReaderFactory bdfReaderFactory,
BdfWriterFactory bdfWriterFactory, BdfWriterFactory bdfWriterFactory,
@@ -66,7 +66,6 @@ abstract class Connector extends Thread {
pluginName = plugin.getClass().getName(); pluginName = plugin.getClass().getName();
keyPair = crypto.generateAgreementKeyPair(); keyPair = crypto.generateAgreementKeyPair();
keyParser = crypto.getAgreementKeyParser(); keyParser = crypto.getAgreementKeyParser();
messageDigest = crypto.getMessageDigest();
} }
@Nullable @Nullable
@@ -78,13 +77,15 @@ abstract class Connector extends Thread {
} }
void sendPublicKeyHash(BdfWriter w) throws IOException { 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(); w.flush();
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " sent hash"); if (LOG.isLoggable(INFO)) LOG.info(pluginName + " sent hash");
} }
byte[] receivePublicKeyHash(BdfReader r) throws IOException { byte[] receivePublicKeyHash(BdfReader r) throws IOException {
int hashLength = messageDigest.getDigestLength(); int hashLength = crypto.getHashLength();
byte[] b = r.readRaw(hashLength); byte[] b = r.readRaw(hashLength);
if (b.length < hashLength) throw new FormatException(); if (b.length < hashLength) throw new FormatException();
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " received hash"); 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) SecretKey deriveMasterSecret(byte[] hash, byte[] key, boolean alice)
throws GeneralSecurityException { throws GeneralSecurityException {
// Check that the hash matches the key // 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)) if (LOG.isLoggable(INFO))
LOG.info(pluginName + " hash does not match key"); LOG.info(pluginName + " hash does not match key");
throw new GeneralSecurityException(); throw new GeneralSecurityException();

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.crypto; package org.briarproject.bramble.crypto;
import org.briarproject.BriarTestCase; import org.briarproject.BriarTestCase;
import org.briarproject.bramble.api.crypto.MessageDigest;
import org.junit.Test; import org.junit.Test;
import org.spongycastle.crypto.BlockCipher; import org.spongycastle.crypto.BlockCipher;
import org.spongycastle.crypto.digests.SHA256Digest; 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[] counter = new byte[16], output = new byte[16];
byte[] newKey = new byte[32]; byte[] newKey = new byte[32];
// Calculate the initial key // Calculate the initial key
MessageDigest digest = new DoubleDigest(new SHA256Digest()); DoubleDigest digest = new DoubleDigest(new SHA256Digest());
digest.update(key); digest.update(key);
digest.update(seed); digest.update(seed);
digest.digest(key, 0, 32); digest.digest(key, 0, 32);