【问题标题】:Key permanently invalidated exception biometric authorization Android密钥永久失效异常生物识别授权Android
【发布时间】:2021-12-06 03:51:34
【问题描述】:

我正在尝试在 Android 应用中实现生物识别授权。我遵循了android官方文档,直到今天一切正常,所以当我删除指纹并添加新指纹时,现在它抛出异常,我尝试将try catch放入getOrCreateSecretKey但它是一样的:(

android.security.keystore.KeyPermanentlyInvalidatedException:密钥永久失效

private class CryptographyManagerImpl : CryptographyManager {

    private val KEY_SIZE = 256
    private val ANDROID_KEYSTORE = "AndroidKeyStore"
    private val ENCRYPTION_BLOCK_MODE = KeyProperties.BLOCK_MODE_GCM
    private val ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_NONE
    private val ENCRYPTION_ALGORITHM = KeyProperties.KEY_ALGORITHM_AES

    override fun getInitializedCipherForEncryption(keyName: String): Cipher {
        val cipher = getCipher()
        val secretKey = getOrCreateSecretKey(keyName)
        cipher.init(Cipher.ENCRYPT_MODE, secretKey)
        return cipher
    }

    override fun getInitializedCipherForDecryption(
        keyName: String,
        initializationVector: ByteArray
    ): Cipher {
        val cipher = getCipher()
        val secretKey = getOrCreateSecretKey(keyName)
        cipher.init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(128, initializationVector))
        return cipher
    }

    override fun encryptData(plaintext: String, cipher: Cipher): CiphertextWrapper {
        val ciphertext = cipher.doFinal(plaintext.toByteArray(Charset.forName("UTF-8")))
        return CiphertextWrapper(ciphertext, cipher.iv)
    }

    override fun decryptData(ciphertext: ByteArray, cipher: Cipher): String {
        val plaintext = cipher.doFinal(ciphertext)
        return String(plaintext, Charset.forName("UTF-8"))
    }

    private fun getCipher(): Cipher {
        val transformation = "$ENCRYPTION_ALGORITHM/$ENCRYPTION_BLOCK_MODE/$ENCRYPTION_PADDING"
        return Cipher.getInstance(transformation)
    }

    private fun getOrCreateSecretKey(keyName: String): SecretKey {
        // If Secretkey was previously created for that keyName, then grab and return it.
        val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE)
        keyStore.load(null) // Keystore must be loaded before it can be accessed
        keyStore.getKey(keyName, null)?.let { return it as SecretKey }

        // if you reach here, then a new SecretKey must be generated for that keyName
        val paramsBuilder = KeyGenParameterSpec.Builder(
            keyName,
            KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
        )
        paramsBuilder.apply {
            setBlockModes(ENCRYPTION_BLOCK_MODE)
            setEncryptionPaddings(ENCRYPTION_PADDING)
            setKeySize(KEY_SIZE)
            setUserAuthenticationRequired(true)
        }

        val keyGenParams = paramsBuilder.build()
        val keyGenerator = KeyGenerator.getInstance(
            KeyProperties.KEY_ALGORITHM_AES,
            ANDROID_KEYSTORE
        )
        keyGenerator.init(keyGenParams)
        return keyGenerator.generateKey()
    }

例外

2021-10-19 17:28:05.252 6613-6613/com.samplebet E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.samplebet, PID: 6613
    java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130) 
     Caused by: android.security.keystore.KeyPermanentlyInvalidatedException: Key permanently invalidated
        at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1533)
        at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1548)
        at android.security.keystore.KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(KeyStoreCryptoOperationUtils.java:54)
        at android.security.keystore.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:89)
        at android.security.keystore.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:265)
        at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:148)
        at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:2980)
        at javax.crypto.Cipher.tryCombinations(Cipher.java:2891)
        at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider(Cipher.java:2796)
        at javax.crypto.Cipher.chooseProvider(Cipher.java:773)
        at javax.crypto.Cipher.init(Cipher.java:1288)
        at javax.crypto.Cipher.init(Cipher.java:1223)
        at com.samplebet.biometric.CryptographyManagerImpl.getInitializedCipherForDecryption(CryptographyManager.kt:98)
        at com.samplebet.auth.AuthActivity.showBiometricPromptForDecryption(AuthActivity.kt:120)
        at com.samplebet.auth.AuthActivity.onCreate$lambda-5(AuthActivity.kt:87)
        at com.samplebet.auth.AuthActivity.$r8$lambda$xxAGKHOwnj6tq1hGqTWaney7IFw(Unknown Source:0)
        at com.samplebet.auth.AuthActivity$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
        at android.view.View.performClick(View.java:8160)
        at android.widget.TextView.performClick(TextView.java:16222)
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119)
        at android.view.View.performClickInternal(View.java:8137)
        at android.view.View.access$3700(View.java:888)
        at android.view.View$PerformClick.run(View.java:30236)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:246)

【问题讨论】:

  • 感谢 Jaameido 的重播,我也看到了这个,但是不知道在我的课堂上在哪里处理这个问题,我尝试了 getOrCreateSecretKey 方法但它不起作用
  • IIRC,当您尝试使用无效密钥执行 Cipher.init 时会引发异常。检查您的堆栈跟踪。
  • @Michael 我更新了帖子,我还不能修复它

标签: java android kotlin encryption android-keystore


【解决方案1】:

发生这种情况是因为在您的密钥生成器参数中包含 setUserAuthenticationRequired(true),当所有生物特征被移除或在设备上添加新的生物特征时,这会使密钥失效。

这意味着当您在删除指纹并添加另一个指纹后尝试使用此类密钥进行解密时,您将在调用 cipher.init 时抛出 KeyPermanentlyInvalidatedException .

捕获异常、删除无效密钥并生成新密钥是解决方案的一部分,因为使用新密钥您将无法再解密加密(使用以前的密钥)数据。为此,您必须有一个后备流程,在该流程中您要求用户使用新密钥再次加密数据。

作为最后的注释:

  • 您可以在生成新密钥时使用 setInvalidatedByBiometricEnrollment 方法(可从 API 24 获得)并将其设置为 false,这将缩小密钥无效但可能被认为不太安全。

  • 不建议在生成密钥时将 setUserAuthenticationRequired 设置为 false(这也可以解决您的问题)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-01
    • 1970-01-01
    • 2014-10-28
    • 2019-05-11
    • 2018-11-18
    • 2017-07-16
    • 2017-06-18
    相关资源
    最近更新 更多