2012-09-03 42 views
10

¿Es seguro este código?SecureRandom semilla segura en Java

SecureRandom randomizer = new SecureRandom(String.valueOf(new Date().getTime()).getBytes()); 

¿Es esta la manera correcta de instanciar la semilla de seguridad aleatoria?

Respuesta

23

No, debe evitar el constructor SecureRandom(byte[]). Es inseguro y no portátil.

No es portátil porque se comporta de forma diferente en Windows frente a otros sistemas operativos.

En la mayoría de los sistemas operativos, el algoritmo predeterminado es "NativePRNG", que obtiene datos aleatorios del sistema operativo (generalmente "/dev/random") e ignora la semilla que usted proporciona.

En Windows, el algoritmo predeterminado es "SHA1PRNG", que combina su semilla con un contador y calcula un resumen del resultado.

Esta es una mala noticia en su ejemplo, porque la entrada (el tiempo UTC actual en milisegundos) tiene un rango relativamente pequeño de valores posibles. Por ejemplo, si un atacante sabe que el generador de números aleatorios se sembró en las últimas 48 horas, puede reducir la semilla a menos de 2 valores posibles, es decir, solo tiene 27 bits de entropía.

Si, por otro lado, ha utilizado el constructor predeterminado SecureRandom() en Windows, habría llamado a la función nativa CryptoGenRandom para obtener una semilla de 128 bits. Entonces, al especificar su propia semilla, ha debilitado la seguridad.

Si realmente desea anular la inicialización predeterminada (por ejemplo, para pruebas unitarias) también debe especificar el algoritmo. P.ej.

SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
sr.setSeed("abcdefghijklmnop".getBytes("us-ascii")); 

Ver también How to solve performance problem with Java SecureRandom?
y esta entrada del blog: http://www.cigital.com/justice-league-blog/2009/08/14/proper-use-of-javas-securerandom/

+1

Tenga en cuenta que el código que proporciona inicializa el generador pseudoaleatorio con solo la cadena codificada como entrada. Entonces crearía el mismo azar cada vez.Creo que quisiste mostrar exactamente esto, pero tal vez quieras aclararlo más en la respuesta (ya que ciertamente no es seguro). También podría ser diferente si cualquier otro proveedor ofreciera '" SHA1PRNG "', por lo que es un poco peligroso. –

+0

¡Esta es la respuesta que esperaba, gracias! –

+0

@MaartenBodewes ¿Por qué crees que la semilla se ignora cuando se usa "NativePRNG"? –

1

El código es razonablemente seguro porque no solo usa la semilla que se le dio para sembrar el aleatorizador.

No es mucho más aleatorio que simplemente usar.

SecureRandom randomizer = new SecureRandom(); 
+2

Sí, probablemente usar el valor predeterminado es mejor: se supone que los diseñadores del algoritmo elegirían un buen esquema de siembra. El esquema anterior probablemente debilita ligeramente la semilla al convertirla en representación de caracteres. –

+4

Es considerablemente * menos * aleatorio que usar el constructor predeterminado. – EJP

+0

@PeterLawrey Aquí se recomienda usar 'nuevo SecureRandom()' pero en [esto] (http://stackoverflow.com/a/8572501/1317865) dices que uses 'System.nanoTime'. En [esto] (http://crypto.stackexchange.com/questions/12306/generate-random-in-secure-message-transfer) situación debería usar 'new SecureRandom()' o 'System.nanoTime'. Gracias de antemano – Favolas

2

creo que lo mejor es dejar que la semilla SecureRandom sí. Esto se hace llamando a nextBytes inmediatamente después de su creación (llamar a setSeed evitará esto).

final byte[] dummy = new byte[512]; 
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
sr.nextBytes(dummy); 

Desea usar SHA1PRNG porque garantiza una implementación rápida sin bloqueo incluso en Linux, donde el valor predeterminado no lo es.

+2

Si la llamada 'nextBytes()' está destinada a simplemente patear la siembra, no usaría 512 byes, pero solo 1 por razones de eficiencia. – eckes

Cuestiones relacionadas