如何将BiometricPrompt与CryptoObject结合使用以同时获得解密和加密的KeyStore访问权限?

问题描述

问题描述:当使用BiometricPrompt身份验证访问Android KeyStore时,每次必须对KeyStore执行读或写操作时都会出现BiometricPrompt。我正在寻找一种只进行一次身份验证的解决方案,然后按照我希望的方式操纵密钥库中的数据,就像在iOS KeyChain上所做的那样。

我已经为Android实现了生物特征认证,以便可以通过在KeyStore params构建器上调用setUserAuthenticationRequired(true)将应用API AuthRefreshToken存储在由生物特征认证保护的应用程序KeyStore中(请参见下文)。我遵循了Google(https://github.com/android/security-samples/tree/main/BiometricLoginKotlin)和其他开发人员的示例,并使解决方案成功运行。我现在试图解决上述问题的第二个工作日没有成功,现在考虑使用不带CryptoObject的BiometricPrompt,这将是一个很大的失望。我怀疑有一段时间可以进行一次身份验证的方法,可能是通过设置paramsBuilder.setUserAuthenticationValidityDurationSeconds(30)来完成的,但是我无法达到预期的结果。

要使用KeyStore并读取API AuthRefreshToken,请使用以下代码:

biometricPrompt = BiometricPromptUtils.createBiometricPrompt(this,::decryptServerTokenFromStorage)
val promptInfo = BiometricPromptUtils.createPromptInfo(this)
biometricPrompt.authenticate(promptInfo,BiometricPrompt.CryptoObject(cipher))

fun decryptServerTokenFromStorage(authResult: BiometricPrompt.AuthenticationResult) {
    ciphertextWrapper?.let { textWrapper ->
        authResult.cryptoObject?.cipher?.let {
            val authRefreshToken = cryptographyManager.decryptData(textWrapper.ciphertext,it)
            // Use authRefreshToken to get authToken from the API
            // The API returns new authRefreshToken which has to be saved back to the KeyStore
        }
    }
}

一切正常,我得到了解密的数据。但是,在使用AuthRefreshToken对应用程序API进行每次身份验证之后,令牌会更改,我必须立即将其保存回KeyStore。发生这种情况时,我使用下面的代码,再次显示BiometricPrompt。这将导致UI流程两次显示BiometricPrompt:

biometricPrompt = BiometricPromptUtils.createBiometricPrompt(this,::encryptServerTokenToStorage)
val promptInfo = BiometricPromptUtils.createPromptInfo(this)
biometricPrompt.authenticate(promptInfo,BiometricPrompt.CryptoObject(cipher))

fun encryptServerTokenToStorage(authResult: BiometricPrompt.AuthenticationResult) {
    authResult.cryptoObject?.cipher?.apply {
            SampleAppUser.refreshAuthToken?.let { refreshAuthToken ->
                Log.d(TAG,"The token from server is $refreshAuthToken")
                val encryptedServerTokenWrapper = cryptographyManager.encryptData(refreshAuthToken,this)
                // Now save encrypted authRefreshToken together with initializationVector in the app prefs for future authentications
            )
        }
    }
}

如何立即通过BiometricPrompt进行身份验证,以便我可以在1分钟或更长时间的间隔内对KeyStore进行完全读/写访问,而无需多次调用BiometricPrompt?

我尝试了不同的方法,并尝试为不同的目的重新创建密码或重新初始化密码,但是在所有这些尝试中,我都收到Javax.Crypto.IllegalBlockSizeException 消息“密钥用户未通过身份验证”

密钥库初始化如下:

    // 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) // KeyProperties.BLOCK_MODE_GCM
        setEncryptionPaddings(ENCRYPTION_PADDING) // KeyProperties.ENCRYPTION_PADDING_NONE
        setKeySize(KEY_SIZE) // 256
        setUserAuthenticationRequired(true) // This is required for BiometricPrompt to work properly
    }

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

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...