FingerprintManager.authenticate()期间发生UserNotAuthenticatedException

我有一个存储在Android KeyStore中的encryption密码。

我想通过使用指纹API对用户进行身份validation来解密该密码。

据我所知,我不得不调用FingerprintManager.authenticate(CryptoObject cryptoObject)方法来开始监听指纹结果。 CryptoObject参数是这样创build的:

 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 ,因为用户没有对这个UserNotAuthenticatedException身份validation。 不知何故,这是有道理的。 但是,这不是一个循环,不可能实现:

  • 为了validation用户,我想使用他/她的指纹
  • 为了听取他/她的指纹,我需要初始化密码,这需要经过authentication的用户

这里有什么问题?

    编辑:

    我使用模拟器(Nexus 4,API 23)。

    这是我用来创build密钥的代码。

     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); } } 

    Related of "FingerprintManager.authenticate()期间发生UserNotAuthenticatedException"

    事实certificate,这个问题与KeyGenParameterSpec一个已知问题有关,它可以防止在没有身份validation的情况下使用公钥(这正是公钥所不需要的)。

    相关的问题/答案可以在这里find: Android指纹APIencryption和解密

    解决方法是从最初创build的密钥创build一个PublicKey ,并使用这个不受限制的PublicKey来初始化密码。 所以我的最终密码使用AES / CBC / PKCS7Padding,并通过这种方法初始化:

     public boolean initCipher(int opMode) { try { Key key = mKeyStore.getKey(KEY_NAME, null); if (opMode == Cipher.ENCRYPT_MODE) { final byte[] encoded = key.getEncoded(); final String algorithm = key.getAlgorithm(); final X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded); PublicKey unrestricted = KeyFactory.getInstance(algorithm).generatePublic(keySpec); mCipher.init(opMode, unrestricted); } else { final IvParameterSpec ivParameterSpec = getIvParameterSpec(); mCipher.init(opMode, key, ivParameterSpec); } return true; } catch (KeyPermanentlyInvalidatedException exception) { return false; } catch ( NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | InvalidAlgorithmParameterException | UnrecoverableKeyException | KeyStoreException exception) { throw new RuntimeException("Failed to initialize Cipher or Key: ", exception); } } @NonNull public IvParameterSpec getIvParameterSpec() { // the IV is stored in the Preferences after encoding. String base64EncryptionIv = PreferenceHelper.getEncryptionIv(mContext); byte[] encryptionIv = Base64.decode(base64EncryptionIv, Base64.DEFAULT); return new IvParameterSpec(encryptionIv); }