Програми Java можуть і повинні використовувати клас java.security.SecureRandom для створення криптографічно сильних випадкових значень за допомогою криптографічно сильного генератора псевдовипадкових чисел ( CSPRNG ). Стандартні реалізації JDK класу java.util.Random не вважаються криптографічно сильними.
У операційних систем /dev/random
, схожих на Unix , є спеціальний файл, який подає псевдовипадкові числа, що отримують доступ до екологічного шуму, зібраного з драйверів пристроїв та інших джерел. Однак він блокує, якщо доступна менша ентропія, ніж вимагається ; /dev/urandom
зазвичай ніколи не блокується, навіть якщо насіння генератора псевдовипадкових чисел не було повністю ініціалізовано ентропією з моменту завантаження. Є ще 3-й спеціальний файл, /dev/arandom
який блокується після завантаження, поки насіння не буде надійно ініціалізовано з достатньою ентропією, а потім ніколи не блокується знову.
За замовчуванням JVM виводить клас SecureRandom за допомогою /dev/random
, тому ваш код Java може блокуватись несподівано . Параметр -Djava.security.egd=file:/dev/./urandom
виклику командного рядка, який використовується для запуску процесу Java, вказує /dev/urandom
замість цього JVM .
/./
Здається, що додаткове змушує 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
EDIT 04/2020:
У коментарі згадується зміна поведінки класу SecureRandom в Java 8.
SHA1PRNG та NativePRNG були зафіксовані для належного дотримання властивостей джерела насіння SecureRandom у файлі java.security. (Незрозуміле рішення за допомогою файлу: /// 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 все ще читається
У Linux та macOS, якщо для пристрою збирання ентропії в java.security встановлено file:/dev/urandom
або file:/dev/random
, тоді NativePRNG віддається перевагу SHA1PRNG. В іншому випадку кращим є SHA1PRNG.
Щоб уточнити, як нові механізми DRBG грають разом з попередніми PRNG, я запускаю кілька тестів на macOS (Darwin) з AdoptOpenJDK (build 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, незалежно від використовуваної платформи, уникаючи несподіваного заблокування коду.