¿Cómo generar datos pseudoaleatorios criptográficamente fuertes muy rápidamente?

6

¿Cuál es la mejor manera de generar un flujo rápido de datos pseudoaleatorios criptográficamente sólidos sin instalar paquetes poco comunes? Dibujar desde / dev / urandom es demasiado lento.

Se me ocurrió una idea al leer la página de manual "limpiar":

  

utilizará el algoritmo fresco RC6 como PRNG; RC6 está codificado con la semilla de 128 bits, y luego un bloque nulo se encripta repetidamente para obtener la secuencia pseudo-aleatoria.

El cifrado de un bloque nulo con una sola clave probablemente no sea la mejor idea, especialmente cuando se requieren grandes cantidades de datos pseudoaleatorios, por lo que rápidamente hice esto en bash:

while dd if=/dev/zero bs=$(shuf -n 1 -i 1024-67108864) count=1 2>/dev/null | openssl aes-256-cbc -nosalt -k "$(head -c 32 < /dev/random)"; do :; done > [whateverneedsrandomness]

Esto encripta un flujo de ceros con una semilla aleatoria de 32 bytes. La corriente se reinicia en promedio cada 32 MB (el rango está entre 1 KB y 64 MB con una resolución de un byte). El intervalo de reinicio es aleatorio para evitar que alguien adivine dónde se utiliza una nueva clave. Elegí a propósito CBC como el modo de bloqueo en lugar de CTR, aunque es más rápido porque he leído que el CTR solo es bueno para transmisiones constantes, y mi conocimiento criptográfico muy limitado me dice que un contador repetitivo que se reinicia todo el tiempo no es un buena idea cuando la "transmisión" tendrá solo unos pocos MB de largo, aunque realmente no lo sé con seguridad.

Una de las preocupaciones que tengo es si la secuencia que sale de openssl está o no totalmente encriptada. Si la entrada no es divisible de manera uniforme por el tamaño del bloque, ¿openssl dejará los datos adicionales en blanco (dejando "huecos" de 0s dispersos a lo largo del flujo resultante)? ¿Tiene relleno algo relacionado con eso?

Mi pregunta es, ¿es esta una buena manera de crear datos aleatorios rápidos? ¿Y hay algo que pasé por alto / pasé por alto, etc., como usar el modo de bloque incorrecto?

    
pregunta kkarl88 24.10.2013 - 08:55
fuente

2 respuestas

9

Editar: La evidencia era cegadora, así que me la perdí. OpenSSL ya ofrece una interfaz para su propio PRNG interno, que se siembra con el /dev/urandom de la máquina, pero luego lo extiende con su propio criptografía. Solo haz esto:

openssl rand 10000000

para producir 10 millones de bytes pseudo-aleatorios. En mi computadora portátil, esto parece ser aproximadamente 3 veces más rápido que /dev/urandom , es decir, 11 MByte / s o menos. Si esto no es lo suficientemente rápido para usted, siga leyendo.

Respuesta original:

Realmente depende del hardware y el contexto involucrados. Ya que estás hablando de un script bash, /dev/urandom y OpenSSL, supongo que:

  • Usted usa Linux.
  • Desea generar un gran archivo lleno de bytes pseudoaleatorios.
  • Desea una solución que sea un conjunto de scripts de paquetes "normales" existentes, no una solución programática.

De hecho, si pudiera escribir su propio código C, sus mejores opciones serían el cifrado AES en modo CTR con el AES-NI instrucciones (en la PC reciente que ofrece estas instrucciones), o un cifrado de flujo dedicado (por ejemplo, uno de estos ). En una CPU Core2 de 2.4 GHz, podría obtener 700 MByte / s de bytes pseudoaleatorios de Sosemanuk. De aquí en adelante supongo que estás limitado a scripts.

El uso del cifrado OpenSSL no es una mala idea, pero hay detalles:

  • Aleatorizar la longitud de cada fragmento es una complicación inútil.
  • No es necesario ir a AES-256; AES-128 ya está bien. AES-256 es un 40% más lento que AES-128, y no agrega mejoras prácticas en seguridad.
  • Al cifrar una secuencia larga de ceros con CBC, en realidad está ejecutando el cifrado de bloque en modo OFB (cifrar un bloque, cifrarlo de nuevo, y otra vez, y otra vez). Esto es razonable siempre y cuando permanezca por debajo del límite 2n/2 , lo que significa que con AES (bloques de 128 bits) no usa un trozo más largo que < em> 2 64 bloques de 16 bytes, es decir, 250 millones de terabytes. Lo más probable es que no lo alcances de todos modos. En ese sentido, la "resiembra" no es realmente necesaria.
  • Cuando "reinicia" (si decide mantener esta función, que no es necesaria), use /dev/urandom , no /dev/random . /dev/urandom está bien para la criptografía (los scripts de arranque del sistema operativo aseguran que el PRNG interno está correctamente sembrado), a pesar de los puntos de vista paranoicos erróneos de la implementación /dev/random . Por otro lado, /dev/random puede bloquear, y por lo tanto ser realmente lento (nada es más lento que un proceso bloqueado).
  • Cuidado con las cuerdas. bash usa cadenas de caracteres; /dev/random y /dev/urandom return bytes , incluidos bytes de valor 0. Esto puede dar como resultado una clave truncada artificialmente y una seguridad reducida. Esto es malo. En su lugar, debe codificar los bytes en hexadecimal y los argumentos de línea de comando -K y -iv con openssl .
  • OpenSSL puede agregar un encabezado que comienza con 8 bytes fijos (por lo tanto, totalmente no aleatorio). No lo hace si usa -K y -iv .
  • OpenSSL también usará algo de relleno, por lo que obtendrás un bloque adicional de 16 bytes al final (esto no es un problema; el relleno está en el texto claro y el cifrado lo "aleatoriza").

Esto conduce al siguiente script:

#!/bin/sh
key=$(dd if=/dev/urandom bs=16 count=1 2>/dev/null | md5sum | cut -d' ' -f1)
iv=$(dd if=/dev/urandom bs=16 count=1 2>/dev/null | md5sum | cut -d' ' -f1)
dd if=/dev/zero bs=65536 count=8192 2>/dev/null | openssl aes-128-cbc -K $key -iv $iv

Cuando se invoca, esta secuencia de comandos genera una secuencia de exactamente 536870928 bytes pseudoaleatorios, que son aptos para fines criptográficos. Siéntase libre de modificar los parámetros bs y count , pero recuerde que dd asignará un búfer RAM de tamaño bs , por lo que generalmente desea mantener bs pequeño, pero no demasiado pequeño para evitar demasiados viajes de ida y vuelta al kernel (8192 a 65536 suelen ser buenos valores).

Uso MD5 aquí solo para la conveniencia de la conversión de bytes a hexadecimal (las deficiencias conocidas de MD5 no tienen ninguna influencia en la seguridad en este caso).

Este script debería funcionar en cualquier instalación de Linux decente. Utiliza solo paquetes que deberían estar allí por defecto. En mi portátil no muy potente, este script produce bytes pseudoaleatorios a una velocidad de 73 MBytes por segundo, lo cual no es malo y probablemente sea suficiente para sus propósitos (si eso no es suficiente, entonces probablemente tendrá otros problemas con I / O cuellos de botella).

    
respondido por el Tom Leek 24.10.2013 - 16:13
fuente
1

Si a menudo se está agotando la fuente de datos aleatoria, le aconsejaría que invierta en un generador de números aleatorios de hardware como enlace .

Por lo general, está limitado a la cantidad de datos aleatorios que puede generar el hardware del generador de números aleatorios en su CPU. Los dispositivos externos como estos pueden generar buenos datos aleatorios a una velocidad mucho más rápida.

    
respondido por el deed02392 24.10.2013 - 11:07
fuente

Lea otras preguntas en las etiquetas