Las aplicaciones Java pueden y deben usar la clase java.security.SecureRandom para producir valores aleatorios criptográficamente fuertes mediante el uso de un generador de números pseudoaleatorios criptográficamente fuertes ( CSPRNG ). Las implementaciones JDK estándar de la clase java.util.Random no se consideran criptográficamente fuertes.
Los sistemas operativos tipo Unix tienen /dev/random
un archivo especial que sirve números pseudoaleatorios que acceden al ruido ambiental recolectado de los controladores de dispositivos y otras fuentes. Sin embargo, bloquea si hay menos entropía disponible que la solicitada ; /dev/urandom
normalmente nunca se bloquea, incluso si la semilla del generador de números pseudoaleatorios no se inicializó completamente con entropía desde el arranque. Todavía hay un tercer archivo especial, /dev/arandom
que se bloquea después del arranque hasta que la semilla se ha inicializado de forma segura con suficiente entropía, y luego nunca se vuelve a bloquear.
Por defecto, la JVM genera la clase SecureRandom usando /dev/random
, por lo tanto, su código Java puede bloquearse inesperadamente . La opción -Djava.security.egd=file:/dev/./urandom
en la invocación de línea de comando utilizada para iniciar el proceso Java le dice a la JVM que la use /dev/urandom
en su lugar.
El extra /./
parece hacer que la JVM use el algoritmo SHA1PRNG que usa SHA-1 como la base del PRNG (generador de números pseudoaleatorios). Es más fuerte que el algoritmo NativePRNG utilizado cuando /dev/urandom
se especifica.
Finalmente, existe un mito que /dev/urandom
es un generador de números aleatorios pseudoaleatorios, un PRNG, mientras que /dev/random
es un generador de números aleatorios "verdadero" . Esto simplemente no es cierto, ambos /dev/random
y /dev/urandom
son alimentados por el mismo CSPRNG (generador de números pseudoaleatorios criptográficamente seguro). Solo el comportamiento cuando su grupo respectivo se queda sin entropía, según algunas estimaciones, difiere: /dev/random
bloques, mientras /dev/urandom
que no.
¿Qué pasa con la entropía baja? No importa.
Resulta que "parecer aleatorio" es el requisito básico para muchos de nuestros bloques de construcción criptográficos. Y si toma la salida de un hash criptográfico, debe ser indistinguible de una cadena aleatoria para que los cifrados lo acepten. Esa es la razón de usar el algoritmo SHA1PRNG, ya que usa una función hash y un contador, junto con una semilla.
¿Cuándo se supone que debe aplicarse?
Siempre, yo diría.
Fuentes:
https://gist.github.com/svrc/5a8accc57219b9548fe1
https://www.2uo.de/myths-about-urandom
EDITAR 04/2020:
Un comentario menciona un cambio en el comportamiento de la clase SecureRandom en Java 8.
SHA1PRNG y NativePRNG se corrigieron para respetar adecuadamente las propiedades de origen de semilla SecureRandom en el archivo java.security. (La solución alternativa oscura que usa file: /// dev / urandom y file: / dev /./ urandom ya no es necesaria).
Esto ya había sido señalado por las pruebas a las que se hace referencia en la sección Fuentes anterior. El extra /./
es necesario para cambiar el algoritmo utilizado por SecureRanom en Java 8 de NativePRNG a SHA1PRNG.
Sin embargo, tengo algunas noticias que me gustaría compartir. Según el JEP-273 , desde Java 9, la clase SecureRandom implementa los tres mecanismos del generador de bits aleatorio determinista (DRBG) descritos en NIST 800-90Ar1 . Estos mecanismos implementan algoritmos modernos tan fuertes como SHA-512 y AES-256.
El JDK tenía dos tipos de implementaciones de SecureRandom :
- Uno depende de la plataforma y se basa en llamadas nativas o dispositivos del sistema operativo, como leer
/dev/{u}random
en Unix o usar CryptoAPI en Windows. Las últimas versiones de Linux y Windows ya admiten DRBG, pero las versiones anteriores y los sistemas integrados pueden no serlo .
- El otro tipo es una implementación pura de Java que utiliza una implementación RNG basada en SHA1 más antigua, que no es tan sólida como los algoritmos utilizados por los mecanismos DRBG aprobados.
Mientras tanto, la Guía del desarrollador de seguridad de Java 13 sigue leyendo
En Linux y macOS, si el dispositivo de recopilación de entropía en java.security se establece en file:/dev/urandom
o file:/dev/random
, entonces NativePRNG se prefiere a SHA1PRNG. De lo contrario, se prefiere SHA1PRNG.
Para aclarar cómo los nuevos mecanismos DRBG juegan junto con los PRNG anteriores, ejecuté algunas pruebas en macOS (Darwin) con AdoptOpenJDK (compilación 13.0.2 + 8). Aquí están los resultados:
file: / dev / random
Orden de preferencia para proveedores:
SecureRandom.NativePRNG
SecureRandom.DRBG
SecureRandom.SHA1PRNG
archivo: / dev / urandom
Orden de preferencia para proveedores:
SecureRandom.NativePRNG
SecureRandom.DRBG
SecureRandom.SHA1PRNG
file: / dev /./ urandom
Orden de preferencia para proveedores:
SecureRandom.DRBG
SecureRandom.SHA1PRNG
SecureRandom.NativePRNG
Conclusión:
Recomiendo usar -Djava.security.egd=file:/dev/./urandom
para asegurarse de aprovechar la implementación más segura de SecureRandom disponible, independientemente de la plataforma utilizada, evitando bloquear el código inesperadamente.
/dev/urandom
selecciona NativePRNG alimentado por/dev/urandom
mientras/dev/./urandom
selecciona SHA1PRNG (también alimentado por/dev/urandom
) cuando se utiliza Java 8. A partir de Java 9, DRBG tiene prioridad cuando/dev/./urandom
se especifica la fuente.Esto ya no es necesario si está utilizando JDK 8 o superior
El problema ha sido solucionado por Java y aquí hay algunos enlaces
contorno
Para más información (busque al azar en la página):
https://docs.oracle.com/javase/8/docs/technotes/guides/security/enhancements-8.html
https://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html
fuente
Esto está relacionado con la diferencia de Linux
/dev/random
y/dev/urandom
el generador de números aleatorios.Tomado de este enlace
Para responder tu pregunta
Basado en el enlace anterior, eso es algo exclusivo de las versiones de Java 5 y siguientes que resultó de problemas con / dev / urandom en sistemas Linux en 2004.
fuente