我正在尝试将android指纹实现到示例应用程序中。使用的密码不被认为是有效的 - 但我不知道为什么,因为基于 android 文档,它应该得到支持。
密码建立在:
return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_RSA + "/" +KeyProperties.BLOCK_MODE_ECB + "/" + KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
此密码在官方文档中列出。
稍后使用的 keyGenerator 和 keyFactory 生成如下。
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null); // Ensure the key store can be loaded before continuing.
keyGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
keyFactory = KeyFactory.getInstance("RSA");
createCipher(); // If this doesn't throw, the cipher we need is available.
我还使用该密码初始化密钥生成器:
keyGenerator.initialize(new KeyGenParameterSpec.Builder(keyAlias,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) //
.setBlockModes(KeyProperties.BLOCK_MODE_ECB) //
.setUserAuthenticationRequired(true) //
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) //
.build());
keyGenerator.generateKeyPair();
我还在加密过程中添加了公钥,而公钥是这样生成的:
private PublicKey getPublicKey() throws GeneralSecurityException {
PublicKey publicKey = keyStore.getCertificate(keyAlias).getPublicKey();
KeySpec spec = new X509EncodedKeySpec(publicKey.getEncoded());
return keyFactory.generatePublic(spec);
}
编辑:添加了私钥的一部分:
PrivateKey getPrivateKey() throws GeneralSecurityException {
return (PrivateKey) keyStore.getKey(keyAlias, null);
}
然后,实际的指纹处理如下:
Cipher cipher = createCipher();
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey());
fingerprintManager.authenticate(new FingerprintManager.CryptoObject(cipher), cancellationSignal,
0, new FingerprintManager.AuthenticationCallback() {/* cutted */ }, null);
解密:
cipher = createCipher();
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey());
fingerprintManager.authenticate(new FingerprintManager.CryptoObject(cipher), cancellationSignal, 0, new FingerprintManager.AuthenticationCallback() {}, null);
结果如下:
进程: com.example.android.fingerprintdialog, PID: 16254 java.lang.IllegalArgumentException: Crypto primitive not under AndroidKeyStore provider: javax.crypto.Cipher@2419dda, spi: com.android.org.conscrypt.OpenSSLCipherRSA$PKCS1@4a4d20b
完整堆栈跟踪:
04-21 11:48:00.031 16254-16254/com.example.android.fingerprintdialog E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.fingerprintdialog, PID: 16254
java.lang.IllegalArgumentException: Crypto primitive not backed by AndroidKeyStore provider: javax.crypto.Cipher@2419dda, spi: com.android.org.conscrypt.OpenSSLCipherRSA$PKCS1@4a4d20b
at android.security.keystore.AndroidKeyStoreProvider.getKeyStoreOperationHandle(AndroidKeyStoreProvider.java:160)
at android.hardware.fingerprint.FingerprintManager$CryptoObject.getOpId(FingerprintManager.java:248)
at android.hardware.fingerprint.FingerprintManager.authenticate(FingerprintManager.java:468)
at android.hardware.fingerprint.FingerprintManager.authenticate(FingerprintManager.java:429)
at com.example.android.fingerprintdialog.MainActivity.tryToEncrypt(MainActivity.java:212)
at com.example.android.fingerprintdialog.MainActivity.access$000(MainActivity.java:61)
我现在也有同样的问题,有新的androidx.biometric
.在尝试执行生物识别身份验证以进行加密时,我遇到了完全相同的错误,例如:
val cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_RSA + "/"
+ KeyProperties.BLOCK_MODE_ECB + "/"
+ KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(KeyFactory.getInstance(KeyProperties.KEY_ALGORITHM_RSA), keyStore))
biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))
getPublicKey
方法和所有其他参数等效于作者列出的参数。
然后我感到我们做错了。
我在本主题中可以找到的所有示例都使用带有 AES 密钥的对称加密图形。对于这种类型的加密,密钥仅用于加密和解密,因此,如果我们进行加密或解密,则需要使用生物识别身份验证进行保护。这就是为什么在所有示例中我们都会看到此加密代码提示: biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))
但是有了RSA(又名。非对称)加密是不同的。加密密钥和解密密钥不同。加密密钥是私钥,因此不需要以任何方式对其进行保护。只有解密,私钥需要。
这就是为什么我们在尝试打开生物识别身份验证提示以激活公钥时获得加密的原因,这是随机数,因为公钥不是秘密。
解决方案非常简单。只需调用没有CryptoObject
( biometricPrompt.authenticate(promptInfo)
) 的 authenticate
方法,稍后,当身份验证成功时,使用您的 publik 密钥进行加密。
希望这可以对某人有所帮助,因为我找不到与此主题相关的任何信息,并且经过几个小时的思考,我才知道那里出了什么问题。
我遇到了同样的异常,当我指定密码提供者和其他提供者时,我修复了它;例如:
String alg = "AES";
Cipher cipher = Cipher.getInstance(alg, "SunJCE");
KeyGenerator generator = KeyGenerator.getInstance(alg, "SunJCE");
SecretKey key = generator.generateKey();
cipher.init(Cipher.ENCRYPT_MODE, key);