6

我正在尝试将 android Fingerprint 实现到示例应用程序中。使用的密码不被认为是有效的 - 但我不知道为什么,因为基于 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:加密原语不受 AndroidKeyStore 提供者支持: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)
4

2 回答 2

2

我现在也遇到了同样的问题,新的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 密钥的 Symmetric Cryptographi。对于这种类型的密码学,密钥是唯一的,并且仅用于加密和解密,因此如果我们进行加密或解密,则需要通过生物认证来保护它。这就是为什么在所有示例中我们都看到此加密提示代码: biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))

但是使用 RSA(又名非对称)加密方式是不同的。加密密钥和解密密钥不同。加密密钥是私钥,因此不需要以任何方式保护它。只有解密,私钥需要。

这就是为什么我们在尝试打开生物识别身份验证提示以激活作为 noncence 的公钥时进行加密的原因,因为公钥不是秘密。

解决方案非常简单。只需调用authenticate不带CryptoObject( biometricPrompt.authenticate(promptInfo)) 的方法,稍后,当身份验证成功时,使用您的公钥进行加密。

希望这可以对某些人有所帮助,因为我找不到与该主题相关的任何信息,并且经过数小时的思考后,我才知道那里出了什么问题。

于 2021-03-08T12:08:17.427 回答
1

我遇到了同样的异常,我在指定密码提供者和其他人时修复了它;例如:

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);
于 2019-08-16T08:41:28.943 回答