2017-02-20 3 views
3

Я использую следующий код для создания AES ключ:Вызов .getEncoded() на SecretKey возвращает нуль

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() , метод возвращает null. В документации говорится, что он должен вернуть закодированный ключ или null, если ключ не поддерживает кодировку, но я не думаю, что ключ не поддерживает кодировку.

мне нужен байт [], потому что я хочу, чтобы зашифровать базу данных области действия (для которой мне нужно объединить 2 AES-256 ключей в виде байт-массивов) [https://realm.io/docs/java/latest/#encryption]

Официальная документация использует SecureRandom, но и утверждает что это глупый способ сделать это и что ключ никогда не хранится. Поэтому я хотел использовать KeyStore для безопасного хранения двух отдельных ключей AES-256.

P.S .: Код является только тестовым кодом, а не конечным продуктом, поэтому любые комментарии к стилю кодирования бесполезны. В настоящее время я просто пытаюсь получить рабочую версию.

редактировать: Так что я попытался следующий код, который успешно генерирует ключ 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);, который также работал. Но когда я вызываю entry2.getEncoded(), метод снова возвращает null. Является ли это проблемой хранилища ключей?

edit2: Итак, я только что узнал, что симметричные ключи, сгенерированные в (хранилище), хранящиеся в хранилище ключей, неизлечимы в Android M, что, по-видимому, предназначено, что ставит меня в проблему, поскольку мне нужно ключ для шифрования базы данных области.

Некоторые представители сферы недвижимости здесь, чтобы рекомендовать лучшие практики?

ответ

2

То, что вы не можете получить закодированный ключ, зависит от того, как Keystore должен быть единственным, кто его знает. Однако вы можете использовать двуслойный ключ:

1) Создайте случайный ключ и сохраните его в хранилище ключей.

2) Создайте «реальный» ключ, используемый Realm, и зашифруйте его, используя ключ из Keystore.

3) Теперь у вас есть совершенно случайный текст, который может быть сохранен, например, SharedPreferences или в файле на диске.

4) Когда люди хотят открыть Царство, прочитайте зашифрованный ключ на диске, расшифруйте его, используя Keystore, и теперь вы можете использовать его для открытия Царства.

Этот репозиторий здесь используется тот же метод, чтобы сохранить пользовательские данные в безопасном режиме: 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 (к хранилищу имеет довольно несколько причуд).

+0

Да, это звучит как лучший обходной момент на данный момент. Благодарю. – wickermoon

Смежные вопросы