Почему dd из / dev / random дает файлы разных размеров?

26

Я запускаю следующую команду в системе Ubuntu:

dd if=/dev/random of=rand bs=1K count=2

Однако каждый раз, когда я запускаю его, я получаю файл другого размера. Почему это? Как я могу создать файл заданного размера, заполненный случайными данными?

Даниил
источник
1
/dev/randomбудет блокироваться, если энтропии недостаточно для создания необходимого количества цифр. это просто нужно время , чтобы собрать такое количество высококачественной псевдо случайной «случайность» ... Либо использовать /dev/urandomдля менее случайного «случайного» значения, или проверить пул энтропии (в цикле, и ждать , как потребность быть) ...
Peter.O
Смотрите также этот вопрос .
Кит Томпсон
3
просто добавьiflag=fullblock
frostschutz

Ответы:

31

Вы наблюдаете комбинацию специфического поведения ddсо специфическим поведением Linux /dev/random. Оба, кстати, редко являются подходящим инструментом для работы.

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

ddэто старая, капризная программа, изначально предназначенная для работы на ленточных устройствах. Когда вы говорите ему прочитать один блок размером 1 КБ, он пытается прочитать один блок. Если чтение возвращает менее 1024 байтов, это все, что вы получите. Так что dd if=/dev/random bs=1K count=2делает два read(2)звонка. Поскольку он считывает данные /dev/random, два readвызова, как правило, возвращают только несколько байтов с различным числом в зависимости от доступной энтропии. Смотрите также, Когда dd подходит для копирования данных? (или, когда read () и write () частично)

Если вы не разрабатываете установщик ОС или клонер, вы никогда не должны использовать его /dev/randomпод Linux, всегда /dev/urandom. Страница urandomman несколько вводит в заблуждение; /dev/urandomна самом деле подходит для криптографии, даже для генерации долгоживущих ключей. Единственное ограничение /dev/urandomсостоит в том, что он должен быть снабжен достаточной энтропией; Обычно дистрибутивы Linux сохраняют энтропию между перезагрузками, поэтому единственный раз, когда вам может не хватить энтропии, это новая установка. Энтропия не стирается в практическом плане. Дополнительную информацию смотрите в разделе Безопасен ли rand из / dev / urandom для ключа входа? и кормление / dev / случайный пул энтропии? ,

Большинство применений ddлучше выражены с помощью таких инструментов, как headили tail. Если вы хотите 2 КБ случайных байтов, запустите

head -c 2k </dev/urandom >rand

Со старыми ядрами Linux вы могли бы

dd if=/dev/urandom of=rand bs=1k count=2

потому что /dev/urandomсчастливо вернул столько байтов, сколько просил. Но это больше не так с ядра 3.16, теперь оно ограничено 32 МБ .

В общем случае , когда вам нужно использовать , ddчтобы извлечь фиксированное количество байт и его вход не из обычного файла или блочного устройства, вам необходимо прочитать побайтно: dd bs=1 count=2048.

Жиль "ТАК - перестань быть злым"
источник
Спасибо за совет по использованию головы вместо дд. Это позволяет мне по-прежнему использовать / dev / random, если я хочу. Хотя / dev / urandom, вероятно, будет достаточно, как вы упомянули, было бы неплохо знать, как использовать / dev / random, если возникнет такая необходимость.
Даниэль
на ядрах с 3.16 /dev/urandom возвращается 32млнread() .
mikeserv
В качестве альтернативы, если вам нужна POSIX-совместимая команда, вы можете использовать хитрость здесь: unix.stackexchange.com/a/192114 dd if=/dev/urandom ibs=1k obs=1k | dd bs=1k count=2
Rufflewind
11

С man 4 randomкоробки RHEL 5:

При чтении устройство / dev / random будет возвращать только случайные байты в пределах предполагаемого количества битов шума в пуле энтропии.

Я получаю файлы размером 213 байт на этой машине. Вернуться к человеку 4 случайным образом:

При чтении устройство / dev / urandom вернет столько байтов, сколько требуется.

Я получаю 2048 байтов от каждого вызова dd if=/dev/urandom of=rand bs=1K count=2

Я заключаю, что разница связана с тем, сколько энтропии генерирует ваша машина между вызовами dd if=/dev/random ...

Брюс Эдигер
источник
Да, практически, если он не в реальном крипто-приложении, @Daniel должен использовать / dev / urandom. Но я озадачен, почему dd if=/dev/random bs=1K count=2останавливается, когда бассейн энтропии явно истощается. Из документов он должен блокироваться, пока не ddстанет больше энтропии, поэтому он будет медленно записывать файл, а не просто выводить текущий пул и выходить из него.
CJC
Я тоже задумался над этим, но он одинаков для RHEL, Slackware 13.1 и довольно актуального Arch. RHEL был x86_64, остальные были 32-битными. К сожалению, документы dd находятся в информационном формате GNU, поэтому я не прочитал их все.
Брюс Эдигер
Это также согласуется с Gentoo.
Мэтью Шарли
4
@cjc: Это потому, что когда вы вызываете read(fd, mybuf, 1024)блокирующий FD, он возвращается, как только базовое устройство возвращает некоторые данные. Если есть 1024 байта для чтения, он возвращает это. Если есть только 201 байт, он вернет 201. Если доступно 0 байт, он заблокируется, пока не станет доступен хотя бы один байт, а затем вернет его / их.
Уоррен Янг
@WarrenYoung истощает содержимое из / dev / random? Я так полагаю.
Майкл Мартинес
5

Почему ddсбрасывают данные? ... Жиль поставил этот занимательный вопрос о dd:
Когда д.д. подходит для копирования данных? (или, когда read () и write () частично)
Вот выдержка из этого вопроса:

    * ... не сложно поставить дд вину; например, попробуйте этот код: **
        yes | dd of=out bs=1024k count=10
    и проверьте размер выходного файла (он, вероятно, будет меньше 10 МБ).


Помимо моего комментария (в конце вашего вопроса), что-то вроде этого интересно посмотреть ... Он ловит ваши байты в файле $trnd. Я полу произвольно выбрал bs = 8

Двигай мышью и наблюдай, как она ускоряется.
Когда мой компьютер простаивает (AFK и нет сетевой активности) и после исчерпания энтропийного пула потребовалось 2 часа 12 минут, чтобы собрать только 1192 байта, после чего я отменил его.

Затем, когда я непрерывно двигал мышью, мне потребовалась относительно короткая 1 минута 15 секунд, чтобы собрать то же количество байтов.

Это довольно ясно показывает, что сбор энтропии не основан на скорости процессора, а скорее основан на случайных событиях , и что моя система Ubuntu использует мышь в качестве одного из значительных случайных факторов.

get=2048
trnd=/tmp/$USER.rnd; >"$trnd"
while (( $(wc -c <"$trnd") < $get )) ;do
    dd if=/dev/random bs=8 count=1 2>/dev/null >>"$trnd"
    echo -n "itt: $((i+=1))  ct: "; wc -c <"$trnd"
done
truncate -s $get "$trnd"
echo -e "\nfinal count: "; wc -c <"$trnd"
Peter.O
источник
1

ddбудет предназначен для блокирования - это, как правило , самый лучший инструмент в вашем распоряжении для чтения входных переменных размеров , если вам это нужно сделать немедленно , потому что ddне будет текущий буфер читает в какой - то будущее write() (если вы очень явно не настроить его таким образом с более крупными набл чем СРК) , но будет вместо этого write()все, что он читает, как только он read()это (и дополнительно обрабатывает это) .

Вот несколько важных определений :

  • ibs=expr
    • Укажите размер входного блока в байтах (по умолчанию 512) .expr
  • obs=expr
    • Укажите размер выходного блока в байтах (по умолчанию 512) .expr
  • bs=expr
    • Установите размеры входного и выходного блоков в exprбайтах, заменяя ibs=и obs=. Если не указано никакого преобразования, кроме sync, noerrorи notrunc, каждый входной блок должен быть скопирован на выход как один блок без агрегирования коротких блоков.

Итак, вы видите, когда ibsи obsопределены вместе, как bsтогда ibsимеет приоритет - но в противном случае, если вы конкретны, то либо obsили cbsделает.

Вот пример, в котором ibsнаиболее важен. Вы могли бы сделать что-то вроде этого, если вы хотите отслеживать, как скоро /dev/randomбассейн заполнится ...

dd "ibs=$size" conv=sync "count=$lmt" \ 
    if=/dev/random of="$somefile"

Пока if=цель вообще читаема, это всегда будет приводить к выходному файлу одинакового размера, потому что ddбудет syncхронизировать чтение блоков с нулями. Другими словами, если dd read()s для блока ввода $((size=10)) $((count=5))времен и read()файл возвращает 2 байта, то 8 байтов, затем 12 байтов, затем 2 байта, а затем 4 байта, ddзапишет в свой выходной файл что-то вроде

 2 read bytes 8NULs \
 8 read bytes 2NULs \
10 read bytes 0NULs \
 4 read bytes 6NULs \
 4 read bytes 6NULs

... потому что dd, по умолчанию, не задерживается. Так что если вам нужно отслеживать в потоке и разделять записи какого-либо другого процесса, ddэто инструмент для вас.

Если вы просто записываете некоторый объем данных в обычный файл, тогда, в отличие от других заявлений, сделанных здесь, вы также можете использовать ddэто - и довольно легко - но вам потребуется более одного и надежный фактор блокировки .

Например, если вы сделали:

{   dd ibs="$size" obs="${size}x$block_factor" |
    dd bs="${size}x$blockfactor" "count=$lmt"
}  <infile >outfile

... первый ddбуферизует столько ibs="$size"входных блоков, сколько необходимо, чтобы заполнить хотя бы один obs="${size}x$block_factor"выходной блок для каждого write()канала в канале между ним и вторым dd. Это означает, что второй ddможет надежно ограничить вывод, count="$lmt"потому что все write()s, которые делает первое, будут соответствовать его размеру блока ввода / вывода - независимо от того, сколько read()s ddдолжно сделать первое , чтобы сделать это.

И что «S , как вы можете использовать , ddчтобы надежно прочитанные трубы или другие тип специальных файлов - с помощью всего лишь немного математики.

mikeserv
источник