gpt4 book ai didi

android - 使用 EncryptedSharedPreferences 获取 KeyStoreException 和 GeneralSecurityException,我该如何解决?

转载 作者:行者123 更新时间:2023-12-03 09:40:32 37 4
gpt4 key购买 nike

背景
在我使用的一个应用程序中,我将重要的东西( token )存储到 EncryptedSharedPreferences 中(取自 herehere ):

/** a hardware-encrypted based shared preference (for the values).
* Note that it is a bit slow, so it's better to always use it in a background thread.
* Also, avoid having it being backed-up in the manifest, as it's hardware based and will become useless: https://stackoverflow.com/a/63795282/878126*/
object SecuredSharedPreferences {
private var cachedDefaultSharedPreferences: SharedPreferences? = null

/**warning: using this function can take some time (249 ms on Pixel 4, for example). Very recommended to avoid calling it on UI thread */
@WorkerThread
fun getDefaultSecuredSharedPreferences(context: Context): SharedPreferences {
if (cachedDefaultSharedPreferences != null)
return cachedDefaultSharedPreferences!!
synchronized(this) {
if (cachedDefaultSharedPreferences != null)
return cachedDefaultSharedPreferences!!
cachedDefaultSharedPreferences = getSecuredSharedPreferences(context, context.packageName + "_secured_preferences")
}
return cachedDefaultSharedPreferences!!
}

@WorkerThread
private fun getSecuredSharedPreferences(context: Context, fileName: String): SharedPreferences {
val masterKey = MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()
return EncryptedSharedPreferences.create(context, fileName, masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
}
}
毕业典礼:
implementation 'androidx.security:security-crypto:1.1.0-alpha03'
问题
我注意到使用此代码时通过 Crashlytics 报告了 2 个错误(报告 here):
  • 第一个是 MasterKey.Builder GeneralSecurityException 行:
  • Fatal Exception: java.security.GeneralSecurityException: Keystore operation failed
    at androidx.security.crypto.MasterKeys.generateKey(MasterKeys.java:146)
    at androidx.security.crypto.MasterKeys.getOrCreate(MasterKeys.java:97)
    at androidx.security.crypto.MasterKey$Builder.buildOnM(MasterKey.java:357)
    at androidx.security.crypto.MasterKey$Builder.build(MasterKey.java:314)
    ...
    Caused by java.security.ProviderException: Keystore operation failed
    at android.security.keystore.AndroidKeyStoreKeyGeneratorSpi.engineGenerateKey(AndroidKeyStoreKeyGeneratorSpi.java:372)
    at javax.crypto.KeyGenerator.generateKey(KeyGenerator.java:612)
    at androidx.security.crypto.MasterKeys.generateKey(MasterKeys.java:142)
    at androidx.security.crypto.MasterKeys.getOrCreate(MasterKeys.java:97)
    at androidx.security.crypto.MasterKey$Builder.buildOnM(MasterKey.java:357)
    at androidx.security.crypto.MasterKey$Builder.build(MasterKey.java:314)
  • 第二个在 EncryptedSharedPreferences.create KeyStoreException 行,并且更频繁地出现并为更多用户提供:
  • Fatal Exception: java.security.KeyStoreException: the master key android-keystore://_androidx_security_master_key_ exists but is unusable
    at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readOrGenerateNewMasterKey(AndroidKeysetManager.java:275)
    at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.build(AndroidKeysetManager.java:236)
    at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:155)
    at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:120)
    ...
    Caused by java.security.UnrecoverableKeyException: Failed to obtain information about key
    at android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStoreSecretKeyFromKeystore(AndroidKeyStoreProvider.java:282)
    at android.security.keystore.AndroidKeyStoreSpi.engineGetKey(AndroidKeyStoreSpi.java:98)
    at java.security.KeyStore.getKey(KeyStore.java:825)
    at com.google.crypto.tink.integration.android.AndroidKeystoreAesGcm.<init>(AndroidKeystoreAesGcm.java:58)
    at com.google.crypto.tink.integration.android.AndroidKeystoreKmsClient.getAead(AndroidKeystoreKmsClient.java:164)
    at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readOrGenerateNewMasterKey(AndroidKeysetManager.java:267)
    at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.build(AndroidKeysetManager.java:236)
    at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:155)
    at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:120)
    编辑:似乎还有更多类型的异常(exception):
  • 无效 Protocol Buffer 异常:
  • Fatal Exception: com.google.crypto.tink.shaded.protobuf.InvalidProtocolBufferException: Protocol message contained an invalid tag (zero).
    at com.google.crypto.tink.shaded.protobuf.GeneratedMessageLite.parsePartialFrom(GeneratedMessageLite.java:1566)
    at com.google.crypto.tink.shaded.protobuf.GeneratedMessageLite.parseFrom(GeneratedMessageLite.java:1663)
    at com.google.crypto.tink.proto.Keyset.parseFrom(Keyset.java:957)
    at com.google.crypto.tink.integration.android.SharedPrefKeysetReader.read(SharedPrefKeysetReader.java:84)
    at com.google.crypto.tink.CleartextKeysetHandle.read(CleartextKeysetHandle.java:58)
    at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.read(AndroidKeysetManager.java:328)
    at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readOrGenerateNewKeyset(AndroidKeysetManager.java:287)
    at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.build(AndroidKeysetManager.java:238)
    at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:160)
    at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:120)
  • 空指针异常:
  • Fatal Exception: java.lang.NullPointerException: Attempt to invoke interface method 'android.security.keymaster.OperationResult android.security.IKeystoreService.begin(android.os.IBinder, java.lang.String, int, boolean, android.security.keymaster.KeymasterArguments, byte[], int)' on a null object reference
    at android.security.KeyStore.begin(KeyStore.java:501)
    at android.security.keystore.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:248)
    at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:109)
    at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:2977)
    at javax.crypto.Cipher.tryCombinations(Cipher.java:2884)
    at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider(Cipher.java:2789)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:956)
    at javax.crypto.Cipher.init(Cipher.java:1199)
    at javax.crypto.Cipher.init(Cipher.java:1143)
    at com.google.crypto.tink.integration.android.AndroidKeystoreAesGcm.encryptInternal(AndroidKeystoreAesGcm.java:84)
    at com.google.crypto.tink.integration.android.AndroidKeystoreAesGcm.encrypt(AndroidKeystoreAesGcm.java:72)
    at com.google.crypto.tink.integration.android.AndroidKeystoreKmsClient.validateAead(AndroidKeystoreKmsClient.java:248)
    at com.google.crypto.tink.integration.android.AndroidKeystoreKmsClient.getAead(AndroidKeystoreKmsClient.java:165)
    at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readOrGenerateNewMasterKey(AndroidKeysetManager.java:267)
    at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.build(AndroidKeysetManager.java:236)
    at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:155)
    at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:120)
    我试过的
    在互联网上搜索,我只发现了第一个异常(GeneralSecurityException)的线索,这可能是自定义 ROM 发生的,因为它们可能无法很好地实现用于加密的硬件 key 。
    事实上,查看 Crashlytics 上的设备,查看每个设备的 Android 版本,我发现它们领先于我所看到的支持它们的最新版本。
    对于第二个异常(exception),可悲的是,我找不到任何解释,也没有解决方案。我认为这可能与应用程序的恢复有关,但这很奇怪,因为它经常发生。在reddit( here)上,有人写道,遇到这种异常,他选择了 wrap the initialization of EncryptedSharedPreferences with "clear all data if fails" and bite the bullet .还建议它可能与拥有 android:allowBackup有关。被禁用(确实如此)。
    不知道其余的。
    问题
    为什么会出现这些异常?我能对他们做什么?
    清除数据是唯一可以做的事情吗?我什至不确定它是否真的有帮助,因为如果我选择拥有它,这意味着每次它即将发生时崩溃报告都会消失......
    是否与 android:allowBackup 相关?被禁用?

    最佳答案

    在使用 Jetpack Security EncryptedSharedPreferences(甚至是稳定的)之前要小心这个 Activity 故障,它主要来自外来设备 - https://issuetracker.google.com/issues/176215143?pli=1
    唯一肮脏的解决方法是 - https://github.com/google/tink/issues/535#issuecomment-912661574
    一旦找到友好的解决方案,我将更新答案。这是解决方法 -

    /**
    * A builder for creating an encrypted shared preference class.
    */
    private const val KEYSTORE_PROVIDER = "AndroidKeyStore"
    private const val SHARED_PREFS_FILENAME = "TVPrefs"

    @KoinApiExtension
    class EncryptedSharedPreferenceBuilder(var context: Context) : KoinComponent {
    private val reporter: Reporter by inject()

    private val masterKeyAlias =
    MasterKey.Builder(context).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()

    fun build(): SharedPreferences {
    return try {
    createSharedPreferences()
    } catch (gsException: GeneralSecurityException) {
    reporter.logException(gsException)
    Timber.d("EncryptedSharedPref: Error occurred while create shared pref=$gsException")
    // There's not much point in keeping data you can't decrypt anymore,
    // delete & re-create; user has to start from scratch
    deleteSharedPreferences()
    createSharedPreferences()
    }
    }

    private fun createSharedPreferences() = EncryptedSharedPreferences.create(
    context,
    SHARED_PREFS_FILENAME,
    masterKeyAlias,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )

    // Clearing getSharedPreferences using default Preference wrapper.
    // This is to work around any key-mismatches that may happen.
    fun clearSharedPreference() {
    context.getSharedPreferences(SHARED_PREFS_FILENAME, Context.MODE_PRIVATE).edit().clear()
    .apply()
    }

    // Workaround [https://github.com/google/tink/issues/535#issuecomment-912170221]
    // Issue Tracker - https://issuetracker.google.com/issues/176215143?pli=1
    private fun deleteSharedPreferences() {
    try {
    val sharedPrefsFile =
    File("${context.filesDir.parent}/shared_prefs/$SHARED_PREFS_FILENAME.xml")

    // Clear the encrypted prefs
    clearSharedPreference()

    // Delete the encrypted prefs file
    if (sharedPrefsFile.exists()) {
    val deleted = sharedPrefsFile.delete()
    Timber.d("EncryptedSharedPref: Shared pref file deleted=$deleted; path=${sharedPrefsFile.absolutePath}")
    } else {
    Timber.d("EncryptedSharedPref: Shared pref file non-existent; path=${sharedPrefsFile.absolutePath}")
    }

    // Delete the master key
    val keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER)
    keyStore.load(null)
    keyStore.deleteEntry(MasterKey.DEFAULT_MASTER_KEY_ALIAS)
    } catch (e: Exception) {
    Timber.d("EncryptedSharedPref: Error occurred while trying to reset shared pref=$e")
    }
    }
    }

    关于android - 使用 EncryptedSharedPreferences 获取 KeyStoreException 和 GeneralSecurityException,我该如何解决?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65463893/

    37 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com