初始化FingerpringManager.Crypto对象,得到没有AndroidKeyStore提供程序支持的Crypto原语?

我正在使用Android FingerPrintManager API并使用KeyPairGenerator创建密钥对,我想使用公钥加密密码,然后通过委托fingerPrint对用户进行身份validation进行解密,但是一旦我运行我的项目就会崩溃并给出

引起:java.lang.IllegalArgumentException:没有AndroidKeyStore提供者支持的Crypto原语

我从这里使用了代码: Android指纹API加密和解密这篇文章说他能够进行ecryption和解密,并且遵循相同的代码和步骤。 这是我的代码

 public KeyStore getKeyStore() { try { return KeyStore.getInstance("AndroidKeyStore"); } catch (KeyStoreException exception) { throw new RuntimeException("Failed to get an instance of KeyStore", exception); } } public KeyPairGenerator getKeyPairGenerator() { try { return KeyPairGenerator.getInstance("RSA", "AndroidKeyStore"); } catch (NoSuchAlgorithmException | NoSuchProviderException exception) { throw new RuntimeException("Failed to get an instance of KeyPairGenerator", exception); } } public Cipher getCipher() { try { return Cipher.getInstance("RSA"); } catch (NoSuchAlgorithmException | NoSuchPaddingException exception) { throw new RuntimeException("Failed to get an instance of Cipher", exception); } } private void createKeyPair() { try { mKeyPairGenerator = getKeyPairGenerator(); mKeyPairGenerator.initialize( new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_DECRYPT) .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP) .setUserAuthenticationRequired(true) .build()); mKeyPairGenerator.generateKeyPair(); } catch (InvalidAlgorithmParameterException exception) { throw new RuntimeException(exception); } } private boolean initCipher(int opmode) { try { mKeyStore = getKeyStore(); mKeyStore.load(null); mCipher = getCipher(); if (opmode == Cipher.ENCRYPT_MODE) { PublicKey key = mKeyStore.getCertificate(KEY_NAME).getPublicKey(); PublicKey unrestricted = KeyFactory.getInstance(key.getAlgorithm()) .generatePublic(new X509EncodedKeySpec(key.getEncoded())); OAEPParameterSpec spec = new OAEPParameterSpec( "SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); mCipher.init(opmode, unrestricted, spec); } else { PrivateKey key = (PrivateKey) mKeyStore.getKey(KEY_NAME, null); mCipher.init(opmode, key); } return true; } catch (KeyPermanentlyInvalidatedException exception) { return false; } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException | NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | InvalidAlgorithmParameterException exception) { throw new RuntimeException("Failed to initialize Cipher", exception); } } private void encrypt(String password) { try { initCipher(Cipher.ENCRYPT_MODE); byte[] bytes = mCipher.doFinal(password.getBytes()); enrcyptedPassword = Base64.encodeToString(bytes, Base64.NO_WRAP); Log.d("EncryptedText", enrcyptedPassword); } catch (IllegalBlockSizeException | BadPaddingException exception) { throw new RuntimeException("Failed to encrypt password", exception); } } private String decryptPassword(Cipher cipher) { try { initCipher(Cipher.DECRYPT_MODE); byte[] bytes = Base64.decode(enrcyptedPassword, Base64.NO_WRAP); return new String(cipher.doFinal(bytes)); } catch (IllegalBlockSizeException | BadPaddingException | RuntimeException exception) { throw new RuntimeException("Failed to decrypt password", exception); } } 

从这里我正在初始化我的CryptoObject:

 createKeyPair(); if (initCipher(Cipher.ENCRYPT_MODE)) { mCryptoObject = new FingerprintManager.CryptoObject (mCipher); encrypt("1111"); if (!isFingerprintAuthAvailable()) { return; } mCancellationSignal = new CancellationSignal(); mSelfCancelled = false; mFingerprintManager.authenticate(mCryptoObject, mCancellationSignal, 0 /* flags */, this, null); 

我在这一行得到例外:

 mFingerprintManager.authenticate(mCryptoObject, mCancellationSignal, 0 /* flags */, this, null); 

@AlexKlyubin是对的,你不需要使用指纹管理器进行加密,只需要解密。 为了加密文本,您需要做的就是调用上面的encrypt(String password)方法。

对于解密,您应该使用FingerprintManagerCompat而不是FingerprintManager 。 为了侦听指纹事件并解密密码,您需要扩展FingerprintManagerCompat.AuthenticationCallback 。 我扩展了这个类,并实现了一个回调接口:

 public class FingerprintAuthentication extends FingerprintManagerCompat.AuthenticationCallback { private final Callback mCallback; public FingerprintCallback(Callback callback) { mCallback = callback; } @Override public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) { mCallback.onAuthenticationSucceeded(result); } @Override public void onAuthenticationHelp(int messageId, CharSequence message) { mCallback.onAuthenticationHelp(messageId, message); } @Override public void onAuthenticationError(int messageId, CharSequence message) { mCallback.onAuthenticationError(messageId, message); } @Override public void onAuthenticationFailed() { mCallback.onAuthenticationFailed(); } public interface Callback { void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result); void onAuthenticationHelp(int messageId, CharSequence message); void onAuthenticationError(int messageId, CharSequence message); void onAuthenticationFailed(); } } 

有了这个,您可以在FragmentActivity实现Callback接口,然后开始侦听事件:

 private void startListening(boolean cipher) { Timber.v("Start listening for fingerprint input"); mCancellationSignal = new CancellationSignal(); if(cipher) { mFingerprintManager.authenticate(new FingerprintManagerCompat.CryptoObject(mCipher), 0, mCancellationSignal, new FingerprintAuthentication(this), null); } else { setStage(Stage.CREDENTIALS); } } 

最后,只有在指纹认证成功后才能解密密码:

 @Override public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) { try { mPassword = decryptPassword(result.getCryptoObject().getCipher()); } catch (IllegalBlockSizeException | BadPaddingException exception) { exception.printStackTrace(); } } 

基本上,当用户首次登录时,您希望为他们显示“将来使用指纹”的选项:

在此处输入图像描述

如果用户选择此选项并单击login,则在调用encrypt() 。 然后,下次要求用户登录时,您将显示指纹对话框:

在此处输入图像描述

这是当你调用startListening(initializeCipher(Cipher.DECRYPT_MODE))

在加密模式下,您使用不是Android Keystore密钥的公钥( unrestricted )初始化Cipher实例。 要解决此问题,您可以使用Android Keystore公钥(即mKeyStore.getCertificate(KEY_NAME).getPublicKey()而不是unrestricted mKeyStore.getCertificate(KEY_NAME).getPublicKey()

但是,通过在用户授权上添加公钥加密,您不清楚会得到什么。 任何人都可以在没有用户授权的情况下执行加密操作,因为加密使用的公钥根据定义并非秘密。 在非对称加密中,涉及私钥的唯一操作(根据定义未公开)是解密和签名。 因此,通常只有在解密或签署用户授权时才有意义。