Чому dd від / dev / random дає різні розміри файлів?


26

Я виконую наступну команду в системі ubuntu:

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

Однак кожного разу, коли я запускаю його, я закінчую файл іншого розміру. Чому це? Як я можу створити файл заданого розміру, наповнений випадковими даними?


1
/dev/randomзаблокується, якщо не вистачить ентропії, щоб генерувати потрібну кількість цифр. просто потрібен час, щоб зібрати цю кількість високоякісної psuedo випадкової "випадковості" ... Або скористайтеся /dev/urandomдля менш випадкового "випадкового" значення або перевірте свій пул ентропії (в циклі, і зачекайте, як потрібно) ...
Пітер.О

Дивіться також це питання .
Кіт Томпсон,

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 підходить для копіювання даних? (або, коли читаються () і записуються () частково)

Якщо ви не розробляєте інсталятор ОС або клонер, ви ніколи не повинні використовувати /dev/randomпід Linux /dev/urandom. Сторінка urandomчоловіка дещо вводить в оману; /dev/urandomнасправді підходить для криптографії навіть для генерації довгожителів. Єдине обмеження /dev/urandom- це те, що воно повинно бути забезпечене достатньою ентропією; Дистрибутиви Linux, як правило, зберігають ентропію між перезавантаженнями, тому єдиний раз, коли вам може не вистачити ентропії, є нова установка. Ентропія не зношується на практиці. Для отримання додаткової інформації читайте, чи безпечний rand від / dev / urandom для ключа входу? та Пункт годування / дев / випадкової ентропії? .

Більшість застосувань 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.


Дякуємо за пораду щодо використання head замість dd. Це дозволяє мені все-таки використовувати / 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 байтів, він блокується, поки щонайменше один байт не стане доступним, а потім поверне його / їх.
Warren Young

@WarrenYoung читання з / dev / випадкового виводить його вміст? Я припускаю, що так.
Майкл Мартінес

5

Чому ddвипадають дані? ... Жилл поставив це захоплююче питання про те dd:
Коли ДД підходить для копіювання даних? (або коли читаються () і пишуться () частково)
Ось уривок із цього питання:

    * ... винуватить АД не важко; наприклад, спробуйте цей код: **
        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"

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=ціль 's читається взагалі, це завжди призведе до виходу одного розміру файлу, тому що 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()які робить перший, збігаються з його блоком вводу-виводу - незалежно від кількості read()s, який ddповинен зробити перший , щоб зробити його таким.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.