触摸三星手机上的指纹后出错:android.security.KeyStoreException:未经过身份验证的密钥用户

时间:2016-03-16 18:20:21

标签: android encryption android-6.0-marshmallow fingerprint android-keystore

我的应用使用Android 6.0指纹API来保护Android KeyStore中的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手机也遇到过这个问题。

10 个答案:

答案 0 :(得分:16)

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

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

答案 1 :(得分:6)

请勿收听“setUserAuthenticationRequired(false)”

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

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

答案 2 :(得分:4)

由于我不认为上述制造商会尽快解决这个问题,我已经通过为三星,OnePlus,华硕和其他一些设备设置KeyGenParameterSpec.setUserAuthenticationRequired(false)来解决这个问题。

答案 3 :(得分:3)

我也遇到过这个问题。在我的情况下,这是因为我通过两次调用FingerprintManager.authenticate()意外地启动了两个并发指纹认证。我删除了第二个电话后错误消失了。

答案 4 :(得分:2)

在将Samsung Galaxy S8与android 8配合使用时,我也遇到了这个问题。为解决此问题,我只是从密钥库中删除了密钥,并在生成新密钥之后使用新密钥对数据进行加密和解密

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

答案 5 :(得分:1)

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

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

答案 6 :(得分:1)

更新:这是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
            }
        }
    }

答案 7 :(得分:0)

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

setUserAuthenticationValidityDurationSeconds(10);

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

就我个人而言,我认为这不是一个很大的风险。

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

答案 8 :(得分:0)

无论是否由于三星的错误而随机发生。每次通过添加新指纹或其他原因使密钥失效时。下一步是使用KeyStore.delete(keyAlias)从KeyStore中删除无效密钥,并清除旧数据,因为删除加密密钥后无法解密。然后要求用户输入新凭据并使用新密钥对其进行加密。新密钥可以与旧密钥具有相同的别名。您可以在此处查看流程示例:Sample of a class wrapping the FingerprintManager flow in Android

答案 9 :(得分:0)

这似乎是更新后出现的Android中的错误。

我在OnePlus上拥有它。我从设置中删除了设备锁,然后重新设置。之后,问题就消失了。