В чем может быть проблема при создании MasterKeys?
У меня есть такая имплементация EncryptedSharedPreferences:
class MyEnqPrefs(ctx: Context) {
init {
...
val sharedPref = EncryptedSharedPreferences.create(
PREF_NAME,
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
ctx,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
...
}
и вот такой лог краша (несколько раз в репортах он был):
...
android.security.KeyStoreException: Unknown error
at android.security.KeyStore.getKeyStoreException()(KeyStore.java:1301)
at android.security.keystore.AndroidKeyStoreKeyGeneratorSpi.engineGenerateKey()(AndroidKeyStoreKeyGeneratorSpi.java:331)
at javax.crypto.KeyGenerator.generateKey()(KeyGenerator.java:612)
at androidx.security.crypto.MasterKeys.generateKey()(MasterKeys.java:130)
at androidx.security.crypto.MasterKeys.getOrCreate()(MasterKeys.java:88)
at application.prefs.MyEnqPrefs.<init>()(MyEnqPrefs.kt:24)
at application.MyApplication.onCreate()(MyApplication.java:453)
at android.app.Instrumentation.callApplicationOnCreate()(Instrumentation.java:1192)
at android.app.ActivityThread.handleBindApplication()(ActivityThread.java:6715)
at android.app.ActivityThread.access$1300()(ActivityThread.java:237)
at android.app.ActivityThread$H.handleMessage()(ActivityThread.java:1913)
at android.os.Handler.dispatchMessage()(Handler.java:106)
at android.os.Looper.loop()(Looper.java:223)
at android.app.ActivityThread.main()(ActivityThread.java:7660)
at java.lang.reflect.Method.invoke()(Method.java:-2)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run()(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main()(ZygoteInit.java:947)
...
из лога я так понимаю, что самое близкое описание краша в этих строчках:
...
at androidx.security.crypto.MasterKeys.generateKey()(MasterKeys.java:130)
at androidx.security.crypto.MasterKeys.getOrCreate()(MasterKeys.java:88)
at application.prefs.MyEnqPrefs.<init>()(MyEnqPrefs.kt:24)
at application.MyApplication.onCreate()(MyApplication.java:453)
...
Получается, что создается MyApplication потом MyEnqPrefs и потом MasterKeys и вот тут происходит краш.
Вопрос - что возможно не так с этим методом MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)? Почему он крашит приложение?
Ответы (1 шт):
Автор решения: Sirop4ik
→ Ссылка
В итоге этот ответ мне помог - https://stackoverflow.com/a/71569624/5709159
/**
* 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")
}
}
}