在SecretKey上调用.getEncoded()会返回null

我使用以下代码生成AES密钥:

KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder("db_enc_key", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT); KeyGenParameterSpec keySpec = builder .setKeySize(256) .setBlockModes("CBC") .setEncryptionPaddings("PKCS7Padding") .setRandomizedEncryptionRequired(true) .setUserAuthenticationRequired(true) .setUserAuthenticationValidityDurationSeconds(5 * 60) .build(); KeyGenerator keyGen = KeyGenerator.getInstance("AES", "AndroidKeyStore"); keyGen.init(keySpec); SecretKey sk = keyGen.generateKey(); 

但每当我尝试通过sk.getEncoded()获取密钥的byte []版本时,该方法返回null。 文档说它应该返回编码的密钥,如果密钥不支持编码,则返回null,但我不认为密钥不支持编码。

我需要byte [],因为我想加密一个领域数据库(我需要将2个AES-256密钥组合为字节数组)[ https://realm.io/docs/java/latest/#encryption]

官方文档使用SecureRandom,但也指出这是一种愚蠢的方式,并且永远不会存储密钥。 因此,我想使用KeyStore安全地存储两个独立的AES-256密钥。

PS:代码只是一个测试代码而不是最终产品,因此对编码风格的任何评论都是无用的。 我目前正试图让一个正在运行的版本。

编辑:所以我尝试了以下代码,它成功生成了一个AES密钥(尽管只有16个字节的长度):

 SecretKey sk1 = KeyGenerator.getInstance("AES").generateKey(); 

当我对它使用getEncoded()方法时,我甚至会得到字节数组,所以我自然而然地使用以下代码将其保存到KeyStore:

 KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(sk1); KeyStore.ProtectionParameter pp = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_ENCRYPT).build(); keyStore.setEntry("db_enc_key_test", entry, pp); 

哪个也有效。 所以我试图通过KeyStore.Entry entry2 = keyStore.getEntry("db_enc_key_test", null);从keystore读取密钥KeyStore.Entry entry2 = keyStore.getEntry("db_enc_key_test", null); 这也很有效。 但是当我调用entry2.getEncoded()该方法再次返回null。 这是一个密钥库问题吗?

edit2:所以我刚刚发现,在Android M中生成(并且显然保存到)密钥库的对称密钥在Android M中是不可移植的,这似乎是有意的,这让我有点问题,因为我需要密钥本身来加密领域数据库。

一些领域的开发人员在这里推荐最佳实践?

你无法检索编码密钥是设计的,因为密钥库应该是唯一知道它的人。 但是,您可以使用双层密钥:

1)生成随机密钥并将其存储在密钥库中。

2)生成Realm使用的“真实”密钥,并使用密钥库中的密钥对其进行加密。

3)现在您有一些完全随机的文本可以存储在例如SharedPreferences或磁盘上的文件中。

4)每当人们想要打开Realm时,请阅读磁盘上的加密密钥,使用密钥库对其进行解密,现在您可以使用它来打开Realm。

这里的repo使用相同的技术以安全的方式保存用户数据: https : //github.com/realm/realm-android-user-store

这可能是你所追求的课程: https : //github.com/realm/realm-android-user-store/blob/master/app/src/main/java/io/realm/android/CipherClient.java它也通过各种Android版本处理后备(Keystore有很多怪癖)。