Securing Your App: Encrypted Shared Preferences in Android
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! :)