You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

移除并添加新指纹后Android生物识别授权抛出KeyPermanentlyInvalidatedException异常求助

解决Android生物识别授权中KeyPermanentlyInvalidatedException异常

这个问题其实是Android Keystore的安全机制在起作用——当你设备上的生物识别凭证(比如指纹、面部识别)发生变更(删除旧指纹、添加新指纹)时,所有关联了setUserAuthenticationRequired(true)的密钥都会被系统标记为永久失效,目的是防止未经授权的人通过新增生物凭证访问你的加密数据。

你之前在getOrCreateSecretKey里加try-catch没用,是因为异常并不是在获取/生成密钥时抛出的,而是在调用cipher.init()初始化加密器的时候触发的。下面是具体的修复方案:

步骤1:添加密钥删除方法

首先在你的CryptographyManagerImpl里新增一个删除Keystore中旧密钥的方法:

private fun deleteKeyFromKeystore(keyName: String) {
    val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE)
    keyStore.load(null)
    if (keyStore.containsAlias(keyName)) {
        keyStore.deleteEntry(keyName)
    }
}

步骤2:在Cipher初始化时捕获异常并重建密钥

修改getInitializedCipherForEncryptiongetInitializedCipherForDecryption方法,捕获KeyPermanentlyInvalidatedException,删除旧密钥后重新生成新密钥再初始化Cipher:

修改后的加密方法:

override fun getInitializedCipherForEncryption(keyName: String): Cipher {
    val cipher = getCipher()
    return try {
        val secretKey = getOrCreateSecretKey(keyName)
        cipher.init(Cipher.ENCRYPT_MODE, secretKey)
        cipher
    } catch (e: KeyPermanentlyInvalidatedException) {
        // 密钥失效,删除旧密钥并重新生成
        deleteKeyFromKeystore(keyName)
        val newSecretKey = getOrCreateSecretKey(keyName)
        cipher.init(Cipher.ENCRYPT_MODE, newSecretKey)
        cipher
    } catch (e: Exception) {
        // 处理其他异常
        throw RuntimeException("Failed to initialize cipher for encryption", e)
    }
}

修改后的解密方法:

override fun getInitializedCipherForDecryption(
    keyName: String,
    initializationVector: ByteArray
): Cipher {
    val cipher = getCipher()
    return try {
        val secretKey = getOrCreateSecretKey(keyName)
        cipher.init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(128, initializationVector))
        cipher
    } catch (e: KeyPermanentlyInvalidatedException) {
        // 密钥失效,删除旧密钥并重新生成
        deleteKeyFromKeystore(keyName)
        val newSecretKey = getOrCreateSecretKey(keyName)
        cipher.init(Cipher.DECRYPT_MODE, newSecretKey, GCMParameterSpec(128, initializationVector))
        cipher
    } catch (e: Exception) {
        // 处理其他异常
        throw RuntimeException("Failed to initialize cipher for decryption", e)
    }
}

额外说明

  • 当密钥失效后,之前用旧密钥加密的数据无法再被解密,这是安全机制的一部分。如果你需要保留旧数据的访问权限,建议在生物凭证变更前,先解密数据并用新密钥重新加密存储;或者设计一套数据迁移方案。
  • 你也可以考虑在生物识别认证失败时,检查是否是密钥失效的原因,给用户友好的提示(比如“你的指纹已变更,请重新设置生物识别授权”)。

内容的提问来源于stack exchange,提问作者misterios

火山引擎 最新活动