RANDOM(7) | Руководство программиста Linux | RANDOM(7) |
random - обзор интерфейсов получения случайных чисел
Генератор случайных чисел ядра полагается на энтропию, собранную с драйверов устройств и других источников окружающего шума, чтобы задать начальное значение криптографически безопасный генератор псевдослучайных чисел (CSPRNG). При разработке главным параметром была безопасность, а не скорость.
Следующие интерфейсы предоставляют доступ к данным ядерного CSPRNG:
Ядро собирает биты энтропии из окружения. Когда собрано достаточное количество произвольных бит, пул энтропии считается инициализированным.
Если вы не генерируете долгосрочные ключи (и, скорее всего, и в этом случае), то, вероятно, не должны читать из устройства /dev/random или запускать getrandom(2) с флагом GRND_RANDOM. Вместо этого читайте устройство /dev/urandom и запускайте getrandom(2) без флага GRND_RANDOM. Алгоритмы шифрования, используемые для источника urandom, довольно консервативны, и поэтому их должно быть достаточно для любых нужд.
Недостаток GRND_RANDOM и чтения из /dev/random в том, что эта операция может заблокировать выполнение на неопределённый период времени. Более того, работа с частично выполненными запросами, которые могут вернуться при использовании GRND_RANDOM или чтении /dev/random, увеличивает сложность кода.
Использование этих интерфейсов для предоставления большого количества данных при моделировании Монте-Карло или другим программам/алгоритмам, выполняющим вероятностную выборку, будет медленным. Кроме того, это излишне, так как таким приложениям не нужны криптографически безопасные случайные числа. Вместо этого используйте интерфейсы, описанные на этой странице, чтобы получить небольшое количество данных для запуска генератора псевдослучайных чисел в пространстве пользователя, который будет задействован для таких приложений.
В следующую таблицу сведено поведение различных интерфейсов получения случайных чисел. Флаг GRND_NONBLOCK можно использовать для управления поведением блокирования getrandom(2). В последней колонке таблицы показано, что может произойти на ранней стадии загрузки ОС, когда пул энтропии ещё не инициализирован.
Интерфейс | Пул | Возникновение блокировки | Поведение, когда пул ещё не готов |
/dev/random | Блокирующий пул | Если энтропии недостаточно, то блокирует до тех пор, пока не наберётся нужно количество энтропии | Блокирует, пока не наберётся нужно количество энтропии |
/dev/urandom | Данные CSPRNG | Никогда не блокируется | Возвращает данные из неинициализированного CSPRNG (может быть низкая энтропия и не подходить для шифрования) |
getrandom() | Тоже, что и /dev/urandom | Не блокирует в ожидании пула | Блокирует до готовности пула |
getrandom() GRND_RANDOM | Тоже, что и /dev/random | Если энтропии недостаточно, то блокирует до тех пор, пока не наберётся нужно количество энтропии | Блокирует до готовности пула |
getrandom() GRND_NONBLOCK | Тоже, что и /dev/urandom | Не блокирует в ожидании пула | EAGAIN |
getrandom() GRND_RANDOM + GRND_NONBLOCK | Тоже, что и /dev/random | EAGAIN, если недостаточно энтропии | EAGAIN |
Количество начального материала, требуемое для генерации ключей шифрования, равно эффективному размеру ключа. Например, 307 2-битный закрытый ключ RSA или Diffie-Hellman имеет эффективный размер ключа бит (для его подбора требуется просмотреть 2^128 значений), поэтому генератору ключа нужно только 128 бит (16 байт) начального материала из /dev/random.
Так как разумно добавить некоторый запас прочности к выше указанному минимуму как защиту против недостатков в алгоритме CSPRNG, никакой доступный криптографический примитив сегодня не может обещать больше чем 256 бит безопасности, поэтому если какая-то программа читает больше чем 256 бит (32 байта) из пула случайных чисел ядра за вызов, или за разумный интервал повторного посева (не менее одной минуты), то это нужно считать признаком того, что шифрование в ней реализовано НЕДОСТАТОЧНО продуманно.
getrandom(2), getauxval(3), getentropy(3), random(4), urandom(4), signal(7)
2017-03-13 | Linux |