Encrypted shared preferences

Encrypted shared preferences

Shared preferences are awesome when you want to persistently save small key-value entries on Android. They are super easy to instantiate and use.

Of course, everything is saved as plain text. A malicious actor with access to the device could easily ready those preferences.

So if you want to save something a bit more confidential (because anything stored on the device is anyway vulnerable if someone has physical access to the device), plain shared preferences are not the solution.

Here's where Encrypted shared preferences come in hand. This is a relatively new Jetpack library that offers easy-to-use access to encryption-related functions for Android developers.

The bad news is that, as expected, using the encrypted shared prefs has a performance overhead due to the encryption/decryption.

The good news is that the library uses the same easy-to-use interface like their unencrypted counterpart. This allows integrating the encrypted version easily with your existing app without many changes.

For instance, you could make a central place for saving/reading shared preferences, and the encryption to be handled by a passed boolean:

    private const val PREFS_NAME = "prefs_name"
    private const val ENCRYPTED_PREFS_NAME = "encrypted_$PREFS_NAME"
    
    private val sharedPrefs by lazy {
        applicationContext.getSharedPreferences(
            PREFS_NAME, Context.MODE_PRIVATE)
    }

    private val encryptedSharedPrefs by lazy {
        val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
        EncryptedSharedPreferences.create(
            ENCRYPTED_PREFS_NAME,
            masterKeyAlias,
            applicationContext,
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )
    }

    fun put(key: String, value: String, encrypted: Boolean = false) {
        val prefs = if (encrypted) sharedPrefs else encryptedSharedPrefs
        with(prefs.edit()) {
            putString(key, value)
            commit()
        }
    }

    fun get(key: String, default: String? = null, encrypted: Boolean = false): String? {
        val prefs = if (encrypted) sharedPrefs else encryptedSharedPrefs
        return prefs.getString(key, default)
    }
    

The master key that's used to encrypt these shared preferences is saved in the Android Keystore system. This makes it hard for the master key to be extracted from the device even if the device falls to unauthorized hands.

Note that the min SDK for using this library is 23+, and by the time of writing the latest version is 1.0.0-alpha2 (hopefully out of alpha soon). Add this to your build.gradle to install:

dependencies {
    implementation "androidx.security:security-crypto:1.0.0-alpha02"
}

Didn't know about this library until recently and I suspect many others don't know about it either. Enjoy and let's make our apps a bit more secure :)

Show Comments