29

我决定使用 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 时出现错误,并显示:Method throwed 'com.google.crypto.tink.shaded.protobuf.InvalidProtocolBufferException' 异常。协议消息包含无效标签(零)。

有人找到了这个实现的解决方案吗,或者你知道为什么会这样吗?我认为这会对很多人有所帮助,因为没有确切的解释这个主密钥应该包含什么。

提前致谢!

4

4 回答 4

17

添加到清单 android:allowBackup="false" android:fullBackupContent="false"

因为在卸载应用程序后,您仍然备份了加密文件,安装新版本后您肯定无法解密。

于 2020-09-05T19:09:38.790 回答
6

我可以通过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'
    }
}
于 2020-12-16T11:40:19.810 回答
4

更新:不同设备上的错误。结果不是解决方案。

我在我的清单中以这种方式设置了 android 属性“fullbackupcontent”

android:fullBackupContent="@xml/backup_descriptor"

这是我的 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-device-conditions

https://developer.android.com/guide/topics/data/autobackup#IncludingFiles

于 2020-09-08T13:46:49.317 回答
4

这是我所做的,它似乎已经修复了错误。不要删除自动备份功能,只需执行以下操作:

在 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:security-crypto:1.1.0-alpha02'

现在,似乎一切都在这个设置下运行良好。

于 2021-03-30T15:27:45.170 回答