88 votes

Pourquoi utiliser le C# Système de classe.Aléatoire à tous au lieu de Système.De sécurité.La cryptographie.RandomNumberGenerator?

Pourquoi quelqu'un usage "standard" générateur de nombre aléatoire à partir du Système.Aléatoire à tous au lieu de toujours à l'aide de la sécurité cryptographique générateur de nombre aléatoire à partir du Système.De sécurité.La cryptographie.RandomNumberGenerator (ou de ses sous-classes, car RandomNumberGenerator est abstrait)?

Nate Lawson nous dit dans son Google Tech Talk présentation "Crypto Strikes Back" à la minute 13:11 ne pas utiliser le "standard" des générateurs de nombres aléatoires à partir de Python, Java et C# et d'utiliser à la place la sécurité cryptographique version.

Je sais faire la différence entre les deux versions de générateurs de nombres aléatoires (voir question 101337).

Mais ce raisonnement est-il de ne pas toujours utiliser le secure générateur de nombre aléatoire? Pourquoi utiliser le Système.Aléatoire à tous? La Performance peut-être?

149voto

klabranche Points 15518

De la vitesse et de l'intention. Si vous êtes de la génération d'un nombre aléatoire et n'ont pas besoin de sécurité, pourquoi utiliser une lente crypto fonction? Vous n'avez pas besoin de sécurité, alors pourquoi prendre quelqu'un d'autre pense que le nombre peut être utilisé pour quelque chose de sûr, quand il ne sera pas?

66voto

Henk Holterman Points 153608

Mis à part la vitesse et la plus utile de l'interface (NextDouble() etc), il est aussi possible de faire un modèle aléatoire de la séquence à l'aide d'un fixe de la valeur de départ. C'est très utile, entre autres, au cours des Essais.

Random gen1 = new Random();     // auto seeded by the clock
Random gen2 = new Random(0);    // Next(10) always yields 7,8,7,5,2,....

56voto

CodesInChaos Points 60274

Tout d'abord la présentation que vous avez lié ne parle que de nombres aléatoires pour des raisons de sécurité. Afin de ne pas réclamer Random est mauvais pour la santé non à des fins de sécurité.

Mais je prétends qu'il est. L' .net 4 mise en œuvre de l' Random est entachée de plusieurs façons. Je recommande que si vous n'avez pas de soins sur la qualité de vos nombres aléatoires. Je recommande d'utiliser mieux tiers des implémentations.

Défaut 1: Le semis

Le constructeur par défaut graines à l'heure actuelle. Ainsi, toutes les instances de l' Random créé avec le constructeur par défaut à l'intérieur d'un court laps de temps de retour de la séquence. Ceci est documenté et "design". Ce qui est particulièrement gênant si vous voulez multi-thread de votre code, puisque vous ne pouvez pas il suffit de créer une instance de Random au début de chaque threads d'exécution.

La solution de contournement est d'être très prudent lors de l'utilisation du constructeur par défaut et amorcer manuellement si nécessaire.

Un autre problème est que la semence de l'espace est plutôt restreint. Donc, si vous générez 50k cas d' Random parfaitement aléatoire graines que vous obtiendrez probablement une séquence de nombres aléatoires à deux reprises(Voir le paradoxe d'anniversaire). Donc manuel de semis n'est pas facile d'obtenir de bon.

Défaut 2: La répartition des nombres aléatoires retourné par Next(int maxValue) est biaisé

Il y a des paramètres pour qui Next(int maxValue) est clairement pas uniforme. Par exemple, si vous calculez r.Next(1431655765)%2 , vous obtiendrez 0 chez environ 2/3 des échantillons (Échantillon de code à la fin de la réponse).

Faille 3: L' NextBytes() méthode est inefficace.

La par octet coût de l' NextBytes() qui est aussi gros que le coût pour générer un nombre entier de l'échantillon avec Next(). À partir de ce que je soupçonne qu'ils créent en effet un échantillon par octet.

Une meilleure mise en œuvre à l'aide de 3 octets de chaque échantillon de vitesse, NextBytes() par près d'un facteur 3.

Grâce à cette faille Random.NextBytes() n'est que d'environ 25% plus rapide que l' System.Security.Cryptography.RNGCryptoServiceProvider.GetBytes sur ma machine (Win7, Core i3 2600MHz)

Je suis sûr que si quelqu'un a inspecté la source/décompilé de byte code qu'il avait trouver encore plus de défauts que j'ai trouvé avec ma boîte noire de l'analyse.


Des exemples de Code:

r.Next(1431655765)%2 est fortement biaisé:

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

Performance:

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);
}

25voto

Michael Points 34110

Système.Le hasard est beaucoup plus performant car il ne génère pas de sécurité cryptographique de nombres aléatoires.

Un simple test sur ma machine à remplir la mémoire tampon de 4 octets avec des données aléatoires de 1 000 000 de fois prend 49 ms de Hasard, mais 2845 ms pour RNGCryptoServiceProvider. Notez que si vous augmentez la taille de la mémoire tampon à remplir, l'écart se rétrécit comme la surcharge RNGCryptoServiceProvider est moins pertinent.

21voto

Jörg W Mittag Points 153275

Les raisons les plus évidentes ont déjà été mentionnés, voici donc une plus obscur: cryptographiques PRNGs ont généralement besoin d'être continuellement être ensemencées avec de "vrais" l'entropie. Ainsi, si vous utilisez un CPRNG trop souvent, vous pourriez épuiser le système du pool d'entropie, qui (selon la mise en œuvre de la CPRNG) sera soit l'affaiblir (permettant ainsi à un attaquant à prévoir) ou il va bloquer tout en essayant de remplir son pool d'entropie (devenant ainsi un vecteur d'attaque pour une attaque par déni de service).

De toute façon, votre application est maintenant devenu un vecteur d'attaque pour d'autres, totalement sans rapport avec les applications qui – contrairement à la vôtre – en fait, d'une importance dépendent sur les propriétés cryptographiques de la CPRNG.

C'est un vrai problème, d'ailleurs, qui a été observé sur des serveurs sans écran (qui, naturellement, ont plutôt petite entropie piscines raison de l'absence de sources d'entropie comme la souris et le clavier) fonctionnant sous Linux, où les demandes de mal utiliser le /dev/random noyau CPRNG pour toutes les sortes de nombres aléatoires, alors que le comportement correct serait de lire une petite graine de la valeur de /dev/urandom et l'utiliser pour les semences de leur propre GÉNÉRATEUR.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X