diff --git a/app/src/main/java/com/keepassdroid/fingerprint/FingerPrintHelper.java b/app/src/main/java/com/keepassdroid/fingerprint/FingerPrintHelper.java
index 749b9c304..933699411 100644
--- a/app/src/main/java/com/keepassdroid/fingerprint/FingerPrintHelper.java
+++ b/app/src/main/java/com/keepassdroid/fingerprint/FingerPrintHelper.java
@@ -30,6 +30,7 @@ import android.support.annotation.RequiresApi;
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
import android.support.v4.os.CancellationSignal;
import android.util.Base64;
+import android.util.Log;
import java.io.IOException;
import java.security.KeyStore;
@@ -47,7 +48,9 @@ import javax.crypto.spec.IvParameterSpec;
@RequiresApi(api = Build.VERSION_CODES.M)
public class FingerPrintHelper {
- private static final String FINGERPRINT_KEYSTORE_KEY = "example-key";
+ private static final String TAG = FingerPrintHelper.class.getName();
+
+ private static final String FINGERPRINT_KEYSTORE_KEY = "com.kunzisoft.keepass.fingerprint.key";
private FingerprintManagerCompat fingerprintManager;
private KeyStore keyStore = null;
@@ -65,8 +68,7 @@ public class FingerPrintHelper {
this.authenticationCallback = authenticationCallback;
}
- public void startListening() {
-
+ public synchronized void startListening() {
// starts listening for fingerprints with the initialised crypto object
cancellationSignal = new CancellationSignal();
fingerprintManager.authenticate(
@@ -77,7 +79,7 @@ public class FingerPrintHelper {
null);
}
- public void stopListening() {
+ public synchronized void stopListening() {
if (!isFingerprintInitialized(false)) {
return;
}
@@ -113,6 +115,7 @@ public class FingerPrintHelper {
this.cryptoObject = new FingerprintManagerCompat.CryptoObject(cipher);
setInitOk(true);
} catch (final Exception e) {
+ Log.e(TAG, "Unable to initialize the keystore", e);
setInitOk(false);
fingerPrintCallback.onFingerPrintException(e);
}
@@ -142,6 +145,8 @@ public class FingerPrintHelper {
return;
}
try {
+ stopListening();
+
createNewKeyIfNeeded(false); // no need to keep deleting existing keys
keyStore.load(null);
final SecretKey key = (SecretKey) keyStore.getKey(FINGERPRINT_KEYSTORE_KEY, null);
@@ -149,10 +154,13 @@ public class FingerPrintHelper {
startListening();
} catch (final UnrecoverableKeyException unrecoverableKeyException) {
+ Log.e(TAG, "Unable to initialize encrypt data", unrecoverableKeyException);
deleteEntryKey();
} catch (final KeyPermanentlyInvalidatedException invalidKeyException) {
+ Log.e(TAG, "Unable to initialize encrypt data", invalidKeyException);
fingerPrintCallback.onInvalidKeyException(invalidKeyException);
} catch (final Exception e) {
+ Log.e(TAG, "Unable to initialize encrypt data", e);
fingerPrintCallback.onFingerPrintException(e);
}
}
@@ -164,14 +172,15 @@ public class FingerPrintHelper {
try {
// actual do encryption here
byte[] encrypted = cipher.doFinal(value.getBytes());
- final String encryptedValue = Base64.encodeToString(encrypted, Base64.DEFAULT);
+ final String encryptedValue = Base64.encodeToString(encrypted, Base64.NO_WRAP);
// passes updated iv spec on to callback so this can be stored for decryption
final IvParameterSpec spec = cipher.getParameters().getParameterSpec(IvParameterSpec.class);
- final String ivSpecValue = Base64.encodeToString(spec.getIV(), Base64.DEFAULT);
+ final String ivSpecValue = Base64.encodeToString(spec.getIV(), Base64.NO_WRAP);
fingerPrintCallback.handleEncryptedResult(encryptedValue, ivSpecValue);
} catch (final Exception e) {
+ Log.e(TAG, "Unable to encrypt data", e);
fingerPrintCallback.onFingerPrintException(e);
}
}
@@ -181,21 +190,26 @@ public class FingerPrintHelper {
return;
}
try {
+ stopListening();
+
createNewKeyIfNeeded(false);
keyStore.load(null);
final SecretKey key = (SecretKey) keyStore.getKey(FINGERPRINT_KEYSTORE_KEY, null);
// important to restore spec here that was used for decryption
- final byte[] iv = Base64.decode(ivSpecValue, Base64.DEFAULT);
+ final byte[] iv = Base64.decode(ivSpecValue, Base64.NO_WRAP);
final IvParameterSpec spec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
startListening();
- } catch (final KeyPermanentlyInvalidatedException invalidKeyException) {
- fingerPrintCallback.onInvalidKeyException(invalidKeyException);
} catch (final UnrecoverableKeyException unrecoverableKeyException) {
+ Log.e(TAG, "Unable to initialize decrypt data", unrecoverableKeyException);
deleteEntryKey();
+ } catch (final KeyPermanentlyInvalidatedException invalidKeyException) {
+ Log.e(TAG, "Unable to initialize decrypt data", invalidKeyException);
+ fingerPrintCallback.onInvalidKeyException(invalidKeyException);
} catch (final Exception e) {
+ Log.e(TAG, "Unable to initialize decrypt data", e);
fingerPrintCallback.onFingerPrintException(e);
}
}
@@ -206,15 +220,17 @@ public class FingerPrintHelper {
}
try {
// actual decryption here
- final byte[] encrypted = Base64.decode(encryptedValue, Base64.DEFAULT);
+ final byte[] encrypted = Base64.decode(encryptedValue, Base64.NO_WRAP);
byte[] decrypted = cipher.doFinal(encrypted);
final String decryptedString = new String(decrypted);
//final String encryptedString = Base64.encodeToString(encrypted, 0 /* flags */);
fingerPrintCallback.handleDecryptedResult(decryptedString);
} catch (final BadPaddingException badPaddingException) {
+ Log.e(TAG, "Unable to decrypt data", badPaddingException);
fingerPrintCallback.onInvalidKeyException(badPaddingException);
} catch (final Exception e) {
+ Log.e(TAG, "Unable to decrypt data", e);
fingerPrintCallback.onFingerPrintException(e);
}
}
@@ -249,6 +265,7 @@ public class FingerPrintHelper {
keyGenerator.generateKey();
}
} catch (final Exception e) {
+ Log.e(TAG, "Unable to create a key in keystore", e);
fingerPrintCallback.onFingerPrintException(e);
}
}
@@ -262,6 +279,7 @@ public class FingerPrintHelper {
| NoSuchAlgorithmException
| IOException
| NullPointerException e) {
+ Log.e(TAG, "Unable to delete entry key in keystore", e);
if (fingerPrintCallback != null)
fingerPrintCallback.onFingerPrintException(e);
}
diff --git a/app/src/main/java/com/keepassdroid/password/PasswordActivity.java b/app/src/main/java/com/keepassdroid/password/PasswordActivity.java
index 265434f76..038ad9cce 100644
--- a/app/src/main/java/com/keepassdroid/password/PasswordActivity.java
+++ b/app/src/main/java/com/keepassdroid/password/PasswordActivity.java
@@ -89,6 +89,8 @@ import static com.keepassdroid.fingerprint.FingerPrintHelper.Mode.STORE_MODE;
public class PasswordActivity extends StylishActivity
implements FingerPrintHelper.FingerPrintCallback, UriIntentInitTaskCallback {
+ private static final String TAG = PasswordActivity.class.getName();
+
public static final String KEY_DEFAULT_FILENAME = "defaultFileName";
private static final String KEY_PASSWORD = "password";
@@ -440,7 +442,7 @@ public class PasswordActivity extends StylishActivity
if ( !fingerprintMustBeConfigured ) {
final boolean validInput = s.length() > 0;
// encrypt or decrypt mode based on how much input or not
- setFingerPrintTextView(validInput ? R.string.store_with_fingerprint : R.string.scanning_fingerprint);
+ setFingerPrintView(validInput ? R.string.store_with_fingerprint : R.string.scanning_fingerprint);
if (validInput)
toggleFingerprintMode(STORE_MODE);
else
@@ -455,22 +457,30 @@ public class PasswordActivity extends StylishActivity
public void onAuthenticationError(
final int errorCode,
final CharSequence errString) {
- Log.i(getClass().getName(), errString.toString());
+ switch (errorCode) {
+ case 5:
+ Log.i(TAG, "Fingerprint authentication error. Code : " + errorCode + " Error : " + errString);
+ break;
+ default:
+ Log.e(TAG, "Fingerprint authentication error. Code : " + errorCode + " Error : " + errString);
+ setFingerPrintView(errString.toString(), true);
+ }
}
@Override
public void onAuthenticationHelp(
final int helpCode,
final CharSequence helpString) {
+ Log.w(TAG, "Fingerprint authentication help. Code : " + helpCode + " Help : " + helpString);
showError(helpString);
- reInitWithSameFingerprintMode();
+ setFingerPrintView(helpString.toString(), true);
fingerprintTextView.setText(helpString);
}
@Override
public void onAuthenticationFailed() {
+ Log.e(TAG, "Fingerprint authentication failed, fingerprint not recognized");
showError(R.string.fingerprint_not_recognized);
- reInitWithSameFingerprintMode();
}
@Override
@@ -504,7 +514,7 @@ public class PasswordActivity extends StylishActivity
@RequiresApi(api = Build.VERSION_CODES.M)
private void initEncryptData() {
- setFingerPrintTextView(R.string.store_with_fingerprint);
+ setFingerPrintView(R.string.store_with_fingerprint);
fingerPrintMode = STORE_MODE;
if (fingerPrintHelper != null)
fingerPrintHelper.initEncryptData();
@@ -512,7 +522,7 @@ public class PasswordActivity extends StylishActivity
@RequiresApi(api = Build.VERSION_CODES.M)
private void initDecryptData() {
- setFingerPrintTextView(R.string.scanning_fingerprint);
+ setFingerPrintView(R.string.scanning_fingerprint);
fingerPrintMode = OPEN_MODE;
if (fingerPrintHelper != null) {
final String ivSpecValue = prefsNoBackup.getString(getPreferenceKeyIvSpec(), null);
@@ -525,12 +535,12 @@ public class PasswordActivity extends StylishActivity
private synchronized void toggleFingerprintMode(final FingerPrintHelper.Mode newMode) {
if( !newMode.equals(fingerPrintMode) ) {
fingerPrintMode = newMode;
- reInitWithSameFingerprintMode();
+ reInitWithFingerprintMode();
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
- private synchronized void reInitWithSameFingerprintMode() {
+ private synchronized void reInitWithFingerprintMode() {
switch (fingerPrintMode) {
case STORE_MODE:
initEncryptData();
@@ -545,8 +555,6 @@ public class PasswordActivity extends StylishActivity
@Override
protected void onPause() {
- super.onPause();
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (fingerPrintAnimatedVector != null) {
fingerPrintAnimatedVector.stopScan();
@@ -557,18 +565,33 @@ public class PasswordActivity extends StylishActivity
fingerPrintHelper.stopListening();
}
}
+ super.onPause();
}
private void setFingerPrintVisibility(final int vis) {
runOnUiThread(() -> fingerprintContainerView.setVisibility(vis));
}
- private void setFingerPrintTextView(final int textId) {
- runOnUiThread(() -> fingerprintTextView.setText(textId));
+ private void setFingerPrintView(final int textId) {
+ setFingerPrintView(textId, false);
}
- private void setFingerPrintAlphaImageView(final float alpha) {
- runOnUiThread(() -> fingerprintContainerView.setAlpha(alpha));
+ private void setFingerPrintView(final CharSequence text) {
+ setFingerPrintView(text, false);
+ }
+
+ private void setFingerPrintView(final int textId, boolean lock) {
+ setFingerPrintView(getString(textId), lock);
+ }
+
+ private void setFingerPrintView(final CharSequence text, boolean lock) {
+ runOnUiThread(() -> {
+ if (lock) {
+ fingerprintContainerView.setAlpha(0.6f);
+ } else
+ fingerprintContainerView.setAlpha(1f);
+ fingerprintTextView.setText(text);
+ });
}
@RequiresApi(api = Build.VERSION_CODES.M)
@@ -589,18 +612,16 @@ public class PasswordActivity extends StylishActivity
setFingerPrintVisibility(View.VISIBLE);
if (!fingerPrintHelper.hasEnrolledFingerprints()) {
- setFingerPrintAlphaImageView(0.6f);
// This happens when no fingerprints are registered. Listening won't start
- setFingerPrintTextView(R.string.configure_fingerprint);
+ setFingerPrintView(R.string.configure_fingerprint, true);
}
// finally fingerprint available and configured so we can use it
else {
fingerprintMustBeConfigured = false;
- setFingerPrintAlphaImageView(1f);
// fingerprint available but no stored password found yet for this DB so show info don't listen
if (!prefsNoBackup.contains(getPreferenceKeyValue())) {
- setFingerPrintTextView(R.string.no_password_stored);
+ setFingerPrintView(R.string.no_password_stored);
// listen for encryption
initEncryptData();
}
@@ -616,7 +637,7 @@ public class PasswordActivity extends StylishActivity
invalidateOptionsMenu();
}
- private void removePrefsNoBackupKeys() {
+ private void removePrefsNoBackupKey() {
prefsNoBackup.edit()
.remove(getPreferenceKeyValue())
.remove(getPreferenceKeyIvSpec())
@@ -632,7 +653,7 @@ public class PasswordActivity extends StylishActivity
.putString(getPreferenceKeyIvSpec(), ivSpec)
.apply();
verifyAllViewsAndLoadDatabase();
- setFingerPrintTextView(R.string.encrypted_value_stored);
+ setFingerPrintView(R.string.encrypted_value_stored);
}
@Override
@@ -644,22 +665,27 @@ public class PasswordActivity extends StylishActivity
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onInvalidKeyException(Exception e) {
- showError(R.string.fingerprint_invalid_key);
- removePrefsNoBackupKeys();
- e.printStackTrace();
- reInitWithSameFingerprintMode(); // restarts listening
+ showError(getString(R.string.fingerprint_invalid_key));
+ deleteEntryKey();
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onFingerPrintException(Exception e) {
- showError(R.string.fingerprint_error);
- e.printStackTrace();
- reInitWithSameFingerprintMode();
+ showError(getString(R.string.fingerprint_error, e.getMessage()));
+ setFingerPrintView(e.getLocalizedMessage(), true);
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.M)
+ private void deleteEntryKey() {
+ fingerPrintHelper.deleteEntryKey();
+ removePrefsNoBackupKey();
+ fingerPrintMode = NOT_CONFIGURED_MODE;
+ checkFingerprintAvailability();
}
private void showError(final int messageId) {
- runOnUiThread(() -> Toast.makeText(getApplicationContext(), messageId, Toast.LENGTH_SHORT).show());
+ showError(getString(messageId));
}
private void showError(final CharSequence message) {
@@ -753,10 +779,7 @@ public class PasswordActivity extends StylishActivity
break;
case R.id.menu_fingerprint_remove_key:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- fingerPrintHelper.deleteEntryKey();
- removePrefsNoBackupKeys();
- fingerPrintMode = NOT_CONFIGURED_MODE;
- checkFingerprintAvailability();
+ deleteEntryKey();
}
break;
default:
@@ -793,11 +816,8 @@ public class PasswordActivity extends StylishActivity
// Recheck fingerprint if error
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- //setEmptyViews();
- //mMessage = getString(R.string.fingerprint_error) + " : " + mMessage;
- // TODO Change fingerprint message
// Stay with the same mode
- reInitWithSameFingerprintMode();
+ reInitWithFingerprintMode();
}
if (db.passwordEncodingError) {
diff --git a/app/src/main/java/com/keepassdroid/settings/NestedSettingsFragment.java b/app/src/main/java/com/keepassdroid/settings/NestedSettingsFragment.java
index affc89de5..cb1269262 100644
--- a/app/src/main/java/com/keepassdroid/settings/NestedSettingsFragment.java
+++ b/app/src/main/java/com/keepassdroid/settings/NestedSettingsFragment.java
@@ -131,16 +131,13 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
if (!fingerprintSupported) {
// False if under Marshmallow
fingerprintEnablePreference.setChecked(false);
- fingerprintEnablePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- FragmentManager fragmentManager = getFragmentManager();
- assert fragmentManager != null;
- ((SwitchPreference) preference).setChecked(false);
- UnavailableFeatureDialogFragment.getInstance(Build.VERSION_CODES.M)
- .show(getFragmentManager(), "unavailableFeatureDialog");
- return false;
- }
+ fingerprintEnablePreference.setOnPreferenceClickListener(preference -> {
+ FragmentManager fragmentManager = getFragmentManager();
+ assert fragmentManager != null;
+ ((SwitchPreference) preference).setChecked(false);
+ UnavailableFeatureDialogFragment.getInstance(Build.VERSION_CODES.M)
+ .show(getFragmentManager(), "unavailableFeatureDialog");
+ return false;
});
}
@@ -148,45 +145,39 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
if (!fingerprintSupported) {
deleteKeysFingerprints.setEnabled(false);
} else {
- deleteKeysFingerprints.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- new AlertDialog.Builder(getContext())
- .setMessage(getResources().getString(R.string.fingerprint_delete_all_warning))
- .setIcon(getResources().getDrawable(
- android.R.drawable.ic_dialog_alert))
- .setPositiveButton(
- getResources().getString(android.R.string.yes),
- new DialogInterface.OnClickListener() {
- @RequiresApi(api = Build.VERSION_CODES.M)
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- FingerPrintHelper.deleteEntryKeyInKeystoreForFingerprints(
- getContext(),
- new FingerPrintHelper.FingerPrintErrorCallback() {
- @Override
- public void onInvalidKeyException(Exception e) {
- }
+ deleteKeysFingerprints.setOnPreferenceClickListener(preference -> {
+ new AlertDialog.Builder(getContext())
+ .setMessage(getResources().getString(R.string.fingerprint_delete_all_warning))
+ .setIcon(getResources().getDrawable(
+ android.R.drawable.ic_dialog_alert))
+ .setPositiveButton(
+ getResources().getString(android.R.string.yes),
+ new DialogInterface.OnClickListener() {
+ @RequiresApi(api = Build.VERSION_CODES.M)
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ FingerPrintHelper.deleteEntryKeyInKeystoreForFingerprints(
+ getContext(),
+ new FingerPrintHelper.FingerPrintErrorCallback() {
+ @Override
+ public void onInvalidKeyException(Exception e) {}
- @Override
- public void onFingerPrintException(Exception e) {
- Toast.makeText(getContext(), R.string.fingerprint_error, Toast.LENGTH_SHORT).show();
- }
- });
- PreferencesUtil.deleteAllValuesFromNoBackupPreferences(getContext());
- }
- })
- .setNegativeButton(
- getResources().getString(android.R.string.no),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- }
- }).show();
- return false;
- }
+ @Override
+ public void onFingerPrintException(Exception e) {
+ Toast.makeText(getContext(),
+ getString(R.string.fingerprint_error, e.getLocalizedMessage()),
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+ PreferencesUtil.deleteAllValuesFromNoBackupPreferences(getContext());
+ }
+ })
+ .setNegativeButton(
+ getResources().getString(android.R.string.no),
+ (dialog, which) -> {
+ }).show();
+ return false;
});
}
break;
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index eb1238bb7..2c6ccc6c8 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -188,9 +188,9 @@
Reconnaissance d\'empreinte digitale non configuré pour cet appareil
Attente d\'une reconnaissance d\'empreinte digitale
Mot de passe encrypté stocké
- Problème de clé invalide
+ Problème de clé invalide. Restaurez votre mot de passe.
Empreinte digitale non reconnue
- Problème d\'empreinte digitale
+ Problème d\'empreinte digitale : %1$s
Utiliser l\'empreinte digitale pour stocker le mot de passe
Pas de mot de passe encore stocké pour cette base de données
Historique
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 02ece7439..39ada7f59 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -161,8 +161,8 @@
Az ujjlenyomat használat nincs még beállítva az eszközön
Várakozás az ujjelnyomat megadására
Titkosított jelszó elmentve
- Érvénytelen kulcs
- Érvénytelen ujjlenyomat
+ Érvénytelen kulcs. Helyezze vissza jelszavát.
+ Érvénytelen ujjlenyomat : %1$s
Használjon ujjlenyomatot a jelszó elmentéséhez
Nincs még jelszó beállítva ehhez az adatbázishoz
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 0ebe07f66..78ecddc1a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -188,9 +188,9 @@
Fingerprint supported but not configured for device
Listening for fingerprints
Encrypted password stored
- Invalid Key problem
+ Invalid fingerprint key problem. Restore your password.
Fingerprint not recognized
- Fingerprint problem
+ Fingerprint problem : %1$s
Use fingerprint to store this password
No password stored yet for this database
History