¿Por qué dd from / dev / random da diferentes tamaños de archivo?

26

Estoy ejecutando el siguiente comando en un sistema ubuntu:

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

Sin embargo, cada vez que lo ejecuto, termino con un archivo de un tamaño diferente. ¿Por qué es esto? ¿Cómo puedo generar un archivo de un tamaño determinado lleno de datos aleatorios?

Daniel
fuente
1
/dev/randomse bloqueará si no hay suficiente entropía disponible para generar la cantidad de dígitos que desea. simplemente toma tiempo reunir esa cantidad de "aleatoriedad" aleatoria de psuedo de alta calidad ... O use /dev/urandompara un valor "aleatorio" menos aleatorio, o verifique su grupo de entropía (en un bucle, y espere según sea necesario) ...
Peter.O
Ver también esta pregunta .
Keith Thompson
3
solo agregueiflag=fullblock
frostschutz el

Respuestas:

31

Estás observando una combinación del comportamiento peculiar de ddcon el comportamiento peculiar de Linux /dev/random. Ambos, por cierto, rara vez son la herramienta adecuada para el trabajo.

Linux /dev/randomdevuelve datos con moderación. Se basa en el supuesto de que la entropía en el generador de números pseudoaleatorios se extingue a una velocidad muy rápida. Dado que la recopilación de nueva entropía es lenta, /dev/randomgeneralmente solo se renuncian unos pocos bytes por vez.

ddes un programa viejo y malhumorado destinado inicialmente a funcionar en dispositivos de cinta. Cuando le dice que lea un bloque de 1kB, intenta leer un bloque. Si la lectura devuelve menos de 1024 bytes, difícil, eso es todo lo que obtienes. Entonces dd if=/dev/random bs=1K count=2hace dos read(2)llamadas. Como está leyendo /dev/random, las dos readllamadas generalmente devuelven solo unos pocos bytes, en número variable dependiendo de la entropía disponible. Consulte también ¿ Cuándo es adecuado dd para copiar datos? (o, cuando se leen () y escriben () parcial)

A menos que esté diseñando un instalador o clonador del sistema operativo, nunca debe usarlo /dev/randombajo Linux, siempre /dev/urandom. La urandompágina del manual es algo engañosa; /dev/urandomDe hecho, es adecuado para la criptografía, incluso para generar claves de larga duración. La única restricción con /dev/urandomes que debe suministrarse con suficiente entropía; Las distribuciones de Linux normalmente guardan la entropía entre reinicios, por lo que el único momento en que podría no tener suficiente entropía es en una instalación nueva. La entropía no desaparece en términos prácticos. Para obtener más información, lea ¿Es seguro un rand de / dev / urandom para una clave de inicio de sesión? y el grupo de alimentación / dev / entropía aleatoria? .

La mayoría de los usos de ddse expresan mejor con herramientas como heado tail. Si quieres 2kB de bytes aleatorios, ejecuta

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

Con los núcleos de Linux más antiguos, podría salirse con la suya

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

porque /dev/urandomfelizmente devolvió tantos bytes como se solicitó. Pero esto ya no es cierto desde el kernel 3.16, ahora está limitado a 32 MB .

En general, cuando se necesita para el uso ddpara extraer un número fijo de bytes y su entrada no proviene de un archivo normal o dispositivo de bloque, es necesario leer byte a byte: dd bs=1 count=2048.

Gilles 'SO- deja de ser malvado'
fuente
Gracias por el consejo sobre el uso de la cabeza en lugar de dd. Eso me permite seguir usando / dev / random si quiero. Aunque / dev / urandom probablemente sería suficiente como usted menciona, es bueno saber cómo usar / dev / random si surge la necesidad.
Daniel
en núcleos desde 3.16 /dev/urandom devuelve 32m porread() .
mikeserv
Alternativamente, si necesita un comando compatible con POSIX, puede usar el truco aquí: unix.stackexchange.com/a/192114 dd if=/dev/urandom ibs=1k obs=1k | dd bs=1k count=2
Rufflewind
11

Desde man 4 randomuna caja RHEL 5:

Cuando se lee, el dispositivo / dev / random solo devolverá bytes aleatorios dentro del número estimado de bits de ruido en el grupo de entropía.

Recibo archivos de 213 bytes en esa máquina. De vuelta al hombre 4 al azar:

Cuando se lee, / dev / urandom device devolverá tantos bytes como se soliciten.

Obtengo 2048 bytes de cada invocación de dd if=/dev/urandom of=rand bs=1K count=2

Concluyo que la diferencia se debe a la cantidad de entropía que genera su máquina entre invocaciones de dd if=/dev/random ...

Bruce Ediger
fuente
Sí, prácticamente, a menos que esté en una aplicación criptográfica real, @Daniel debería usar / dev / urandom. Pero estoy desconcertado de por qué se dd if=/dev/random bs=1K count=2detiene cuando el grupo de entropía aparentemente está drenado. Desde los documentos, debe bloquearse hasta que haya más entropía, por lo ddque escribirá el archivo lentamente, en lugar de simplemente eliminar el grupo actual y salir.
cjc
También me preguntaba sobre eso, pero es consistente en RHEL, Slackware 13.1 y un Arch bastante actual. El RHEL era x86_64, los otros eran de 32 bits. Lamentablemente, los documentos dd están en formato de información GNU, así que no los he leído todos.
Bruce Ediger
También es consistente en Gentoo también.
Matthew Scharley
44
@cjc: es porque cuando llamas read(fd, mybuf, 1024)a un FD de bloqueo, vuelve tan pronto como el dispositivo subyacente devuelve algunos datos. Si hay 1024 bytes para ser leídos, devuelve eso. Si solo hay 201 bytes, devolverá 201. Si hay 0 bytes disponibles, se bloqueará hasta que al menos un byte esté disponible, luego lo devolverá.
Warren Young
@WarrenYoung ¿leer de / dev / random drena su contenido? Supongo que sí.
Michael Martinez
5

¿Por qué se ddcaen los datos? ... Gilles ha planteado esta interesante pregunta sobre dd: ¿
Cuándo es adecuado dd para copiar datos? (o, cuando se lee () y escribe () parcial)
Aquí hay un extracto de esa pregunta:

    * ... no es difícil culpar a dd; por ejemplo, pruebe este código: **
        yes | dd of=out bs=1024k count=10
    y verifique el tamaño del archivo de salida (es probable que sea muy inferior a 10 MB).


Aparte de mi comentario (al final de su pregunta), algo como esto es interesante de ver ... Captura sus bytes en el archivo $trnd. He elegido semi-arbitrariamente bs = 8

Mueve el mouse y observa cómo se acelera.
Con mi computadora inactiva (AFK y sin actividad de red), y después de agotar el grupo de entropía, me tomó 2 horas 12 minutos recolectar solo 1192 bytes, momento en el cual lo cancelé.

Luego, al mover el mouse continuamente, me tomó un tiempo relativamente más corto de 1 minuto y 15 segundos para recopilar la misma cantidad de bytes.

Esto muestra con bastante claridad que la recopilación de entropía no se basa en la velocidad de la CPU, sino que se basa en eventos aleatorios , y que mi sistema Ubuntu usa el mouse como uno de sus factores aleatorios significativos .

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

ddestá diseñado para bloquear: por lo general, es la mejor herramienta a su disposición para leer desde entradas de tamaño variable si lo necesita de inmediato, ya ddque no almacenará las lecturas de corriente en el futuro write() (a menos que lo configure de manera muy explícita de esa manera con un obs mayor que ibs) , pero, en cambio write(), leerá todo lo que lea tan pronto como read()sea (y opcionalmente lo procesará) .

Aquí hay algunas definiciones importantes :

  • ibs=expr
    • Especifique el tamaño del bloque de entrada, en bytes, por (el valor predeterminado es 512) .expr
  • obs=expr
    • Especifique el tamaño del bloque de salida, en bytes, por (el valor predeterminado es 512) .expr
  • bs=expr
    • Establezca los tamaños de bloque de entrada y salida en exprbytes, reemplazando ibs=y obs=. Si no se especifica otra conversión que sync, noerrory notruncse especifica, cada bloque de entrada se copiará a la salida como un bloque único sin agregar bloques cortos.

Así que ya ves, cuándo ibsy obsse definen juntos como bsentonces ibstiene prioridad, pero de lo contrario, si eres específico, entonces obso lo cbshace.

Aquí hay un ejemplo en el que ibses más importante. Puede hacer algo como esto si desea realizar un seguimiento de lo pronto que se /dev/randomllenó la piscina ...

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

Mientras if='s objetivo se puede leer en absoluto, que será siempre como resultado el mismo tamaño de archivo de salida, porque ddse synchronize bloques de lectura en el nulos. En otras palabras, si dd read()s es para un bloque de entrada de $((size=10)) $((count=5))tiempos y el read()archivo devuelve 2 bytes, luego 8 bytes, luego 12 bytes, luego 2 bytes, luego 4 bytes, ddescribirán en su archivo de salida algo como

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

... porque dd, por defecto, no se retrasa. Entonces, si necesita realizar un seguimiento in-stream y delimitar las escrituras de algún otro proceso, esta ddes la herramienta para usted.

Si solo está escribiendo cierta cantidad de datos en un archivo normal, a diferencia de otras declaraciones hechas aquí, también puede usarlo ddpara esto, y con bastante facilidad, pero necesitará más de uno y un factor de bloqueo confiable .

Por ejemplo, si hiciste:

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

... el primero ddalmacenará tantos ibs="$size"bloques de entrada como sean necesarios para llenar al menos un obs="${size}x$block_factor"bloque de salida por cada write()tubería entre él y el segundo dd. Esto significa que el segundo ddpuede limitar la salida de manera confiable count="$lmt"porque todos los write()s que realiza el primero coincidirán con su tamaño de bloque de E / S, independientemente de cuántos read()s dddebe hacer el primero para hacerlo.

Y así es como puede usar ddpara leer de manera confiable tuberías u otros tipos de archivos especiales, con solo un poco de matemática.

mikeserv
fuente