【问题标题】:EncryptedSharedPreferences isUserAuthenticationRequired not working properlyEncryptedSharedPreferences isUserAuthenticationRequired 无法正常工作
【发布时间】:2020-09-21 00:09:02
【问题描述】:

我正在使用 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 仅确保只有在用户获得授权时才会激活密钥。

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)

【问题讨论】:

  • 您能否在创建的加密共享首选项中存储和获取数据?
  • 是的,我可以存储和获取数据。
  • 你检查hasFingerprint是否返回true?
  • 是的,它正在返回 true
  • 对我来说,如果我没有明确要求用户使用 BiometricPrompt developer.android.com/training/sign-in/biometric-auth 进行身份验证,则在尝试创建 encryptedsharedpreference 对象时,您编写的代码会抛出 UserNotAuthenticatedException 。我正在使用运行 android 10 的 Smasung Galaxy M20。但我有点困惑,它允许我在创建其对象后编辑共享首选项,即使我执行超过 1 秒的身份验证时间的读写操作。

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


【解决方案1】:

我找到了它不需要身份验证后 1 秒的原因。这是因为,一旦启动了加密的共享首选项,它就会加载用于加密和解密内存中数据的密钥,然后这些密钥用于访问文件中的数据。您可以阅读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);

【讨论】:

    猜你喜欢
    • 2016-12-01
    • 1970-01-01
    • 2016-09-01
    • 2012-07-11
    • 2018-04-08
    • 2017-04-20
    • 2018-10-02
    • 2016-09-04
    • 2010-10-06
    相关资源
    最近更新 更多