Por qué usar el sistema de clases C#.Al azar en absoluto en lugar de Sistema.Seguridad.Criptografía.RandomNumberGenerator?


¿Por qué alguien usaría el generador de números aleatorios "estándar" del sistema ?Random en lugar de usar siempre el generador de números aleatorios criptográficamente seguro del sistema .Seguridad.Criptografía.RandomNumberGenerator (o sus subclases porque RandomNumberGenerator es abstracto)?

Nate Lawson nos dice en su presentación de Google Tech Talk " Crypto Contraataca " en el minuto 13: 11 no usar los generadores de números aleatorios "estándar" de Python, Java y C# y en su lugar utilizar la versión criptográficamente segura.

Conozco la diferencia entre las dos versiones de generadores de números aleatorios (ver pregunta 101337).

Pero, ¿qué razón hay para no utilizar siempre el generador seguro de números aleatorios? Por qué utilizar el Sistema.¿Al azar? Rendimiento tal vez?

Author: Christopher Schultz, 2009-08-11

13 answers

Velocidad e intención. Si está generando un número aleatorio y no necesita seguridad, ¿por qué usar una función de cripto lenta? No necesita seguridad, así que ¿por qué hacer que otra persona piense que el número puede usarse para algo seguro cuando no lo será?

 114
Author: klabranche,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-28 16:06:09

Aparte de la velocidad y la interfaz más útil (NextDouble() etc), también es posible hacer una secuencia aleatoria repetible utilizando un valor de semilla fijo. Eso es bastante útil, entre otras cosas durante las pruebas.

Random gen1 = new Random();     // auto seeded by the clock
Random gen2 = new Random(0);    // Next(10) always yields 7,8,7,5,2,....
 58
Author: Henk Holterman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-21 16:36:04

En primer lugar, la presentación que ha vinculado solo habla de números aleatorios por motivos de seguridad. Por lo tanto, no afirma que Random sea malo para fines no relacionados con la seguridad.

Pero sí afirmo que lo es. La implementación de. net 4 de Random tiene varios defectos. Recomiendo usarlo solo si no te importa la calidad de tus números aleatorios. Recomiendo usar mejores implementaciones de terceros.

Defecto 1: La siembra

El constructor predeterminado se siembra con el hora actual. Por lo tanto, todas las instancias de Random creadas con el constructor predeterminado dentro de un corto período de tiempo (ca. 10ms) devuelve la misma secuencia. Esto está documentado y "por diseño". Esto es particularmente molesto si quieres multihilo de tu código, ya que no puedes simplemente crear una instancia de Random al principio de la ejecución de cada subproceso.

La solución es tener mucho cuidado al usar el constructor predeterminado y sembrar manualmente cuando sea necesario.

Otro problema aquí es que el espacio de la semilla es bastante pequeño (31 bits). Así que si generas 50k instancias de Random con semillas perfectamente aleatorias, probablemente obtendrás una secuencia de números aleatorios dos veces (debido a la paradoja de cumpleaños ). Por lo tanto, la siembra manual tampoco es fácil de hacer bien.

Defecto 2: La distribución de números aleatorios devueltos por {[7] } está sesgada

Hay parámetros para los cuales Next(int maxValue) claramente no es uniforme. Por ejemplo, si calcula r.Next(1431655765) % 2 obtendrá 0 en aproximadamente 2/3 de las muestras. (Código de ejemplo al final de la respuesta.)

Defecto 3: El método NextBytes() es ineficiente.

El costo por byte de NextBytes() es casi tan grande como el costo de generar una muestra entera completa con Next(). De esto sospecho que de hecho crean una muestra por byte.

Una mejor implementación usando 3 bytes de cada muestra aceleraría NextBytes() por casi un factor 3.

Gracias a este defecto Random.NextBytes() es solo un 25% más rápido que System.Security.Cryptography.RNGCryptoServiceProvider.GetBytes en mi máquina (Win7, Core i3 2600MHz).

Estoy seguro de que si alguien inspeccionara el código fuente/byte descompilado encontraría incluso más defectos de los que encontré con mi análisis de caja negra.


Ejemplos de Código

r.Next(0x55555555) % 2 está fuertemente sesgado:

Random r = new Random();
const int mod = 2;
int[] hist = new int[mod];
for(int i = 0; i < 10000000; i++)
{
    int num = r.Next(0x55555555);
    int num2 = num % 2;
    hist[num2]++;
}
for(int i=0;i<mod;i++)
    Console.WriteLine(hist[i]);

Rendimiento:

byte[] bytes=new byte[8*1024];
var cr=new System.Security.Cryptography.RNGCryptoServiceProvider();
Random r=new Random();

// Random.NextBytes
for(int i=0;i<100000;i++)
{
    r.NextBytes(bytes);
}

//One sample per byte
for(int i=0;i<100000;i++)
{   
    for(int j=0;j<bytes.Length;j++)
      bytes[j]=(byte)r.Next();
}

//One sample per 3 bytes
for(int i=0;i<100000;i++)
{
    for(int j=0;j+2<bytes.Length;j+=3)
    {
        int num=r.Next();
        bytes[j+2]=(byte)(num>>16);   
        bytes[j+1]=(byte)(num>>8);
        bytes[j]=(byte)num;
    }
    //Yes I know I'm not handling the last few bytes, but that won't have a noticeable impact on performance
}

//Crypto
for(int i=0;i<100000;i++)
{
    cr.GetBytes(bytes);
}
 43
Author: CodesInChaos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-29 20:14:22

Sistema.Random es mucho más eficiente, ya que no genera números aleatorios criptográficamente seguros.

Una prueba simple en mi máquina llenando un búfer de 4 bytes con datos aleatorios 1,000,000 veces toma 49 ms para Random, pero 2845 ms para RNGCryptoServiceProvider. Tenga en cuenta que si aumenta el tamaño del búfer que está llenando, la diferencia se reduce ya que la sobrecarga para RNGCryptoServiceProvider es menos relevante.

 23
Author: Michael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-10 21:38:11

Las razones más obvias ya se han mencionado, así que aquí hay una más oscura: los PRNGS criptográficos típicamente necesitan ser resembrados continuamente con entropía "real". Por lo tanto, si usa un CPRNG con demasiada frecuencia, podría agotar el grupo de entropía del sistema, que (dependiendo de la implementación del CPRNG) lo debilitará (lo que permitirá a un atacante predecirlo) o se bloqueará mientras intenta llenar su grupo de entropía (convirtiéndose así en un vector de ataque para un DOS ataque).

De cualquier manera, su aplicación ahora se ha convertido en un vector de ataque para otras aplicaciones totalmente no relacionadas que – a diferencia de la suya – en realidad vitalmente dependen de las propiedades criptográficas del CPRNG.

Este es un problema real del mundo real, por cierto, que se ha observado en servidores sin cabeza (que naturalmente tienen pools de entropía bastante pequeños porque carecen de fuentes de entropía como entrada de ratón y teclado) que ejecutan Linux, donde las aplicaciones utilizan incorrectamente el /dev/random kernel CPRNG para todo tipo de números aleatorios, mientras que el comportamiento correcto sería leer un pequeño valor de semilla de /dev/urandom y usarlo para sembrar su propio PRNG.

 18
Author: Jörg W Mittag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-10 22:11:00

Si estás programando un juego de cartas en línea o un lotter, entonces deberías asegurarte de que la secuencia sea casi imposible de adivinar. Sin embargo, si está mostrando a los usuarios, por ejemplo, una cita del día, el rendimiento es más importante que la seguridad.

 11
Author: Dan Diplo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-10 21:36:08

Esto se ha discutido con cierta profundidad, pero en última instancia, el tema del rendimiento es una consideración secundaria al seleccionar un RNG. Hay una amplia gama de RNGs por ahí, y el enlatado Lehmer LCG que la mayoría de RNGs sistema consiste en no es el mejor ni incluso necesariamente el más rápido. En sistemas viejos y lentos fue un excelente compromiso. Ese compromiso rara vez es realmente relevante en estos días. La cosa persiste en los sistemas actuales principalmente porque A) la cosa ya está construido, y no hay ninguna razón real para 'reinventar la rueda' en este caso, y B) para lo que la gran mayoría de la gente lo usará, es 'lo suficientemente bueno'.

En última instancia, la selección de un RNG se reduce a la relación Riesgo/Recompensa. En algunas aplicaciones, por ejemplo un videojuego, no hay riesgo alguno. Un Lehmer RNG es más que adecuado, y es pequeño, conciso, rápido, bien entendido y 'en la caja'.

Si la aplicación es, por ejemplo, un juego de póquer en línea o lotería cuando hay premios reales involucrados y el dinero real entra en juego en algún momento de la ecuación, el 'en la caja' Lehmer ya no es adecuado. En una versión de 32 bits, solo tiene 2^32 posibles estados válidos antes de que comience a circular en el mejor de los casos. En estos días, esa es una puerta abierta a un ataque de fuerza bruta. En un caso como este, el desarrollador querrá ir a algo así como un Período Muy Largo RNG de algunas especies, y probablemente la semilla de un proveedor criptográficamente fuerte. Esto da un buen compromiso entre la velocidad y la seguridad. En tal caso, la persona estará buscando algo como el Mersenne Twister , o un Generador Recursivo Múltiple de algún tipo.

Si la aplicación es algo así como comunicar grandes cantidades de información financiera a través de una red, ahora hay un gran riesgo, y supera en gran medida cualquier posible recompensa. Todavía hay vehículos blindados porque a veces los hombres fuertemente armados es la única seguridad eso es adecuado, y créeme, si una brigada de personas de operaciones especiales con tanques, cazas y helicópteros fuera financieramente viable, sería el método de elección. En un caso como este, usar un RNG criptográficamente fuerte tiene sentido, porque cualquiera que sea el nivel de seguridad que pueda obtener, no es tanto como desee. Así que tomará todo lo que pueda encontrar, y el costo es un problema de segundo lugar muy, muy remoto, ya sea en tiempo o dinero. Y si eso significa que cada secuencia aleatoria toma 3 segundos para generar en un ordenador muy potente, vas a esperar los 3 segundos, porque en el esquema de las cosas, que es un costo trivial.

 9
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-22 19:10:47

Tenga en cuenta que el Sistema.La clase aleatoria en C# está codificada incorrectamente, por lo que debe evitarse.

Https://connect.microsoft.com/VisualStudio/feedback/details/634761/system-random-serious-bug#tabs

 8
Author: evolvedmicrobe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-20 00:35:10

No todos necesitan números aleatorios criptográficamente seguros, y podrían beneficiarse más de un prng simple más rápido. Quizás lo más importante es que puede controlar la secuencia para el Sistema.Números aleatorios.

En una simulación que utilice números aleatorios que desee recrear, vuelva a ejecutar la simulación con la misma semilla. Puede ser útil para rastrear errores cuando también desea regenerar un escenario defectuoso dado, ejecutando su programa con la misma secuencia de errores aleatorios números que bloquearon el programa.

 4
Author: nos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-10 21:33:58

Si no necesito la seguridad, es decir, solo quiero un valor relativamente indeterminado no uno que sea criptográficamente fuerte, Random tiene una interfaz mucho más fácil de usar.

 2
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-10 21:31:15

Diferentes necesidades requieren diferentes RNGS. Para crypto, desea que sus números aleatorios sean lo más aleatorios posible. Para las simulaciones de Monte Carlo, desea que llenen el espacio de manera uniforme y que puedan iniciar el RNG desde un estado conocido.

 2
Author: quant_dev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-25 09:09:53

Random no es un generador de números aleatorios, es un generador de secuencias pseudoaleatorias deterministas, que toma su nombre por razones históricas.

La razón para usar System.Random es si desea estas propiedades, a saber, una secuencia determinista, que está garantizada para producir la misma secuencia de resultados cuando se inicializa con la misma semilla.

Si desea mejorar la "aleatoriedad" sin sacrificar la interfaz, puede heredar de System.Random sobreescribiendo varios métodos.

¿Por qué querrías una secuencia determinista

Una razón para tener una secuencia determinista en lugar de una verdadera aleatoriedad es porque es repetible.

Por ejemplo, si está ejecutando una simulación numérica, puede inicializar la secuencia con un número aleatorio (verdadero) y registrar qué número se utilizó.

Entonces, si lo desea para repetir la misma simulación exacta , por ejemplo, con fines de depuración, puede hacerlo inicializando la secuencia con el valor registrado .

¿Por qué querrías esta secuencia en particular, no muy buena

La única razón en la que puedo pensar sería por la compatibilidad hacia atrás con el código existente que usa esta clase.

En resumen, si desea mejorar la secuencia sin cambiar el resto de su código, adelante.

 2
Author: Ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-02 14:27:02

Escribí un juego (Deslizadores de cristal en el iPhone: Aquí) que pondría una serie "aleatoria" de gemas (imágenes) en el mapa y rotarías el mapa como lo querías y las seleccionarías y desaparecerían. - Similar a Bejeweled. Estaba usando Random (), y se sembró con el número de garrapatas 100ns desde que el teléfono arrancó, una semilla bastante aleatoria.

Me pareció increíble que generaría juegos que eran casi idénticos entre sí-de las 90 o más gemas, de 2 colores, me gustaría obtener dos EXACTAMENTE iguales a excepción de 1 a 3 gemas! Si volteas 90 monedas y obtienes el mismo patrón excepto por 1-3 volteos, ¡eso es MUY poco probable! Tengo varias capturas de pantalla que muestran lo mismo. Me sorprendió lo mal que estaba el sistema.Random() era! Asumí, que DEBO haber escrito algo horriblemente mal en mi código y lo estaba usando mal. Pero me equivoqué, fue el generador.

Como un experimento-y una solución final, volví al generador de números aleatorios que He estado usando desde 1985 más o menos - que es mucho mejor. Es más rápido, tiene un período de 1.3 * 10^154 (2^521) antes de que se repita. El algoritmo original se sembró con un número de 16 bits, pero lo cambié a un número de 32 bits y mejoré la siembra inicial.

El original está aquí:

Ftp://ftp.grnet.gr/pub/lang/algorithms/c/jpl-c/random.c

A lo largo de los años, he arrojado todas las pruebas de números aleatorios que se me ocurrieron a esto, y las superé a todas. Yo no espere que sea de cualquier valor como criptográfico,pero devuelve un número tan rápido como" return *p++; " hasta que se queda sin los bits 521, y luego ejecuta un proceso rápido sobre los bits para crear nuevos aleatorios.

Creé un wrapper de C#, llamado JPLRandom() implementé la misma interfaz que Random() y cambié todos los lugares donde lo llamé en el código.

La diferencia era MUCHO mejor-Dios Mío, me sorprendió-no debería haber manera de que pudiera decir con solo mirar el pantallas de 90 o más gemas en un patrón, pero hice un lanzamiento de emergencia de mi juego después de esto.

Y nunca usaría el Sistema.Random () para cualquier cosa nunca más. ¡Estoy SORPRENDIDO de que su versión esté impresionada por algo que ahora tiene 30 años!

- Traderhut Juegos

 -1
Author: Traderhut Games,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-26 23:59:18