首页 文章

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

提问于
浏览
13

我的应用程序使用Android 6.0 Fingerprint 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的三星实现中的一些内部时序问题引起的 .

Edit :OnePlus和Acer手机也遇到过这个问题 .

9 回答

  • 1

    不要听“setUserAuthenticationRequired(false)”

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

    添加日志并检查您是否只开始只扫描一次指纹 .

  • 0

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

  • 4

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

  • 1

    设置 KeyGenParameterSpec.setUserAuthenticationRequired(false) 可能是一个潜在的安全问题 . 应该类似于 KeyPermanentlyInvalidatedException 处理上述错误 . 如果在创建SecretKey后添加新指纹,则会在Cipher初始化时引发KeyPermanentlyInvalidatedException . 但是,如果在添加新指纹之前初始化密码,则'll get the above KeyStoreException for Key User not authenticated, when you'尝试使用该密码进行加密或解密 .

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

  • 15

    当使用三星Galaxy S8和Android 8时,我也遇到了这个问题 . 为了解决这个问题,我只需从密钥库中删除密钥并在使用新密钥加密和解密数据之后生成新密钥

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

    因为我没有通过为三星,OnePlus,华硕和其他一些设备设置 KeyGenParameterSpec.setUserAuthenticationRequired(false) 来解决它 .

  • 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)
    
  • 0

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

    setUserAuthenticationValidityDurationSeconds(10);
    

    然而,这使得技术上可以在该时间 Span 内多次使用密钥而无需进一步的用户认证 .

    我个人认为这不是一个很大的风险 .

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

  • 5

    UPDATE: 这是Android 8.0的已知问题https://issuetracker.google.com/issues/65578763

    我刚刚在三星看到这个错误,并且似乎是在添加新指纹时引起的 . 在我们的代码中,我们期望在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
                }
            }
        }
    

相关问题