android - EncryptedSharedPreferences isUserAuthenticationRequired 无法正常工作

标签 android android-jetpack android-biometric encrypted-shared-preference android-jetpack-security

我正在使用 EncryptedSharedPreferences 来存储加密数据。

val biometricManager = BiometricManager.from(this)
val hasFingerprint = biometricManager.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS

val advanceSpec = KeyGenParameterSpec.Builder(
    "master_key",
    KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
).apply {
    setBlockModes(KeyProperties.BLOCK_MODE_GCM)
    setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
    setKeySize(256)
    if(hasFingerprint){
        setUserAuthenticationRequired(true)
        setUserAuthenticationValidityDurationSeconds(1)
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            setInvalidatedByBiometricEnrollment(false)
        }
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
            setIsStrongBoxBacked(true)
            setUserConfirmationRequired(true)
        }
    }
}.build()

val masterKey = MasterKeys.getOrCreate(advanceSpec)
val preferences = EncryptedSharedPreferences.create(
    "TestPreferences",
    masterKey,
    applicationContext,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

实际上,我错过了 BiometricPrompt 部分。我认为调用 setUserAuthenticationRequired(true) 会自动处理用户身份验证。但我们必须自己出示 BiometricPrompt。 isUserAuthenticationRequired 仅确保 key 仅在用户获得授权时才会被激活。

val biometricPrompt = BiometricPrompt(
            activity,
            ContextCompat.getMainExecutor(activity),
            object: BiometricPrompt.AuthenticationCallback() {
                override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                    super.onAuthenticationSucceeded(result)
                    createSharedPreferences()
                }
            }
        )

        biometricPrompt.authenticate(promptInfo)

但是,有一个问题。它仅在创建 EncryptedSharedPreferences 时抛出 UserNotAuthenticatedException。之后我们就可以根据需要执行读写操作。它没有考虑 setUserAuthenticationValidityDurationSeconds(1)

最佳答案

我找到了1秒后不需要认证的原因。这是因为,一旦启动加密共享首选项,它就会加载用于加密和解密内存中的数据的 key ,然后使用这些 key 来访问文件中的数据。您可以阅读EncryptedSharedPreference类中的代码。这是非常明显的。

KeysetHandle daeadKeysetHandle = new AndroidKeysetManager.Builder()
                .withKeyTemplate(prefKeyEncryptionScheme.getKeyTemplate())
                .withSharedPref(context, KEY_KEYSET_ALIAS, fileName)
                .withMasterKeyUri(KEYSTORE_PATH_URI + masterKeyAlias)
                .build().getKeysetHandle();
        KeysetHandle aeadKeysetHandle = new AndroidKeysetManager.Builder()
                .withKeyTemplate(prefValueEncryptionScheme.getKeyTemplate())
                .withSharedPref(context, VALUE_KEYSET_ALIAS, fileName)
                .withMasterKeyUri(KEYSTORE_PATH_URI + masterKeyAlias)
                .build().getKeysetHandle();

        DeterministicAead daead = daeadKeysetHandle.getPrimitive(DeterministicAead.class);
        Aead aead = aeadKeysetHandle.getPrimitive(Aead.class);

        return new EncryptedSharedPreferences(fileName, masterKeyAlias,
                context.getSharedPreferences(fileName, Context.MODE_PRIVATE), aead, daead);

关于android - EncryptedSharedPreferences isUserAuthenticationRequired 无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62153438/

相关文章:

android - 将自定义布局添加到生物识别提示

android - 在单个 Activity 中交换 fragment ?

java - 等待 Firebase 异步回调在循环内完成

android-jetpack - onItemAtEndLoaded 在 onZeroItemsLoaded 之后立即调用

通过 rememberSaveable State 编写的 Android Jetpack Compose 无法在后退按钮中存活

Android - BiometricPrompt 检测是否是面部识别码或触摸识别码

android - 添加新的生物特征时使 SecretKey 无效

android - 从 sencha touch 2.0 应用程序将数据发送到服务器的最佳方式?

android - 按钮有什么属性可以让它看起来很时尚吗?

android - 如何处理Room中嵌套的1对1对象中的关系数据(将ForeignKey转换为对象)