指纹触摸三星手机后出错:android.security.KeyStoreException: Key user not authenticated

Error after Fingerprint touched on Samsung phones: android.security.KeyStoreException: Key user not authenticated

我的应用程序使用 Android 6.0 指纹 API 来保护 Android 密钥库中的 AES 密钥。存储的密钥只能在用户通过指纹传感器验证时使用,因为 KeyGenParameterSpec 是用 setUserAuthenticationRequired(true) 初始化的。

当用户触摸传感器时,我从回调 onAuthenticationSucceeded(Cipher) 中获取初始化密码,并将其用于解密。

除三星手机 Android 外,此功能完美无缺 6. 当我尝试使用返回的密码时,三星手机有时会抛出 android.security.KeyStoreException: Key user not authenticated。因此,即使密码由 onAuthenticationSucceeded(Cipher) 返回,Android KeyStore 仍认为用户未通过指纹传感器进行身份验证。

崩溃似乎是在应用程序长时间未使用时发生的。当应用程序启动时,通常一切正常。

因为这个错误是随机发生的,而且只发生在三星手机上...这似乎是由 Android 6.0 KeyStore 和 FingerPrint API 的三星实现内部的一些内部计时问题引起的。

编辑:OnePlus 和 Acer 手机也遇到过这个问题。

由于我不希望提到的制造商很快解决这个问题,我已经通过为三星、OnePlus、华硕和其他一些设备设置 KeyGenParameterSpec.setUserAuthenticationRequired(false) 解决了这个问题。

设置KeyGenParameterSpec.setUserAuthenticationRequired(false)可能是一个潜在的安全问题。上述错误的处理方式应类似于 KeyPermanentlyInvalidatedException。如果在创建您的 SecretKey 后添加新指纹,密码初始化 会抛出 KeyPermanentlyInvalidatedException。但是,如果在添加新指纹之前初始化了密码,当您尝试使用该密码 加密或解密 时,您将得到上述密钥用户未通过身份验证的 KeyStoreException。

重现此错误很容易。当您的应用程序的指纹验证屏幕处于后台时,请尝试添加新指纹。现在切换回应用程序,输入指纹,加密或解密方法会抛出此错误。我可以通过捕获异常并以与 KeyPermanentlyInvalidatedException 相同的方式处理它来解决这个问题。

不要听 "setUserAuthenticationRequired(false)"

我已经能够通过听两遍在三星上重现这一点。我认为正在发生的事情是,你听了两次,在一个电话上进行身份验证,但通过另一个电话引用它。

添加日志并检查您是否只开始监听一次指纹。

通过明确设置经过身份验证的密钥的有效期,它可以在我的 Samsung Galaxy S8 上运行:

setUserAuthenticationValidityDurationSeconds(10);

然而,这使得技术上可以在该时间跨度内多次使用密钥,而无需进一步的用户身份验证。

个人认为风险不大。

我没有测试过使用这些保护措施加密可能需要几秒钟才能完成的大型流。我想知道如果加密任务花费的时间超过有效期允许的时间会怎样

我也遇到过这个问题。在我的例子中,这是因为我不小心通过调用 FingerprintManager.authenticate() 两次启动了 two 并发指纹认证。一旦我删除了第二个调用,错误就消失了。

我在使用 RSA 时也遇到了这个问题,可以通过创建 public 密钥的副本来解决它,只要我想加密一些数据。

// create a copy of the public key -> workaround for android.security.KeyStoreException: Key user not authenticated
val publicKey = KeyFactory
    .getInstance("RSA")
    .generatePublic(X509EncodedKeySpec(keyPair.public.encoded))

// encrypt with the public key
val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.ENCRYPT_MODE, publicKey)
val encryptedData = cipher.doFinal(data)

更新: 这是 Android 8.0 的一个已知问题 https://issuetracker.google.com/issues/65578763

我刚刚在 Samsung 上看到这个错误,似乎是在添加新指纹时引起的。在我们的代码中,我们期望在 signature.initSign() 期间抛出 KeyPermenantlyInvalidatedException。这不会发生,初始化的签名在 CryptoObject 内部成功传递给 FingerprintManager。然后成功验证指纹并调用 onAuthenticationSucceeded。尝试调用 signature.update(byte[] bytes).

时发生错误

我认为的预期行为是 KeyInvalidatedException 实际上被抛出,但我不确定我们能否期望这个问题得到解决。我的解决方案是在 onAuthenticationSucceeded 端捕获它。

@Override
    public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
        Log.d(LOG_TAG, "Device Authentication Succeeded");
        try {
            Signature signature = result.getCryptoObject().getSignature();
            String authData = getAuthData();
            signature.update(authData.getBytes());
            // do something with signature

        } catch (SignatureException e) {
            Log.d(LOG_TAG, e.getMessage());
            if(e.getMessage() != null && e.getMessage().contains("Key user not authenticated")) {
                // handle as if were KeyPermanentlyInvalidatedException
            } else {
                Log.d(LOG_TAG, e.getMessage());
                // handle as regular error
            }
        }
    }

我在使用带有 android 8 的 Samsung Galaxy S8 时也遇到了这个问题。为了解决这个问题,我尝试从密钥库中删除密钥,然后生成一个新密钥,然后我使用新生成的密钥进行加密并解密数据

try {
    keyStore.deleteEntry(KEY_ALIAS);
} catch (KeyStoreException e) {
    e.printStackTrace();
}

这似乎是 Android 中的一个错误,在更新后出现。

我在 OnePlus 上安装过它。我从设置中删除了设备锁并重新设置。之后,问题就解决了。