我决定使用AndroidX安全库中的新EncryptedSharedPreferences。由于该应用程序支持API 21及更高版本,我决定试用这个新的v1.1.0-alpha02版本,因为它支持API 21+
因此,我成功地实现了API 23+,但对于不支持Android KeyStore的旧版本,我无法使其正确,并且没有确切的说明应该如何创建主密钥以使其以某种方式工作。
初始化SharedPrefs:的代码
EncryptedSharedPreferences.create(
"prefs_name",
createMasterKey(),
App.appContext,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
使用此功能创建主密钥
private fun createMasterKey(): String {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
} else {
val alias = "my_alias"
val start: Calendar = GregorianCalendar()
val end: Calendar = GregorianCalendar()
end.add(Calendar.YEAR, 30)
val spec = KeyPairGeneratorSpec.Builder(App.appContext)
.setAlias(alias)
.setSubject(X500Principal("CN=$alias"))
.setSerialNumber(BigInteger.valueOf(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()
}
}
我在某个地方找到了这个解决方案,但它没有得到验证(没有证实它确实有效(,但它似乎应该有效。
当为API 21和22使用此代码块时,创建EncryptedSharedPreferences时会出现错误,并显示:方法引发了"com.google.crypto.tink.shaded.protobuf.InvalidProtocolBufferException"异常。协议消息包含无效标记(零(。
有人找到了这个实现的解决方案吗?或者你知道为什么会发生这种情况吗?我认为这会帮助很多人,因为没有确切的解释这个主密钥应该包含什么。
提前感谢!
添加到清单android:allowBackup="false" android:fullBackupContent="false"
因为卸载应用程序后,您仍然备份了加密文件,安装新版本后肯定无法解密。
以下是我所做的,它似乎已经修复了错误。与其删除自动备份功能,不如这样做:
在AndroidManifest.xml 中
android:allowBackup="true"
android:fullBackupContent="@xml/backup_descriptor"
在backup_descriptor.xml 中
<full-backup-content>
<exclude domain="sharedpref" path="keys.xml"/>
</full-backup-content>
keys.xml是加密的共享首选项文件名。以这种方式排除所有加密的共享首选项文件。
此外,我正在使用实现‘androidx.security:安全加密:1.1.0-alpha02’
目前,似乎一切都在这个设置中运行良好。
我可以用两种方法修复InvalidProtocolBufferException
,尽管我不喜欢它们中的任何一种:
使用旧版本的security-crypto
implementation 'androidx.security:security-crypto:1.1.0-alpha01'
使用security-crypto
的最新版本(在撰写本文时(,但强制使用较旧版本的tink:
implementation 'androidx.security:security-crypto:1.1.0-alpha03'
implementation('com.google.crypto.tink:tink-android') {
version {
strictly '1.4.0'
}
}
更新:不同设备上的错误。结果不是解决方案
我设置了android propreties";fullbackupcontent";在我的舱单中
android:fullBackupContent="@xml/backup_descriptor"
这是我的备份描述符文件
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<!-- App data isn't included in user's backup unless client-side encryption is enabled. -->
<include domain="file" path="." requireFlags="clientSideEncryption" />
<!-- Exclude specific shared preferences that contain GCM registration Id -->
<!-- <exclude domain=["file" | "database" | "sharedpref" | "external" | "root"]-->
<!-- path="string" />-->
</full-backup-content>
现在我的应用程序又开始工作了&我可以继续允许备份。
来源:https://developer.android.com/guide/topics/data/autobackup#define-设备条件
https://developer.android.com/guide/topics/data/autobackup#IncludingFiles
这是我在谷歌问题跟踪器上找到的一个不同的解决方案
正如谷歌文档所说;注意:EncryptedFile类和EncryptedSharedPreferences
类中的方法都不是线程安全的"您需要将调用封装在一个同步的方法中。
@synchronized
fun createSharedPreferences() {
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
prefs = EncryptedSharedPreferences.create(
"file-name",
masterKeyAlias,
context,
PrefKeyEncryptionScheme.AES256_SIV,
PrefValueEncryptionScheme.AES256_GCM)
}
src。https://issuetracker.google.com/issues/147480931#comment19