From 7fbad8dc26cfe27535ba2d7d5ac0360abd374ff6 Mon Sep 17 00:00:00 2001
From: akwizgran <akwizgran@users.sourceforge.net>
Date: Wed, 14 Jan 2015 20:46:03 +0000
Subject: [PATCH] Use FortunaGenerator to implement PseudoRandom.

---
 .../briarproject/android/AndroidModule.java   |  7 +-
 .../android/PasswordActivity.java             |  3 +-
 .../briarproject/android/SetupActivity.java   |  7 +-
 .../briarproject/api/crypto/SecretKey.java    |  3 +
 .../briarproject/api/db/DatabaseConfig.java   |  6 +-
 .../crypto/CryptoComponentImpl.java           | 82 +++++++------------
 .../briarproject/crypto/PseudoRandomImpl.java | 38 +++------
 .../src/org/briarproject/db/H2Database.java   |  2 +-
 .../org/briarproject/TestDatabaseConfig.java  |  7 +-
 9 files changed, 63 insertions(+), 92 deletions(-)

diff --git a/briar-android/src/org/briarproject/android/AndroidModule.java b/briar-android/src/org/briarproject/android/AndroidModule.java
index d3b2029e70..1adf330941 100644
--- a/briar-android/src/org/briarproject/android/AndroidModule.java
+++ b/briar-android/src/org/briarproject/android/AndroidModule.java
@@ -9,6 +9,7 @@ import javax.inject.Singleton;
 import org.briarproject.api.android.AndroidExecutor;
 import org.briarproject.api.android.AndroidNotificationManager;
 import org.briarproject.api.android.ReferenceManager;
+import org.briarproject.api.crypto.SecretKey;
 import org.briarproject.api.db.DatabaseConfig;
 import org.briarproject.api.lifecycle.LifecycleManager;
 import org.briarproject.api.ui.UiCallback;
@@ -54,7 +55,7 @@ public class AndroidModule extends AbstractModule {
 		final File dir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
 		return new DatabaseConfig() {
 
-			private volatile byte[] key = null;
+			private volatile SecretKey key = null;
 
 			public boolean databaseExists() {
 				return dir.isDirectory() && dir.listFiles().length > 0;
@@ -64,11 +65,11 @@ public class AndroidModule extends AbstractModule {
 				return dir;
 			}
 
-			public void setEncryptionKey(byte[] key) {
+			public void setEncryptionKey(SecretKey key) {
 				this.key = key;
 			}
 
-			public byte[] getEncryptionKey() {
+			public SecretKey getEncryptionKey() {
 				return key;
 			}
 
diff --git a/briar-android/src/org/briarproject/android/PasswordActivity.java b/briar-android/src/org/briarproject/android/PasswordActivity.java
index 727985f1b1..ce3672019c 100644
--- a/briar-android/src/org/briarproject/android/PasswordActivity.java
+++ b/briar-android/src/org/briarproject/android/PasswordActivity.java
@@ -23,6 +23,7 @@ import org.briarproject.android.util.FixedVerticalSpace;
 import org.briarproject.android.util.LayoutUtils;
 import org.briarproject.api.crypto.CryptoComponent;
 import org.briarproject.api.crypto.CryptoExecutor;
+import org.briarproject.api.crypto.SecretKey;
 import org.briarproject.api.db.DatabaseConfig;
 import org.briarproject.util.StringUtils;
 
@@ -140,7 +141,7 @@ public class PasswordActivity extends RoboActivity {
 				if(key == null) {
 					tryAgain();
 				} else {
-					databaseConfig.setEncryptionKey(key);
+					databaseConfig.setEncryptionKey(new SecretKey(key));
 					setResultAndFinish();
 				}
 			}
diff --git a/briar-android/src/org/briarproject/android/SetupActivity.java b/briar-android/src/org/briarproject/android/SetupActivity.java
index 109ce0cee8..d6e6d7a5bd 100644
--- a/briar-android/src/org/briarproject/android/SetupActivity.java
+++ b/briar-android/src/org/briarproject/android/SetupActivity.java
@@ -34,6 +34,7 @@ import org.briarproject.api.crypto.CryptoComponent;
 import org.briarproject.api.crypto.CryptoExecutor;
 import org.briarproject.api.crypto.KeyPair;
 import org.briarproject.api.crypto.PasswordStrengthEstimator;
+import org.briarproject.api.crypto.SecretKey;
 import org.briarproject.api.db.DatabaseConfig;
 import org.briarproject.util.StringUtils;
 
@@ -225,7 +226,7 @@ OnEditorActionListener {
 		// Store the DB key and create the identity in a background thread
 		cryptoExecutor.execute(new Runnable() {
 			public void run() {
-				byte[] key = crypto.generateSecretKey().getBytes();
+				SecretKey key = crypto.generateSecretKey();
 				databaseConfig.setEncryptionKey(key);
 				byte[] encrypted = encryptDatabaseKey(key, password);
 				storeEncryptedDatabaseKey(encrypted);
@@ -247,9 +248,9 @@ OnEditorActionListener {
 			LOG.info("Key storage took " + duration + " ms");
 	}
 
-	private byte[] encryptDatabaseKey(byte[] key, String password) {
+	private byte[] encryptDatabaseKey(SecretKey key, String password) {
 		long now = System.currentTimeMillis();
-		byte[] encrypted = crypto.encryptWithPassword(key, password);
+		byte[] encrypted = crypto.encryptWithPassword(key.getBytes(), password);
 		long duration = System.currentTimeMillis() - now;
 		if(LOG.isLoggable(INFO))
 			LOG.info("Key derivation took " + duration + " ms");
diff --git a/briar-api/src/org/briarproject/api/crypto/SecretKey.java b/briar-api/src/org/briarproject/api/crypto/SecretKey.java
index 62b75a9452..f863bbebee 100644
--- a/briar-api/src/org/briarproject/api/crypto/SecretKey.java
+++ b/briar-api/src/org/briarproject/api/crypto/SecretKey.java
@@ -3,9 +3,12 @@ package org.briarproject.api.crypto;
 /** A secret key used for encryption and/or authentication. */
 public class SecretKey {
 
+	public static final int LENGTH = 32; // Bytes
+
 	private final byte[] key;
 
 	public SecretKey(byte[] key) {
+		if(key.length != LENGTH) throw new IllegalArgumentException();
 		this.key = key;
 	}
 
diff --git a/briar-api/src/org/briarproject/api/db/DatabaseConfig.java b/briar-api/src/org/briarproject/api/db/DatabaseConfig.java
index e452fe15c5..862afe1c8d 100644
--- a/briar-api/src/org/briarproject/api/db/DatabaseConfig.java
+++ b/briar-api/src/org/briarproject/api/db/DatabaseConfig.java
@@ -2,15 +2,17 @@ package org.briarproject.api.db;
 
 import java.io.File;
 
+import org.briarproject.api.crypto.SecretKey;
+
 public interface DatabaseConfig {
 
 	boolean databaseExists();
 
 	File getDatabaseDirectory();
 
-	void setEncryptionKey(byte[] key);
+	void setEncryptionKey(SecretKey key);
 
-	byte[] getEncryptionKey();
+	SecretKey getEncryptionKey();
 
 	long getMaxSize();
 }
diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java
index be63cd6178..989a9b28a6 100644
--- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java
+++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java
@@ -9,7 +9,6 @@ import static org.briarproject.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 import java.security.GeneralSecurityException;
 import java.security.SecureRandom;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.logging.Logger;
@@ -49,7 +48,6 @@ class CryptoComponentImpl implements CryptoComponent {
 	private static final Logger LOG =
 			Logger.getLogger(CryptoComponentImpl.class.getName());
 
-	private static final int CIPHER_KEY_BYTES = 32; // 256 bits
 	private static final int AGREEMENT_KEY_PAIR_BITS = 256;
 	private static final int SIGNATURE_KEY_PAIR_BITS = 256;
 	private static final int STORAGE_IV_BYTES = 16; // 128 bits
@@ -73,8 +71,6 @@ class CryptoComponentImpl implements CryptoComponent {
 		{ 'A', '_', 'F', 'R', 'A', 'M', 'E', '\0' };
 	private static final byte[] B_FRAME =
 		{ 'B', '_', 'F', 'R', 'A', 'M', 'E', '\0' };
-	// Blank secret for argument validation
-	private static final byte[] BLANK_SECRET = new byte[CIPHER_KEY_BYTES];
 
 	private final SecureRandom secureRandom;
 	private final ECKeyPairGenerator agreementKeyPairGenerator;
@@ -105,7 +101,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	public SecretKey generateSecretKey() {
-		byte[] b = new byte[CIPHER_KEY_BYTES];
+		byte[] b = new byte[SecretKey.LENGTH];
 		secureRandom.nextBytes(b);
 		return new SecretKey(b);
 	}
@@ -115,7 +111,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	public PseudoRandom getPseudoRandom(int seed1, int seed2) {
-		return new PseudoRandomImpl(getMessageDigest(), seed1, seed2);
+		return new PseudoRandomImpl(seed1, seed2);
 	}
 
 	public SecureRandom getSecureRandom() {
@@ -172,9 +168,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	public int[] deriveConfirmationCodes(byte[] secret) {
-		if(secret.length != CIPHER_KEY_BYTES)
-			throw new IllegalArgumentException();
-		if(Arrays.equals(secret, BLANK_SECRET))
+		if(secret.length != SecretKey.LENGTH)
 			throw new IllegalArgumentException();
 		byte[] alice = counterModeKdf(secret, CODE, 0);
 		byte[] bob = counterModeKdf(secret, CODE, 1);
@@ -185,9 +179,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	public byte[][] deriveInvitationNonces(byte[] secret) {
-		if(secret.length != CIPHER_KEY_BYTES)
-			throw new IllegalArgumentException();
-		if(Arrays.equals(secret, BLANK_SECRET))
+		if(secret.length != SecretKey.LENGTH)
 			throw new IllegalArgumentException();
 		byte[] alice = counterModeKdf(secret, NONCE, 0);
 		byte[] bob = counterModeKdf(secret, NONCE, 1);
@@ -237,26 +229,20 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	public byte[] deriveGroupSalt(byte[] secret) {
-		if(secret.length != CIPHER_KEY_BYTES)
-			throw new IllegalArgumentException();
-		if(Arrays.equals(secret, BLANK_SECRET))
+		if(secret.length != SecretKey.LENGTH)
 			throw new IllegalArgumentException();
 		return counterModeKdf(secret, SALT, 0);
 	}
 
 	public byte[] deriveInitialSecret(byte[] secret, int transportIndex) {
-		if(secret.length != CIPHER_KEY_BYTES)
-			throw new IllegalArgumentException();
-		if(Arrays.equals(secret, BLANK_SECRET))
+		if(secret.length != SecretKey.LENGTH)
 			throw new IllegalArgumentException();
 		if(transportIndex < 0) throw new IllegalArgumentException();
 		return counterModeKdf(secret, FIRST, transportIndex);
 	}
 
 	public byte[] deriveNextSecret(byte[] secret, long period) {
-		if(secret.length != CIPHER_KEY_BYTES)
-			throw new IllegalArgumentException();
-		if(Arrays.equals(secret, BLANK_SECRET))
+		if(secret.length != SecretKey.LENGTH)
 			throw new IllegalArgumentException();
 		if(period < 0 || period > MAX_32_BIT_UNSIGNED)
 			throw new IllegalArgumentException();
@@ -264,9 +250,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	}
 
 	public SecretKey deriveTagKey(byte[] secret, boolean alice) {
-		if(secret.length != CIPHER_KEY_BYTES)
-			throw new IllegalArgumentException();
-		if(Arrays.equals(secret, BLANK_SECRET))
+		if(secret.length != SecretKey.LENGTH)
 			throw new IllegalArgumentException();
 		if(alice) return deriveKey(secret, A_TAG, 0);
 		else return deriveKey(secret, B_TAG, 0);
@@ -274,9 +258,7 @@ class CryptoComponentImpl implements CryptoComponent {
 
 	public SecretKey deriveFrameKey(byte[] secret, long streamNumber,
 			boolean alice) {
-		if(secret.length != CIPHER_KEY_BYTES)
-			throw new IllegalArgumentException();
-		if(Arrays.equals(secret, BLANK_SECRET))
+		if(secret.length != SecretKey.LENGTH)
 			throw new IllegalArgumentException();
 		if(streamNumber < 0 || streamNumber > MAX_32_BIT_UNSIGNED)
 			throw new IllegalArgumentException();
@@ -366,32 +348,30 @@ class CryptoComponentImpl implements CryptoComponent {
 
 	// Key derivation function based on a hash function - see NIST SP 800-56A,
 	// section 5.8
-	private byte[] concatenationKdf(byte[]... args) {
+	private byte[] concatenationKdf(byte[]... inputs) {
 		// The output of the hash function must be long enough to use as a key
 		MessageDigest messageDigest = getMessageDigest();
-		if(messageDigest.getDigestLength() < CIPHER_KEY_BYTES)
+		if(messageDigest.getDigestLength() < SecretKey.LENGTH)
 			throw new RuntimeException();
-		// Each argument is length-prefixed - the length must fit in an
+		// Each input is length-prefixed - the length must fit in an
 		// unsigned 8-bit integer
-		for(byte[] arg : args) {
-			if(arg.length > 255) throw new IllegalArgumentException();
-			messageDigest.update((byte) arg.length);
-			messageDigest.update(arg);
+		for(byte[] input : inputs) {
+			if(input.length > 255) throw new IllegalArgumentException();
+			messageDigest.update((byte) input.length);
+			messageDigest.update(input);
 		}
 		byte[] hash = messageDigest.digest();
-		// The output is the first CIPHER_KEY_BYTES bytes of the hash
-		if(hash.length == CIPHER_KEY_BYTES) return hash;
-		byte[] output = new byte[CIPHER_KEY_BYTES];
-		System.arraycopy(hash, 0, output, 0, output.length);
-		return output;
+		// The output is the first SecretKey.LENGTH bytes of the hash
+		if(hash.length == SecretKey.LENGTH) return hash;
+		byte[] truncated = new byte[SecretKey.LENGTH];
+		System.arraycopy(hash, 0, truncated, 0, truncated.length);
+		return truncated;
 	}
 
 	// Key derivation function based on a PRF in counter mode - see
 	// NIST SP 800-108, section 5.1
 	private byte[] counterModeKdf(byte[] secret, byte[] label, long context) {
-		if(secret.length != CIPHER_KEY_BYTES)
-			throw new IllegalArgumentException();
-		if(Arrays.equals(secret, BLANK_SECRET))
+		if(secret.length != SecretKey.LENGTH)
 			throw new IllegalArgumentException();
 		// The label must be null-terminated
 		if(label[label.length - 1] != '\0')
@@ -402,20 +382,20 @@ class CryptoComponentImpl implements CryptoComponent {
 		prf.init(k);
 		int macLength = prf.getMacSize();
 		// The output of the PRF must be long enough to use as a key
-		if(macLength < CIPHER_KEY_BYTES) throw new RuntimeException();
+		if(macLength < SecretKey.LENGTH) throw new RuntimeException();
 		byte[] mac = new byte[macLength];
 		prf.update((byte) 0); // Counter
 		prf.update(label, 0, label.length); // Null-terminated
 		byte[] contextBytes = new byte[4];
 		ByteUtils.writeUint32(context, contextBytes, 0);
 		prf.update(contextBytes, 0, contextBytes.length);
-		prf.update((byte) CIPHER_KEY_BYTES); // Output length
+		prf.update((byte) SecretKey.LENGTH); // Output length
 		prf.doFinal(mac, 0);
-		// The output is the first CIPHER_KEY_BYTES bytes of the MAC
-		if(mac.length == CIPHER_KEY_BYTES) return mac;
-		byte[] output = new byte[CIPHER_KEY_BYTES];
-		System.arraycopy(mac, 0, output, 0, output.length);
-		return output;
+		// The output is the first SecretKey.LENGTH bytes of the MAC
+		if(mac.length == SecretKey.LENGTH) return mac;
+		byte[] truncated = new byte[SecretKey.LENGTH];
+		System.arraycopy(mac, 0, truncated, 0, truncated.length);
+		return truncated;
 	}
 
 	// Password-based key derivation function - see PKCS#5 v2.1, section 5.2
@@ -424,7 +404,7 @@ class CryptoComponentImpl implements CryptoComponent {
 		Digest digest = new SHA256Digest();
 		PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(digest);
 		gen.init(utf8, salt, iterations);
-		int keyLengthInBits = CIPHER_KEY_BYTES * 8;
+		int keyLengthInBits = SecretKey.LENGTH * 8;
 		CipherParameters p = gen.generateDerivedParameters(keyLengthInBits);
 		return ((KeyParameter) p).getKey();
 	}
@@ -461,7 +441,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	private long sampleRunningTime(int iterations) {
 		byte[] password = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' };
 		byte[] salt = new byte[PBKDF_SALT_BYTES];
-		int keyLengthInBits = CIPHER_KEY_BYTES * 8;
+		int keyLengthInBits = SecretKey.LENGTH * 8;
 		long start = System.nanoTime();
 		Digest digest = new SHA256Digest();
 		PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(digest);
diff --git a/briar-core/src/org/briarproject/crypto/PseudoRandomImpl.java b/briar-core/src/org/briarproject/crypto/PseudoRandomImpl.java
index de83754f96..b29dc806d2 100644
--- a/briar-core/src/org/briarproject/crypto/PseudoRandomImpl.java
+++ b/briar-core/src/org/briarproject/crypto/PseudoRandomImpl.java
@@ -1,41 +1,23 @@
 package org.briarproject.crypto;
 
-import org.briarproject.api.crypto.MessageDigest;
 import org.briarproject.api.crypto.PseudoRandom;
 import org.briarproject.util.ByteUtils;
 
 class PseudoRandomImpl implements PseudoRandom {
 
-	private final MessageDigest messageDigest;
+	private final FortunaGenerator generator;
 
-	private byte[] state;
-	private int offset;
-
-	PseudoRandomImpl(MessageDigest messageDigest, int seed1, int seed2) {
-		this.messageDigest = messageDigest;
-		byte[] seedBytes = new byte[8];
-		ByteUtils.writeUint32(seed1, seedBytes, 0);
-		ByteUtils.writeUint32(seed2, seedBytes, 4);
-		messageDigest.update(seedBytes);
-		state = messageDigest.digest();
-		offset = 0;
+	PseudoRandomImpl(int seed1, int seed2) {
+		byte[] seed = new byte[8];
+		ByteUtils.writeUint32(seed1, seed, 0);
+		ByteUtils.writeUint32(seed2, seed, 4);
+		generator = new FortunaGenerator(seed);
 	}
 
-	public synchronized byte[] nextBytes(int bytes) {
-		byte[] b = new byte[bytes];
-		int half = state.length / 2;
-		int off = 0, len = b.length, available = half - offset;
-		while(available < len) {
-			System.arraycopy(state, offset, b, off, available);
-			off += available;
-			len -= available;
-			messageDigest.update(state, half, half);
-			state = messageDigest.digest();
-			offset = 0;
-			available = half;
-		}
-		System.arraycopy(state, offset, b, off, len);
-		offset += len;
+	public synchronized byte[] nextBytes(int length) {
+		byte[] b = new byte[length];
+		int offset = 0;
+		while(offset < length) offset += generator.nextBytes(b, offset, length);
 		return b;
 	}
 }
diff --git a/briar-core/src/org/briarproject/db/H2Database.java b/briar-core/src/org/briarproject/db/H2Database.java
index fc91e20dca..f357593910 100644
--- a/briar-core/src/org/briarproject/db/H2Database.java
+++ b/briar-core/src/org/briarproject/db/H2Database.java
@@ -83,7 +83,7 @@ class H2Database extends JdbcDatabase {
 
 	@Override
 	protected Connection createConnection() throws SQLException {
-		byte[] key = config.getEncryptionKey();
+		byte[] key = config.getEncryptionKey().getBytes();
 		if(key == null) throw new IllegalStateException();
 		Properties props = new Properties();
 		props.setProperty("user", "user");
diff --git a/briar-tests/src/org/briarproject/TestDatabaseConfig.java b/briar-tests/src/org/briarproject/TestDatabaseConfig.java
index 27eb702845..285a6c42a5 100644
--- a/briar-tests/src/org/briarproject/TestDatabaseConfig.java
+++ b/briar-tests/src/org/briarproject/TestDatabaseConfig.java
@@ -2,13 +2,14 @@ package org.briarproject;
 
 import java.io.File;
 
+import org.briarproject.api.crypto.SecretKey;
 import org.briarproject.api.db.DatabaseConfig;
 
 public class TestDatabaseConfig implements DatabaseConfig {
 
 	private final File dir;
 	private final long maxSize;
-	private volatile byte[] key = new byte[] { 'f', 'o', 'o' };
+	private volatile SecretKey key = new SecretKey(new byte[SecretKey.LENGTH]);
 
 	public TestDatabaseConfig(File dir, long maxSize) {
 		this.dir = dir;
@@ -23,11 +24,11 @@ public class TestDatabaseConfig implements DatabaseConfig {
 		return dir;
 	}
 
-	public void setEncryptionKey(byte[] key) {
+	public void setEncryptionKey(SecretKey key) {
 		this.key = key;
 	}
 
-	public byte[] getEncryptionKey() {
+	public SecretKey getEncryptionKey() {
 		return key;
 	}
 
-- 
GitLab