¿Java SecureRandom no bloquea? ¿Cómo?

22

Sé por experiencia que la lectura de / dev / random bloquea cuando el grupo de entropía del kernel de Linux se queda sin entropía. Además, he visto muchos artículos y entradas de blog que indican que cuando se ejecuta en Linux, java.security.SecureRandom usa / dev / random como su fuente de entropía y, por lo tanto, bloquea cuando el grupo de entropía del kernel se queda sin entropía.

Sin embargo, no puedo producir un experimento que haga que SecureRandom se bloquee. A la inversa, parece fácil obtener un simple bash de una línea que lee desde / dev / random para bloquear.

Aquí está el código java que estoy usando para estos experimentos:

import java.security.SecureRandom;

public class A {
    public static void main(String[] args) {
        SecureRandom sr = new SecureRandom();
        int out = 0;
        for (int i = 0; i < 1<<20 ; i++) {
            out ^= sr.nextInt();
        }
        System.out.println(out);
    }
}

Genera poco más de 1,000,000 enteros aleatorios de 32 bits. Eso debería ser 2 ^ (20 + log2 (32)) = 2 ^ 25 bits o 2 ^ 22 (un poco más de 4 millones) bytes de entropía, ¿verdad? Sin embargo, nunca se bloquea. Siempre termina en aproximadamente 1,2 segundos, sin importar si muevo el mouse o no.

El bash one-liner que usé es:

head -c 100 /dev/random | xxd

Esto bloquea fácilmente. Mientras mantengo mi mano alejada del mouse y el teclado, permanecerá allí sin hacer nada durante varios minutos. Y solo pido 100 bytes de entropía.

Seguro que me estoy perdiendo algo aquí. ¿Podría alguien explicar lo que está pasando?

¡Gracias!

    
pregunta user1483512 14.08.2013 - 20:46
fuente

5 respuestas

37

Tanto OpenJDK como Sun leen desde /dev/urandom , no /dev/random , al menos en la máquina donde probé (OpenJDK JRE 6b27 y Sun JRE 6.26 en Debian squeeze amd64). Por alguna razón, ambos también abren /dev/random pero nunca leen. Así que los artículos del blog que leíste estaban equivocados o aplicados a una versión diferente a la mía (y, aparentemente, a la tuya).

Puedes verificar si el tuyo lee desde /dev/random o /dev/urandom al rastrearlo:

strace -o a.strace -f -e file java A

y busque la parte relevante de la traza:

21165 open("/dev/random", O_RDONLY)     = 6
…
21165 open("/dev/urandom", O_RDONLY)    = 7
…
21165 read(7, "2312Zs0564l44[wS6q@", 20) = 20
…

No se preocupe, /dev/urandom está perfectamente bien para la criptografía.

    
respondido por el Gilles 14.08.2013 - 21:02
fuente
9

SecureRandom de Java usa / dev / random, pero solo brevemente.

Específicamente, solo lo usa cuando se genera información semilla, ya sea llamando explícitamente a SecureRandom.generateSeed() o mediante la primera llamada a nextInt()

Por lo tanto, para repetir su ejemplo de bash, puede hacer lo siguiente, y debería bloquearlo.

import java.security.SecureRandom;

public class A {
    public static void main(String[] args) {
        SecureRandom sr;
        int out = 0;
        for (int i = 0; i < 1<<20 ; i++) {
            sr = new SecureRandom();
            out ^= sr.nextInt();
        }
        System.out.println(out);
    }
}
    
respondido por el diedthreetimes 14.11.2014 - 07:06
fuente
3
La propiedad

$JAVA_HOME/lib/security/java.security : securerandom.source determina qué dispositivo usar cuando se usa SecureRandom . El valor predeterminado es /dev/urandom , lo que significa que Java nunca se bloqueará.

Para los recién llegados al tema, /dev/urandom es una versión especial de /dev/random , que utilizará la verdadera entropía de /dev/random cuando esté disponible y luego los datos pseudo aleatorios sembrarán la verdadera entropía si estuviera disponible.

En entornos sin cabeza, VM y en la nube, recomiendo sembrar urandom desde una fuente externa, como enlace

    
respondido por el Alastair McCormack 09.03.2014 - 20:01
fuente
3

En Linux reciente (los últimos 6 años, por ejemplo) la diferencia computacional entre / dev / random (bloqueo) y / dev / urandom (no bloqueo) es muy marginal; la entropía sin procesar se lava a través de un generador de números aleatorios y ambos dispositivos usan los mismos bits. La única diferencia es que / dev / random tiene un limitador de velocidad que evita que se ejecute durante demasiado tiempo sin volver a sembrar. La estimación de la tasa en sí es bastante discutible.

Esto se explica en enlace , que resalta el punto de que / dev / urandom es suficiente para sembrar tu Algoritmos criptográficos para claves de sesión. Si no lo llama con demasiada frecuencia, ambos deben ser de una calidad idéntica o casi idéntica.

He visto el bloqueo a través de / dev / random al ejecutar un rastreador web que necesitaba hacer más de 1000 conexiones SSL simultáneas (claves de sesión), y sí, cambiamos a / dev / urandom; para la generación masiva de pares de claves públicas / privadas de larga data (una situación rara), un dispositivo de entropía personalizado es el mejor.

    
respondido por el Paul Baclace 30.09.2015 - 23:54
fuente
3

No solo para mantener vivo un hilo antiguo, sino que algunas personas pueden haberse perdido una parte importante de la larga historia detrás de esto ... Se trata de un error conocido y persistente conocido al usar / dev / urandom desde las versiones 1.4 a las versiones 1.7. Vea los enlaces a continuación:

enlace

enlace

Por lo que sé, esto finalmente se ha abordado en Java 8 según lo declarado por Oracle: enlace

  

SHA1PRNG y NativePRNG fueron corregidos para respetar adecuadamente la   Propiedades de origen de inicialización SecureRandom en el archivo java.security. (Los   solución oscura usando file: /// dev / urandom y file: / dev /./ urandom   ya no es necesario.)

    
respondido por el ozys 28.01.2016 - 18:20
fuente

Lea otras preguntas en las etiquetas