Perché dd da / dev / random offre file di dimensioni diverse?


26

Sto eseguendo il seguente comando su un sistema Ubuntu:

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

Tuttavia, ogni volta che lo eseguo, finisco con un file di dimensioni diverse. Perchè è questo? Come posso generare un file di una determinata dimensione riempito con dati casuali?


1
/dev/randombloccherà se non c'è abbastanza entropia disponibile per generare il numero di cifre che desideri. ci vuole semplicemente tempo per raccogliere quella quantità di "casualità" casuale psuedo di alta qualità ... O utilizzare /dev/urandomper un valore "casuale" meno casuale, o controllare il pool di entropia (in un ciclo e attendere, se necessario) ...
Peter.O


3
basta aggiungereiflag=fullblock
frostschutz il

Risposte:


31

Stai osservando una combinazione del comportamento peculiare di ddcon il comportamento peculiare di quello di Linux /dev/random. Entrambi, comunque, raramente sono lo strumento giusto per il lavoro.

Linux /dev/randomrestituisce i dati con parsimonia. Si basa sul presupposto che l'entropia nel generatore di numeri pseudocasuali si spenga a una velocità molto elevata. Poiché la raccolta di nuova entropia è lenta, in /dev/randomgenere abbandona solo pochi byte alla volta.

ddè un vecchio programma irritabile inizialmente destinato a funzionare su dispositivi a nastro. Quando gli dici di leggere un blocco di 1kB, tenta di leggere un blocco. Se la lettura restituisce meno di 1024 byte, difficile, questo è tutto ciò che ottieni. Quindi dd if=/dev/random bs=1K count=2effettua due read(2)chiamate. Poiché sta leggendo /dev/random, le due readchiamate in genere restituiscono solo pochi byte, in numero variabile a seconda dell'entropia disponibile. Vedi anche Quando dd è adatto alla copia dei dati? (o, quando sono read () e write () parziale)

A meno che non si stia progettando un programma di installazione o clonazione del sistema operativo, non si dovrebbe mai usare /dev/randomsotto Linux, sempre /dev/urandom. La urandompagina man è in qualche modo fuorviante; /dev/urandomè infatti adatto per la crittografia, anche per generare chiavi di lunga durata. L'unica limitazione /dev/urandomè che deve essere fornita con entropia sufficiente; Le distribuzioni Linux normalmente salvano l'entropia tra i riavvii, quindi l'unica volta che potresti non avere abbastanza entropia è su una nuova installazione. L'entropia non svanisce in termini pratici. Per ulteriori informazioni, leggi Un rand di / dev / urandom è sicuro per una chiave di accesso? e Feeding / dev / pool di entropia casuale? .

La maggior parte degli usi di ddsono meglio espressi con strumenti come heado tail. Se si desidera 2 KB di byte casuali, eseguire

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

Con i vecchi kernel Linux, potresti cavartela

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

perché ha /dev/urandomrestituito felicemente tutti i byte richiesti. Ma questo non è più vero dal kernel 3.16, ora è limitato a 32 MB .

In generale, quando è necessario utilizzare ddper estrarre un numero fisso di byte e il suo ingresso non proviene da un file regolare o dispositivo a blocchi, è necessario leggere byte per byte: dd bs=1 count=2048.


Grazie per il suggerimento su come usare head anziché dd. Questo mi permette di usare ancora / dev / random se voglio. Sebbene / dev / urandom sia probabilmente sufficiente come dici tu, è bello sapere come usare / dev / random in caso di necessità.
Daniel,

su kernel dal 3.16 /dev/urandom restituisce 32m perread() .
Mikeserv,

In alternativa, se hai bisogno di un comando conforme a POSIX, puoi usare il trucco qui: unix.stackexchange.com/a/192114 dd if=/dev/urandom ibs=1k obs=1k | dd bs=1k count=2
Rufflewind

11

Da man 4 randomun box RHEL 5:

Quando letto, il dispositivo / dev / random restituirà solo byte casuali entro il numero stimato di bit di rumore nel pool di entropia.

Ottengo file di dimensioni 213 byte su quella macchina. Torna a man 4 random:

Quando viene letto, il dispositivo / dev / urandom restituirà tutti i byte richiesti.

Ricevo 2048 byte da ogni invocazione di dd if=/dev/urandom of=rand bs=1K count=2

Concludo che la differenza è dovuta a quanta entropia genera la tua macchina tra le invocazioni dd if=/dev/random ...


Sì, praticamente, a meno che non sia in una vera applicazione di crittografia, @Daniel dovrebbe usare / dev / urandom. Ma sono perplesso sul motivo per cui si dd if=/dev/random bs=1K count=2ferma quando la piscina dell'entropia è apparentemente prosciugata. Dai documenti, dovrebbe bloccarsi fino a quando non c'è più entropia, quindi ddscriverà il file lentamente, invece di scaricare il pool corrente ed uscire.
cjc,

Mi chiedevo anche questo, ma è coerente tra RHEL, Slackware 13.1 e un Arch piuttosto attuale. Il RHEL era x86_64, gli altri erano a 32 bit. Sfortunatamente i documenti dd sono in formato info GNU, quindi non li ho letti tutti.
Bruce Ediger,

È coerente anche con Gentoo.
Matthew Scharley,

4
@cjc: è perché quando si richiama read(fd, mybuf, 1024)un FD bloccante restituisce non appena il dispositivo sottostante restituisce alcuni dati. Se ci sono 1024 byte da leggere, restituisce quello. Se ci sono solo 201 byte, restituirà 201. Se ci sono 0 byte disponibili, si bloccherà fino a quando non sarà disponibile almeno un byte, quindi lo restituirà.
Warren Young,

@WarrenYoung la lettura da / dev / random ne prosciuga il contenuto? Suppongo di si.
Michael Martinez,

5

Perché ddrilasciare i dati? ... Gilles ha posto questa interessante domanda su dd:
Quando è adatto per copiare i dati? (o, quando sono read () e write () parziale)
Ecco un estratto da quella domanda:

    * ... non è difficile mettere in errore dd; ad esempio prova questo codice: **
        yes | dd of=out bs=1024k count=10
    e controlla la dimensione del file out (è probabile che sia ben al di sotto di 10 MB).


A parte il mio commento (alla fine della tua domanda), qualcosa di simile è iterest da guardare ... Cattura i tuoi byte nel file $trnd. Ho scelto semi-arbitrariamente bs = 8

Muovi il mouse e guardalo accelerare.
Con il mio computer inattivo (AFK e nessuna attività di rete) e dopo aver esaurito il pool di entropia, ci sono voluti 2 ore e 12 minuti per raccogliere solo 1192 byte, a quel punto l'ho cancellato.

Quindi, spostando continuamente il mouse, sono stati necessari 1 minuto e 15 secondi relativamente più brevi per raccogliere lo stesso numero di byte.

Ciò dimostra chiaramente che la raccolta di entropia non è basata sulla velocità della CPU, ma piuttosto su eventi casuali e che il mio sistema Ubuntu utilizza il mouse come uno dei suoi significativi fattori casuali.

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è progettato per il blocco - di solito è lo strumento migliore a tua disposizione per leggere da input di dimensioni variabili se ne hai bisogno immediatamente fatto perché ddnon memorizzerà le letture correnti in futuro write() (a meno che tu non lo configuri in modo molto esplicito con obs più grande di ibs) , ma sarà invece write()tutto ciò che legge non appena lo read()è (e facoltativamente lo elabora) .

Ecco alcune definizioni importanti :

  • ibs=expr
    • Specificare la dimensione del blocco di input, in byte, per (il valore predefinito è 512) .expr
  • obs=expr
    • Specificare la dimensione del blocco di output, in byte, per (il valore predefinito è 512) .expr
  • bs=expr
    • Impostare le dimensioni dei blocchi di input e output su exprbyte, sostituendo ibs=e obs=. Se nessuna conversione diversa da sync, noerrored notruncè specificata, ciascun blocco di ingresso deve essere copiato nell'uscita come blocco singolo senza aggregare blocchi corti.

Quindi, vedete, quando ibse obssono definiti insieme come bspoi ibsha la precedenza - ma per il resto, se specifica, allora o obso cbsnon.

Ecco un esempio in cui ibsè più importante. Potresti fare qualcosa del genere se volessi monitorare quanto presto il /dev/randompool si è riempito ...

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

Fintanto che if=il target è leggibile, ciò comporterà sempre lo stesso file di output di dimensioni, perché ddsarà in grado di syncsincronizzare i blocchi letti su null. In altre parole, se dd read()s per un blocco di input di $((size=10)) $((count=5))volte e il read()file restituisce 2 byte, quindi 8 byte, quindi 12 byte, quindi 2 byte, quindi 4 byte, ddscriverà sul suo file di output qualcosa come

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

... perché dd, per impostazione predefinita, non tarda. Quindi, se hai bisogno di tracciare in-stream e delimitare le scritture di qualche altro processo, ddè lo strumento che fa per te.

Se stai solo scrivendo una certa quantità di dati in un file normale, contrariamente ad altre dichiarazioni qui, puoi anche usarlo ddper questo - e abbastanza facilmente - ma avrai bisogno di più di un fattore di blocco affidabile .

Ad esempio, se hai fatto:

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

... il primo ddavrebbe bufferizzato tutti i ibs="$size"blocchi di input necessari per riempire almeno un obs="${size}x$block_factor"blocco di output per ciascuno write()nel tubo tra esso e il secondo dd. Ciò significa che il secondo ddpuò limitare in modo affidabile l'output count="$lmt"perché tutte le write()s che la prima produce corrisponderanno al suo blocco di I / O - indipendentemente da quanti read()s la prima dddeve fare per renderlo tale.

E che 's come si può utilizzare ddper leggere in modo affidabile i tubi o altri tipi di file speciali - con solo un po' di matematica.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.