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

SecureRandom с NativePRNG против SHA1PRNG

Мне нужно генерировать криптографически сильные случайные числа и байтовые массивы. Для этой цели я использую класс Java SecureRandom. Но я не уверен, чтобы выбрать алгоритм PRNG с точки зрения их криптографической силы.

Какой из следующих экземпляров генерирует более непредсказуемые числа? Или они равны?

SecureRandom nativePrng = SecureRandom.getInstance("NativePRNG")
SecureRandom sha1Prng = SecureRandom.getInstance("SHA1PRNG")

Кроме того, мы можем сгенерировать эти экземпляры с помощью поставщика "SUN" (например, SecureRandom.getInstance("SHA1PRNG", "SUN")). Это имеет значение?

Спасибо заранее.

4b9b3361

Ответ 1

TL; DR: используйте new SecureRandom(), когда вы не уверены, и дайте системе разобраться. Возможно, используйте SecureRandom.getInstanceStrong() для долгосрочной генерации ключей.

Не ожидайте, что генератор случайных чисел сгенерирует определенную выходную последовательность в приложении во время выполнения, даже если вы запустите его самостоятельно.


С генераторами случайных чисел всегда трудно сказать, что лучше. Linux и большинство Unix-систем имеют довольно хорошо продуманный генератор случайных чисел, поэтому не мешает использовать /dev/random или /dev/urandom, т.е. "NativePRNG". Проблема с использованием /dev/random заключается в том, что он блокируется до тех пор, пока не будет достаточно энтропии. Поэтому я бы советовал против этого, если у вас нет особых требований в отношении генерации ключей.


"SHA1PRNG" использует хеш-функцию и счетчик вместе с начальным числом. Алгоритм относительно прост, но он не был хорошо описан. Обычно считается безопасным. Поскольку он запускается только от одного из системных генераторов во время запуска и, следовательно, требует меньше обращений к ядру, он, вероятно, будет менее ресурсоемким - в моей системе он работает примерно в 9 раз быстрее, чем "NativePRNG" (который настроен для использования /dev/urandom). Кажется, что оба облагают налогом только одно ядро моего двухъядерного ноутбука Ubuntu (в то время он часто переключался с одного ядра на другое, что, вероятно, планировало ядро, что виновато). Если вам нужна высокая производительность, выберите это, особенно если устройство /dev/urandom работает медленно в конкретной конфигурации системы.

Обратите внимание, что "SHA1PRNG", присутствующий в устаревшей реализации Apache Harmony, отличается от того, что есть в поставщике SUN (используется Oracle в стандартной реализации Java SE). Версия в Джакарте также использовалась в более старых версиях Android. Хотя я не смог сделать полный обзор, он не выглядит слишком безопасным.

ОБНОВЛЕНИЕ: и я не ошибся наполовину, было показано, что SHA1PRNG не является псевдослучайным для версий & lt; 4.2.2 и многое другое здесь.

Помните, что "SHA1PRNG" не является требованием к реализации Java SE. В большинстве сред выполнения он будет присутствовать, но прямая ссылка на него из кода сделает ваш код менее переносимым.


В настоящее время (начиная с Java 9) OpenJDK и Oracle JDK также содержат несколько реализаций, которые просто называются "DRBG". Это реализует список динамических генераторов случайных битов, указанных NIST в SP-108. Это также не требования к реализации Java. Однако их можно использовать, если требуется FIPS-совместимый генератор случайных чисел.

Тем не менее, они не меняют рекомендации здесь; если бы разработчики думали, что они лучше, чем реализация по умолчанию, то они просто сделали бы это по умолчанию. Контракт SecureRandom не меняется: он просто необходим для генерации случайных чисел. Изменения в алгоритме по умолчанию уже были сделаны в прошлом.


В общем случае не стоит требовать конкретного поставщика. Указание поставщика может повредить совместимости; например, не каждая среда выполнения Java может иметь доступ к поставщику SUN - у Android, конечно, нет. Это также делает ваше приложение менее гибким во время выполнения, то есть вы не можете поместить поставщика выше в списке и использовать его вместо этого.

Так что указывайте поставщика только в том случае, если вы зависите от одной из функций, которые он предоставляет. Например, вы можете указать поставщика, если у вас есть конкретное аппаратное устройство, генерирующее случайные действия, или криптографическая библиотека, сертифицированная FIPS. Вероятно, было бы неплохо сделать алгоритм/поставщик параметром конфигурации для вашего приложения, если вам нужно указать поставщика.

Идея не указывать поставщика также присутствует в этом блоге безопасности Android-разработчика.


Поэтому постарайтесь не выбирать какой-либо конкретный генератор случайных чисел. Вместо этого просто перейдите к пустому конструктору аргументов: new SecureRandom() и позвольте системе выбрать лучший генератор случайных чисел. Можно использовать новый настраиваемый SecureRandom.getInstanceStrong() в Java 8 и выше, если у вас есть какие-то особые требования, например, для. генерация долгосрочных ключей.

Не кешируйте экземпляры SecureRandom, просто дайте им изначально отсеять себя и позвольте виртуальной машине справиться с ними. Я не увидел заметной разницы в работе.


Когда вообще не использовать SecureRandom:

В качестве общего предупреждения я настоятельно рекомендую не использовать генератор случайных чисел для чего-либо, кроме генерации случайных чисел. Даже если вы можете запустить его самостоятельно и даже если вы выберете Sun SHA1PRNG, не рассчитывайте, что сможете извлечь ту же последовательность случайных чисел из генератора случайных чисел. Так что не используйте его для получения ключей из паролей, чтобы назвать один пример.

Если вам требуется повторяющаяся последовательность, используйте потоковый шифр и начальную информацию для ключа и IV. Зашифруйте открытый текст, состоящий из нулей, чтобы получить ключевой поток псевдослучайных значений. В качестве альтернативы вы можете использовать функцию расширяемого вывода (XOF), такую как SHAKE128 или SHAKE256 (где доступно).

Возможно, вы захотите рассмотреть другой, небезопасный генератор случайных чисел вместо SecureRandom, если доступный RNG обеспечивает недостаточную производительность и если безопасность не является проблемой. Ни одна реализация SecureRandom не будет такой быстрой, как небезопасные генераторы случайных чисел, такие как алгоритм Мерсенна Твистера или алгоритм, реализованный классом Random. Они были оптимизированы для простоты и скорости, а не для обеспечения безопасности или качества.

Можно расширить класс SecureRandom и вставить в библиотечный вызов детерминированную, засеянную случайную реализацию. Таким образом, библиотека извлекает генератор псевдослучайных чисел с четко определенным выводом. Однако следует отметить, что генератор случайных чисел может использоваться алгоритмами по-разному. Например. RSA может переключиться на более оптимизированный способ поиска простых чисел, а ключи DES могут быть сгенерированы с помощью скорректированных или непосредственно вычисленных битов четности.

Ответ 2

Как из ссылки. здесь:

Собственная реализация PRNG для Solaris/Linux. Взаимодействует с /dev/random и /dev/urandom, поэтому он доступен только если эти файлы присутствуют. В противном случае вместо этого класса используется SHA1PRNG.

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