我正在尝试使用 masterKey 来加密共享首选项。但是,有时我的用户会由于密钥库中的 invalidKeyException 而崩溃。我无法在本地重现这个=\
java.security.KeyStoreException: the master key android-keystore://_androidx_security_master_key_ exists but is unusable
Caused by: java.security.InvalidKeyException: Keystore cannot load the key with ID: _androidx_security_master_key_
有什么想法为什么会发生这种情况吗?
val masterKey = MasterKey.Builder(context)
.setKeyGenParameterSpec(
KeyGenParameterSpec.Builder(
MasterKey.DEFAULT_MASTER_KEY_ALIAS,
PURPOSE_ENCRYPT or PURPOSE_DECRYPT
)
.setBlockModes(BLOCK_MODE_GCM)
.setEncryptionPaddings(ENCRYPTION_PADDING_NONE)
.setKeySize(MasterKey.DEFAULT_AES_GCM_MASTER_KEY_SIZE)
.build()
)
.build()
securePrefs = EncryptedSharedPreferences.create(
context,
PREFERENCES,
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
该问题也已详细报告给 Google 错误跟踪器。关注那里的讨论可能会更好。
您可以在此处查看 Android 问题:https://issuetracker.google.com/issues/176215143?pli=1
我可以建议简单的解决方法,从系统密钥库中删除首选项和密钥的数据。通过此修复,重新安装您的应用程序后无法恢复数据。但至少你的应用程序可以从新页面启动而不会崩溃。您可以创建一些自定义构建器并使用它来创建加密首选项:
class EncryptedPreferenceBuilder(val context: Context) {
companion object {
private const val TAG = "EncryptedPreferenceBuilder"
private const val KEYSTORE_PROVIDER = "AndroidKeyStore"
}
private val masterKeyAlias = MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()
fun build(prefName: String): SharedPreferences {
return try {
createSharedPreferences(prefName)
} catch (e: Exception) {
Log.e(TAG, "Error occurred while create shared preference")
deleteSharedPreferences(prefName)
deleteMasterKey()
createSharedPreferences(prefName)
}
}
private fun createSharedPreferences(prefName: String) = EncryptedSharedPreferences.create(
context,
prefName,
masterKeyAlias,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
private fun clearSharedPreference(prefName: String) {
context.getSharedPreferences(prefName, Context.MODE_PRIVATE).edit().clear().apply()
}
private fun deleteSharedPreferences(prefName: String) {
try {
clearSharedPreference(prefName)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
context.deleteSharedPreferences(prefName)
} else {
FileUtils.delete("${context.filesDir.parent}/shared_prefs/$prefName.xml")
}
} catch (e: Exception) {
Log.e(TAG, "Error delete preferences")
}
}
private fun deleteMasterKey() {
try {
val keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER)
keyStore.load(null)
keyStore.deleteEntry(MasterKey.DEFAULT_MASTER_KEY_ALIAS)
} catch (e: Exception) {
Log.e(TAG, "Error delete MasterKey")
}
}
}
用途:
val prefs = EncryptedSharedPreferenceBuilder(context).build("APP_PREFS_NAME")