Leer desde / dev / random no produce ningún dato

19

A menudo uso el comando

cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' | head --bytes 32

para generar contraseñas pseudoaleatorias. Esto no funciona con /dev/random.

Específicamente

  • cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' produce salida
  • cat /dev/random | strings --bytes 1 produce salida
  • cat /dev/random | strings --bytes 1 | tr -d '\n\t ' no produce salida

NB: cuando se usa /dev/random es posible que deba mover el mouse o presionar las teclas (por ejemplo, ctrl, shift, etc.) para generar entropía.

¿Por qué el último ejemplo no funciona? Tiene tralgún tipo de búfer interno grande que se /dev/urandomllena rápidamente pero/dev/random no?

PD: estoy usando CentOS 6.5

cat /proc/version
Linux version 2.6.32-431.3.1.el6.x86_64 ([email protected]) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) ) #1 SMP Fri Jan 3 21:39:27 UTC 2014
Aaron J Lang
fuente
¿Cuál es su distribución, su versión de kernel? en Cygwin ambos valores de retorno.
Kiwy
@Kiwy Ver edición.
Aaron J Lang
1
¿Sabes pwgenen particular pwgen -s?
MvG
2
El -scambio los hace menos memorables, más verdaderamente aleatorios. @Boyd: ¿está ampliamente disponible makepasswd más allá de las distribuciones basadas en Debian? A mi modo de ver, pwgen está disponible para CentOS, mientras que makepasswd no .
MvG
1
@BoydStephenSmithJr. Estoy de acuerdo con @ MvG que makepasswdno está disponible en mi plataforma, gracias de todos modos
Aaron J Lang

Respuestas:

27

Eventualmente lo hará.

En:

cat /dev/random | strings --bytes 1 | tr -d '\n\t '

cat nunca se almacenará en el búfer, pero es superfluo de todos modos ya que no hay nada que concatenar aquí.

< /dev/random strings --bytes 1 | tr -d '\n\t '

stringssin embargo, dado que su salida ya no es una terminal, almacenará su salida en bloques (de algo así como 4 u 8kB) en lugar de líneas cuando la salida vaya a una terminal.

Por lo tanto, solo comenzará a escribir en stdout cuando haya acumulado 4kB de caracteres para generar, que en /dev/random que llevará un tiempo.

trla salida va a una terminal (si está ejecutando eso en un indicador de shell en una terminal), por lo que almacenará su salida en línea. Porque estás quitando el\n , nunca tendrá una línea completa para escribir, por lo tanto, escribirá tan pronto como se haya acumulado un bloque completo (como cuando la salida no va a una terminal).

Por lo tanto, tres probable que no escriba nada hasta que stringshaya leído lo suficiente de/dev/random como para escribir 8kB (2 bloques posiblemente mucho más) de datos (ya que el primer bloque probablemente contendrá algunos caracteres de nueva línea o tabulación o espacio).

En este sistema, estoy probando esto, puedo obtener un promedio de 3 bytes por segundo /dev/random(en lugar de 12MiB /dev/urandom), por lo que en el mejor de los casos (los primeros 4096 bytes /dev/randomson todos imprimibles), estamos hablar 22 minutos antes de trcomenzar a emitir cualquier cosa. Pero es más probable que sean horas (en una prueba rápida, puedo ver stringsescribir un bloque cada 1 o 2 bloques leídos, y los bloques de salida contienen aproximadamente el 30% de los caracteres de nueva línea, por lo que espero que sea necesario leer al menos 3 bloques antes trtiene 4096 caracteres para la salida).

Para evitar eso, podrías hacer:

< /dev/random stdbuf -o0 strings --bytes 1 | stdbuf -o0 tr -d '\n\t '

stdbuf es un comando GNU (que también se encuentra en algunos BSD) que altera el almacenamiento en búfer stdio de los comandos a través de un truco LD_PRELOAD.

Tenga en cuenta que en lugar de strings, puede usar el tr -cd '[:graph:]'cual también excluirá tab, nueva línea y espacio.

Es posible que también desee arreglar la configuración regional para Cevitar posibles sorpresas futuras con los caracteres UTF-8.

Stéphane Chazelas
fuente
wow explicación impresionante.
Kiwy
2
¡Increíble! Gran explicación y solución. Siempre he usado cat'inútilmente' porque nunca me ha gustado redirigir stdin al final de una tubería, ahora puedo 'guardar un proceso' y todavía tener comandos legibles. Mi solución final fue< /dev/random stdbuf -o0 tr -Cd '[:graph:]' | stdbuf -o0 head --bytes 32
Aaron J Lang
@AaronJLang, buen punto sobre [:graph:]. Me había olvidado de eso.
Stéphane Chazelas
@AaronJLang, no lo necesita stdbufa head -c32menos que desee permitir que escriba los datos tan pronto como lo tenga (como en varios fragmentos en lugar de un fragmento de 32 bytes tan pronto como los tenga)
Stéphane Chazelas
2
En mi opinión, / dev / urandom es ampliamente suficiente para el uso del autor. Si alguien tuviera curiosidad acerca de cómo, específicamente, urandom funciona en comparación con random, sugeriría leer los comentarios en la parte superior del controlador en drivers / char / random.c del árbol de fuentes del núcleo. Los comentarios mencionan un análisis del PRNG y su implementación. Con suerte, este documento responderá a la pregunta "¿qué tan aleatorio es más o menos aleatorio en comparación con aleatorio?" Disponible aquí: eprint.iacr.org/2012/251.pdf
etherfish
5

Generar números aleatorios para muchas aplicaciones de seguridad requiere suficiente entropía: la entropía mide cuán impredecible es la aleatoriedad. Un procesador determinista no puede generar entropía, por lo que la entropía debe provenir del exterior, ya sea de un componente de hardware con un comportamiento no determinista o de otros factores que son lo suficientemente difíciles de reproducir, como el tiempo de las acciones del usuario (ahí es donde mueve el mouse viene en). Una vez que se dispone de suficiente entropía, la criptografía se puede utilizar para generar un flujo prácticamente ilimitado de números aleatorios.

Linux funciona acumulando entropía en un grupo, luego usando criptografía para producir números aleatorios aceptables tanto a través /dev/randomcomo /dev/urandom. La diferencia es que /dev/randomaplica un cálculo de entropía extremadamente conservador que reduce la estimación de la entropía en el grupo por cada byte que genera, mientras /dev/urandomque no se preocupa por la cantidad de entropía en el grupo.

Si la estimación de entropía en el grupo es demasiado baja, /dev/randombloquea hasta que se pueda acumular más entropía. Esto puede afectar gravemente la velocidad a la que /dev/randompuede producir resultados. Esto es lo que estás observando aquí. No tiene nada que ver con tr; pero stringslee la salida con almacenamiento en búfer, por lo que tiene que leer un búfer completo (unos pocos KB) /dev/randomsolo para producir al menos un byte de entrada.

/dev/urandomes perfectamente aceptable para generar una clave criptográfica , porque la entropía no disminuye de manera perceptible. (Si mantiene su máquina funcionando durante más tiempo del que ha existido el universo, no puede descuidar estas consideraciones, pero de lo contrario es bueno). Solo hay un caso en el /dev/urandomque no es bueno, que está en un sistema recién instalado que no tiene Todavía no tuve tiempo de generar entropía, o un sistema recién arrancado que arranca desde medios de solo lectura.

Eliminar stringsde su cadena de arranque probablemente acelerará su proceso. A continuación trse filtrarán los caracteres que no se imprimen:

</dev/random LC_ALL=C tr -dc '!-~'

Pero puede usar /dev/urandomaquí , siempre y cuando tenga cuidado de no generar contraseñas en un sistema que no haya tenido tiempo de acumular suficiente entropía. Puede verificar el nivel del grupo de entropía de Linux en /proc/sys/kernel/random/entropy_avail(si lo usa /dev/random, la cifra en este archivo será conservadora, posiblemente mucho).

Gilles 'SO- deja de ser malvado'
fuente
1

Debe usar /dev/urandompara obtener números aleatorios (pseudo) de alta calidad, y /dev/randomsolo cuando necesite números aleatorios que sean realmente impredecibles. Un atacante debajo de los recursos de la NSA tendrá un muy mal rato a agrietarse /dev/urandom(y no se olvide de caucho de la criptografía de la manguera ). El núcleo llena un búfer con bytes "realmente aleatorios", eso es lo que /dev/randomda. Lamentablemente, la tasa a la que se generan esos datos es baja, por lo que leer mucho de se /dev/random detendrá esperando la aleatoriedad.

Puede considerar usar random.org o su generador de contraseñas , o uno de los muchos generadores de contraseñas aleatorias que están flotando, eche un vistazo a, por ejemplo, esta página para obtener algunos consejos sobre la línea de comandos (no es que los recomiende todos) , pero deberían darte ideas), o podrías usar algo como mkpasswd(1)(aquí en Fedora 19 parte de expect-5.45-8.fc19.x86_64).

vonbrand
fuente