I have an encrypted password stored in the Android KeyStore.
I want to decrypt that password by authenticating the user using the fingerprint API.
As far as I understand, I have to call the FingerprintManager.authenticate(CryptoObject cryptoObject)
method to start listening for the fingerprint result. The CryptoObject parameter is created like this:
public static Cipher getDecryptionCipher(Context context) throws KeyStoreException {
try {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
SecretKey secretKey = getKeyFromKeyStore();
final IvParameterSpec ivParameterSpec = getIvParameterSpec(context);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
return cipher;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | IOException | UnrecoverableKeyException | CertificateException | InvalidAlgorithmParameterException | InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
Cipher cipher = FingerprintCryptoHelper.getDecryptionCipher(getContext());
FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);
fingerprintManager.authenticate(cryptoObject, ...);
The method getDecryptionCipher()
works correctly until the cipher.init()
call. On this call I get an UserNotAuthenticatedException
, because the user is not authenticated for this secretKey. Which makes sense somehow. But isn't this a loop, impossible to fulfill:
- To authenticate the user, I want to use his/her fingerprint
- To listen for his/her fingerprint, I need to init the Cipher, which in return needs an authenticated user
What's wrong here??
EDIT:
I work with the emulator (Nexus 4, API 23).
Here's the code I use to create the key.
private SecretKey createKey() {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
keyGenerator.init(new KeyGenParameterSpec.Builder(
KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(AUTHENTICATION_DURATION_SECONDS)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build());
return keyGenerator.generateKey();
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
throw new RuntimeException("Failed to create a symmetric key", e);
}
}