Iced Tea Labs Share to be shared

Android Data Encryption using Jetpack Security

Android Data Encryption using Jetpack Security

Photo by [Philipp Katzenberger](https://unsplash.com/@fantasyflip?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

As an Android developer, you probably want to encrypt your application data at some points for security reasons. Those sensitive data can be varied from personal identifiable information (PII), financial records, to enterprise-related data.

By using Jetpack Security (JetSec), you can easily encrypt Files and SharePreferences locally to protect your sensitive information.

Include JetSec into the project

To use JetSec in your project, just simply adding the dependencies below in your app’s build.gradle:

dependencies {
    implementation "androidx.security:security-crypto:1.0.0-rc03"
}

Key Generation

JetSec library uses the 2-part system for key management:

Before doing any cryptographic operation, you have to generate the key first.

Out of the box, JetSec provides the default master key within the MasterKey class with the AES256_GCM_SPEC specification. The master key is generated and stored in the Android Keystore system, which makes it difficult to extract the key material.

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

The default master key should be fine for general purposes. In case you want to create a master key with a custom specification, JetSpec also supports that:

val customSpec = KeyGenParameterSpec.Builder(
        "master_key",
        KeyProperties.*PURPOSE_ENCRYPT *or KeyProperties.*PURPOSE_DECRYPT
*)
        .setBlockModes(KeyProperties.*BLOCK_MODE_GCM*)
        .setEncryptionPaddings(KeyProperties.*ENCRYPTION_PADDING_NONE*)
        .setKeySize(256)
        .setUserAuthenticationRequired(true)
        .setUserAuthenticationValidityDurationSeconds(60)
        .*apply ***{
            **if (Build.VERSION.*SDK_INT *>= Build.VERSION_CODES.*P*) {
                setUnlockedDeviceRequired(true)
                setIsStrongBoxBacked(true)
            }
        **}
        **.build()

val masterKeyAlias = MasterKeys.getOrCreate(customSpec)

EncryptedSharedPreferences

If you need to save data in the key-value format securely, JetSpec provides EncryptedSharedPreferences which share the same interface with the normal SharedPreferences.

Using EncryptedSharedPreferences, both keys and values are encrypted:

The below code snippets show you how to edit a record of the encrypted shared preferences:

val sharedPrefs: SharedPreferences = EncryptedSharedPreferences.create(
        "secured_shared_prefs",
        masterKeyAlias,
        *applicationContext*,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.*AES256_SIV*,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.*AES256_GCM
*)

sharedPrefs.edit()
        .putString("auth_token", "random_auth_token")
        .apply()

And the result 🎉

EncryptedFile

The EncryptedFile class provides custom implementation of FileInputStream and FileOutputStream, allows you to read and write encrypted files easier.

To provide secure read and write operations from file streams, JetSec uses the Streaming Authenticated Encryption with Associated Data (AEAD) primitive. The data is divided into chunks and encrypted using AES256-GCM.

The below code snippets show you how to write data into file securely:

val fileToWrite = File(getDir("sensitive_data", *MODE_PRIVATE*), "encrypted_data.txt")
val encryptedFile = EncryptedFile.Builder(
        fileToWrite,
        *applicationContext*,
        masterKeyAlias,
        EncryptedFile.FileEncryptionScheme.*AES256_GCM_HKDF_4KB
*).build()

val fileContent = "Hello world!"
        .*toByteArray*(StandardCharsets.*UTF_8*)

encryptedFile
        .openFileOutput()
        .*run ***{
            **write(fileContent)
            flush()
            close()
        **}**

… and read encrypted data from a file securely:

val fileToRead = File(getDir("sensitive_data", *MODE_PRIVATE*), "encrypted_data.txt")
val encryptedFile = EncryptedFile.Builder(
        fileToRead,
        *applicationContext*,
        masterKeyAlias,
        EncryptedFile.FileEncryptionScheme.*AES256_GCM_HKDF_4KB
*).build()

val byteArrayOutputStream = ByteArrayOutputStream()
encryptedFile.openFileInput().*run ***{
    **var nextByte: Int = read()

    while (nextByte != -1) {
        byteArrayOutputStream.write(nextByte)
        nextByte = read()
    }

    close()
**}

**val plaintext = *String*(byteArrayOutputStream.toByteArray())

And the result 🎉

If you have any feedback/corrections, please feel free to leave a comment below.

Thanks for reading and happy coding! 💻

comments powered by Disqus