Чтение из / dev / random не дает никаких данных

19

Я часто использую команду

cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' | head --bytes 32

генерировать псевдослучайные пароли. Это не работает с /dev/random.

конкретно

  • cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' производит вывод
  • cat /dev/random | strings --bytes 1 производит вывод
  • cat /dev/random | strings --bytes 1 | tr -d '\n\t ' не производит вывод

NB. При использовании /dev/randomвам может потребоваться покачивать мышью или нажимать клавиши (например, Ctrl, Shift и т. Д.), Чтобы генерировать энтропию.

Почему последний пример не работает? Есть ли trкакой-то большой внутренний буфер, который /dev/urandomбыстро заполняется, но /dev/randomне заполняет ?

PS Я использую CentOS 6.5

cat /proc/version
Linux version 2.6.32-431.3.1.el6.x86_64 (mockbuild@c6b10.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) ) #1 SMP Fri Jan 3 21:39:27 UTC 2014
Аарон Дж Ланг
источник
какой у вас дистрибутив, версия вашего ядра? на Cygwin оба возвращают значения.
Киви
@Kiwy Смотрите редактировать.
Аарон Дж. Лэнг
1
Вы знаете pwgen, в частности pwgen -s?
MvG
2
-sПереключатель делает их менее запоминающимся, более истинно случайными. @Boyd: широко ли доступен makepasswd за пределами дистрибутивов на основе Debian? На мой взгляд, pwgen доступен для CentOS, а makepasswd - нет .
MvG
1
@BoydStephenSmithJr. Я согласен с @ MvG, makepasswdкоторого нет на моей платформе, в любом случае, спасибо
Aaron J Lang

Ответы:

27

Это будет в конце концов.

В:

cat /dev/random | strings --bytes 1 | tr -d '\n\t '

cat никогда не буферизуется, но это все равно излишне, так как здесь нечего объединять.

< /dev/random strings --bytes 1 | tr -d '\n\t '

stringsтем не менее, поскольку его выходные данные не длиннее, терминал будет буферизовать свои выходные данные блоками (размером примерно 4 или 8 КБ), а не линиями, когда выходные данные поступают на терминал.

Таким образом, он начнет писать в стандартный вывод, только когда наберет 4 КБ символов для вывода, что /dev/randomзаймет некоторое время.

trвывод идет на терминал (если вы запускаете его по приглашению оболочки в терминале), поэтому он буферизует свой вывод построчно. Поскольку вы удаляете \n, у него никогда не будет полной строки для записи, поэтому вместо этого он будет писать, как только будет накоплен полный блок (например, когда вывод не идет в терминал).

Так что, trскорее всего, ничего не напишет, пока stringsне прочтет достаточно, /dev/randomчтобы записать 8 КБ (2 блока, возможно, намного больше) данных (поскольку первый блок, вероятно, будет содержать символы новой строки, символа табуляции или пробела).

В этой системе, на которой я /dev/randomпримеряю , я могу получать в среднем 3 байта в секунду (вместо 12 МБ /dev/urandom), поэтому в лучшем случае (первые 4096 байтов /dev/random- все для печати), мы разговор за 22 минуты до trначала что-либо выводить. Но, скорее всего, это будут часы (в быстром тесте я вижу stringsзапись блока каждые 1–2 прочитанных блока, а выходные блоки содержат около 30% символов новой строки, так что я ожидаю, что нужно будет прочитать по крайней мере, за 3 блока до tr4096 символов для вывода).

Чтобы избежать этого, вы можете сделать:

< /dev/random stdbuf -o0 strings --bytes 1 | stdbuf -o0 tr -d '\n\t '

stdbuf является командой GNU (также встречающейся в некоторых BSD), которая изменяет буферизацию команд stdio с помощью трюка LD_PRELOAD.

Обратите внимание, что вместо strings, вы можете использовать, tr -cd '[:graph:]'который также исключит табуляцию, перевод строки и пробел.

Вы также можете исправить локаль, чтобы Cизбежать возможных сюрпризов в будущем с символами UTF-8.

Стефан Шазелас
источник
вау внушительное объяснение.
Kiwy
2
Удивительный! Отличное объяснение и решение. Я всегда использовал cat«бесполезно», потому что мне никогда не нравилось перенаправление stdin в конце конвейера, теперь я могу «сохранить процесс» и по-прежнему иметь удобочитаемые команды. Мое окончательное решение было< /dev/random stdbuf -o0 tr -Cd '[:graph:]' | stdbuf -o0 head --bytes 32
Aaron J Lang
@AaronJLang, хорошая мысль о [:graph:]. Я забыл об этом.
Стефан Шазелас
@AaronJLang, вам не нужно stdbuffor, head -c32если вы не хотите позволить ему записывать данные, как только они получаются (как в нескольких кусках вместо одного 32-байтового блока, как только он их получил)
Стефан Шазелас,
2
На мой взгляд, / dev / urandom вполне достаточно для использования автором. Если кому-то было интересно узнать, как, в частности, работает urandom по сравнению со random, я бы посоветовал прочитать комментарии в верхней части драйвера в drivers / char / random.c дерева исходных текстов ядра. В комментариях упоминается анализ PRNG и его реализация. Надеемся, что эта статья ответит на вопрос "насколько случайный случай более случайный по сравнению со случайным?" Доступно здесь: eprint.iacr.org/2012/251.pdf
etherfish
5

Генерация случайных чисел для многих приложений безопасности требует достаточной энтропийно-энтропийной оценки степени непредсказуемости случайности. Детерминированный процессор не может генерировать энтропию, поэтому энтропия должна исходить извне - либо от аппаратного компонента с недетерминированным поведением, либо от других факторов, которые достаточно трудно воспроизвести, таких как время действий пользователя (вот где шевелит мышь приходит в). Когда достаточная энтропия становится доступной, криптография может использоваться для генерирования практически неограниченного потока случайных чисел.

Linux работает, накапливая энтропию в пуле, а затем использует криптографию для получения приемлемых случайных чисел как через, так /dev/randomи через /dev/urandom. Разница заключается в том, что /dev/randomприменяется чрезвычайно консервативный расчет энтропии, который уменьшает оценку энтропии в пуле для каждого генерируемого ею байта, тогда /dev/urandomкак не влияет на количество энтропии в пуле.

Если оценка энтропии в пуле слишком низкая, /dev/randomблоки могут накопиться , пока не будет накоплено больше энтропии. Это может серьезно подорвать скорость, с которой /dev/randomможно производить продукцию. Это то, что вы наблюдаете здесь. Это не имеет ничего общего с tr; но stringsчитает выходные данные с буферизацией, поэтому он должен прочитать полный буфер (несколько килобайт) /dev/randomтолько для того, чтобы создать хотя бы один байт ввода.

/dev/urandomвполне приемлем для генерации криптографического ключа , потому что энтропия фактически не уменьшается каким-либо ощутимым образом. (Если вы продолжаете работать на своей машине дольше, чем существовала вселенная, вы не можете пренебрегать этими соображениями, но в остальном у вас все хорошо.) Есть только один случай, когда /dev/urandomплохо, - это недавно установленная система, которая не У нас еще не было времени на создание энтропии или системы с новой загрузкой, которая загружается с носителя только для чтения.

Исключение stringsиз цепочки загрузки, вероятно, ускорит ваш процесс. Ниже trбудут отфильтрованы непечатаемые символы:

</dev/random LC_ALL=C tr -dc '!-~'

Но вы можете использовать /dev/urandomздесь , если вы позаботитесь о том, чтобы не генерировать пароли в системе, которая не успела накопить достаточную энтропию. Вы можете проверить уровень пула энтропии Linux /proc/sys/kernel/random/entropy_avail(если вы используете /dev/random, рисунок в этом файле будет консервативным, возможно, очень сильно).

Жиль "ТАК - прекрати быть злым"
источник
1

Вы должны использовать /dev/urandomдля получения высококачественных (псевдо) случайных чисел, и /dev/randomтолько тогда, когда вам абсолютно необходимы случайные числа, которые действительно непредсказуемы. Злоумышленнику, находящемуся ниже ресурсов АНБ, будет очень трудно взломать /dev/urandom(и не забывать о криптографии с резиновыми шлангами ). Ядро заполняет буфер «действительно случайными» байтами, вот что /dev/randomдает. К сожалению , скорость , с которой они даются невысока, поэтому чтение много из из /dev/random будет стойла ждет случайности.

Вы могли бы рассмотреть возможность использования random.org или его генератора паролей , или одного из множества парящих случайных генераторов паролей, посмотрите, например, на эту страницу несколько советов командной строки (не то, чтобы я рекомендовал их все , но они должны дать вам идеи), или вы можете использовать что-то вроде mkpasswd(1)(здесь, на Fedora 19 часть expect-5.45-8.fc19.x86_64).

vonbrand
источник