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 независимо от используемой платформы, избегая при этом неожиданной блокировки кода.