Seth Lopez - Big Nerd Ranch Wed, 16 Nov 2022 21:30:46 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.5 Encrypting Shared Preferences with the AndroidX Security Library https://bignerdranch.com/blog/encrypting-shared-preferences-with-the-androidx-security-library/ Tue, 28 Jan 2020 20:37:51 +0000 https://nerdranchighq.wpengine.com/?p=4079 The Android framework provides us with `SharedPreferences`, which is a great way to store a small amount of key-value data. Sometimes that data needs to be encrypted to keep it away from prying eyes. The AndroidX Security library provides us with a simple and easy way to do so.

The post Encrypting Shared Preferences with the AndroidX Security Library appeared first on Big Nerd Ranch.

]]>
The Android framework provides us with SharedPreferences, which is a great way to store a small amount of key-value data. When working with sensitive data, however, it’s important to consider that SharedPreferences stores data as plain text. We should encrypt sensitive data to keep it from prying eyes. How can we do so?

One option is to write our own encryption wrapper around SharedPreferences using the Android KeyStore. Unfortunately, that can be pretty complicated and involve a lot of setup. Another option is to use a third-party library, which means that we need to spend time finding and vetting one. Thankfully, the AndroidX Security library was recently added and makes storing encrypted shared preferences data simple and easy for apps with a min-sdk of 23+.

On to the details

To get started with the AndroidX Security library, add the following dependency to your module-level build.gradle file.

implementation "androidx.security:security-crypto:1.0.0-alpha02"

This is the latest version as of this writing. Be sure to check the library’s releases page to see if a newer version is available.

It’s important to note that this library is currently in the alpha phase. This means that while the functionality is stable, parts of the API may be changed or removed in future versions.

With the dependency added, the next step is to create an encryption master key and store it in the Android KeyStore. The security library provides us with an easy way to do this. The following code can be placed where you plan to create your EncryptedSharedPreferences instance.

val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

We’re given a default key generation specification, AES256_GCM_SPEC, to use for creating the master key. While it’s recommended to use this specification, you can also provide your own KeyGenParameterSpec if you need more control over how the key is generated.

Finally, we just need an instance of EncryptedSharedPreferences, which is a wrapper around SharedPreferences and handles all of the encryption for us. Unlike SharedPreferences, which we can get from Context#getSharedPreferences or Activity#getPreferences, we’ll need to create our own instance of EncryptedSharedPreferences.

val sharedPreferences = EncryptedSharedPreferences.create(
	"shared_preferences_filename",
	masterKeyAlias,
	context,
	EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
	EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

We provide the name for the shared preferences file, the masterKeyAlias we created earlier, and a Context. The final two arguments are the schemes with which keys and values are encrypted. They are the only options provided by the library.

Once we’ve created our EncryptedSharedPreferences instance, we can use it just like SharedPreferences to store and read values. Altogether, we have the following:

val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
val sharedPreferences = EncryptedSharedPreferences.create(
	"shared_preferences_filename",
	masterKeyAlias,
	context,
	EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
	EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

// storing a value
sharedPreferences
	.edit()
	.putString("some_key", "some_data")
	.apply()

// reading a value
sharedPreferences.getString("some_key", "some_default_value") // -> "some_data"

Double-checking our work

How do we know that our data is being encrypted? Let’s take a look at the contents of our shared preferences file. If you’d like to view the contents of your own shared preferences file, StackOverflow has you covered. Using the normal SharedPreferences, this is what we have:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="some_key">some_data</string>
</map>

As we can see, both the key and value are stored unencrypted. Using EncryptedSharedPreferences, our shared preferences file resembles the following:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="ATP1ABa3NIlOap2c7iNkVaUcQmTocrnpkXl0PyI=">AU+p3hwqCgvlDOtIaawFHWVDf4rFsqghM7ivFTEJesrRp19D+zk7tqsqlGZPLAbryHI=</string>
    <string name="__androidx_security_crypto_encrypted_prefs_key_keyset__">12a901802f1a5d2fbc5cd3c9b545a89ca8ace8f125f8e601a8ac51929303ead8a2bbdf5428bd054360b97c1727ef93ef63b64f43ceac92156f3aee9402dd247009d9779571c6ceacfcd4e7123665cc9dd94c44c5c2c6241a8de070d365d94010f8affb6097d4b0fec1c628120a8f901c23caa03d32ecc6ce270e3cc3341e6455b87a80474b3818c3ad678faa4199a9a45078b218c89b8c5a8cbd1780a68b4f8196eb5153b6422df2bdfee6541a44089680d49f03123c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e4165735369764b65791001189680d49f032001</string>
    <string name="__androidx_security_crypto_encrypted_prefs_value_keyset__">128801da6fdef289b2c6e2933c341b1b3df3b39330671d76df362ba8b0a1d807cdc9d2d4d7bc3062139377e4fa61428f3817c0e368c3196c95fdbcca3c37075e7132abae1fe0f128ceef7278a06a01e0cacf29edc1f3c1c1d37875c27c0cf5d86d0b2bb39efcac84828f664838b77aa4c406028af912e860cad8bff51aca6aaf45167d5ab5c8e57bf05db61a44089cbca7fd04123c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e41657347636d4b65791001189cbca7fd042001</string>
</map>

We can see that our key-value data has been encrypted and that two keysets were stored, as well. There is one keyset for shared preference keys and another for values. Keysets contain cryptographic keys that are used to encrypt and decrypt the shared preference data. The master key we created earlier is used to encrypt these keysets so they can be stored in shared preferences along with the data they’re for.

Wrapping up

Android’s SharedPreferences is a useful tool to store key-value data, and when that data is sensitive, it’s a good idea to encrypt it. The recent AndroidX Security library is a welcome addition that provides us with a simple and easy-to-use interface to do so.

The post Encrypting Shared Preferences with the AndroidX Security Library appeared first on Big Nerd Ranch.

]]>