2

I'm trying to create an encrypted SharedPreferences implementation but the example given in the Android website is for API 23 and above. Specifically, the problem is creating a master key using this code is MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC).

On the current version of androidx security ('androidx.security:security-crypto:1.1.0-alpha01'), you could technically create the implementation for EncryptedSharedPreferences except that the getOrCreate() function state above is for API 23 and above only. So if I understood it correctly, the only thing missing for me to be able to do the following lines of code:

private fun createSharedPref(context: Context): SharedPreferences {
    return create(
        "secret_shared_prefs",
        masterKeyAlias,
        context,
        PrefKeyEncryptionScheme.AES256_SIV,
        PrefValueEncryptionScheme.AES256_GCM
    )
}

Is to create my own custom MasterKey. Is there a way to do that in API 21?

Here's how I coded it so far:

class SharedPreferencesUtil {
    companion object {
        private val masterKeyAlias = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
        } else {
            TODO("VERSION.SDK_INT < M")
            //I need help here
        }


        private fun createSharedPref(context: Context): SharedPreferences {
            return create(
                "secret_shared_prefs",
                masterKeyAlias,
                context,
                PrefKeyEncryptionScheme.AES256_SIV,
                PrefValueEncryptionScheme.AES256_GCM
            )
        }


        fun saveObject(context: Context, key: String, data: Any) {
            val gson = Gson()
            val json = gson.toJson(data)
            val prefs = createSharedPref(context)
            prefs.edit().putString(key, json).apply()
        }


        fun getJson(context: Context, key: String): String {
            val prefs = createSharedPref(context)
            val json = prefs.getString(key, "null")
            return json!!
        }


        fun clearPreferences(context: Context) {
            val prefs = createSharedPref(context).edit()
            //remove my data
        }
    }
}
CoolMind
  • 26,736
  • 15
  • 188
  • 224
kobowo
  • 2,529
  • 2
  • 24
  • 37

1 Answers1

2

I found a working solution (source)

I replaced my implementation of the master key to as follows:

private fun createMasterKey(context: Context): String {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
    } else {
        val alias = "your_alias"
        val start: Calendar = GregorianCalendar()
        val end: Calendar = GregorianCalendar()
        end.add(Calendar.YEAR, 30)

        val spec =
            KeyPairGeneratorSpec.Builder(context) 
                .setAlias(alias)
                .setSubject(X500Principal("CN=$alias"))
                .setSerialNumber(
                    BigInteger.valueOf(
                        Math.abs(alias.hashCode()).toLong()
                    )
                )
                .setStartDate(start.time).setEndDate(end.time)
                .build()

        val kpGenerator: KeyPairGenerator = KeyPairGenerator.getInstance(
            "RSA",
            "AndroidKeyStore"
        )
        kpGenerator.initialize(spec)
        val kp: KeyPair = kpGenerator.generateKeyPair()
        kp.public.toString()
    }
}
kobowo
  • 2,529
  • 2
  • 24
  • 37
  • `MasterKeys` is deprecated. `KeyPairGeneratorSpec.Builder` requires API 18 and is deprecated. – CoolMind Mar 22 '21 at 10:44
  • @CoolMind do you have a better solution? – Aykhan Hagverdili Jul 27 '21 at 05:35
  • @AyxanHaqverdili, sorry, I changed a project and maybe see sources later. See https://stackoverflow.com/questions/62498977/how-to-create-masterkey-after-masterkeys-deprecated-in-android and others. – CoolMind Jul 27 '21 at 06:27
  • @CoolMind I was actually reading that exact post when you commented. It doesn't work for API 22 which is kind of the point here. – Aykhan Hagverdili Jul 27 '21 at 06:28
  • @AyxanHaqverdili, maybe. I tested my solution on API 21 too. Maybe see https://medium.com/swlh/protect-your-android-users-data-encryptedsharedpreferences-f423342ade24 and https://medium.com/android-club/store-data-securely-encryptedsharedpreferences-bff71ac39a55. Or create master key depending on API version. – CoolMind Jul 27 '21 at 06:31
  • @CoolMind I do create the master key depending on the API. On 23+ I use the non-deprecated version you linked. The problem is API 22. This answer works but I don't know how secure it is. – Aykhan Hagverdili Jul 27 '21 at 06:35