Biometric encryption
This commit is contained in:
parent
8fbf44b75a
commit
ffba642fa0
17
.idea/deploymentTargetDropDown.xml
Normal file
17
.idea/deploymentTargetDropDown.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="deploymentTargetDropDown">
|
||||
<runningDeviceTargetSelectedWithDropDown>
|
||||
<Target>
|
||||
<type value="RUNNING_DEVICE_TARGET" />
|
||||
<deviceKey>
|
||||
<Key>
|
||||
<type value="SERIAL_NUMBER" />
|
||||
<value value="R38N50464FV" />
|
||||
</Key>
|
||||
</deviceKey>
|
||||
</Target>
|
||||
</runningDeviceTargetSelectedWithDropDown>
|
||||
<timeTargetWasSelectedWithDropDown value="2023-09-18T17:20:49.048823275Z" />
|
||||
</component>
|
||||
</project>
|
@ -10,8 +10,8 @@
|
||||
<option name="gradleJvm" value="jbr-17" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
<option value="/mnt/sshd/Files/Desktop/testing/android/Cringe-Authenticator" />
|
||||
<option value="/mnt/sshd/Files/Desktop/testing/android/Cringe-Authenticator/app" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
|
@ -74,7 +74,6 @@ dependencies {
|
||||
implementation 'com.google.mlkit:barcode-scanning:17.1.0'
|
||||
implementation 'com.google.code.gson:gson:2.8.9'
|
||||
|
||||
|
||||
def camerax_version = "1.2.3"
|
||||
implementation "androidx.camera:camera-core:${camerax_version}"
|
||||
implementation "androidx.camera:camera-camera2:${camerax_version}"
|
||||
|
@ -0,0 +1,26 @@
|
||||
package com.cringe_studios.cringe_authenticator.crypto;
|
||||
|
||||
public class BiometricKey {
|
||||
|
||||
private final String id;
|
||||
private final byte[] encryptedKey;
|
||||
private final byte[] iv;
|
||||
|
||||
public BiometricKey(String id, byte[] encryptedKey, byte[] iv) {
|
||||
this.id = id;
|
||||
this.encryptedKey = encryptedKey;
|
||||
this.iv = iv;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public byte[] getEncryptedKey() {
|
||||
return encryptedKey;
|
||||
}
|
||||
|
||||
public byte[] getIV() {
|
||||
return iv;
|
||||
}
|
||||
}
|
@ -1,17 +1,37 @@
|
||||
package com.cringe_studios.cringe_authenticator.crypto;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.security.keystore.KeyGenParameterSpec;
|
||||
import android.security.keystore.KeyProperties;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.cringe_studios.cringe_authenticator.util.OTPDatabase;
|
||||
import com.cringe_studios.cringe_authenticator.util.SettingsUtil;
|
||||
|
||||
import org.bouncycastle.crypto.generators.Argon2BytesGenerator;
|
||||
import org.bouncycastle.crypto.params.Argon2Parameters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
@ -19,6 +39,8 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class Crypto {
|
||||
|
||||
private static final String KEY_STORE = "AndroidKeyStore";
|
||||
|
||||
public static byte[] generateHash(CryptoParameters parameters, String password) throws CryptoException {
|
||||
Argon2Parameters params = new Argon2Parameters.Builder()
|
||||
.withVersion(parameters.getArgon2Version())
|
||||
@ -55,12 +77,16 @@ public class Crypto {
|
||||
return generateBytes(parameters.getEncryptionIVLength());
|
||||
}
|
||||
|
||||
public static byte[] encrypt(CryptoParameters parameters, byte[] bytes, SecretKey key) throws CryptoException {
|
||||
public static CryptoResult encryptWithResult(CryptoParameters parameters, byte[] bytes, SecretKey key, boolean useIV) throws CryptoException {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(parameters.getEncryptionAlgorithm());
|
||||
GCMParameterSpec spec = new GCMParameterSpec(parameters.getEncryptionGCMTagLength() * 8, parameters.getIV());
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||
return cipher.doFinal(bytes);
|
||||
if(useIV) {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||
}else {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
}
|
||||
return new CryptoResult(cipher.doFinal(bytes), cipher.getIV());
|
||||
}catch(NoSuchAlgorithmException | NoSuchPaddingException |
|
||||
InvalidAlgorithmParameterException | InvalidKeyException | BadPaddingException |
|
||||
IllegalBlockSizeException e) {
|
||||
@ -68,10 +94,14 @@ public class Crypto {
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] decrypt(CryptoParameters parameters, byte[] bytes, SecretKey key) throws CryptoException {
|
||||
public static byte[] encrypt(CryptoParameters parameters, byte[] bytes, SecretKey key) throws CryptoException {
|
||||
return encryptWithResult(parameters, bytes, key, true).getEncrypted();
|
||||
}
|
||||
|
||||
public static byte[] decrypt(CryptoParameters parameters, byte[] bytes, SecretKey key, byte[] overrideIV) throws CryptoException {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(parameters.getEncryptionAlgorithm());
|
||||
GCMParameterSpec spec = new GCMParameterSpec(parameters.getEncryptionGCMTagLength() * 8, parameters.getIV());
|
||||
GCMParameterSpec spec = new GCMParameterSpec(parameters.getEncryptionGCMTagLength() * 8, overrideIV != null ? overrideIV : parameters.getIV());
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, spec);
|
||||
return cipher.doFinal(bytes);
|
||||
}catch(NoSuchAlgorithmException | NoSuchPaddingException |
|
||||
@ -81,4 +111,53 @@ public class Crypto {
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] decrypt(CryptoParameters parameters, byte[] bytes, SecretKey key) throws CryptoException {
|
||||
return decrypt(parameters, bytes, key, null);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
public static BiometricKey createBiometricKey(CryptoParameters parameters) throws CryptoException {
|
||||
try {
|
||||
KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEY_STORE);
|
||||
|
||||
String keyID = UUID.randomUUID().toString();
|
||||
generator.init(new KeyGenParameterSpec.Builder(keyID,
|
||||
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
|
||||
.setKeySize(parameters.getEncryptionAESKeyLength() * 8)
|
||||
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
|
||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
||||
.setUserAuthenticationRequired(true)
|
||||
.setUserAuthenticationValidityDurationSeconds(60)
|
||||
.setRandomizedEncryptionRequired(true)
|
||||
.build());
|
||||
|
||||
SecretKey biometricKey = generator.generateKey();
|
||||
SecretKey key = OTPDatabase.getLoadedKey();
|
||||
CryptoResult encryptedKey = Crypto.encryptWithResult(parameters, key.getEncoded(), biometricKey, false);
|
||||
return new BiometricKey(keyID, encryptedKey.getEncrypted(), encryptedKey.getIV());
|
||||
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static SecretKey getBiometricKey(BiometricKey key) throws CryptoException {
|
||||
try {
|
||||
KeyStore store = KeyStore.getInstance(KEY_STORE);
|
||||
store.load(null);
|
||||
return (SecretKey) store.getKey(key.getId(), null);
|
||||
} catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException | IOException e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteBiometricKey(BiometricKey key) throws CryptoException {
|
||||
try {
|
||||
KeyStore ks = KeyStore.getInstance(KEY_STORE);
|
||||
ks.load(null);
|
||||
ks.deleteEntry(key.getId());
|
||||
} catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package com.cringe_studios.cringe_authenticator.crypto;
|
||||
|
||||
public class CryptoResult {
|
||||
|
||||
private byte[] encrypted;
|
||||
private byte[] iv;
|
||||
|
||||
public CryptoResult(byte[] encrypted, byte[] iv) {
|
||||
this.encrypted = encrypted;
|
||||
this.iv = iv;
|
||||
}
|
||||
|
||||
public byte[] getEncrypted() {
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
public byte[] getIV() {
|
||||
return iv;
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package com.cringe_studios.cringe_authenticator.fragment;
|
||||
import static androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG;
|
||||
import static androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
@ -16,10 +17,12 @@ import androidx.annotation.Nullable;
|
||||
import androidx.biometric.BiometricManager;
|
||||
|
||||
import com.cringe_studios.cringe_authenticator.MainActivity;
|
||||
import com.cringe_studios.cringe_authenticator.crypto.BiometricKey;
|
||||
import com.cringe_studios.cringe_authenticator.crypto.Crypto;
|
||||
import com.cringe_studios.cringe_authenticator.crypto.CryptoException;
|
||||
import com.cringe_studios.cringe_authenticator.crypto.CryptoParameters;
|
||||
import com.cringe_studios.cringe_authenticator.databinding.FragmentSettingsBinding;
|
||||
import com.cringe_studios.cringe_authenticator.util.BiometricUtil;
|
||||
import com.cringe_studios.cringe_authenticator.util.DialogUtil;
|
||||
import com.cringe_studios.cringe_authenticator.util.FabUtil;
|
||||
import com.cringe_studios.cringe_authenticator.util.OTPDatabase;
|
||||
@ -28,6 +31,7 @@ import com.cringe_studios.cringe_authenticator.util.SettingsUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
@ -106,9 +110,35 @@ public class SettingsFragment extends NamedFragment {
|
||||
binding.settingsEnableIntroVideo.setChecked(SettingsUtil.isIntroVideoEnabled(requireContext()));
|
||||
binding.settingsEnableIntroVideo.setOnCheckedChangeListener((view, checked) -> SettingsUtil.setEnableIntroVideo(requireContext(), checked));
|
||||
|
||||
if(BiometricManager.from(requireContext()).canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS) {
|
||||
binding.settingsBiometricLock.setChecked(SettingsUtil.isBiometricLock(requireContext()));
|
||||
binding.settingsBiometricLock.setOnCheckedChangeListener((view, checked) -> SettingsUtil.setBiometricLock(requireContext(), checked));
|
||||
if(SettingsUtil.isDatabaseEncrypted(requireContext())
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
&& BiometricManager.from(requireContext()).canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS) {
|
||||
binding.settingsBiometricLock.setChecked(SettingsUtil.isBiometricEncryption(requireContext()));
|
||||
binding.settingsBiometricLock.setOnCheckedChangeListener((view, checked) -> {
|
||||
if(checked) {
|
||||
OTPDatabase.promptLoadDatabase(requireActivity(), () -> {
|
||||
Log.i("PROMPT", "§BERIIO");
|
||||
BiometricUtil.promptBiometricAuth(requireActivity(), () -> {
|
||||
try {
|
||||
BiometricKey biometricKey = Crypto.createBiometricKey(SettingsUtil.getCryptoParameters(requireContext()));
|
||||
SettingsUtil.enableBiometricEncryption(requireContext(), biometricKey);
|
||||
} catch (CryptoException e) {
|
||||
e.printStackTrace();
|
||||
DialogUtil.showErrorDialog(requireContext(), "Failed to enable: " + e);
|
||||
}
|
||||
}, () -> view.setChecked(false));
|
||||
}, null);
|
||||
}else {
|
||||
try {
|
||||
BiometricKey key = SettingsUtil.getBiometricKey(requireContext());
|
||||
if(key != null) Crypto.deleteBiometricKey(key);
|
||||
} catch (CryptoException e) {
|
||||
DialogUtil.showErrorDialog(requireContext(), "Failed to delete key: " + e);
|
||||
}
|
||||
|
||||
SettingsUtil.disableBiometricEncryption(requireContext());
|
||||
}
|
||||
});
|
||||
}else {
|
||||
binding.settingsBiometricLock.setChecked(false);
|
||||
binding.settingsBiometricLock.setEnabled(false);
|
||||
|
@ -18,9 +18,11 @@ import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.cringe_studios.cringe_authenticator.MainActivity;
|
||||
import com.cringe_studios.cringe_authenticator.R;
|
||||
import com.cringe_studios.cringe_authenticator.crypto.BiometricKey;
|
||||
import com.cringe_studios.cringe_authenticator.crypto.Crypto;
|
||||
import com.cringe_studios.cringe_authenticator.crypto.CryptoException;
|
||||
import com.cringe_studios.cringe_authenticator.databinding.ActivityUnlockBinding;
|
||||
import com.cringe_studios.cringe_authenticator.util.BiometricUtil;
|
||||
import com.cringe_studios.cringe_authenticator.util.DialogUtil;
|
||||
import com.cringe_studios.cringe_authenticator.util.OTPDatabase;
|
||||
import com.cringe_studios.cringe_authenticator.util.OTPDatabaseException;
|
||||
@ -36,6 +38,7 @@ import java.util.concurrent.Executor;
|
||||
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class UnlockActivity extends AppCompatActivity {
|
||||
|
||||
@ -57,47 +60,20 @@ public class UnlockActivity extends AppCompatActivity {
|
||||
binding = ActivityUnlockBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
try {
|
||||
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
|
||||
ks.load(null);
|
||||
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
|
||||
ks.setEntry("amogus", new KeyStore.SecretKeyEntry(key), new KeyStoreParameter.Builder(this).build());
|
||||
} catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
if(SettingsUtil.isBiometricLock(this)) {
|
||||
Executor executor = ContextCompat.getMainExecutor(this);
|
||||
BiometricPrompt prompt = new BiometricPrompt(this, executor, new BiometricPrompt.AuthenticationCallback() {
|
||||
@Override
|
||||
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
|
||||
failure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
|
||||
if(SettingsUtil.isBiometricEncryption(this) && BiometricUtil.isSupported(this)) {
|
||||
binding.unlockBiometrics.setOnClickListener(view -> BiometricUtil.promptBiometricAuth(this, this::success, () -> {}));
|
||||
BiometricUtil.promptBiometricAuth(this, () -> {
|
||||
BiometricKey biometricKey = SettingsUtil.getBiometricKey(this);
|
||||
try {
|
||||
SecretKey biometricSecretKey = Crypto.getBiometricKey(biometricKey);
|
||||
byte[] keyBytes = Crypto.decrypt(SettingsUtil.getCryptoParameters(this), biometricKey.getEncryptedKey(), biometricSecretKey, biometricKey.getIV());
|
||||
SecretKey key = new SecretKeySpec(keyBytes, "AES");
|
||||
OTPDatabase.loadDatabase(this, key);
|
||||
success();
|
||||
} catch (CryptoException | OTPDatabaseException e) {
|
||||
DialogUtil.showErrorDialog(this, "Failed to load database: " + e);
|
||||
}
|
||||
});
|
||||
|
||||
boolean supportsBiometricAuth = BiometricManager.from(this).canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS;
|
||||
boolean recentlyUnlocked = savedInstanceState != null && (System.currentTimeMillis() - savedInstanceState.getLong("pauseTime", 0L) < LOCK_TIMEOUT);
|
||||
|
||||
if(!recentlyUnlocked && SettingsUtil.isBiometricLock(this) && supportsBiometricAuth) {
|
||||
BiometricPrompt.PromptInfo info = new BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(getString(R.string.app_name))
|
||||
.setSubtitle(getString(R.string.biometric_lock_subtitle))
|
||||
.setAllowedAuthenticators(BIOMETRIC_STRONG | DEVICE_CREDENTIAL)
|
||||
.build();
|
||||
|
||||
//prompt.authenticate(info);
|
||||
|
||||
binding.unlockBiometrics.setOnClickListener(view -> {
|
||||
//prompt.authenticate(info);
|
||||
});
|
||||
}else {
|
||||
success();
|
||||
}
|
||||
}, () -> {});
|
||||
}
|
||||
|
||||
binding.unlockButton.setOnClickListener(view -> {
|
||||
|
@ -0,0 +1,52 @@
|
||||
package com.cringe_studios.cringe_authenticator.util;
|
||||
|
||||
import static androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG;
|
||||
import static androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.biometric.BiometricManager;
|
||||
import androidx.biometric.BiometricPrompt;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.cringe_studios.cringe_authenticator.R;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class BiometricUtil {
|
||||
|
||||
public static boolean isSupported(Context context) {
|
||||
return BiometricManager.from(context).canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS;
|
||||
}
|
||||
|
||||
public static void promptBiometricAuth(FragmentActivity context, Runnable success, Runnable failure) {
|
||||
if(!isSupported(context)) {
|
||||
failure.run();
|
||||
return;
|
||||
}
|
||||
|
||||
Executor executor = ContextCompat.getMainExecutor(context);
|
||||
BiometricPrompt prompt = new BiometricPrompt(context, executor, new BiometricPrompt.AuthenticationCallback() {
|
||||
@Override
|
||||
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
|
||||
failure.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
|
||||
success.run();
|
||||
}
|
||||
});
|
||||
|
||||
BiometricPrompt.PromptInfo info = new BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(context.getString(R.string.app_name))
|
||||
.setSubtitle(context.getString(R.string.biometric_lock_subtitle))
|
||||
.setAllowedAuthenticators(BIOMETRIC_STRONG | DEVICE_CREDENTIAL)
|
||||
.build();
|
||||
|
||||
prompt.authenticate(info);
|
||||
}
|
||||
|
||||
}
|
@ -182,6 +182,10 @@ public class OTPDatabase {
|
||||
return loadedDatabase;
|
||||
}
|
||||
|
||||
public static SecretKey getLoadedKey() {
|
||||
return loadedKey;
|
||||
}
|
||||
|
||||
public static void encrypt(Context ctx, SecretKey key, CryptoParameters parameters) throws OTPDatabaseException, CryptoException {
|
||||
if(!isDatabaseLoaded()) throw new IllegalStateException("Database is not loaded");
|
||||
loadedKey = key;
|
||||
|
@ -5,6 +5,7 @@ import android.content.SharedPreferences;
|
||||
import android.util.Base64;
|
||||
|
||||
import com.cringe_studios.cringe_authenticator.R;
|
||||
import com.cringe_studios.cringe_authenticator.crypto.BiometricKey;
|
||||
import com.cringe_studios.cringe_authenticator.crypto.CryptoParameters;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
@ -120,6 +121,8 @@ public class SettingsUtil {
|
||||
ctx.getSharedPreferences(GENERAL_PREFS_NAME, Context.MODE_PRIVATE).edit()
|
||||
.putBoolean("encryption", false)
|
||||
.remove("encryption.parameters")
|
||||
.remove("encryption.biometric")
|
||||
.remove("encryption.biometric.key")
|
||||
.apply();
|
||||
}
|
||||
|
||||
@ -127,10 +130,10 @@ public class SettingsUtil {
|
||||
return GSON.fromJson(ctx.getSharedPreferences(GENERAL_PREFS_NAME, Context.MODE_PRIVATE).getString("encryption.parameters", "{}"), CryptoParameters.class);
|
||||
}
|
||||
|
||||
public static void enableBiometricEncryption(Context ctx, byte[] encryptedBiometricKey) {
|
||||
public static void enableBiometricEncryption(Context ctx, BiometricKey biometricKey) {
|
||||
ctx.getSharedPreferences(GENERAL_PREFS_NAME, Context.MODE_PRIVATE).edit()
|
||||
.putBoolean("encryption.biometric", true)
|
||||
.putString("encryption.biometric.key", Base64.encodeToString(encryptedBiometricKey, Base64.DEFAULT))
|
||||
.putString("encryption.biometric.key", GSON.toJson(biometricKey))
|
||||
.apply();
|
||||
}
|
||||
|
||||
@ -141,21 +144,16 @@ public class SettingsUtil {
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static byte[] getEncryptedBiometricKey(Context ctx) {
|
||||
public static boolean isBiometricEncryption(Context ctx) {
|
||||
return ctx.getSharedPreferences(GENERAL_PREFS_NAME, Context.MODE_PRIVATE).getBoolean("encryption.biometric", false);
|
||||
}
|
||||
|
||||
public static BiometricKey getBiometricKey(Context ctx) {
|
||||
String encoded = ctx.getSharedPreferences(GENERAL_PREFS_NAME, Context.MODE_PRIVATE).getString("encryption.biometric.key", null);
|
||||
if(encoded == null) return null;
|
||||
return Base64.decode(encoded, Base64.DEFAULT);
|
||||
return GSON.fromJson(encoded, BiometricKey.class);
|
||||
}
|
||||
|
||||
/*public static void setBiometricLock(Context ctx, boolean biometricLock) {
|
||||
SharedPreferences prefs = ctx.getSharedPreferences(GENERAL_PREFS_NAME, Context.MODE_PRIVATE);
|
||||
prefs.edit().putBoolean("biometricLock", biometricLock).apply();
|
||||
}
|
||||
|
||||
public static boolean isBiometricLock(Context ctx) {
|
||||
return ctx.getSharedPreferences(GENERAL_PREFS_NAME, Context.MODE_PRIVATE).getBoolean("biometricLock", true);
|
||||
}*/
|
||||
|
||||
public static void setEnableIntroVideo(Context ctx, boolean enableIntroVideo) {
|
||||
SharedPreferences prefs = ctx.getSharedPreferences(GENERAL_PREFS_NAME, Context.MODE_PRIVATE);
|
||||
prefs.edit().putBoolean("enableIntroVideo", enableIntroVideo).apply();
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id 'com.android.application' version '8.1.0' apply false
|
||||
id 'com.android.library' version '8.1.0' apply false
|
||||
id 'com.android.application' version '8.1.1' apply false
|
||||
id 'com.android.library' version '8.1.1' apply false
|
||||
id 'com.google.protobuf' version '0.9.3' apply false
|
||||
}
|
Loading…
Reference in New Issue
Block a user