Refactor Android-specific code out of bramble-core.

This commit is contained in:
akwizgran
2020-01-10 17:31:16 +00:00
parent f650b2236e
commit c61c9bbc02
13 changed files with 210 additions and 230 deletions

View File

@@ -133,11 +133,11 @@ public interface CryptoComponent {
* given password. The ciphertext will be decryptable using the same
* password after the app restarts.
*
* @param keyStoreConfig Configures the use of a stored key to strengthen
* the password-based key. If null, no stored key will be used
* @param keyStrengthener Used to strengthen the password-based key. If
* null, the password-based key will not be strengthened
*/
byte[] encryptWithPassword(byte[] plaintext, String password,
@Nullable KeyStoreConfig keyStoreConfig);
@Nullable KeyStrengthener keyStrengthener);
/**
* Decrypts and authenticates the given ciphertext that has been read from
@@ -145,20 +145,19 @@ public interface CryptoComponent {
* given password. Returns null if the ciphertext cannot be decrypted and
* authenticated (for example, if the password is wrong).
*
* @param keyStoreConfig Configures the use of a stored key to strengthen
* the password-based key. If null, or if no stored key was used when
* encrypting the ciphertext, then no stored key will be used
* @param keyStrengthener Used to strengthen the password-based key. If
* null, or if strengthening was not used when encrypting the ciphertext,
* the password-based key will not be strengthened
*/
@Nullable
byte[] decryptWithPassword(byte[] ciphertext, String password,
@Nullable KeyStoreConfig keyStoreConfig);
@Nullable KeyStrengthener keyStrengthener);
/**
* Returns true if the given ciphertext was encrypted using a stored key
* to strengthen the password-based key. The validity of the ciphertext is
* not checked.
* Returns true if the given ciphertext was encrypted using a strengthened
* key. The validity of the ciphertext is not checked.
*/
boolean isEncryptedWithStoredKey(byte[] ciphertext);
boolean isEncryptedWithStrengthenedKey(byte[] ciphertext);
/**
* Encrypts the given plaintext to the given public key.

View File

@@ -1,32 +0,0 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.security.spec.AlgorithmParameterSpec;
import java.util.List;
/**
* Configures the use of a stored key to strengthen password-based encryption.
* The key may be stored in a hardware security module, but this is not
* guaranteed. See
* {@link CryptoComponent#encryptWithPassword(byte[], String, KeyStoreConfig)}
* and
* {@link CryptoComponent#decryptWithPassword(byte[], String, KeyStoreConfig)}.
*/
@NotNullByDefault
public interface KeyStoreConfig {
String getKeyStoreType();
String getKeyAlias();
String getProviderName();
String getMacAlgorithmName();
/**
* Returns a list of {@link AlgorithmParameterSpec AlgorithmParameterSpecs}
* to use for key generation, in order of preference.
*/
List<AlgorithmParameterSpec> getParameterSpecs();
}

View File

@@ -0,0 +1,23 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* Interface for strengthening a password-based key, for example by using a
* key stored in a key management service or hardware security module.
*/
@NotNullByDefault
public interface KeyStrengthener {
/**
* Returns true if the strengthener has been initialised.
*/
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
boolean isInitialised();
/**
* Initialises the strengthener if necessary and returns a strong key
* derived from the given key.
*/
SecretKey strengthenKey(SecretKey k);
}

View File

@@ -1,6 +1,6 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.crypto.KeyStoreConfig;
import org.briarproject.bramble.api.crypto.KeyStrengthener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.File;
@@ -21,9 +21,9 @@ public interface DatabaseConfig {
File getDatabaseKeyDirectory();
/**
* Returns a {@link KeyStoreConfig} for strengthening the encryption of the
* database key, or null if no keystore should be used.
* Returns a {@link KeyStrengthener} for strengthening the encryption of
* the database key, or null if no strengthener should be used.
*/
@Nullable
KeyStoreConfig getKeyStoreConfig();
KeyStrengthener getKeyStrengthener();
}

View File

@@ -2,7 +2,7 @@ package org.briarproject.bramble.account;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyStoreConfig;
import org.briarproject.bramble.api.crypto.KeyStrengthener;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.Identity;
@@ -178,7 +178,7 @@ class AccountManagerImpl implements AccountManager {
private boolean encryptAndStoreDatabaseKey(SecretKey key, String password) {
byte[] plaintext = key.getBytes();
byte[] ciphertext = crypto.encryptWithPassword(plaintext, password,
databaseConfig.getKeyStoreConfig());
databaseConfig.getKeyStrengthener());
return storeEncryptedDatabaseKey(toHexString(ciphertext));
}
@@ -211,19 +211,19 @@ class AccountManagerImpl implements AccountManager {
return null;
}
byte[] ciphertext = fromHexString(hex);
KeyStoreConfig keyStoreConfig = databaseConfig.getKeyStoreConfig();
KeyStrengthener keyStrengthener = databaseConfig.getKeyStrengthener();
byte[] plaintext = crypto.decryptWithPassword(ciphertext, password,
keyStoreConfig);
keyStrengthener);
if (plaintext == null) {
LOG.info("Failed to decrypt database key");
return null;
}
SecretKey key = new SecretKey(plaintext);
// If the DB key was encrypted without using a stored key and a stored
// key is now available, re-encrypt the DB key with the stored key
if (keyStoreConfig != null &&
!crypto.isEncryptedWithStoredKey(ciphertext)) {
LOG.info("Re-encrypting database key with stored key");
// If the DB key was encrypted with a weak key and a key strengthener
// is now available, re-encrypt the DB key with a strengthened key
if (keyStrengthener != null &&
!crypto.isEncryptedWithStrengthenedKey(ciphertext)) {
LOG.info("Re-encrypting database key with strengthened key");
encryptAndStoreDatabaseKey(key, password);
}
return key;

View File

@@ -9,7 +9,7 @@ import org.briarproject.bramble.api.crypto.AgreementPublicKey;
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.KeyStoreConfig;
import org.briarproject.bramble.api.crypto.KeyStrengthener;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.crypto.SecretKey;
@@ -25,28 +25,20 @@ import org.spongycastle.crypto.digests.Blake2bDigest;
import org.whispersystems.curve25519.Curve25519;
import org.whispersystems.curve25519.Curve25519KeyPair;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStore.Entry;
import java.security.KeyStore.SecretKeyEntry;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.inject.Inject;
import static java.lang.System.arraycopy;
import static java.util.logging.Level.INFO;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_AGREEMENT;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_SIGNATURE;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.now;
@@ -61,7 +53,7 @@ class CryptoComponentImpl implements CryptoComponent {
private static final int STORAGE_IV_BYTES = 24; // 196 bits
private static final int PBKDF_SALT_BYTES = 32; // 256 bits
private static final byte PBKDF_FORMAT_SCRYPT = 0;
private static final byte PBKDF_FORMAT_SCRYPT_KEYSTORE = 1;
private static final byte PBKDF_FORMAT_SCRYPT_STRENGTHENED = 1;
private final SecureRandom secureRandom;
private final PasswordBasedKdf passwordBasedKdf;
@@ -322,7 +314,7 @@ class CryptoComponentImpl implements CryptoComponent {
@Override
public byte[] encryptWithPassword(byte[] input, String password,
@Nullable KeyStoreConfig keyStoreConfig) {
@Nullable KeyStrengthener keyStrengthener) {
AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher();
int macBytes = cipher.getMacBytes();
// Generate a random salt
@@ -332,8 +324,7 @@ class CryptoComponentImpl implements CryptoComponent {
int cost = passwordBasedKdf.chooseCostParameter();
// Derive the encryption key from the password
SecretKey key = passwordBasedKdf.deriveKey(password, salt, cost);
if (keyStoreConfig != null)
key = requireNonNull(deriveKey(key, keyStoreConfig, true));
if (keyStrengthener != null) key = keyStrengthener.strengthenKey(key);
// Generate a random IV
byte[] iv = new byte[STORAGE_IV_BYTES];
secureRandom.nextBytes(iv);
@@ -344,8 +335,8 @@ class CryptoComponentImpl implements CryptoComponent {
byte[] output = new byte[outputLen];
int outputOff = 0;
// Format version
byte formatVersion = keyStoreConfig == null
? PBKDF_FORMAT_SCRYPT : PBKDF_FORMAT_SCRYPT_KEYSTORE;
byte formatVersion = keyStrengthener == null
? PBKDF_FORMAT_SCRYPT : PBKDF_FORMAT_SCRYPT_STRENGTHENED;
output[outputOff] = formatVersion;
outputOff++;
// Salt
@@ -367,65 +358,10 @@ class CryptoComponentImpl implements CryptoComponent {
}
}
/**
* Derives a key from the given key and another key stored in a keystore.
*
* @param generateIfMissing Whether the stored key should be generated and
* stored if it doesn't already exist
* @return The derived key, or null if the stored key doesn't exist and
* {@code generateIfMissing} is false
*/
@Nullable
private SecretKey deriveKey(SecretKey key, KeyStoreConfig config,
boolean generateIfMissing) {
try {
// Load the keystore
KeyStore ks = KeyStore.getInstance(config.getKeyStoreType());
ks.load(null);
// Load or generate the stored key
javax.crypto.SecretKey storedKey = null;
Entry e = ks.getEntry(config.getKeyAlias(), null);
if (e == null) {
if (!generateIfMissing) {
LOG.warning("Key not found in keystore");
return null;
}
// Try the parameter specs in order of preference
for (AlgorithmParameterSpec spec : config.getParameterSpecs()) {
try {
KeyGenerator kg = KeyGenerator.getInstance(
config.getMacAlgorithmName(),
config.getProviderName());
kg.init(spec);
storedKey = kg.generateKey();
break;
} catch (Exception e1) {
if (LOG.isLoggable(INFO))
LOG.info("Could not generate key: " + e1);
// Fall back to next spec
}
}
if (storedKey == null) throw new IllegalArgumentException();
LOG.info("Stored key in keystore");
} else {
if (!(e instanceof SecretKeyEntry))
throw new IllegalArgumentException();
storedKey = ((SecretKeyEntry) e).getSecretKey();
LOG.info("Loaded key from keystore");
}
// Use the input key and the stored key to derive the output key
Mac mac = Mac.getInstance(config.getMacAlgorithmName());
mac.init(storedKey);
return new SecretKey(mac.doFinal(key.getBytes()));
} catch (GeneralSecurityException | IOException e) {
throw new IllegalArgumentException(e);
}
}
@Override
@Nullable
public byte[] decryptWithPassword(byte[] input, String password,
@Nullable KeyStoreConfig keyStoreConfig) {
@Nullable KeyStrengthener keyStrengthener) {
AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher();
int macBytes = cipher.getMacBytes();
// The input contains the format version, salt, cost parameter, IV,
@@ -439,11 +375,9 @@ class CryptoComponentImpl implements CryptoComponent {
inputOff++;
// Check whether we support this format version
if (formatVersion != PBKDF_FORMAT_SCRYPT &&
formatVersion != PBKDF_FORMAT_SCRYPT_KEYSTORE) {
formatVersion != PBKDF_FORMAT_SCRYPT_STRENGTHENED) {
return null;
}
boolean useKeyStore = keyStoreConfig != null &&
formatVersion == PBKDF_FORMAT_SCRYPT_KEYSTORE;
// Salt
byte[] salt = new byte[PBKDF_SALT_BYTES];
arraycopy(input, inputOff, salt, 0, salt.length);
@@ -459,9 +393,10 @@ class CryptoComponentImpl implements CryptoComponent {
inputOff += iv.length;
// Derive the decryption key from the password
SecretKey key = passwordBasedKdf.deriveKey(password, salt, (int) cost);
if (useKeyStore) {
key = deriveKey(key, keyStoreConfig, false);
if (key == null) return null;
if (formatVersion == PBKDF_FORMAT_SCRYPT_STRENGTHENED) {
if (keyStrengthener == null || !keyStrengthener.isInitialised())
return null; // Can't derive the same strengthened key
key = keyStrengthener.strengthenKey(key);
}
// Initialise the cipher
try {
@@ -481,9 +416,9 @@ class CryptoComponentImpl implements CryptoComponent {
}
@Override
public boolean isEncryptedWithStoredKey(byte[] ciphertext) {
public boolean isEncryptedWithStrengthenedKey(byte[] ciphertext) {
return ciphertext.length > 0 &&
ciphertext[0] == PBKDF_FORMAT_SCRYPT_KEYSTORE;
ciphertext[0] == PBKDF_FORMAT_SCRYPT_STRENGTHENED;
}
@Override

View File

@@ -1,7 +1,7 @@
package org.briarproject.bramble.account;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyStoreConfig;
import org.briarproject.bramble.api.crypto.KeyStrengthener;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.Identity;
@@ -40,8 +40,8 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
private final DatabaseConfig databaseConfig =
context.mock(DatabaseConfig.class);
private final KeyStoreConfig keyStoreConfig =
context.mock(KeyStoreConfig.class);
private final KeyStrengthener keyStrengthener =
context.mock(KeyStrengthener.class);
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
private final IdentityManager identityManager =
context.mock(IdentityManager.class);
@@ -71,8 +71,8 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
will(returnValue(dbDir));
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
allowing(databaseConfig).getKeyStoreConfig();
will(returnValue(keyStoreConfig));
allowing(databaseConfig).getKeyStrengthener();
will(returnValue(keyStrengthener));
}});
accountManager =
@@ -95,7 +95,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
public void testSignInReturnsFalseIfPasswordIsWrong() throws Exception {
context.checking(new Expectations() {{
oneOf(crypto).decryptWithPassword(encryptedKey, password,
keyStoreConfig);
keyStrengthener);
will(returnValue(null));
}});
@@ -116,9 +116,9 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
public void testSignInReturnsTrueIfPasswordIsRight() throws Exception {
context.checking(new Expectations() {{
oneOf(crypto).decryptWithPassword(encryptedKey, password,
keyStoreConfig);
keyStrengthener);
will(returnValue(key.getBytes()));
oneOf(crypto).isEncryptedWithStoredKey(encryptedKey);
oneOf(crypto).isEncryptedWithStrengthenedKey(encryptedKey);
will(returnValue(true));
}});
@@ -142,12 +142,12 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
public void testSignInReEncryptsKey() throws Exception {
context.checking(new Expectations() {{
oneOf(crypto).decryptWithPassword(encryptedKey, password,
keyStoreConfig);
keyStrengthener);
will(returnValue(key.getBytes()));
oneOf(crypto).isEncryptedWithStoredKey(encryptedKey);
oneOf(crypto).isEncryptedWithStrengthenedKey(encryptedKey);
will(returnValue(false));
oneOf(crypto).encryptWithPassword(key.getBytes(), password,
keyStoreConfig);
keyStrengthener);
will(returnValue(newEncryptedKey));
}});
@@ -297,7 +297,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
oneOf(crypto).generateSecretKey();
will(returnValue(key));
oneOf(crypto).encryptWithPassword(key.getBytes(), password,
keyStoreConfig);
keyStrengthener);
will(returnValue(encryptedKey));
}});
@@ -327,7 +327,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
throws Exception {
context.checking(new Expectations() {{
oneOf(crypto).decryptWithPassword(encryptedKey, password,
keyStoreConfig);
keyStrengthener);
will(returnValue(null));
}});
@@ -345,12 +345,12 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
throws Exception {
context.checking(new Expectations() {{
oneOf(crypto).decryptWithPassword(encryptedKey, password,
keyStoreConfig);
keyStrengthener);
will(returnValue(key.getBytes()));
oneOf(crypto).isEncryptedWithStoredKey(encryptedKey);
oneOf(crypto).isEncryptedWithStrengthenedKey(encryptedKey);
will(returnValue(true));
oneOf(crypto).encryptWithPassword(key.getBytes(), newPassword,
keyStoreConfig);
keyStrengthener);
will(returnValue(newEncryptedKey));
}});

View File

@@ -1,6 +1,6 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.api.crypto.KeyStoreConfig;
import org.briarproject.bramble.api.crypto.KeyStrengthener;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -30,7 +30,7 @@ public class TestDatabaseConfig implements DatabaseConfig {
@Nullable
@Override
public KeyStoreConfig getKeyStoreConfig() {
public KeyStrengthener getKeyStrengthener() {
return null;
}
}

View File

@@ -1,6 +1,6 @@
package org.briarproject.briar.android;
import org.briarproject.bramble.api.crypto.KeyStoreConfig;
import org.briarproject.bramble.api.crypto.KeyStrengthener;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -8,19 +8,18 @@ import java.io.File;
import javax.annotation.Nullable;
import static android.os.Build.VERSION.SDK_INT;
@NotNullByDefault
class AndroidDatabaseConfig implements DatabaseConfig {
private final File dbDir, keyDir;
@Nullable
private final KeyStoreConfig keyStoreConfig;
private final KeyStrengthener keyStrengthener;
AndroidDatabaseConfig(File dbDir, File keyDir) {
AndroidDatabaseConfig(File dbDir, File keyDir,
@Nullable KeyStrengthener keyStrengthener) {
this.dbDir = dbDir;
this.keyDir = keyDir;
keyStoreConfig = SDK_INT >= 23 ? new AndroidKeyStoreConfig() : null;
this.keyStrengthener = keyStrengthener;
}
@Override
@@ -35,7 +34,7 @@ class AndroidDatabaseConfig implements DatabaseConfig {
@Nullable
@Override
public KeyStoreConfig getKeyStoreConfig() {
return keyStoreConfig;
public KeyStrengthener getKeyStrengthener() {
return keyStrengthener;
}
}

View File

@@ -1,66 +0,0 @@
package org.briarproject.briar.android;
import android.security.keystore.KeyGenParameterSpec;
import org.briarproject.bramble.api.crypto.KeyStoreConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.security.spec.AlgorithmParameterSpec;
import java.util.List;
import androidx.annotation.RequiresApi;
import static android.os.Build.VERSION.SDK_INT;
import static android.security.keystore.KeyProperties.PURPOSE_SIGN;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
@RequiresApi(23)
@NotNullByDefault
class AndroidKeyStoreConfig implements KeyStoreConfig {
private final List<AlgorithmParameterSpec> specs;
AndroidKeyStoreConfig() {
KeyGenParameterSpec noStrongBox =
new KeyGenParameterSpec.Builder("db", PURPOSE_SIGN)
.setKeySize(256)
.build();
if (SDK_INT >= 28) {
// Prefer StrongBox if available
KeyGenParameterSpec strongBox =
new KeyGenParameterSpec.Builder("db", PURPOSE_SIGN)
.setIsStrongBoxBacked(true)
.setKeySize(256)
.build();
specs = asList(strongBox, noStrongBox);
} else {
specs = singletonList(noStrongBox);
}
}
@Override
public String getKeyStoreType() {
return "AndroidKeyStore";
}
@Override
public String getKeyAlias() {
return "db";
}
@Override
public String getProviderName() {
return "AndroidKeyStore";
}
@Override
public String getMacAlgorithmName() {
return "HmacSHA256";
}
@Override
public List<AlgorithmParameterSpec> getParameterSpecs() {
return specs;
}
}

View File

@@ -0,0 +1,118 @@
package org.briarproject.briar.android;
import android.security.keystore.KeyGenParameterSpec;
import org.briarproject.bramble.api.crypto.KeyStrengthener;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStore.Entry;
import java.security.KeyStore.SecretKeyEntry;
import java.security.spec.AlgorithmParameterSpec;
import java.util.List;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import androidx.annotation.RequiresApi;
import static android.os.Build.VERSION.SDK_INT;
import static android.security.keystore.KeyProperties.KEY_ALGORITHM_HMAC_SHA256;
import static android.security.keystore.KeyProperties.PURPOSE_SIGN;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
@RequiresApi(23)
@NotNullByDefault
class AndroidKeyStrengthener implements KeyStrengthener {
private static final Logger LOG =
getLogger(AndroidKeyStrengthener.class.getName());
private static final String KEY_STORE_TYPE = "AndroidKeyStore";
private static final String PROVIDER_NAME = "AndroidKeyStore";
private static final String KEY_ALIAS = "db";
private static final int KEY_BITS = 256;
private final List<AlgorithmParameterSpec> specs;
AndroidKeyStrengthener() {
KeyGenParameterSpec noStrongBox =
new KeyGenParameterSpec.Builder(KEY_ALIAS, PURPOSE_SIGN)
.setKeySize(KEY_BITS)
.build();
if (SDK_INT >= 28) {
// Prefer StrongBox if available
KeyGenParameterSpec strongBox =
new KeyGenParameterSpec.Builder(KEY_ALIAS, PURPOSE_SIGN)
.setIsStrongBoxBacked(true)
.setKeySize(KEY_BITS)
.build();
specs = asList(strongBox, noStrongBox);
} else {
specs = singletonList(noStrongBox);
}
}
@GuardedBy("this")
@Nullable
private javax.crypto.SecretKey storedKey = null;
@Override
public synchronized boolean isInitialised() {
if (storedKey != null) return true;
try {
KeyStore ks = KeyStore.getInstance(KEY_STORE_TYPE);
ks.load(null);
Entry entry = ks.getEntry(KEY_ALIAS, null);
if (entry instanceof SecretKeyEntry) {
storedKey = ((SecretKeyEntry) entry).getSecretKey();
LOG.info("Loaded key from keystore");
return true;
}
return false;
} catch (GeneralSecurityException | IOException e) {
throw new RuntimeException(e);
}
}
@Override
public synchronized SecretKey strengthenKey(SecretKey k) {
try {
if (!isInitialised()) initialise();
// Use the input key and the stored key to derive the output key
Mac mac = Mac.getInstance(KEY_ALGORITHM_HMAC_SHA256);
mac.init(storedKey);
return new SecretKey(mac.doFinal(k.getBytes()));
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
private synchronized void initialise() throws GeneralSecurityException {
// Try the parameter specs in order of preference
for (AlgorithmParameterSpec spec : specs) {
try {
KeyGenerator kg = KeyGenerator.getInstance(
KEY_ALGORITHM_HMAC_SHA256, PROVIDER_NAME);
kg.init(spec);
storedKey = kg.generateKey();
LOG.info("Stored key in keystore");
return;
} catch (Exception e) {
if (LOG.isLoggable(INFO))
LOG.info("Could not generate key: " + e);
// Fall back to next spec
}
}
throw new GeneralSecurityException("Could not generate key");
}
}

View File

@@ -10,6 +10,7 @@ import com.vanniktech.emoji.RecentEmoji;
import org.briarproject.bramble.api.FeatureFlags;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyStrengthener;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.event.EventBus;
@@ -56,6 +57,7 @@ import dagger.Module;
import dagger.Provides;
import static android.content.Context.MODE_PRIVATE;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS;
@@ -101,7 +103,9 @@ public class AppModule {
File dbDir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
File keyDir = app.getApplicationContext().getDir("key", MODE_PRIVATE);
StrictMode.setThreadPolicy(tp);
return new AndroidDatabaseConfig(dbDir, keyDir);
KeyStrengthener keyStrengthener = SDK_INT >= 23
? new AndroidKeyStrengthener() : null;
return new AndroidDatabaseConfig(dbDir, keyDir, keyStrengthener);
}
@Provides

View File

@@ -1,6 +1,6 @@
package org.briarproject.briar.headless
import org.briarproject.bramble.api.crypto.KeyStoreConfig
import org.briarproject.bramble.api.crypto.KeyStrengthener
import org.briarproject.bramble.api.db.DatabaseConfig
import java.io.File
@@ -11,5 +11,5 @@ internal class HeadlessDatabaseConfig(private val dbDir: File, private val keyDi
override fun getDatabaseKeyDirectory() = keyDir
override fun getKeyStoreConfig(): KeyStoreConfig? = null
override fun getKeyStrengthener(): KeyStrengthener? = null
}