mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 03:09:04 +01:00
Refactor Android-specific code out of bramble-core.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user