1 Feb 2015

Encrypted shared preferences in Android

Hello Friends,

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

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

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.

Prerequisite:

MinSDK
minimum SDK version of your app should be 21 

Note: Version 1.0.0 supports Marshmallow(API 23) and above only. Newer versions support 21 and below but they won’t use Keystore.


Add the library: Add the following line in the build.gradle of your app
implementation "androidx.security:security-crypto:1.1.0-alpha03"
implementation 'com.google.code.gson:gson:2.8.6' 

Code Snippet: Let’s see how to work with Encrypted preference in the code. I have created a general class to access preference using Kotlin language.

 @RequiresApi(Build.VERSION_CODES.M)
object AppPreference {

    const val PREF_NAME = "EncryptedPref"
    const val KEY_NAME = "Name"

    private fun getPreferences(context: Context): SharedPreferences {

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

        return EncryptedSharedPreferences.create(context,PREF_NAME,masterKey,
                                                 EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                                                 EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
                                                )
    }

    private fun getEditor(context: Context): SharedPreferences.Editor {
        return getPreferences(context).edit()
    }

    fun writeBooleanValue(context: Context,key: String?,value: Boolean)
    {
        getEditor(context).putBoolean(key, value).commit()
    }

    fun getBooleanValue(context: Context, key: String?,defValue: Boolean): Boolean
    {
        return getPreferences(context).getBoolean(key, defValue)
    }

    fun writeIntegerValue(context: Context,key: String?,value: Int)
    {
        getEditor(context).putInt(key, value).commit()
    }

    fun getIntegerValue(context: Context,key: String?,defValue: Int): Int
    {
        return getPreferences(context).getInt(key, defValue)
    }

    fun writeStringValue(context: Context,key: String?,value: String?)
    {
        getEditor(context).putString(key, value).commit()
    }

    fun getStringValue(context: Context,key: String?): String?
    {
        return getPreferences(context).getString(key, null)
    }

    /**
     * Saves object into the Preferences.
     *
     * @param object Object of model class (of type [T]) to save
     * @param key Key with which Shared preferences to
     **/
    fun <T> writeObjectValue(context: Context, key: String,obj: T) {
        //Convert object to JSON String.
        val jsonString = GsonBuilder().create().toJson(obj)
        getEditor(context).putString(key, jsonString).commit()
    }

    /**
     * Used to retrieve object from the Preferences.
     *
     * @param key Shared Preference key with which object was saved.
     **/
    inline fun <reified T> getObjectValue(mContext: Context, key: String): T? {
        //We get JSON String which was saved.
        val pref = mContext.getSharedPreferences(PREF_NAME, 0)
        val value = pref.getString(key, null)
        //JSON String was found which means object can be get.
        //We convert this JSON String to model object. Parameter "c" (of
        //type Class < T >" is used to cast.
        return GsonBuilder().create().fromJson(value, T::class.java)
    }

    fun clearAllPreference(context: Context)
    {
        getEditor(context).clear().commit()
    }
    fun clearPreference(context: Context,key: String)
    {
        getEditor(context).remove(key).commit()
    }
}
Store data to the Preference:

1. Write String to the preference:
   AppPreference.writeStringValue(this, KEY, values)

2. Write Object to the preference:
   AppPreference.writeObjectValue(this, KEY, Object)
Retrieve data from the Preference:

 1. Retrieve String to the preference:
   AppPreference.getStringValue(this, KEY)

 2. Retrieve Object to the preference:
   val obj : ModelClass? = AppPreference.getObjectValue(this, KEY)

Clear the Preference:

 1. Clear the specific preference:
   AppPreference.clearPreference(contex, KEY)

 2. Clear all preference:
   AppPreference.clearAllPreference(context)
You may like : 

Preferences DataStore: Example
Normal Share Preference: Example
Store & Retrieve hash map in shared preferences: Example


I will be happy if you will provide your feedback or follow this blog. Any suggestion and help will be appreciated.
Thank you :)