How do we securely store Secrets in Android?
By: Kasun Chinthaka Piyarathna
Tags: Encryption, Secure, Android App Development, Android, Preferences Android

Photo by Denny Müller on Unsplash

First of all, you should understand that we cannot give 100% perfect secure options. That means Any secure option can be broken somehow. But I am here suggesting one of the best-secured options to store your secrets in an Android app.

There are two types of secrets you have to deal with.

Static Secrets Dynamic Secrets

Static Secrets

According to what the name implies these secrets are static. Doesn’t change runtime or frequently.

Ex: Google maps key, Facebook app Id, CleverTap Token

Dynamic Secrets

These are the secrets that are created on run time based on some user actions.

Ex: AccessToken, Email, Password, or Any Sensitive/Personal Information

Here we are talking about how to securely store dynamic secrets in Android. Most developers use SharedPreferences in order to save these kinds of secrets. Let’s check what is SharedPreferences, how do we use it, If it is not secure enough, let’s find another solution to store secrets.

What is SharedPreferences?

SharedPreferences can be used to store data types like String, Int, Float, Boolean, Long, or StringSet.

It is a key-value store. In order to retrieve the value you stored, you have to provide the key you have given already. It is easy right?

At the activity or application level, you will be able to store values to SharedPreferences.

By default It is private, Other apps cannot access it. Great. (Read the whole article, before taking this to your mind)

How do we use SharedPreferences?

private final SharedPreferences sharedPreferences;



public SharedPref(Context context, String preferencesName) {

sharedPreferences = context.getSharedPreferences(preferencesName, Context.MODE_PRIVATE);

}



public void put(String key, String value) {

SharedPreferences.Editor editor = sharedPreferences.edit();

editor.putString(key, value);

editor.apply();

}



public String get(String key) {

return sharedPreferences.getString(key, "");

}

Is it secure?

SharedPreferences are XML files that are stored in your android device’s data/data/YourApplicationFolder. So anyone with root-level access/superuser privileges to your android device can easily access these data.

Question,

Let’s think that someone or any application accessed this data, Can they read these as plain texts?

YES.

You can easily check this with your emulator running on Android Studio. When running the emulator, open Device File Explorer on Android Studio, Click on data, data folder, find your application, expand its folders, You will see a folder named shared_prefs. Inside it, you will see your preferences.xml file(This name should be the preference name you have already given). Open it and check.

Let’s think I have Stored a key-value pair something like below through the above code

Key - key1

Value - value1

Then shared_prefs XML looks like this

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>

<map>

<string name="key1">value1</string>

</map>

This is bad. It has been saved just like we entered. Key-value pairs here are absolutely the plain texts we gave before. So anyone with rooted level access/superuser privileges can easily read these values.

Ok then, you feel like SharedPreferences is less secure to store secrets.

So do we have a more secure option to store something securely? But it should be easy, something like SharedPreferences. Do we have any??

Yes absolutely.

Have you heard about EncryptedSharedPreferences? Just use EncryptedSharedPreferences instead of normal SharedPreferences.

What is EncryptedSharedPreferences?

EncryptedSharedPreferences use one of the most used encryption algorithm(called AES256) to encode/decode key-value pairs. Since it encrypts key-value pairs, It is very hard to read what are the key-value pairs used in the application by just looking at the SharedPreferences. EncryptedSharedPreferences uses a master key to process data. This master key is stored in the Android KeyStore file which is already stored in a very secure place in Android OS.

How do we use EncryptedSharedPreferences

EncryptedSharedPreferences is just the same as normal SharedPreferences. But there is a slight change when creating an instance of ESP. Now you have to pass context, fileName, masterKey, prefKeyEncryptionScheme & prefValueEncryptionScheme.

You can create a masterKey with the support of androidx.security.cripto.

implementation 'androidx.security:security-crypto-ktx:1.1.0-alpha03' private SharedPreferences sharedPreferences;



public SecureSharedPref(Context context, String preferencesName) {

try {

MasterKey masterKey = new MasterKey.Builder(context)

.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)

.build();

sharedPreferences = EncryptedSharedPreferences.create(

context,

preferencesName,

masterKey,

EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,

EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM

);

} catch (GeneralSecurityException | IOException e) {

e.printStackTrace();

}

}



public void put(String key, String value) {

SharedPreferences.Editor editor = sharedPreferences.edit();

editor.putString(key, value);

editor.apply();

}



public String get(String key) {

return sharedPreferences.getString(key, "");

}

We already know about the cons of SharedPreferences. Although SharedPreferences are default private, Anyone with rooted level access/ superuser privileges can access it. But in this case with EncryptedSharedPreferences, no one can read data inside it as it is encrypted. So it is very Secure. Let’s see with the emulator, how can we see stored key-value pairs now.

I have tried the same key-value pair which I used above. But with EncryptedSharedPreferences now.

Key- key1

Value - value1

Then shared_prefs XML looks like this

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>

<map>

<string name="__androidx_security_crypto_encrypted_prefs_key_keyset__">12a9011705ac0aef6ea7530c18a4e9f012ac709557a931ec46402ff6731d5d18b5e1ac810d57e0265de513e81e0613a9525c0eb5bc9f534106bd22120e950f39c5409086d0bf585c814b2fe6f494de55dfbbd6e4d94d0f013a338eb36faac8d90b90a889a3038aabf21389ccd02759967beb767226cc21c49509cc9a311db7eb5951b53e1115ac10fb8cb40f387ee1c17e65fea5346ee8b7d5f2a8298379e03037920f39b6308290fd91e6d31a4408dca5849b02123c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e4165735369764b6579100118dca5849b022001</string>

<string name="__androidx_security_crypto_encrypted_prefs_value_keyset__">1288019d89191b2c2419a2793db5999004326df7717f352a166716f818295b0cf3e3cdaa67db216ef5700447fb6e65ab6637c6c3e3cb0308cc3a32dbf01d1756b0e09835b7ae64ccd4b2917ea73ad4098ad07f290477fd10fe76ac4ca5f7724f5d1dff4bda4354bfcb6fccd0004abfe569505f8eeba51325c394aff09cf61f352c089ef74cc9d897be105d1a4408978dc5a702123c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e41657347636d4b6579100118978dc5a7022001</string>

</map>

Nice, Although rooted level access can see this, they can’t read it since

Plain text cannot be found & Keys and values both are encrypted.

Conclusion

There are no 100% secure options to store data in any OS. How we can guarantee that?. Isn’t it?. But we have to use a best solution we have. Just like COVID19 vaccines.

EncryptedSharedPreferences implements SharedPreference Interface. So it is very simple to use it same as normal SharedPreferences.

But with Encryption support, It gives an additional security layer. That’s awesome.

You can find the code here.

Happy Coding.