ทำไม dd จาก / dev / random ให้ขนาดไฟล์ต่างกัน


26

ฉันใช้คำสั่งต่อไปนี้ในระบบอูบุนตู:

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

อย่างไรก็ตามทุกครั้งที่รันฉันจะพบว่าไฟล์มีขนาดแตกต่างกัน ทำไมนี้ ฉันจะสร้างไฟล์ขนาดที่กำหนดซึ่งเต็มไปด้วยข้อมูลแบบสุ่มได้อย่างไร


1
/dev/randomจะบล็อกหากมีจำนวนเอนโทรปีไม่เพียงพอที่จะสร้างจำนวนหลักที่คุณต้องการ มันใช้เวลานานในการรวบรวมจำนวนที่สุ่ม "สุ่ม" ที่มีคุณภาพสูงของ psuedo ... ใช้ทั้ง/dev/urandomค่าสุ่ม "สุ่ม" น้อยกว่าหรือตรวจสอบพูลเอนโทรปีของคุณ (ในลูปและรอตามที่ต้องการ) ...
Peter.O


3
เพียงแค่เพิ่มiflag=fullblock
frostschutz

คำตอบ:


31

คุณสังเกตการรวมกันของพฤติกรรมที่แปลกประหลาดของที่มีพฤติกรรมที่แปลกประหลาดของลินุกซ์dd /dev/randomทั้งสองอย่างนั้นไม่ค่อยเป็นเครื่องมือที่เหมาะสมสำหรับงาน

Linux /dev/randomส่งคืนข้อมูลเท่าที่จำเป็น มันขึ้นอยู่กับข้อสันนิษฐานว่าเอนโทรปีของเครื่องกำเนิดหมายเลขเทียมถูกดับในอัตราที่รวดเร็วมาก เนื่องจากการรวบรวมเอนโทรปีใหม่นั้นช้า/dev/randomโดยทั่วไปจะปล่อยเพียงไม่กี่ไบต์ต่อครั้ง

ddเป็นโปรแกรมเก่าที่บ้าๆบอ ๆ ตั้งใจแรกเริ่มที่จะทำงานบนอุปกรณ์เทป เมื่อคุณบอกให้อ่านหนึ่งบล็อกของ 1kB มันจะพยายามอ่านหนึ่งบล็อก ถ้าการอ่านส่งกลับน้อยกว่า 1024 ไบต์ยากนั่นคือทั้งหมดที่คุณได้รับ ดังนั้นจึงโทรออกdd if=/dev/random bs=1K count=2สองread(2)สาย เนื่องจากเป็นการอ่านจากโดยทั่วไปการโทร/dev/randomทั้งสองreadจะกลับมาเพียงไม่กี่ไบต์ในจำนวนที่แตกต่างกันขึ้นอยู่กับเอนโทรปีที่มีอยู่ ดูเพิ่มเติมเมื่อใดเหมาะสำหรับการคัดลอกข้อมูล (หรือเมื่อมีการอ่าน () และเขียน () บางส่วน)

ถ้าคุณกำลังออกแบบการติดตั้ง OS หรือ Cloner คุณไม่ควรใช้/dev/randomภายใต้ Linux /dev/urandomเสมอ urandomหน้าคนค่อนข้างเข้าใจผิด; /dev/urandomในความเป็นจริงแล้วเหมาะสำหรับการเข้ารหัสแม้กระทั่งการสร้างคีย์ที่มีอายุการใช้งานยาวนาน ข้อ จำกัด เพียงอย่างเดียว/dev/urandomคือต้องให้เอนโทรปีเพียงพอ การแจกแจง Linux มักจะบันทึกเอนโทรปีระหว่างการรีบูตดังนั้นครั้งเดียวที่คุณอาจมีเอนโทรปีไม่เพียงพอที่อยู่ในการติดตั้งใหม่ เอนโทรปีไม่สวมในแง่ปฏิบัติ สำหรับข้อมูลเพิ่มเติมอ่านrand จาก / dev / urandom ปลอดภัยสำหรับรหัสเข้าสู่ระบบหรือไม่? และเอนโทรปีการให้อาหาร / dev / สุ่ม .

การใช้งานส่วนใหญ่ddจะแสดงได้ดีขึ้นด้วยเครื่องมือเช่นหรือhead tailหากคุณต้องการ 2kB ของการสุ่มไบต์ให้เรียกใช้

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

ด้วยเคอร์เนล Linux ที่เก่ากว่าคุณสามารถหนีไปได้

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

เพราะ/dev/urandomมีความสุขกลับมาเป็นจำนวนมากตามที่ร้องขอ แต่นี้ไม่เป็นความจริงอีกต่อไปตั้งแต่เคอร์เนล 3.16, ก็ตอนนี้ จำกัด อยู่ที่ 32MB

โดยทั่วไปเมื่อคุณจำเป็นต้องใช้ddในการสกัดจำนวนคงที่ของไบต์และใส่มันไม่ได้มาจากไฟล์ปกติหรืออุปกรณ์ป้องกัน, dd bs=1 count=2048คุณจะต้องอ่านไบต์โดยไบต์:


ขอบคุณสำหรับเคล็ดลับในการใช้หัวแทนที่จะเป็นวว ที่ช่วยให้ฉันยังคงใช้ / dev / สุ่มถ้าฉันต้องการ แม้ว่า / dev / urandom อาจจะเพียงพอตามที่คุณกล่าวถึงมันเป็นเรื่องดีที่จะรู้วิธีการใช้ / dev / random หากจำเป็นต้องเกิดขึ้น
แดเนียล

ในเมล็ดตั้งแต่ 3.16 ต่อผลตอบแทน/dev/urandom 32m 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 จะส่งกลับสุ่ม bytes ภายในจำนวนบิตของสัญญาณรบกวนใน Entropy pool โดยประมาณ

ฉันได้ไฟล์ขนาด 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 ดังนั้นฉันจึงไม่ได้อ่านทั้งหมด
Bruce Ediger

นอกจากนี้ยังสอดคล้องกับ Gentoo เช่นกัน
Matthew Scharley

4
@cjc: เป็นเพราะเมื่อคุณโทรหาread(fd, mybuf, 1024)FD ที่ปิดกั้นมันจะกลับมาทันทีที่อุปกรณ์อ้างอิงส่งคืนข้อมูลบางส่วน หากมี 1024 ไบต์ที่ต้องอ่านจะส่งคืนค่านั้น หากมีเพียง 201 ไบต์ก็จะส่งคืน 201 หากมี 0 ไบต์ก็จะบล็อกจนกว่าจะมีอย่างน้อยหนึ่งไบต์จะใช้งานได้แล้วส่งคืน / พวกเขา
Warren Young

@WarrenYoung ไม่อ่านจาก / dev / การสุ่มเนื้อหาระบายหรือไม่? ฉันคิดอย่างนั้น
Michael Martinez

5

ทำไมddข้อมูลหล่น ... Gillesได้โพสต์คำถามที่น่าสนใจเกี่ยวกับdd:
dd เหมาะสำหรับการคัดลอกข้อมูลเมื่อใด (หรือเมื่อมีการอ่าน () และเขียน () บางส่วน)
นี่คือข้อความที่ตัดตอนมาจากคำถามนั้น:

    * ... มันไม่ใช่เรื่องยากที่จะใส่ dd ผิด ตัวอย่างเช่นลองใช้รหัสนี้: **
        yes | dd of=out bs=1024k count=10
    และตรวจสอบขนาดของไฟล์ (อาจมีขนาดต่ำกว่า 10MB)


นอกเหนือจากความคิดเห็นของฉัน (ในตอนท้ายของคำถามของคุณ) บางอย่างเช่นนี้เป็น iteresting จะดู ... $trndมันจับไบต์ในไฟล์ ฉันเลือก bs = 8 โดยพลการ

เลื่อนเมาส์ของคุณและดูมันเร็วขึ้น
เมื่อคอมพิวเตอร์ของฉันไม่มีการใช้งาน (AFK และไม่มีกิจกรรมเครือข่าย) และหลังจากหมดเอนโทรปีพูมันใช้เวลา2 ชั่วโมง 12 นาทีในการเก็บรวบรวมเพียง1,222ไบต์ที่จุดนี้ฉันยกเลิก

จากนั้นเมื่อฉันขยับเมาส์อย่างต่อเนื่องฉันใช้เวลาสั้นลง1 นาที 15 วินาทีในการรวบรวมจำนวนไบต์เท่ากัน

นี้แสดงให้เห็นอย่างชัดเจนว่าสวยเก็บรวบรวมเอนโทรปีไม่ได้ตามความเร็วของ CPU แต่มันเป็นเหตุการณ์สุ่มตามและที่ 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จะไม่ buffer ปัจจุบันอ่านในอนาคตบางwrite() (เว้นแต่คุณมากอย่างชัดเจนกำหนดค่ามันเป็นอย่างนั้นกับ OBS ขนาดใหญ่กว่า IBS)แต่จะแทน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จะsynchronize บล็อกอ่านใน nulls กล่าวอีกนัยหนึ่งคือถ้าdd read()s สำหรับอินพุตบล็อกของ$((size=10)) $((count=5))เวลาและread()ไฟล์ส่งคืน 2 ไบต์จากนั้น 8 ไบต์จากนั้น 12 ไบต์จากนั้น 12 ไบต์จากนั้น 2 ไบต์จากนั้น 4 ไบต์ddจะเขียนลงในไฟล์ outfile เช่น

 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จะ buffer เป็นจำนวนมากibs="$size"บล็อกการป้อนข้อมูลที่เป็นความจำเป็นในการกรอกข้อมูลอย่างน้อยหนึ่งobs="${size}x$block_factor"บล็อกเอาท์พุทสำหรับทุกท่อระหว่างมันและสองwrite() ddซึ่งหมายความว่ารายการที่สองddสามารถ จำกัด ผลลัพธ์ได้อย่างน่าเชื่อถือcount="$lmt"เพราะสิ่งที่write()ทำครั้งแรกทั้งหมดจะจับคู่กับขนาดบล็อกของ i / o โดยไม่คำนึงว่าจะต้องทำread()ครั้งแรกกี่ครั้งdd

และนั่นคือวิธีที่คุณสามารถใช้ddเพื่ออ่านไพพ์หรือไฟล์พิเศษชนิดอื่น ๆ ได้อย่างน่าเชื่อถือ - ด้วยคณิตศาสตร์เพียงเล็กน้อย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.