Step-by-Step Guide on Securing SharedPreferences in Android
Security is a very important topic and has to be taken seriously when developing Android applications, especially if sensitive data is stored on the device. In this article, we will learn how we can encrypt our Shared Preferences in Android using Jetpack’s Security library.
Normally, developers choose implementing AES encryption for securing data. But there is often the need for a “secret”. If this password or “secret” is hard-coded into your app or uses some system value like MAC address, anyone looking through a decompiled version of your code can easily decipher what it takes to decrypt the data. You could generate a random long secret but if you put it in regular SharedPreferences, it will get persisted in plain text and can become a security loophole.
So what is the solution here?
Android Jetpack provides a new library Security which allows you to encrypt/decrypt data with a more robust and secure mechanism using a much friendly API. This helps you avoid using third-party libraries or writing your own custom encryption implementations like AES etc. It also recommends to not use Android Keystore System (previously used for such purposes in Android) and choose Android’s Jetpack Security instead.
Another interesting thing about Jetpack Security is that it also gives you a EncryptedSharedPreferences
API separately, so that you use it directly instead of creating a wrapper around existing SharedPreferences
.
Let’s now see how you can actually implement it in your Android apps easily.
The Normal Way of SharedPreferences
Normally, if you use SharedPreferences
, you can use it by calling Context#getSharedPreferences()
like the code below.
val preferences = getSharedPreferences("normal_prefs", MODE_PRIVATE)
// Storing Data in Preferences
with(preferences.edit()) {
putBoolean("Bool", true)
putString("String", "Some normal string value")
putInt("Integer", 10)
commit()
}
// Reading data from Preferences
val boolValue = preferences.getBoolean("Bool", false)
val strValue = preferences.getString("String", "")
val intValue = preferences.getInt("Integer", 0)
Once you have some data stored in the SharedPreferences
, you can actually view that in Android Studio by opening Device File Explorer panel. Note that this requires any device/emulator is connected via USB Debugging.
Open Device File Explorer, and then go to the data -> data -> YOUR_APP_PACKAGAE_NAME -> shared_prefs
directory. You will see a file with the name normal_prefs.xml
in this directory. The normal_prefs
is passed in the above line with calling getSharedPreferences()
method. This file will contain all the data stored in SharedPreferences
in the XML format.
The way this file is shown to you is how it will be shown to any hacker trying to see the data of your app. So, it’s very important to make this secure and encrypt it.
The Secure Way of SharedPreferences
To use the EncryptedSharedPreferences
, first add the Jetpack Security library by adding this line app’s build.gradle
file.
implementation "androidx.security:security-crypto:1.0.0"
Now you can use the EncryptedSharedPreferences
. But for that you need a Key. The Key here is like a secure code used for the encryption/decryption purposes. You can create this by the following code:
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val mainKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
Note the AES256_GCM_SPEC
. It is a security specification in Jetpack Security, which is recommended for general use cases. AES256-GCM is symmetric and generally fast on modern devices.
Once you have your mainKeyAlias
, you can use this to get instance of EncryptedSharedPreferences
. And then you can use it exactly the same way as you were reading/writing data with normal SharedPreferences
.
val securePreferences = EncryptedSharedPreferences.create(
"secure_prefs",
mainKeyAlias,
applicationContext,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
// Storing Data in Preferences
with(securePreferences.edit()) {
putBoolean("Bool", true)
putString("String", "Some normal string value")
putInt("Integer", 10)
commit()
}
// Reading data from Preferences
val boolValue = securePreferences.getBoolean("Bool", false)
val strValue = securePreferences.getString("String", "")
val intValue = securePreferences.getInt("Integer", 0)
If we look closely at the class, EncryptedSharedPreferences
is an implementation of Shared Preferences that allows the keys and values to be encrypted. Getting the encrypted key value pairs will be the same as it is for the common shared preferences.
Note that I have set the file name to secure_prefs
instead of the normal_prefs
for the sake of example here. You can use any name you like here. Once you open the secure_prefs
file through Device File Explorer, you can see it that you can’t understand what’s written there. Both keys and values are encrypted.
You saw how you can encrypt/decrypt SharedPreferences very easily with the help of Jetpack Security library. Security is very important while developing applications. Everyone should think of using these libraries as much as possible to ensure that users evolve in a secure environment.
At the end, please Subscribe to my newsletter #Time with Wajahat to learn learn about the life experiences, lessons, career advices, technology & programming tips manually handcrafted and curated by Wajahat Karim.