Java-приложения могут и должны использовать класс java.security.SecureRandom для создания криптографически сильных случайных значений с помощью криптографически сильного генератора псевдослучайных чисел ( CSPRNG ). Стандартные реализации JDK класса java.util.Random не считаются криптографически стойкими.
Unix-подобные операционные системы имеют /dev/randomспециальный файл, который обслуживает псевдослучайные числа, получая доступ к окружающему шуму, полученному от драйверов устройств и других источников. Однако он блокируется, если энтропии меньше, чем требуется ; /dev/urandomобычно никогда не блокируется, даже если начальное число генератора псевдослучайных чисел не было полностью инициализировано энтропией с момента загрузки. Есть еще 3-й специальный файл, /dev/arandomкоторый блокируется после загрузки, пока начальное число не будет безопасно инициализировано с достаточной энтропией, а затем никогда не блокируется снова.
По умолчанию JVM использует класс SecureRandom/dev/random , поэтому ваш код Java может неожиданно блокироваться . Опция -Djava.security.egd=file:/dev/./urandomв вызове командной строки, используемая для запуска процесса Java, указывает JVM использовать /dev/urandomвместо этого.
Дополнительное, /./кажется, заставляет JVM использовать алгоритм SHA1PRNG, который использует SHA-1 в качестве основы PRNG (Генератор псевдослучайных чисел). Он сильнее, чем алгоритм NativePRNG, используемый, когда /dev/urandomон указан.
Наконец, существует миф, что /dev/urandomэто генератор псевдослучайных чисел, PRNG, в то время /dev/randomкак это «истинный» генератор случайных чисел . Это просто не так, как /dev/randomи /dev/urandomпитаются тем же CSPRNG (криптографически безопасный генератор псевдослучайных чисел). Только поведение, когда их соответствующий пул исчерпывает энтропию, согласно некоторой оценке, отличается: /dev/randomблокирует, в то время /dev/urandomкак нет.
Как насчет энтропии на исходе? Это не важно
Оказывается, что «смотреть случайным образом» является основным требованием для многих наших криптографических блоков. И если вы берете вывод криптографического хэша, он должен быть неотличим от случайной строки, чтобы шифры могли его принять. Это причина использования алгоритма SHA1PRNG, поскольку он использует хеш-функцию и счетчик вместе с начальным числом.
Когда предполагается применять?
Всегда, я бы сказал.
Источники:
https://gist.github.com/svrc/5a8accc57219b9548fe1
https://www.2uo.de/myths-about-urandom
РЕДАКТИРОВАТЬ 04/2020:
Комментарий упоминает об изменении поведения класса SecureRandom в Java 8.
SHA1PRNG и NativePRNG были исправлены для правильного соблюдения свойств исходного кода SecureRandom в файле java.security. (Запутанный обходной путь с использованием file: /// dev / urandom и file: / dev /./ urandom больше не требуется.)
На это уже указывали тесты, указанные в разделе «Источники» выше. /./Требуется дополнительное, чтобы изменить алгоритм, используемый SecureRanom в Java 8, с NativePRNG на SHA1PRNG.
Тем не менее, у меня есть некоторые новости, которыми я хотел бы поделиться. Согласно JEP-273 , начиная с Java 9, класс SecureRandom реализует три механизма детерминированного генератора случайных битов (DRBG) , описанных в NIST 800-90Ar1 . Эти механизмы реализуют современные сильные алгоритмы, такие как SHA-512 и AES-256.
В JDK было два вида реализаций SecureRandom :
- Один из них зависит от платформы и основан на собственных вызовах или устройствах ОС, таких как чтение
/dev/{u}randomв Unix или использование CryptoAPI в Windows. Последние выпуски Linux и Windows уже поддерживают DRBG, но более старые выпуски и встроенные системы могут этого не делать .
- Другой вид - это чистая реализация Java, которая использует более старую реализацию RNG на основе SHA1, которая не так сильна, как алгоритмы, используемые утвержденными механизмами DRBG.
Между тем, в Руководстве разработчика по Java 13 Security все еще говорится
В Linux и macOS, если устройство сбора энтропии в java.security установлено на file:/dev/urandomили file:/dev/random, то NativePRNG предпочтительнее, чем SHA1PRNG. В противном случае SHA1PRNG является предпочтительным.
Чтобы выяснить, как новые механизмы DRBG взаимодействуют с предыдущими PRNG, я запустил некоторые тесты на macOS (Darwin) с AdoptOpenJDK (сборка 13.0.2 + 8). Вот результаты:
file: / dev / random
Порядок предпочтений для провайдеров:
SecureRandom.NativePRNG
SecureRandom.DRBG
SecureRandom.SHA1PRNG
file: / dev / urandom
Порядок предпочтений для провайдеров:
SecureRandom.NativePRNG
SecureRandom.DRBG
SecureRandom.SHA1PRNG
file: / dev /./ urandom
Порядок предпочтений для провайдеров:
SecureRandom.DRBG
SecureRandom.SHA1PRNG
SecureRandom.NativePRNG
Вывод:
Я бы порекомендовал использовать -Djava.security.egd=file:/dev/./urandomего, чтобы убедиться в использовании самой мощной из доступных реализаций SecureRandom независимо от используемой платформы, избегая при этом неожиданной блокировки кода.