Лучший способ создать ключи AES, чем посев SecureRandom

Мне нужно отправить зашифрованные данные с Java клиента на сервер C# . Сейчас я изучаю, как шифровать данные с использованием AES (требование). После этого принятого ответа на шифрование и дешифрование android с AES я делаю следующее:

 byte[] keyStart = "qweroiwejrwoejlsifeoisrn".getBytes(); // Random character string byte[] toEncrypt = myMessageString.getBytes(); keyGen = KeyGenerator.getInstance("AES"); sr = SecureRandom.getInstance("SHA1PRNG"); sr.setSeed(keyStart); keyGen.init(128, sr); SecretKey secretKey = keyGen.generateKey(); byte[] secretKeyByte = secretKey.getEncoded(); SecretKeySpec skeySpec = new SecretKeySpec(secretKeyByte, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); cipher.doFinal(toEncrypt); 

Поскольку алгоритм использует SecureRandom с помощью keyStart я не уверен, что это может быть декодировано на C# или даже в другой программе Java без SecureRandom .

Будет ли это шифрование / дешифрование работать, просто зная значение keyStart или, поскольку я использую SecureRandom мне все равно нужно передать что-то еще, чтобы расшифровать?

Кроме того, есть ли лучший способ сделать это или это просто отлично?

Нет, вся идея, что вы должны использовать SecureRandom для вывода ключей из статических данных, довольно плоха:

  1. Основная функция SecureRandom – генерировать случайные значения, она не должна использоваться как генератор для ключевого streamа;
  2. SecureRandom , когда экземпляр с "SHA1PRNG" не реализует четко определенный алгоритм, и, как известно, алгоритм изменится даже от одного Sun JDK к другому;
  3. Oracle обеспечил реализацию "SHA1PRNG" используя начальное семя, как только семя, другие могут просто добавить семя в случайный пул.

"SHA1PRNG" использование "SHA1PRNG" качестве функции деривации ключей создает проблемы в нескольких версиях Android и может не работать на любом другом Java RE.


Так что же вам делать?

  1. Используйте new SecureRandom() или даже лучше, KeyGenerator для генерации действительно случайного ключа, без посева генератора случайных чисел, если вам нужен новый случайный ключ;
  2. Непосредственно укажите byte[] известного ключа SecretKeySpec или используйте шестнадцатеричный декодер для декодирования его из шестнадцатеричных (обратите внимание, что экземпляры String трудно удалить из памяти, так что делайте это только в том случае, если нет другого пути);
  3. Используйте PBKDF2, если вы хотите создать ключ из пароля (используйте более высокий счетчик итераций, чем тот, который указан в ссылке);
  4. Используйте истинный механизм определения ключевых ключей, если вы хотите создать несколько ключей из одного ключевого семестра, например, использовать HKDF (см. Ниже).

Вариант 4 был бы предпочтительным, если бы семя было сгенерировано, например, с помощью алгоритма согласования ключей, такого как Diffie-Hellman или ECDH.


Обратите внимание, что для варианта 3, PBKDF2, было бы разумным сохранить только пароли ASCII. Это связано с тем, что реализация PBKDF2 Oracle не использует кодировку UTF-8.


Что касается варианта 4, я помог добавить все хорошие KBKDF в библиотеки Bouncy Castle, поэтому вам не нужно самостоятельно внедрять KBKDF, если вы можете добавить Bouncy Castle в свой путь к classам и / или список установленных поставщиков безопасности. Вероятно, лучшим KBKDF на данный момент является HKDF. Если вы не можете добавить Bouncy Castle в свой путь к classу, вы можете использовать крайние левые байты вывода SHA-256 по данным деривации как «KDF« бедных ».

  • Обработка криптовых исключений
  • Какая оптимальная длина для паролей пользователей?
  • Шифрование / Расшифровка больших файлов (.NET)
  • Фундаментальное различие между алгоритмами Hashing и Encryption
  • Самый простой способ шифрования текстового файла в java
  • Давайте будем гением компьютера.