我有一个加密的密码存储在android密钥库中。
我想通过使用指纹api对用户进行身份验证来解密该密码。
据我所知,我必须调用FingerprintManager.authenticate(CryptoObject cryptoObject)方法来开始监听指纹结果。CryptoObject参数的创建方式如下:

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, ...);

方法getDecryptionCipher()正常工作,直到调用cipher.init()为止。在这个调用中,我得到一个UserNotAuthenticatedException,因为用户没有为此secretkey进行身份验证。这是有道理的。但这不是一个循环,不可能实现:
要验证用户身份,我想使用他/她的指纹
为了监听他/她的指纹,我需要初始化密码,作为回报,密码需要经过身份验证的用户
这里怎么了??
编辑:
我使用模拟器(nexus 4,api 23)。
这是我用来创建密钥的代码。
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);
    }
}

最佳答案

我找到了逃过22号陷阱的方法!
你这样做:
你像往常一样
如果没有try{(因为用户在密钥的有效期内通过了身份验证,即因为他几秒钟前解锁了设备),则执行加密/解密例程。结束!
您捕获了.init-使用Cipher运行UserNotAuthenticatedException工作流(是!)UserNotAuthenticatedException,然后在FingerprintManager.authenticate回调中再次初始化密码(是!),但这次它不会抛出null并使用这个初始化的实例来加密/解密(回调返回CryptoObject,正如我们用onAuthenticationSucceededcryptoobject调用它一样,因此我们不能使用它)。结束!
就这么简单…
但我花了两天的时间才找到这个方法。更不用说-似乎所有在线认证示例都是错误的!

07-24 15:27