vulnerability util securerandom getinstancestrong example ejemplo java random cryptography prng

java - util - SecureRandom con NativePRNG vs SHA1PRNG



securerandom ruby (2)

A partir de una ref. here :

Implementación nativa de PRNG para Solaris / Linux. Interactúa con / dev / random y / dev / urandom, por lo que solo está disponible si esos archivos están presentes. De lo contrario, se usa SHA1PRNG en lugar de esta clase.

El proveedor de SUN se puede utilizar como predeterminado (depende principalmente del orden del proveedor que esté presente).

Necesito generar números aleatorios y matrices de bytes criptográficamente fuertes. Para este propósito, estoy usando la clase SecureRandom de Java. Pero no estoy seguro de elegir qué algoritmo PRNG en términos de su fuerza criptográfica.

¿Cuál de las siguientes instancias genera un número más impredecible? ¿O son iguales?

SecureRandom nativePrng = SecureRandom.getInstance("NativePRNG") SecureRandom sha1Prng = SecureRandom.getInstance("SHA1PRNG")

Además, podemos generar estas instancias con el proveedor "SUN" (por ejemplo, SecureRandom.getInstance("SHA1PRNG", "SUN") ). ¿Esto hace una diferencia?

Gracias por adelantado.


TL; DR: use el new SecureRandom() cuando no esté seguro y deje que el sistema lo new SecureRandom() . Posiblemente use SecureRandom.getInstanceStrong() para la generación de claves a largo plazo.

No espere que un generador de números aleatorios genere una secuencia de salida específica dentro de una aplicación de tiempo de ejecución.

Con generadores de números aleatorios siempre es difícil decir cuál es el mejor. Linux y la mayoría de los Unix tienen un generador de números aleatorios bastante bien pensado, por lo que no está mal usar /dev/random o /dev/urandom , es decir, "NativePRNG" . El problema con el uso de /dev/random es que bloquea hasta que haya suficiente entropía disponible. Por lo tanto, aconsejaría no hacerlo a menos que tenga algunos requisitos especiales con respecto a la generación de claves.

"SHA1PRNG" usa una función hash y un contador, junto con una semilla. El algoritmo es relativamente simple, pero no se ha descrito bien. Generalmente se piensa que es seguro. Como solo se inicia de uno de los generadores del sistema durante el inicio y, por lo tanto, requiere menos llamadas al kernel, es probable que requiera menos recursos. En mi sistema, se ejecuta aproximadamente 9 veces más rápido que el "NativePRNG" (que está configurado para usar /dev/urandom ). Parece que ambos gravan solo un núcleo de mi computadora portátil Ubuntu de doble núcleo (en un momento, con frecuencia cambiaba de un núcleo a otro, eso es probablemente la programación del kernel, que es la culpa). Si necesita un alto rendimiento, elija este, especialmente si el dispositivo /dev/urandom está lento en la configuración específica del sistema.

Tenga en cuenta que el "SHA1PRNG" presente en la implementación de Apache Harmony retirada es diferente de la del proveedor de SUN (utilizado por Oracle en la implementación estándar de Java SE). La versión dentro de Jakarta también se usó en versiones anteriores de Android. Aunque no he podido hacer una revisión completa, no parece ser muy seguro.

EDIT: y no me equivoqué al respecto, se ha demostrado que SHA1PRNG no es pseudoaleatorio para versiones <4.2.2 y más aquí .

En general, tampoco es una buena idea requerir un proveedor específico. Especificar un proveedor puede dañar la interoperabilidad; No todos los runtime de Java pueden tener acceso al proveedor de SUN, por ejemplo, Android ciertamente no. También hace que su aplicación sea menos flexible en el tiempo de ejecución, es decir, no puede poner a un proveedor más alto en la lista y usarlo en su lugar.

Solo indique un proveedor si depende de una de las características que proporciona. Por ejemplo, es posible que desee especificar un proveedor si tiene un dispositivo de hardware específico que genere los randoms o una biblioteca criptográfica que haya sido certificada por FIPS. Probablemente sea una buena idea hacer del algoritmo / proveedor una opción de configuración para su aplicación si tiene que especificar un proveedor.

La idea de no especificar un proveedor también está presente en este Blog de seguridad para desarrolladores de Android .

Así que trate de abstenerse de elegir cualquier generador aleatorio específico. En su lugar, simplemente elija el constructor de argumentos vacío: new SecureRandom() y deje que el sistema elija el mejor generador de números aleatorios. Es posible utilizar el nuevo SecureRandom.getInstanceStrong() configurable en Java 8 si tiene algún requisito específico para, por ejemplo, la generación de claves a largo plazo.

No SecureRandom caché las instancias de SecureRandom , simplemente déjelos SecureRandom inicialmente y deje que la VM las maneje. No vi una diferencia notable en la operación.

Cuando no utilizar SecureRandom en absoluto:

Como advertencia general, recomiendo encarecidamente no utilizar el generador de números aleatorios para otra cosa que no sea la generación de números aleatorios. Incluso si puede inicializarlo usted mismo e incluso si elige SHA1PRNG de Sun, no cuente con poder extraer la misma secuencia de números aleatorios del generador de números aleatorios . Por lo tanto, no lo use para la clave de derivación de contraseñas, para nombrar un ejemplo.

Si necesita una secuencia de repetición, utilice un cifrado de flujo y use la información de inicialización para la clave y IV. Cifre el texto simple que consta de ceros para recuperar el flujo de claves de los valores pseudoaleatorios. Alternativamente, puede usar una función de salida extensible (XOF) como SHAKE128 o SHAKE256 (donde esté disponible).

Obviamente, para operaciones de muy alta velocidad que no requieren seguridad, no use SecureRandom ; no será tan rápido como otros generadores de números aleatorios deterministas como los basados ​​en el algoritmo Twister de Mersenne.