Endre Olah
Endre Olah

Reputation: 955

How to create masterKey after MasterKeys deprecated in Android

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);

Upvotes: 33

Views: 21962

Answers (7)

mtrakal
mtrakal

Reputation: 6427

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
        )
    }
}

Upvotes: 1

Matt Robertson
Matt Robertson

Reputation: 3165

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)
)

Upvotes: 0

CmoiJulien
CmoiJulien

Reputation: 697

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
    )
}

Upvotes: 16

Neha Rathore
Neha Rathore

Reputation: 427

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.

Upvotes: 11

Jimale Abdi
Jimale Abdi

Reputation: 2864

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()

Upvotes: 3

yohannes  seifu
yohannes seifu

Reputation: 649

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);

Upvotes: 55

xproph
xproph

Reputation: 1241

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

Upvotes: 37

Related Questions