Смысл 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 случайных байта. Однако вам нужно где-то хранить эти байты. Вы можете создать ключ AES с AndroidKeyStore и использовать его для шифрования 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
так же, как ваше приложение.
AndroidKeyStore действительно может повысить ценность, если вы добавите некоторые дополнительные средства защиты в dbKeyWrappingKey
. Например, если вы установите для него требование аутентификации пользователя в течение, скажем, пяти минут, можно будет использовать dbWrappingKey
для расшифровки dbKey
, когда пользователь рядом, чтобы ввести свой PIN-код / шаблон / пароль или коснуться сканера отпечатков пальцев , Обратите внимание, что это работает только в том случае, если у пользователя есть PIN-код / шаблон / пароль, но если они этого не делают, ваша база данных широко открыта для любого, кто все равно поднимает трубку.
См. KeyGenParameterSpec
обо всех вещах, которые вы можете сделать, чтобы ограничить способы использования dbKeyWrappingKey
.