¿Genera números pseudoaleatorios criptográficamente fuertes en Javascript?

22

¿Hay alguna buena manera de generar números pseudoaleatorios (o aleatorios reales) criptográficamente sólidos en Javascript?

El requisito crucial: si el Javascript de a.com genera algunos números aleatorios, nadie más podrá predecir esos números aleatorios. Por ejemplo, Javascript en evil.com no debería poder predecir los números aleatorios que obtuvo a.com.

Resumen de lo que sé sobre este tema. Esto es lo que he podido encontrar, en mi propia investigación:

  • Todos los navegadores proporcionan Math.random() como una llamada de biblioteca para generar números pseudoaleatorios. Desafortunadamente, no proporciona números aleatorios de calidad criptográfica y no cumple con el requisito anterior. En los navegadores que he visto, Math.random() usa un PRNG no criptográfico, y su estado interno se comparte en varios sitios. Por lo tanto, evil.com puede llamar a Math.random() varias veces, recuperar el estado interno del PRNG y luego inferir qué números aleatorios obtuvo a.com cuando llamó a Math.random() . Además, utiliza un PRNG de calidad no criptográfica, por lo que si a.com genera una clave aleatoria y un IV aleatorio utilizando Math.random() y luego publica el IV, podría ser posible inferir el estado interno del PRNG (del IV) y luego recuperar la clave. Entonces, Math.random() está fuera de lugar.

  • Encontré un artículo de investigación que analiza la criptografía en Javascript. Su código, la Biblioteca de criptografía de Javascript de Stanford , está disponible públicamente. Incluye un número pseudoaleatorio de fuerza criptográfica.

    Sin embargo, parece que tiene una limitación considerable: si estoy leyendo el documento correctamente, se requieren entre 10 y 40 segundos de interacción del usuario con su sitio antes de que el número pseudoaleatorio se coteja adecuadamente. Además, cada sitio tiene que volver a empezar desde cero: si a.com incluye la biblioteca SJCL, parece que el script de a.com tiene que esperar a que el usuario interactúe con el sitio a.com durante 10-40 segundos (normalmente) antes de que a.com pueda generar números aleatorios de calidad criptográfica. Esta es una limitación bastante significativa.

    Aquí está su papel:

  • El ensayo clásico, Criptografía de Javascript considerada dañina , menciona la falta de una buena manera de Obtenga números aleatorios de criptografía en Javascript como una barrera importante para hacer criptografía segura en Javascript. El ensayo considera varios enfoques obvios y explica por qué tienen defectos.

La conclusión es que no conozco ninguna solución razonable; Las opciones que encontré parecen bastante problemáticas. Sin embargo, han pasado varios años desde que se escribieron esos documentos y ensayos, y sé que la tecnología web puede cambiar rápidamente. ¿Alguien sabe de alguna buena solución a este problema?

    
pregunta D.W. 11.09.2012 - 10:31
fuente

4 respuestas

17

Hay una API experimental para esto: window.crypto.getRandomValues .

Se admite en

  • Chrome 11.0
  • Firefox 21
  • Internet Explore 11.0
  • Chrome con piel de Opera 15.0

Opera 12 no admite esta API, pero su Math.Random es seguro.

  

Opera aún no ha implementado window.crypto.getRandomValues (). Sin embargo,   nuestro Math.Random () está utilizando un generador aleatorio criptográficamente seguro.   Si se usa con cuidado (teniendo en cuenta que solo devuelve 53 bits de entropía para   cada llamada) es posible usarlo para implementar una versión javascript de   window.crypto.getRandomValues (). Solo asegúrate de hacer esto solo en   Opera, junto con algunos buenos comentarios en el código.

enlace

    
respondido por el CodesInChaos 11.09.2012 - 11:24
fuente
6

En un contexto web, Javascript es proporcionado por un servidor web de confianza (es decir, un servidor web que ya tiene el poder de ser muy desagradable, al enviar un código alterado). También puede seguir confiando en él y solicitar una semilla aleatoria de ese servidor, con una llamada Ajax secundaria, o simplemente haciendo que el servidor incluya la semilla aleatoria en el código de Javascript directamente, lo que debería ser un par de líneas. de código PHP. Algo así:

<script src="theJavascriptCode.js"></script>
<?php
    $randblob = bin2hex(openssl_random_pseudo_bytes(16));
    echo "<script>init_PRNG(\"$randblob\")</script>"
?>

El código Javascript puede incluir una buena implementación de PRNG, sembrada a través de la función init_PRNG() .

(Sin embargo, la seguridad contra integradores descuidados puede ser difícil. No se puede probar fácilmente, solo con Javascript, que su semilla provino de un PRNG fuerte, y no de algo débil, o incluso del lado del servidor codificado). / p>     

respondido por el Thomas Pornin 16.04.2013 - 13:00
fuente
2

También puede probar la implementación de Fortuna incluida en la Biblioteca de criptografía de Javascript (licencia AGPL 3)

(producido por Clipperz , el administrador de contraseñas en línea, soy cofundador)

    
respondido por el Marco Barulli 11.09.2012 - 16:15
fuente
2

Desafortunadamente, los navegadores simplemente no proporcionan suficiente entropía para producir números aleatorios fuertes. Creo que siempre será un compromiso con la usabilidad.

Iría a ver seedrandom.js (licencia BSD). Se basa en RC4, y parece ser bastante popular. Le permite conectar la entropía de sus propias fuentes, con una API bastante simple. Solo lo he usado una vez, y nunca he visto las pruebas de seguridad, pero ciertamente es más fácil y rápido que muchas otras soluciones que he visto.

Mis fuentes de entropía adicionales fueron:

  • Hash de mt_rand() y microtime() de salidas de PHP
  • Datos de posición del mouse tomados cada 1s
  • Datos de tiempo del teclado (en este caso, el usuario completó un formulario antes de que se requiriera RNG)

También puedes sincronizar algunas llamadas Ajax a través de la red y agregar esos horarios al grupo.

No sé la cantidad de entropía que realmente se produjo, pero fue todo lo que podía esperar obtener sin incomodar al usuario.

    
respondido por el Polynomial 11.09.2012 - 10:49
fuente

Lea otras preguntas en las etiquetas