Securing Your App: Encrypted Shared Preferences in Android

Keyndroid
Keyndroid Insights
Published in
3 min readApr 28, 2024

Shared preferences play a pivotal role in Android development by facilitating the storage of data in key-value pairs. They primarily serve to retain user-specified details and configuration settings within an application.

Shared preferences are typically employed for managing small-scale data sets structured in a key-value format. However, for handling larger volumes of data, developers often turn to more robust solutions such as SQLite, Room, or Realm databases.

Have you ever pondered over the inner workings of how your shared preference data is managed? Let’s delve into this by considering a hypothetical scenario where we’ve crafted a class called PrefHelper

class PrefHelper(context: Context) {
private val sharedPreferences = context.getSharedPreferences("userData", Context.MODE_PRIVATE)
private val editor = sharedPreferences.edit()

fun saveUserId(userId: String) {
editor.putString("UserId", userId).apply()
}
}

In this example, we have a class PrefHelper designed to facilitate interaction with shared preferences. It initializes a SharedPreferences object named userData in private mode, ensuring its accessibility is confined to the current application. Additionally, it provides a method saveUserId for storing a user's ID in the shared preferences under the key "UserId".

Certainly! To view how the data is stored in your application’s shared preferences, Open Device Explorer in Android Studio and navigate to the following path: data/data/your.package.name/shared_prefs/your_preference_filename.xml.

Upon examination, it becomes apparent that the data is stored in plain text format.

In such cases, the solution lies in implementing Encrypted Shared Preferences, which offers a safeguard against this vulnerability.

This explains why Google introduced EncryptedSharedPreference in the Jetpack library. It builds upon Shared Preferences but encrypts all data, ensuring that even if someone accesses the XML file, the data remains encrypted. Let’s proceed with implementing encrypted shared preferences.

Step 1. Implement AndroidX Security SDK in your project

To utilize encrypted shared preferences, you must integrate the SDK into your app’s Gradle file at the project level.

dependencies {
implementation("androidx.security:security-crypto:1.1.0-alpha06")
}

Step 2. Generate the master key

We require a master key object to store all subkeys.

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

Step 3. Generate the shared preference Object

Replace your conventional shared preferences with the encrypted variant by initializing a new EncryptedSharedPreferences instance and pass the master key which we craeted in step 2.

var sharedPreferences: SharedPreferences = EncryptedSharedPreferences.create(
context,
"userDataEncrypted",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

This represents the complete EncryptedPrefHelper class.

class EncryptedPrefHelper(context:Context) {
var masterKey: MasterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()

var sharedPreferences: SharedPreferences = EncryptedSharedPreferences.create(
context,
"userDataEncrypted",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
val editor=sharedPreferences.edit()
fun saveUserId(userId:String){
editor.putString("UserId",userId).apply()
}
}

Isn’t it simple? Let’s now examine what’s stored in the XML file.

We notice that the data is encrypted, and although the file size may have increased somewhat, the enhanced security it offers is definitely worthwhile, don’t you agree?

What’s holding you back? Let’s continue securing your apps and enjoy coding! :)

--

--