使用存储在KeyStore中的密钥加密Realm



我正在尝试在我的应用程序中设置一个加密的默认领域实例。其想法是使用具有给定别名的KeyPairGenerator生成密钥,将其存储在AndroidKeyStore中,并在每次需要时使用所述密钥。

我做什么

这就是我生成密钥的方式:

  KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
        ks.load(null);
        if (!ks.containsAlias(KEY_ALIAS)) {
            Calendar start = Calendar.getInstance();
            Calendar end = Calendar.getInstance();
            end.add(Calendar.YEAR, 99);
            KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
                    .setAlias(KEY_ALIAS)
                    .setSubject(new X500Principal("CN=Example, O=ExampleOrg"))
                    .setSerialNumber(BigInteger.ONE)
                    .setStartDate(start.getTime())
                    .setEndDate(end.getTime())
                    .build();
            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
            generator.initialize(spec);
            KeyPair keyPair = generator.generateKeyPair();
        }

我使用KeyPairGenerator,因为我需要支持api版本18及更高版本。

以下是我如何在我的应用程序中设置我的默认领域实例:

 RealmConfiguration config = null;
    try {
        config = new RealmConfiguration
                .Builder(this)
                .encryptionKey(ks.getKey(KEY_ALIAS, null).getEncoded())
                .name("dealmatrix.realm")
                .schemaVersion(1)
                .build();

其中ks是像这样获取的密钥存储实例:

Keystore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);

哪里出了问题

我的问题是这个表达式:

ks.getKey(KEY_ALIAS, null).getEncoded()

返回null,可以理解这会导致异常。

我在网上读到,这是KeyStore系统的预期行为。

如果我确实无法获得存储的加密密钥的字节数组,我应该如何使用所述密钥加密我的领域?

有没有其他方法可以安全地存储加密密钥,以便我可以在领域配置中使用它?

Realm存储库的feature/example/store_password分支中有一个WIP示例项目,该项目使用Android密钥库。

https://github.com/realm/realm-java/tree/feature/example/store_password/examples/StoreEncryptionPassword

核心逻辑是用Store.java 编写的

在发布这个示例项目之前,我们需要更多的工作(清理、添加注释、支持旧设备)。但我认为这个项目对你有帮助。

从getEncoded返回null的Android密钥库密钥按预期工作。getEncoded应该返回私钥的密钥材料(通常为PKCS#8 DER编码格式),如果不支持密钥材料导出,则返回null。Android密钥库设计不泄露/导出私钥或密钥的密钥材料,因此getEncoded返回null。看见https://developer.android.com/training/articles/keystore.html#SecurityFeatures.

对于Signature和Cipher抽象,您仍然可以很好地使用这些密钥。

Android密钥库禁止从中提取私钥。因此,设计将在Android密钥库之外生成Realm密钥,以便您可以使用它对Realm数据库进行加密/解密。

但为了安全地存储Realm密钥,您可以使用Android密钥库的功能,用Android密钥库加密Realm密钥并将其存储在本地(例如共享首选项)。稍后,您可以读取加密的Realm密钥,用Android密钥库解密,然后再次使用它解锁您的Realm数据库。

最新更新