Подтвердить что ты не робот

Как создать безопасный случайный ключ AES в Java?

Каков рекомендуемый способ создания безопасного, случайного ключа AES на Java, используя стандартный JDK?

В других сообщениях я нашел это, но использование SecretKeyFactory может быть лучшей идеей:

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom(); // cryptograph. secure random 
keyGen.init(random); 
SecretKey secretKey = keyGen.generateKey();

Было бы здорово, если бы в ответ было объяснено, почему это хороший способ генерации случайного ключа. Спасибо!

4b9b3361

Ответ 1

Я бы использовал ваш предложенный код, но с небольшим упрощением:

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // for example
SecretKey secretKey = keyGen.generateKey();

Позвольте провайдеру выбрать, как он планирует получить случайность - не определяйте то, что может быть не так хорошо, как тот, который уже выбрал поставщик.

Этот пример кода предполагает (как указывает Маартен ниже), что вы настроили свой файл java.security, чтобы включить предпочтительного поставщика в верхней части списка. Если вы хотите вручную указать поставщика, просто позвоните KeyGenerator.getInstance("AES", "providerName");.

Для действительно безопасного ключа вам необходимо использовать аппаратный модуль безопасности (HSM) для создания и защиты ключа. Производители HSM, как правило, поставляют поставщика JCE, который сделает все ключевое поколение для вас, используя приведенный выше код.

Ответ 2

Использование KeyGenerator было бы предпочтительным методом. Как указал Дункан, я бы обязательно дал размер ключа во время инициализации. KeyFactory - это метод, который следует использовать для существующих ключей.

ОК, так что давайте доберемся до этого. В принципе ключи AES могут иметь любую ценность. Нет "слабых клавиш", как в (3) DES. Также нет битов, которые имеют определенное значение, как в (3) бит четности DES. Таким образом, генерация ключа может быть такой же простой, как создание массива байтов со случайными значениями и создание вокруг него SecretKeySpec.

Но все еще есть преимущества для метода, который вы используете: KeyGenerator специально создан для генерации ключей. Это означает, что код может быть оптимизирован для этого поколения. Это может обеспечить эффективность и безопасность. Это может быть запрограммировано, чтобы избежать атак с временным канальным каналом, которые могли бы вызвать, например, ключ. Обратите внимание, что уже может быть хорошей идеей очистить все byte[], которые содержат ключевую информацию, поскольку они могут быть просочились в файл подкачки (это может быть так или иначе).

Кроме того, как сказано, не все алгоритмы используют полностью случайные ключи. Поэтому использование KeyGenerator упростит переход на другие алгоритмы. Более современные шифры будут принимать только случайные ключи; это рассматривается как основное преимущество, например, DES.

Наконец, и в моем случае самая важная причина в том, что метод KeyGenerator является единственным допустимым способом обработки ключей AES в защищенном маркере (смарт-карта, TPM, USB-токен или HSM). Если вы создаете byte[] с помощью SecretKeySpec, тогда ключ должен поступать из памяти. Это означает, что ключ может быть помещен в защищенный токен, но ключ открыт в памяти независимо. Обычно защищенные жетоны работают только с ключами, которые либо генерируются в защищенном токене, либо инъецируются, например. смарт-карту или церемонию ключа. A KeyGenerator может поставляться с провайдером, чтобы ключ был напрямую сгенерирован в защищенном токене.

Как указано в Duncan answer: всегда указывайте размер ключа (и любые другие параметры) явно. Не полагайтесь на настройки поставщика по умолчанию, так как это будет непонятно, что делает ваше приложение, и каждый поставщик может иметь свои собственные значения по умолчанию.

Ответ 3

Много хороших советов в других постах. Это то, что я использую:

Key key;
SecureRandom rand = new SecureRandom();
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(256, rand);
key = generator.generateKey();

Если вам нужен другой поставщик случайности, который я когда-либо делал для тестирования, просто замените rand на

MySecureRandom rand = new MySecureRandom();