[英]Is it possible to generate a 64-byte (256-bit) key and store/retrieve it with AndroidKeyStore?
在我的Android应用程序中,我需要一种对存储在本地数据库中的数据进行加密的方法。 我选择Realm DB是因为它提供了与加密的无缝集成。 我只需要在初始化Realm实例时传递密钥。 该密钥必须为64字节大小。
出于安全原因,我发现最好的存储方式是在AndroidKeyStore中。 我正在努力寻找一种方法来生成具有该大小的密钥(使用任何算法),并将其放入64字节数组中。 我正在尝试保留API 19的minSdk,但我相信如果需要可以将其提高到23(这两个版本之间对AndroidKeyStore进行了许多更改)。
有人有主意吗? 这是我的代码:
类Encryption.java
private static KeyStore ks = null;
private static String ALIAS = "com.oi.pap";
public static byte[] loadkey(Context context) {
byte[] content = new byte[64];
try {
if (ks == null) {
createNewKeys(context);
}
ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
content= ks.getCertificate(ALIAS).getEncoded(); //<----- HERE, I GET SIZE GREATER THAN 64
Log.e(TAG, "original key :" + Arrays.toString(content));
} catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
content = Arrays.copyOfRange(content, 0, 64); //<---- I would like to remove this part.
return content;
}
private static void createNewKeys(Context context) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
try {
// Create new key if needed
if (!ks.containsAlias(ALIAS)) {
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
end.add(Calendar.YEAR, 1);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
.setAlias(ALIAS)
.setSubject(new X500Principal("CN=PapRealmKey, O=oipap"))
.setSerialNumber(BigInteger.ONE)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.setKeySize(256)
.setKeyType(KeyProperties.KEY_ALGORITHM_EC)
.build();
KeyPairGenerator generator = KeyPairGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
generator.initialize(spec);
KeyPair keyPair = generator.generateKeyPair();
Log.e(TAG, "generated key :" + Arrays.toString(keyPair.getPrivate().getEncoded()));
}
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
}
}
AndroidKeyStore的目的是将敏感密钥材料从您的应用程序,操作系统中移出,并移入安全的硬件中,绝不会泄漏或受到损害。 因此,根据设计,如果您在AndroidKeyStore中创建密钥,则永远无法获取密钥资料。
在这种情况下,Realm DB需要密钥材料,因此您不能为其提供AndroidKeyStore密钥。 另外,Realm想要的是您尝试生成的两个AES密钥,而不是EC密钥。
生成所需关键材料的正确方法是:
byte[] dbKey = new byte[64];
Random random = new SecureRandom();
random.nextBytes(dbKey);
// Pass dbKey to Realm DB...
Arrays.fill(dbKey, 0); // Wipe key after use.
只有64个随机字节。 但是,您将需要将这些字节存储在某个地方。 您可以使用AndroidKeyStore创建AES密钥,并使用它来加密dbKey
。 就像是:
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGenerator.init(
new KeyGenParameterSpec.Builder("dbKeyWrappingKey",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
SecretKey key = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV();
byte[] encryptedDbKey = cipher.doFinal(dbKey);
你需要节省iv
和encryptedDbKey
的地方(而不是在数据库!),这样就可以恢复dbKey
。 然后您可以使用以下方法解密:
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
key = (SecretKey) keyStore.getKey("dbKeyWrappingKey", null);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(128, iv));
byte[] dbKey = cipher.doFinal(encryptedDbKey);
// Pass dbKey to Realm DB and then wipe it.
但是,尽管如此,我不认为您应该做任何事情。 我认为这实际上不会为您提供任何安全性,而Android默认情况下不会为您提供任何安全性。 如果攻击者试图转储包含您的数据库的设备存储,则他将一无所获,因为Android仍然会加密所有存储。 如果攻击者可以启动设备,则他可以像您的应用程序一样运行代码,并以与您的应用程序相同的方式使用它来解密dbKey
。
如果您在dbKeyWrappingKey
上添加一些其他保护,则AndroidKeyStore可能真正增加价值的dbKeyWrappingKey
。 例如,如果将其设置为要求在五分钟之内进行用户身份验证,则只有当用户在附近输入PIN /图案/密码或触摸指纹扫描器时,才可以使用dbWrappingKey
解密dbKey
。 请注意,这仅在用户具有PIN /图案/密码的情况下才有效,但是如果没有,则您的数据库对任何仍然接听电话的人都是开放的。
有关限制dbKeyWrappingKey
使用方式的所有操作,请参见KeyGenParameterSpec
。
据我所知,解决此问题的通常方法是,生成自己所需大小的随机密钥(主密钥),并且可以在密钥存储的帮助下对该主密钥进行加密。
解密数据:
换句话说,不是主密钥存储在密钥存储区中,但是密钥存储区可用于保护/加密您的主密钥。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.