Mengapa dd dari / dev / random memberikan ukuran file yang berbeda?

26

Saya menjalankan perintah berikut pada sistem ubuntu:

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

Namun, setiap kali saya menjalankannya, saya mendapatkan file dengan ukuran berbeda. Kenapa ini? Bagaimana saya bisa menghasilkan file dengan ukuran tertentu yang diisi dengan data acak?

Daniel
sumber
1
/dev/randomakan memblokir jika tidak ada cukup entropi yang tersedia untuk menghasilkan jumlah digit yang Anda inginkan. hanya perlu waktu untuk mengumpulkan jumlah "acak" acak psuedo acak berkualitas tinggi ... Baik gunakan /dev/urandomuntuk nilai "acak" yang kurang acak, atau periksa kumpulan entropi Anda (dalam satu lingkaran, dan tunggu seperlunya) ...
Peter.O
Lihat juga pertanyaan ini .
Keith Thompson
3
tambahkan sajaiflag=fullblock
frostschutz

Jawaban:

31

Anda mengamati kombinasi perilaku aneh dddengan perilaku aneh Linux /dev/random. Omong-omong, keduanya jarang merupakan alat yang tepat untuk pekerjaan itu.

Linux /dev/randommengembalikan data dengan hemat. Hal ini didasarkan pada asumsi bahwa entropi pada generator nomor pseudorandom dipadamkan dengan kecepatan yang sangat cepat. Karena mengumpulkan entropi baru lambat, /dev/randombiasanya hanya melepaskan beberapa byte pada satu waktu.

ddadalah program lama yang rewel yang pada awalnya dimaksudkan untuk beroperasi pada perangkat pita. Ketika Anda menyuruhnya membaca satu blok 1kB, ia mencoba membaca satu blok. Jika pembacaan mengembalikan kurang dari 1024 byte, sulit, itu saja yang Anda dapatkan. Jadi, dd if=/dev/random bs=1K count=2buat dua read(2)panggilan. Karena membaca dari /dev/random, dua readpanggilan biasanya mengembalikan hanya beberapa byte, dalam jumlah yang bervariasi tergantung pada entropi yang tersedia. Lihat juga Kapan dd cocok untuk menyalin data? (atau, ketika dibaca () dan tulis () parsial)

Kecuali Anda mendesain installer atau cloner OS, Anda seharusnya tidak pernah menggunakan /dev/randomLinux, selalu /dev/urandom. The urandomhalaman manual agak menyesatkan; /dev/urandomsebenarnya cocok untuk kriptografi, bahkan untuk menghasilkan kunci berumur panjang. Satu-satunya batasan /dev/urandomadalah bahwa ia harus dilengkapi dengan entropi yang memadai; Distribusi Linux biasanya menyimpan entropi di antara reboot, jadi satu-satunya saat Anda mungkin tidak memiliki cukup entropi adalah pada instalasi baru. Entropi tidak hilang secara praktis. Untuk informasi lebih lanjut, baca Apakah rand dari / dev / urandom aman untuk kunci masuk? dan Feeding / dev / pool entropi acak? .

Sebagian besar penggunaan ddlebih baik diungkapkan dengan alat seperti headatau tail. Jika Anda ingin 2kB byte acak, jalankan

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

Dengan kernel Linux yang lebih lama, Anda bisa lolos

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

karena /dev/urandomdengan senang hati mengembalikan byte sebanyak yang diminta. Tetapi ini tidak lagi benar sejak kernel 3.16, sekarang terbatas pada 32MB .

Secara umum, ketika Anda harus menggunakan dduntuk mengekstrak jumlah tetap byte dan input tidak datang dari sebuah file biasa atau perangkat blok, Anda perlu membaca byte dengan byte: dd bs=1 count=2048.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Terima kasih atas tip menggunakan kepala bukan dd. Itu memungkinkan saya untuk tetap menggunakan / dev / random jika saya mau. Meskipun / dev / urandom mungkin sudah cukup seperti yang Anda sebutkan, itu baik untuk mengetahui cara menggunakan / dev / acak jika perlu.
Daniel
pada kernel sejak 3.16 /dev/urandom menghasilkan 32m perread() .
mikeserv
Atau, jika Anda memerlukan perintah yang sesuai dengan POSIX, Anda dapat menggunakan trik ini di sini: unix.stackexchange.com/a/192114 dd if=/dev/urandom ibs=1k obs=1k | dd bs=1k count=2
Rufflewind
11

Dari man 4 randompada kotak RHEL 5:

Saat membaca, perangkat / dev / random hanya akan mengembalikan byte acak dalam perkiraan jumlah bit noise di kumpulan entropi.

Saya mendapatkan file ukuran 213 byte pada mesin itu. Kembali ke man 4 acak:

Saat membaca, / dev / urandom perangkat akan mengembalikan sebanyak byte yang diminta.

Saya mendapatkan 2048 byte dari setiap doa dd if=/dev/urandom of=rand bs=1K count=2

Saya menyimpulkan bahwa perbedaannya adalah karena berapa banyak entropi yang dihasilkan mesin Anda di antara pemanggilan dd if=/dev/random ...

Bruce Ediger
sumber
Ya, praktis, kecuali dia menggunakan aplikasi crypto sungguhan, @Daniel harus menggunakan / dev / urandom. Tapi saya bingung mengapa dd if=/dev/random bs=1K count=2berhenti ketika kolam entropi tampaknya terkuras. Dari dokumen, harus diblokir sampai ada lebih banyak entropi, sehingga ddakan menulis file perlahan, bukan hanya membuang kolam saat ini dan keluar.
cjc
Saya bertanya-tanya tentang hal itu juga, tetapi konsisten di seluruh RHEL, Slackware 13.1 dan Arch yang cukup baru. RHEL adalah x86_64, yang lain 32-bit. Sayangnya dokumen dd dalam format info GNU, jadi saya belum membaca semuanya.
Bruce Ediger
Ini juga konsisten dengan Gentoo.
Matthew Scharley
4
@ cjc: Itu karena ketika Anda memanggil read(fd, mybuf, 1024)FD yang memblokir, ia akan kembali segera setelah perangkat yang mendasarinya mengembalikan beberapa data. Jika ada 1024 byte di sana untuk dibaca, ia mengembalikannya. Jika hanya ada 201 byte, ia akan mengembalikan 201. Jika ada 0 byte yang tersedia, ia akan memblokir hingga setidaknya satu byte tersedia, kemudian mengembalikannya.
Warren Young
@ WarrenYoung tidak membaca dari / dev / acak mengeringkan isinya? Saya berasumsi begitu.
Michael Martinez
5

Mengapa dddata drop? ... Gilles telah mengajukan pertanyaan menarik tentang dd:
Kapan dd cocok untuk menyalin data? (atau, ketika dibaca () dan tulis () parsial)
Berikut adalah kutipan dari pertanyaan itu:

    * ... tidak sulit menyalahkan dd; misalnya, coba kode ini: **
        yes | dd of=out bs=1024k count=10
    dan periksa ukuran file yang keluar (kemungkinannya di bawah 10MB).


Selain dari komentar saya (di akhir pertanyaan Anda), sesuatu seperti ini adalah iteresting untuk ditonton ... Ini menangkap byte Anda dalam file $trnd. Saya telah semi-sewenang-wenang memilih bs = 8

Gerakkan mouse Anda dan perhatikan kecepatannya.
Dengan komputer saya menganggur (AFK dan tidak ada aktivitas Jaringan), dan setelah melelahkan kumpulan entropi, butuh 2 jam 12 menit untuk mengumpulkan hanya 1.192 byte, di mana saat itu saya membatalkannya.

Kemudian, dengan saya menggerakkan mouse terus-menerus, dibutuhkan waktu yang relatif lebih pendek 1 menit 15 detik untuk mengumpulkan jumlah byte yang sama.

Ini menunjukkan dengan cukup jelas bahwa mengumpulkan entropi bukan berdasarkan kecepatan CPU, melainkan berdasarkan kejadian acak , dan bahwa sistem Ubuntu saya menggunakan mouse sebagai salah satu faktor acak yang signifikan .

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
sumber
1

ddadalah dirancang untuk memblokir - biasanya alat terbaik yang Anda inginkan untuk membaca dari input berukuran variabel jika Anda membutuhkannya dilakukan segera karena ddtidak akan buffer saat membaca ke dalam beberapa masa depan write() (kecuali jika Anda sangat eksplisit mengkonfigurasinya seperti itu dengan obs lebih besar dari IBS) , tetapi akan sebaliknya write()semua yang dibacanya segera setelah read()itu (dan secara opsional memprosesnya) .

Berikut ini beberapa definisi penting :

  • ibs=expr
    • Tentukan ukuran blok input, dalam bytes, oleh (standarnya adalah 512) .expr
  • obs=expr
    • Tentukan ukuran blok output, dalam bytes, oleh (standarnya adalah 512) .expr
  • bs=expr
    • Atur ukuran blok input dan output ke exprbyte, menggantikan ibs=dan obs=. Jika tidak ada konversi selain sync,, noerrordan notruncditentukan, setiap blok input harus disalin ke output sebagai satu blok tanpa mengagregasi blok pendek.

Jadi Anda lihat, ketika ibsdan obsdidefinisikan bersama sebagai bsmaka ibsdiutamakan - tetapi sebaliknya, jika Anda tertentu, maka baik obsatau cbstidak.

Berikut adalah contoh yang ibspaling penting. Anda mungkin melakukan sesuatu seperti ini jika Anda ingin melacak seberapa cepat /dev/randomkolam diisi ...

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

Asalkan if=target dapat dibaca sama sekali, itu akan selalu menghasilkan file output berukuran sama, karena ddakan synchronize blok read-in pada nulls. Dengan kata lain, jika dd read()s untuk input-blok $((size=10)) $((count=5))kali dan read()file mengembalikan 2 byte, lalu 8 byte, lalu 12 byte, lalu 2 byte, maka 4 byte, ddakan menulis ke sesuatu yang lebih besar dari file seperti

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

... karena dd, secara default, tidak menunda. Jadi, jika Anda perlu melacak streaming dan membatasi penulisan beberapa proses lainnya, ddadalah alat untuk Anda.

Jika Anda hanya menulis sejumlah data ke file biasa, berlawanan dengan pernyataan lain yang dibuat di sini, Anda juga dapat menggunakan ddini - dan cukup mudah - tetapi Anda akan membutuhkan lebih dari satu dan faktor pemblokiran yang andal .

Misalnya, jika Anda melakukannya:

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

... yang pertama ddakan buffer sebanyak mungkin ibs="$size"blok input yang diperlukan untuk mengisi setidaknya satu obs="${size}x$block_factor"blok output untuk setiap write()ke pipa di antara itu dan yang kedua dd. Ini berarti bahwa yang kedua dddapat membatasi output dengan andal count="$lmt"karena semua write()s yang pertama dibuat akan cocok dengan blokir i / o - terlepas dari berapa banyak read()yang pertama ddharus dilakukan untuk membuatnya jadi.

Dan itulah cara yang dapat Anda gunakan dduntuk secara andal membaca pipa atau jenis file khusus lainnya - hanya dengan sedikit matematika.

mikeserv
sumber