Qué tan seguro es el java.security.SecureRandom de Oracle

10

El año pasado hubo muchas noticias sobre las debilidades explotables de la criptografía que se originaron a partir de generadores de números aleatorios débiles. En algunos casos fue negligencia por parte de los desarrolladores, en otros fue organizaciones de inteligencia que sabotearon intencionalmente estándares para la generación segura de RNG .

¿Qué pasa con la implementación del SecureRandom generador de números aleatorios utilizado en JavaVM de Oracle? ¿Qué algoritmo utiliza cuando no especificas uno? ¿Y ese algoritmo y su implementación son lo suficientemente seguros como para usarlos en criptografía?

    
pregunta Philipp 31.12.2013 - 14:01
fuente

1 respuesta

13

El código fuente completo de JDK (no solo las clases estándar, sino también las clases específicas de Sun y el código nativo de C ++) solía estar disponible bajo una "licencia de investigación", y tengo una copia en mi disco, para JDK 1.6 (Supongo que hoy en día irías a OpenJDK).

Vemos que crear una instancia java.security.SecureRandom implica invocar el PRNG predeterminado, que es la clase específica de Sun sun.security.provider.SecureRandom .

El PRNG se siembra a partir de sun.security.provider.SeedGenerator , que a su vez intentará basarse en lo que proporciona el sistema operativo, es decir, /dev/urandom o /dev/random en sistemas similares a Unix (como Linux), CryptoAPI's CryptGenRandom() en Windows. Si tales cosas no están disponibles (o están desactivadas desde la configuración de JVM), entonces la semilla se extraerá cronometrando la velocidad a la que el sistema operativo puede cambiar de contexto entre hilos; este es un mecanismo alternativo que rara vez, si alguna vez, se activa.

La semilla se amplía con lo que parece ser un PRNG personalizado y hecho en casa basado en SHA-1. Funciona así:

  • Hay un estado de 160 bits s , que tiene 20 bytes, y también se interpreta como un módulo entero 2160 aplicando la convención little-endian.
  • La salida es producida por trozos de 20 bytes.
  • Para producir el siguiente fragmento c :
    • c = SHA-1 ( s )
    • s = s + c + 1 mod 2160

Hay un mecanismo que garantiza que s se cambie en algún momento; Si s parece no haber cambiado con la actualización, entonces su primer byte se incrementa con fuerza. Esto nunca se invoca; la probabilidad de tal ocurrencia es 2-160 y forzarla con una semilla especial requeriría romper la resistencia de preimagen de SHA-1, lo cual no sabemos cómo hacerlo.

Hablando criptográficamente, esto no es atroz; debería alcanzar un ciclo, en promedio, solo después de aproximadamente 280 trozos, y el ciclo debe tener la misma longitud promedio; eso es mucho (unos 24 millones de billones de gigabytes), así que eso es bueno. Si SHA-1 es un oracle aleatorio entonces el PRNG es" obviamente "seguro siempre que los atacantes no puedan enumerar un espacio de 160 bits (en realidad no pueden) y una semilla dada no se usa para producir más de 24 millones de billones de gigabytes ( y no lo hará, ni en un tiempo razonable o incluso irrazonable). Sabemos que SHA-1 es no un oráculo aleatorio, pero aún parece lo suficientemente aleatorio.

Personalmente, no consideraría que este PRNG sea un problema para el uso criptográfico; no tiene una "constante mágica" y, por lo tanto, es muy poco probable que sea de puerta trasera. La única parte mala de esto es que no es no estándar , por lo tanto no está estudiado.

Si (cuando) necesito tener, en Java, una aleatoriedad que sea lo suficientemente buena para la criptografía formal (es decir, buena, y también demostrablemente buena para fines reglamentarios), luego uso java.security.SecureRandom para generar una inicialización inicial (al menos 16 bytes), que luego ejecuto a través de HMAC_DRBG (especificado en NIST SP800-90A ) (la misma publicación contiene el Dual_EC_DRBG de la fama siniestra, pero HMAC_DRBG todavía es considerado bueno y limpio por los criptógrafos).

    
respondido por el Tom Leek 31.12.2013 - 23:11
fuente

Lea otras preguntas en las etiquetas