0

I have such an implementation of 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
        )
...
}

and in the crash report, I see such a log (a few times I got such crash report):

...
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)
...

so as far as I see the closest issue description from the log is:

...
    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)
...

According to the log looks like MyApplication creates, then it creates MyEnqPrefs then it tries to create MasterKeys and crash happens.

So, the question is - what is a possible problem with the approach I use to create master key alias - MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)?

Sirop4ik
  • 4,543
  • 2
  • 54
  • 121

1 Answers1

0

So, finally I am good with this approach - 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")
        }
    }
}
Sirop4ik
  • 4,543
  • 2
  • 54
  • 121