【问题标题】:Android Fingerprint - Crypto primitive not backed by AndroidKeyStore providerAndroid 指纹 - 不受 AndroidKeyStore 提供程序支持的加密原语
【发布时间】:2016-04-21 10:16:43
【问题描述】:

我正在尝试将 android Fingerprint 实现到示例应用程序中。 使用的密码未被识别为有效 - 但我不知道为什么,因为基于 android 文档,应该支持它。

密码建立在:

return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_RSA + "/" +KeyProperties.BLOCK_MODE_ECB + "/" + KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);

这个密码列在官方docs

后面用到的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)

【问题讨论】:

  • 你能把你的电话显示给KeyPairGenerator.getInstance吗?
  • 您的示例说您使用 getPrivateKey 初始化 Cipher,但它没有提供 getPrivateKey 的代码。请提供 getPrivateKey 的代码。
  • 谢谢迈克尔和亚历克斯 - 我想我添加了必要的细节。如果需要更多详细信息以及是否应该将课程上传到 github 或 gist,请告诉我。
  • 你能找到解决这个问题的方法吗?
  • 我能够在 Android M 和 RSA 上使用它,我认为您不需要使用 KeyFactory。查看此代码并对其进行调整以使用 RSA blog.stylingandroid.com/user-authentication-part-1

标签: android android-keystore android-security android-fingerprint-api


【解决方案1】:

我现在也遇到了同样的问题,新的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(又名不对称)加密方式是不同的。加密密钥和解密密钥不同。加密密钥是私钥,因此不需要以任何方式保护它。只有解密,私钥需要。

这就是为什么我们要进行加密,因为我们正试图打开生物识别身份验证提示来激活公钥,这是 noncence,因为公钥不是秘密。

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2016-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多