26

I am using the following code to store some information encrypted in my app.

    val masterKey = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)

    val sharedPreferences = EncryptedSharedPreferences.create(
        "secret_shared_prefs",
        masterKey,
        this,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )

Since the MasterKeys class deprecated in Android, I should use the MasterKey class and but I cannot figure out what is the right method to get the same mastery defined.

Could somebody show the exact match with the available MasterKey and MasterKey.Builder classes?

The below solution worked like this:

val spec = KeyGenParameterSpec.Builder(
        "_androidx_security_master_key_",
        KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
    )
        .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
        .setKeySize(256)
        .build()

    val masterKey: MasterKey = MasterKey.Builder(this)
        .setKeyGenParameterSpec(spec)
        .build()

    val sharedPreferences = EncryptedSharedPreferences.create(
        this,
        "secret_shared_prefs",
        masterKey, // masterKey created above
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM);
Endre Olah
  • 875
  • 2
  • 9
  • 25
  • 3
    Hey, instead of using the hard coded Maste key alias and key size of 256, you should use `MasterKey.DEFAULT_MASTER_KEY_ALIAS` and `MasterKey.DEFAULT_AES_GCM_MASTER_KEY_SIZE` – Takeya Aug 12 '20 at 11:14
  • 1
    EncryptedSharedPreferences.create(...) is also deprecated – Ahmad Shahwaiz Jul 27 '21 at 13:48

7 Answers7

51

try this one


MasterKey masterKey = new MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
        .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
        .build();

SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
        context,
        SHARED_PREF_NAME,
        masterKey,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM);
Alex Art.
  • 8,711
  • 3
  • 29
  • 47
yohannes seifu
  • 609
  • 5
  • 5
34

I had exactly the same problem today. See below for fix/workaround (example is in Java code but you can easily do the same in Kotlin)

  1. Use MasterKey.Builder to create MasterKey (instead of MasterKeys). Build it with "manually" created KeyGenParameterSpec:

     // this is equivalent to using deprecated MasterKeys.AES256_GCM_SPEC
     KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
             MASTER_KEY_ALIAS,
             KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
             .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
             .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
             .setKeySize(KEY_SIZE)
             .build();
    
     MasterKey masterKey = new MasterKey.Builder(MainActivity.this)
             .setKeyGenParameterSpec(spec)
             .build();
    
  2. Create EncryptedSharedPreferences using slightly different version of "create" method:

     EncryptedSharedPreferences.create(
             MainActivity.this,
             "your-app-preferences-name",
             masterKey, // masterKey created above
             EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
             EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM);
    

That should do the trick :)

Reference and more details: https://devmainapps.blogspot.com/2020/06/android-masterkeys-deprecated-how-to.html

xproph
  • 1,171
  • 11
  • 7
15

My version to get secret shared preference :

private fun getSecretSharedPref(context: Context): SharedPreferences {
    val masterKey = MasterKey.Builder(context)
            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
            .build()

    return EncryptedSharedPreferences.create(context,
            "secret_shared_prefs",
            masterKey,
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )
}
CmoiJulien
  • 659
  • 8
  • 6
11

you can use either of the way

KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
     MASTER_KEY_ALIAS,
     KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
     .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
     .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
     .setKeySize(KEY_SIZE)
     .build();

MasterKey masterKey = new MasterKey.Builder(MainActivity.this)
     .setKeyGenParameterSpec(spec)
     .build();

or

MasterKey masterKey = new 
              MasterKey.Builder(context,MasterKey.DEFAULT_MASTER_KEY_ALIAS).
              setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build();

MasterKey.KeyScheme.AES256_GCM internally use same key generatespec as stated above.

Csaba Toth
  • 10,021
  • 5
  • 75
  • 121
Neha Rathore
  • 429
  • 2
  • 9
3

You can use it like this below

//Creating MasterKey
            val masterKey = MasterKey.Builder(context)
                .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
                .build()

            val fileToRead = "your_file_name.txt"
            val encryptedFile = EncryptedFile.Builder(context,
                File(context.filesDir, fileToRead),
                masterKey,
                EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
            ).build()
Jimale Abdi
  • 2,574
  • 5
  • 26
  • 33
1

Kotlin version based on responses here with dependency on Security kotlin version androidx.security:security-crypto-ktx

class EncryptedPrefsImpl(context: Context) { 
    private companion object {    
        const val PREFERENCES_NAME = "some_file_name_here"
    }

    private val spec = KeyGenParameterSpec.Builder(
        MasterKey.DEFAULT_MASTER_KEY_ALIAS,
        KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
    ).apply {
        setBlockModes(KeyProperties.BLOCK_MODE_GCM)
        setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
        setKeySize(MasterKey.DEFAULT_AES_GCM_MASTER_KEY_SIZE)
    }.build()

    private val masterKey = MasterKey.Builder(context).apply {
        setKeyGenParameterSpec(spec)
    }.build()

    val preferences: SharedPreferences by lazy {
        EncryptedSharedPreferences(
            context,
            PREFERENCES_NAME,
            masterKey
        )
    }
}
mtrakal
  • 6,121
  • 2
  • 25
  • 35
  • Wow, something new. First time saw someone just for example at least mentioned `MasterKey.DEFAULT_MASTER_KEY_ALIAS` – sud007 Jun 16 '23 at 11:29
0

If you're using the -ktx version of androidx.security:security-crypto you can reduce some of the boilerplate to just this:

val encryptedSharedPrefs = EncryptedSharedPreferences(
    context,
    ENCRYPTED_STORAGE_FILENAME,
    MasterKey(context)
)
mtrakal
  • 6,121
  • 2
  • 25
  • 35
Matt Robertson
  • 2,928
  • 5
  • 34
  • 62