Better biometric key implementation

This commit is contained in:
J-Jamet
2019-09-02 18:46:55 +02:00
parent c9594948a2
commit edcfa8cf7b
5 changed files with 26 additions and 22 deletions

View File

@@ -25,9 +25,9 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
var onCheckedPasswordChangeListener: CompoundButton.OnCheckedChangeListener? = null, var onCheckedPasswordChangeListener: CompoundButton.OnCheckedChangeListener? = null,
var passwordView: TextView?, var passwordView: TextView?,
var loadDatabase: (password: String?) -> Unit) var loadDatabase: (password: String?) -> Unit)
: BiometricHelper.BiometricUnlockCallback { : BiometricUnlockDatabaseHelper.BiometricUnlockCallback {
private var biometricHelper: BiometricHelper? = null private var biometricUnlockDatabaseHelper: BiometricUnlockDatabaseHelper? = null
private var biometricMode: Mode = Mode.NOT_CONFIGURED private var biometricMode: Mode = Mode.NOT_CONFIGURED
private var isBiometricPromptAutoOpenEnable = PreferencesUtil.isBiometricPromptAutoOpenEnable(context) private var isBiometricPromptAutoOpenEnable = PreferencesUtil.isBiometricPromptAutoOpenEnable(context)
@@ -46,11 +46,11 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
// Check if fingerprint well init (be called the first time the fingerprint is configured // Check if fingerprint well init (be called the first time the fingerprint is configured
// and the activity still active) // and the activity still active)
if (biometricHelper == null || !biometricHelper!!.isFingerprintInitialized) { if (biometricUnlockDatabaseHelper == null || !biometricUnlockDatabaseHelper!!.isFingerprintInitialized) {
biometricHelper = BiometricHelper(context, this) biometricUnlockDatabaseHelper = BiometricUnlockDatabaseHelper(context, this)
// callback for fingerprint findings // callback for fingerprint findings
biometricHelper?.setAuthenticationCallback(biometricCallback) biometricUnlockDatabaseHelper?.setAuthenticationCallback(biometricCallback)
} }
// Add a check listener to change fingerprint mode // Add a check listener to change fingerprint mode
@@ -131,12 +131,12 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
Mode.WAIT_CREDENTIAL -> {} Mode.WAIT_CREDENTIAL -> {}
Mode.STORE -> { Mode.STORE -> {
// newly store the entered password in encrypted way // newly store the entered password in encrypted way
biometricHelper?.encryptData(passwordView?.text.toString()) biometricUnlockDatabaseHelper?.encryptData(passwordView?.text.toString())
} }
Mode.OPEN -> { Mode.OPEN -> {
// retrieve the encrypted value from preferences // retrieve the encrypted value from preferences
prefsNoBackup.getString(preferenceKeyValue, null)?.let { prefsNoBackup.getString(preferenceKeyValue, null)?.let {
biometricHelper?.decryptData(it) biometricUnlockDatabaseHelper?.decryptData(it)
} }
} }
} }
@@ -174,7 +174,7 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
setAdvancedUnlockedTitleView(R.string.open_biometric_prompt_store_credential) setAdvancedUnlockedTitleView(R.string.open_biometric_prompt_store_credential)
setAdvancedUnlockedMessageView("") setAdvancedUnlockedMessageView("")
biometricHelper?.initEncryptData { biometricPrompt, cryptoObject, promptInfo -> biometricUnlockDatabaseHelper?.initEncryptData { biometricPrompt, cryptoObject, promptInfo ->
cryptoObject?.let { crypto -> cryptoObject?.let { crypto ->
// Set listener to open the biometric dialog and save credential // Set listener to open the biometric dialog and save credential
@@ -193,9 +193,9 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
setAdvancedUnlockedTitleView(R.string.open_biometric_prompt_unlock_database) setAdvancedUnlockedTitleView(R.string.open_biometric_prompt_unlock_database)
setAdvancedUnlockedMessageView("") setAdvancedUnlockedMessageView("")
if (biometricHelper != null) { if (biometricUnlockDatabaseHelper != null) {
prefsNoBackup.getString(preferenceKeyIvSpec, null)?.let { prefsNoBackup.getString(preferenceKeyIvSpec, null)?.let {
biometricHelper?.initDecryptData(it) { biometricPrompt, cryptoObject, promptInfo -> biometricUnlockDatabaseHelper?.initDecryptData(it) { biometricPrompt, cryptoObject, promptInfo ->
cryptoObject?.let { crypto -> cryptoObject?.let { crypto ->
// Set listener to open the biometric dialog and check credential // Set listener to open the biometric dialog and check credential
@@ -244,7 +244,7 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
biometricMode = Mode.UNAVAILABLE biometricMode = Mode.UNAVAILABLE
initBiometricMode() initBiometricMode()
biometricHelper = null biometricUnlockDatabaseHelper = null
} }
fun inflateOptionsMenu(menuInflater: MenuInflater, menu: Menu) { fun inflateOptionsMenu(menuInflater: MenuInflater, menu: Menu) {
@@ -262,7 +262,7 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
} }
fun deleteEntryKey() { fun deleteEntryKey() {
biometricHelper?.deleteEntryKey() biometricUnlockDatabaseHelper?.deleteEntryKey()
removePrefsNoBackupKey() removePrefsNoBackupKey()
biometricMode = Mode.NOT_CONFIGURED biometricMode = Mode.NOT_CONFIGURED
checkBiometricAvailability() checkBiometricAvailability()

View File

@@ -46,7 +46,7 @@ import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.IvParameterSpec
@RequiresApi(api = Build.VERSION_CODES.M) @RequiresApi(api = Build.VERSION_CODES.M)
class BiometricHelper(private val context: FragmentActivity, private val biometricUnlockCallback: BiometricUnlockCallback?) { class BiometricUnlockDatabaseHelper(private val context: FragmentActivity, private val biometricUnlockCallback: BiometricUnlockCallback?) {
private var biometricPrompt: BiometricPrompt? = null private var biometricPrompt: BiometricPrompt? = null
@@ -130,7 +130,7 @@ class BiometricHelper(private val context: FragmentActivity, private val biometr
.build()) .build())
keyGenerator?.generateKey() keyGenerator?.generateKey()
} }
}catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Unable to create a key in keystore", e) Log.e(TAG, "Unable to create a key in keystore", e)
biometricUnlockCallback?.onBiometricException(e) biometricUnlockCallback?.onBiometricException(e)
} }
@@ -289,7 +289,7 @@ class BiometricHelper(private val context: FragmentActivity, private val biometr
companion object { companion object {
private val TAG = BiometricHelper::class.java.name private val TAG = BiometricUnlockDatabaseHelper::class.java.name
private const val BIOMETRIC_KEYSTORE = "AndroidKeyStore" private const val BIOMETRIC_KEYSTORE = "AndroidKeyStore"
private const val BIOMETRIC_KEYSTORE_KEY = "com.kunzisoft.keepass.biometric.key" private const val BIOMETRIC_KEYSTORE_KEY = "com.kunzisoft.keepass.biometric.key"
@@ -302,7 +302,7 @@ class BiometricHelper(private val context: FragmentActivity, private val biometr
*/ */
fun deleteEntryKeyInKeystoreForBiometric(context: FragmentActivity, fun deleteEntryKeyInKeystoreForBiometric(context: FragmentActivity,
biometricUnlockCallback: BiometricUnlockErrorCallback) { biometricUnlockCallback: BiometricUnlockErrorCallback) {
val fingerPrintHelper = BiometricHelper(context, object : BiometricUnlockCallback { val fingerPrintHelper = BiometricUnlockDatabaseHelper(context, object : BiometricUnlockCallback {
override fun handleEncryptedResult(value: String, ivSpec: String) {} override fun handleEncryptedResult(value: String, ivSpec: String) {}

View File

@@ -48,7 +48,7 @@ import com.kunzisoft.keepass.activities.stylish.Stylish
import com.kunzisoft.keepass.app.database.FileDatabaseHistory import com.kunzisoft.keepass.app.database.FileDatabaseHistory
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.education.Education import com.kunzisoft.keepass.education.Education
import com.kunzisoft.keepass.biometric.BiometricHelper import com.kunzisoft.keepass.biometric.BiometricUnlockDatabaseHelper
import com.kunzisoft.keepass.biometric.AdvancedUnlockedViewManager import com.kunzisoft.keepass.biometric.AdvancedUnlockedViewManager
import com.kunzisoft.keepass.icons.IconPackChooser import com.kunzisoft.keepass.icons.IconPackChooser
import com.kunzisoft.keepass.settings.preferencedialogfragment.* import com.kunzisoft.keepass.settings.preferencedialogfragment.*
@@ -252,9 +252,9 @@ class NestedSettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferen
.setPositiveButton(resources.getString(android.R.string.yes) .setPositiveButton(resources.getString(android.R.string.yes)
) { _, _ -> ) { _, _ ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
BiometricHelper.deleteEntryKeyInKeystoreForBiometric( BiometricUnlockDatabaseHelper.deleteEntryKeyInKeystoreForBiometric(
activity, activity,
object : BiometricHelper.BiometricUnlockErrorCallback { object : BiometricUnlockDatabaseHelper.BiometricUnlockErrorCallback {
override fun onInvalidKeyException(e: Exception) {} override fun onInvalidKeyException(e: Exception) {}
override fun onBiometricException(e: Exception) { override fun onBiometricException(e: Exception) {

View File

@@ -72,12 +72,16 @@ class AdvancedUnlockInfoView @JvmOverloads constructor(context: Context,
title = context.getString(textId) title = context.getString(textId)
} }
var message: CharSequence var message: CharSequence?
get() { get() {
return unlockMessageTextView?.text?.toString() ?: "" return unlockMessageTextView?.text?.toString() ?: ""
} }
set(value) { set(value) {
unlockMessageTextView?.text = value if (value == null || value.isEmpty())
unlockMessageTextView?.visibility = GONE
else
unlockMessageTextView?.visibility = VISIBLE
unlockMessageTextView?.text = value ?: ""
} }
fun setMessage(@StringRes textId: Int) { fun setMessage(@StringRes textId: Int) {

View File

@@ -103,6 +103,7 @@
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:elevation="4dp" android:elevation="4dp"
android:layout_marginBottom="12dp"
android:src="@drawable/fingerprint" android:src="@drawable/fingerprint"
android:background="@drawable/background_image" android:background="@drawable/background_image"
tools:targetApi="lollipop" /> tools:targetApi="lollipop" />
@@ -112,7 +113,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:layout_marginTop="12dp"
android:layout_marginBottom="8dp"> android:layout_marginBottom="8dp">
<TextView <TextView
android:layout_width="20dp" android:layout_width="20dp"