|
// |
|
// Get EncryptedSharedPreferences and handle restore of accidentallly |
|
// backuped file that we can no longer decrypt. If the master key provided |
|
// is not able to decrypt the shared preferences, the file will be recreated. |
|
// |
|
// Tested with "androidx.security:security-crypto:1.1.0-alpha06" |
|
// |
|
|
|
package pl.rynkowski.platform_utils |
|
|
|
import android.content.Context |
|
import android.content.SharedPreferences |
|
import androidx.security.crypto.EncryptedSharedPreferences |
|
import androidx.security.crypto.MasterKey |
|
import java.security.KeyStore |
|
import timber.log.Timber |
|
|
|
private const val appMasterKeyAlias = "custom_master_key" |
|
|
|
fun Context.getMasterKey(): MasterKey { |
|
val keystore = KeyStore.getInstance("AndroidKeyStore") |
|
keystore.load(null) |
|
val masterKeyAlias = |
|
if (keystore.isKeyEntry(appMasterKeyAlias)) appMasterKeyAlias |
|
else MasterKey.DEFAULT_MASTER_KEY_ALIAS |
|
return MasterKey.Builder(this, masterKeyAlias) |
|
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM) |
|
.build() |
|
} |
|
|
|
fun Context.getEncryptedSharedPreferences(filename: String): SharedPreferences { |
|
val masterKey = getMasterKey() |
|
// Return the shared preferences if we can |
|
val sharedPreferences = getEncryptedSharedPreferencesOrNull(filename, masterKey) |
|
return sharedPreferences ?: run { |
|
// otherwise delete and try again |
|
Timber.w("Cannot retrieve preferences encrypted with current master key. Deleting and recreating.") |
|
deleteSharedPreferences(filename) |
|
return getEncryptedSharedPreferencesOrThrow(filename, masterKey) |
|
} |
|
} |
|
|
|
fun Context.getEncryptedSharedPreferencesOrNull(filename: String, key: MasterKey): SharedPreferences? = |
|
try { |
|
getEncryptedSharedPreferencesOrThrow(filename = filename, key = key) |
|
} catch (e: Exception) { |
|
null |
|
} |
|
|
|
fun Context.getEncryptedSharedPreferencesOrThrow(filename: String, key: MasterKey): SharedPreferences = |
|
EncryptedSharedPreferences.create( |
|
this, |
|
filename, |
|
key, |
|
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, |
|
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM, |
|
) |
|
|
|
fun Context.getSharedPrefs(filename: String, encrypted: Boolean = false): SharedPreferences = |
|
if (encrypted) { |
|
getEncryptedSharedPreferences(filename) |
|
} else { |
|
getSharedPreferences(filename, Context.MODE_PRIVATE) |
|
} |