Как создать безопасный случайный ключ 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();

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

3 ответов


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

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

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

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

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


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

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

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

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

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

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


много хорошего advince в других сообщениях. Вот что я использую:

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

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

MySecureRandom rand = new MySecureRandom();