RANDOM(4) | Руководство программиста Linux | RANDOM(4) |
random, urandom - ядерные устройства-источники случайных чисел
#include <linux/random.h>
int ioctl(fd, RNDrequest, param);
Специальные символьные файлы /dev/random и /dev/urandom (появились в Linux 1.3.30) предоставляют интерфейс к генератору случайных чисел, встроенному в ядро. Файл /dev/random имеет старший номер устройства 1 и младший номер устройства 8. Файл /dev/urandom имеет старший номер устройства 1 и младший номер устройства 9.
Генератор случайных чисел собирает окружающий шум от работы драйверов устройств и из других источников в пул энтропии. Генератор также постоянно оценивает количество битов шума в пуле энтропии. Именно с помощью этого пула создаются случайные числа.
В Linux 3.17 и новее предоставляется более простой и безопасный интерфейс getrandom(2), который не требует специальных файлов; смотрите справочную страницу getrandom(2).
При чтении из устройства /dev/urandom возвращаются произвольные байты, полученные из генератора псевдослучайных чисел, инициализированного из пула энтропии. Чтение из этого устройства не приводит к блокировке (то есть, ЦП не отдаёт управление), но может вызвать заметную задержку при запросе большого количества данных.
При чтении во время начальной загрузки ОС /dev/urandom может возвращать данные до инициализации пула энтропии. Если это неприемлемо для приложения, используйте getrandom(2) или /dev/random.
Устройство /dev/random является устаревшим интерфейсом, который относится ко времени времени, когда криптографическим примитивам, используемым в реализации /dev/urandom, не очень не доверяли. Интерфейс возвращает произвольные байты только с подсчитанным количеством бит свежего шума в пуле энтропии, блокируя работу при необходимости. Устройство /dev/random подходит для приложений, которым нужна произвольность высокого качества и без проблем относятся к задержкам на неопределённое время.
Если пул энтропии пуст, попытка чтения /dev/random приведёт к блокировке, пока не будет собран дополнительный окружающий шум. Если вызов open(2) для /dev/random запускается с флагом O_NONBLOCK, то последующий read(2) не будет заблокируется, если количество запрашиваемых байт недостаточно. Вместо этого будут возвращены имеющиеся байты. Если ни одного байта нет, то read(2) вернёт -1 и значение errno станет равно EAGAIN.
При открытии /dev/urandom флаг O_NONBLOCK не учитывается. При вызове read(2) для устройства /dev/urandom чтение до 256 байт вернёт запрошенное количество байт и не будет прервано обработчиком сигнала. Чтение с буфером больше ограничения может вернуть количество байт меньше запрошенного или завершиться ошибкой EINTR при прерывании обработчиком сигнала.
Начиная с Linux 3.16, вызов read(2) может прочитать из /dev/urandom почти 32 МБ. Из /dev/random будет прочитано не более 512 байт (340 байт для ядер Linux до версии 2.6.12).
При записи в /dev/random или /dev/urandom выполняется обновление пула энтропии записываемыми данными, но при этом не увеличивается счётчик энтропии. Это означает, что изменения отразятся в обоих файлах, но это не ускорит процесс чтения из /dev/random.
Интерфейс /dev/random считается устаревшим, во всех случаях предпочтительно использовать /dev/urandom; исключением являются приложения, которым нужны произвольные байты во время загрузки системы; в таких приложениях нужно использовать getrandom(2), так как этот вызов выполняет блокировку для ожидания наполнения пула энтропии.
Если файл начальных чисел (seed file) сохраняется между перезагрузками как рекомендуется далее (во всех основных дистрибутивах Linux это делается начиная с 2000 года), то результат шифрования стоек от атакующего, не имеющего локально привилегированного доступа, до перезагрузки машины, и вполне подходит для ключей шифрования сетевых сеансов. Так как чтение из /dev/random может привести к блокировке, пользователи хотели бы открывать его в неблокирующем режиме (или выполнять чтение с задержкой), и иметь механизм оповещения, если желаемый уровень энтропии в данный момент недоступен.
Если в системе нет /dev/random и /dev/urandom, то их можно создать следующими командами:
mknod -m 666 /dev/random c 1 8 mknod -m 666 /dev/urandom c 1 9 chown root:root /dev/random /dev/urandom
Когда Linux-система запускается без участия человека, пул энтропии может оказаться в довольно предсказуемом состоянии. Это снижает значимый объём шума в пуле энтропии ниже оцениваемого. Для преодоления этого эффекта можно сохранять информацию пула энтропии во время выключения и восстанавливать во время запуска системы. Для этого добавьте строки в сценарий, который выполняется при запуске Linux-системы:
echo "Инициализация генератора случайных чисел…" random_seed=/var/run/random-seed # перенос случайного начального числа от запуска к запуску # загрузка и сохранение всего пула энтропии if [ -f $random_seed ]; then cat $random_seed >/dev/urandom else touch $random_seed fi chmod 600 $random_seed poolfile=/proc/sys/kernel/random/poolsize [ -r $poolfile ] && bits=$(cat $poolfile) || bits=4096 bytes=$(expr $bits / 8) dd if=/dev/urandom of=$random_seed count=1 bs=$bytes
Также добавьте следующие строки в сценарий, который выполняется при завершении работы Linux-системы:
# перенос случайного начального числа от выключения до запуска # сохранение всего пула энтропии echo "Сохранение случайного начального числа…" random_seed=/var/run/random-seed touch $random_seed chmod 600 $random_seed poolfile=/proc/sys/kernel/random/poolsize [ -r $poolfile ] && bits=$(cat $poolfile) || bits=4096 bytes=$(expr $bits / 8) dd if=/dev/urandom of=$random_seed count=1 bs=$bytes
В примерах выше мы предполагаем, что используется ядро Linux 2.6.0 или новее, в котором /proc/sys/kernel/random/poolsize содержит размер пула энтропии в битах (смотрите ниже).
Файлы в каталоге /proc/sys/kernel/random (начиная с 2.3.16) предоставляют дополнительную информацию об устройстве /dev/random:
Для файловых дескрипторов, соединённых с файлами /dev/random и /dev/urandom, определены запросы ioctl(2), перечисленные ниже. Все выполняемые запросы обращаются к входному пулу энтропии, который относится к и к /dev/random, и к /dev/urandom. Для выполнения всех запросов (кроме RNDGETENTCNT) требуется мандат CAP_SYS_ADMIN.
struct rand_pool_info { int entropy_count; int buf_size; __u32 buf[0]; };
/dev/random /dev/urandom
Обзор и сравнение возможных интерфейсов, через которые можно получать случайные данные, смотрите в random(7).
Во время начальной загрузки ОС чтение из /dev/urandom может возвращать данные до инициализации пула энтропии.
mknod(1), getrandom(2), random(7)
RFC 1750, "Randomness Recommendations for Security"
2017-09-15 | Linux |