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 nombres aléatoires à partir de Système.Aléatoire à tous au lieu de toujours à l'aide de la sécurité cryptographique générateur de nombres aléatoires à partir de 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?
Trop de gens utilisent sérieusement que comme une justification pour ce qu'ils font (généralement pas à haute voix). Le Code est plus lu que c'est écrit, qui se soucie de trivial différences de longueur?
Mais de toute façon, pourquoi devriez-vous utiliser de chiffrement Rng si vous ne faites pas de la cryptographie?
c'est ce que les alias sont pour ->
using R = System.Security.Cryptography.RandomNumberGenerator; R.Create();
OriginalL'auteur Lernkurve | 2009-08-10
Vous devez vous connecter pour publier un commentaire.
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?
Il convient de noter que de façon Aléatoire.GetNext est loin d'être bonne à "propager" les nombres aléatoires sur le spectre, en particulier dans une tige filetée de l'environnement. J'ai couru à travers ce problème lors de l'écriture d'un programme pour tester différentes solutions à la Rand7 de Rand5 problème. Dans un rapide fileté de test, il suffit maintenant de 100000 nombres aléatoires entre 0 et 10, 82470 de nombres générés étaient de 0. J'ai vu de tels écarts dans mes précédents tests. Crytpography aléatoire est très bien dans sa distribution de nombres. Je suppose que la leçon est toujours de tester vos données aléatoires pour voir que c'est "suffisamment aléatoire" pour vos besoins.
Je pense que vous avez mal utilisé
Random
. Laissez-moi deviner: Vous avez créé une nouvelle instance de laRandom
classe pour chaque nombre, qui, depuis qu'elle est alimentée par un grossier minuterie sera ensemencé avec la même valeur pour un intervalle d'environ 1-16ms.En plus de cela, il y a une race condition avec
Random
qui provoque le retour de tous les 0 lorsque le même objet est utilisé à partir de plusieurs threads.Voir le commentaire ci-dessus, voir aussi cette réponse
OriginalL'auteur klabranche
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.Ian Bell et David Braben a utilisé un générateur aléatoire dans le jeu d'ordinateur Elite pour créer un vaste liste de planètes et de leurs attributs (taille, etc), avec très peu de mémoire. Cela repose également sur le générateur de la création d'un modèle déterministe (à partir d'une graine) - que les Crypto on n'a évidemment pas fournir (par conception.) Il y a un peu plus d'informations sur la façon dont ils l'ont fait ici: wiki.alioth.net/index.php/Random_number_generator et le livre "Jeu Infini de l'Univers: Techniques Mathématiques" ISBN:1584500581 a une discussion plus générale sur ces techniques.
Ne gardez à l'esprit que MSDN ne garantit pas cette propriété à tenir à travers .NET versions: "La mise en œuvre du générateur de nombre aléatoire dans l'Aléatoire de la classe n'est pas assuré de rester le même sur toutes les versions principales de la .NET Framework."
conséquence, le code de votre application ne doit pas supposer que la même les semences de suite dans la même séquence pseudo-aléatoire dans les différentes versions de la .NET Framework." - je ne sais pas, semble assez clair pour moi. Cependant, je ne serais pas surpris si ils ne peuvent pas la modifier, dans la pratique, sans casser les programmes existants, en dépit de cet avertissement.
Vous êtes en train de dire une chose et puis l'exact opposé de celui-ci. Vous êtes contredire vous-même directement.
OriginalL'auteur Henk Holterman
Tout d'abord la présentation que vous avez lié ne parle que de nombres aléatoires pour des raisons de sécurité. Donc, il ne revendique pas de
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
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.Faille 1: Le semis
Le constructeur par défaut graines à l'heure actuelle. Ainsi, toutes les instances de
Random
créé avec le constructeur par défaut à l'intérieur d'un court laps de temps (ca. 10ms) le retour de la même 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 deRandom
au début de chaque exécution du thread.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 ici est que la semence de l'espace est assez petit (31 bits). Donc, si vous générez 50k instances de
Random
parfaitement aléatoire graines que vous obtiendrez probablement une séquence de nombres aléatoires à deux reprises (en raison de la le paradoxe d'anniversaire). Donc manuel de semis n'est pas facile d'obtenir de bon.Faille 2: La répartition des nombres aléatoires retourné par
Next(int maxValue)
est biaiséeIl y a des paramètres pour lesquels
Next(int maxValue)
est clairement pas uniforme. Par exemple, si vous calculezr.Next(1431655765) % 2
vous obtiendrez0
dans environ 2/3 des échantillons. (Exemple de code à la fin de la réponse.)Faille 3: Le
NextBytes()
méthode est inefficace.La par octet coût de
NextBytes()
est aussi gros que le coût pour générer un nombre entier de l'échantillon avecNext()
. À 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 queSystem.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'elle pourrait trouver encore plus de défauts que j'ai trouvé avec ma boîte noire de l'analyse.
Exemples de Code
r.Next(0x55555555) % 2
est fortement biaisé:Performance:
Intéressant, peut confirmer votre conclusion: sur ma machine Suivant(1431655765) offre également aux 2/3 avec tout le semis. Qu'est-ce que la magie de 1431655765? Comment avez-vous trouvé ce numéro?
Regardez le nombre hexadécimal ou en bits. C'est la magie se pose de la façon douteuse
Random
utilise pour transformer un 31 bits entier dans un certain nombre avec la limite supérieure spécifiée. J'ai oublié les détails, mais c'est quelque chose commerandomValue * max / 2^{31}
.Hm. Donc, ce que la mise en œuvre de l'Aléatoire pour le C# ne vous recommandons d'utiliser?
Ah la vache, la non-uniformité de la distribution de
Next()
, démontré par ici, c'est assez spectaculaire de bug et encore aujourd'hui, 6 ans après avoir écrit pour la première fois vos résultats. (Je dis "bug" plutôt que de se contenter de "faille", parce que la doc prétendre que "de nombres Pseudo-aléatoires sont choisis avec la même probabilité à partir d'un ensemble fini de nombres". Ce n'est pas vrai, et votre code ici nous le prouve.)OriginalL'auteur CodesInChaos
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.
Vous pourriez penser que c'est sévère, mais -1 pour l'affichage des résultats d'un test d'évaluation des performances sans y compris le code de l'indice de référence. Même si les caractéristiques de performance de
Random
etRNGCryptoServiceProvider
n'a pas changé depuis les 8 dernières années (ce qui pour tout, je sais qu'ils peuvent avoir), j'en ai assez vu complètement brisé les indices de référence utilisés sur un Débordement de Pile de ne pas avoir confiance dans les résultats d'un test dont le code n'est pas disponible au public.OriginalL'auteur Michael
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 ensemencer leurs propre PRNG.Temps de système n'est pas une source d'entropie, parce que c'est prévisible. Je ne suis pas sûr au sujet du nombre d'octets libres, mais je doute que c'est un de haute qualité, source d'entropie soit. Par l'envoi de requêtes au serveur, l'attaquant peut provoquer le nombre d'octets libres pour diminuer, rendant partiellement déterministe. L'application devient un vecteur d'attaque à cause de l'épuisement de la source d'entropie, il force l'autre, critique de sécurité de l'application pour utiliser le moins aléatoire de nombres aléatoires -- ou attendre jusqu'à ce que la source d'entropie est reconstitué.
Je comprends que si l'on dispose d'un générateur pseudo-aléatoire de la fed, par exemple avec une version 32 bits de semences, une attaque par force brute va souvent être assez facile; même un 64 bits, les graines peuvent être soumis à des fêtes d'anniversaire des attaques. Une fois que la graine est beaucoup plus que cela, cependant, je n'arrive pas à voir le risque. Si l'on dispose d'un générateur de hasard, qui pour chaque octet de sortie prend en passe de 128 bits de l'état par l'intermédiaire d'un bloc de l'algorithme de chiffrement et puis des sorties bas de 8 bits, comment un attaquant, même avec concerts consécutifs d'octets de sortie en déduire l'état, en l'absence de faiblesses dans l'algorithme de chiffrement lui-même?
OriginalL'auteur Jörg W Mittag
Si vous êtes à la programmation d'un jeu de cartes en ligne ou lotter, alors vous voulez vous assurer que la séquence est à peu près impossible à deviner. Toutefois, si vous êtes en montrant aux utilisateurs, par exemple, une citation du jour la performance est plus important que la sécurité.
OriginalL'auteur Dan Diplo
Noter que le Système.Hasard de classe en C# est codé de manière incorrecte, devrait donc être évité.
https://connect.microsoft.com/VisualStudio/feedback/details/634761/system-random-serious-bug#tabs
OriginalL'auteur evolvedmicrobe
Cela a été discuté assez longuement, mais en fin de compte, la question de la performance est une considération secondaire lors de la sélection d'un générateur de nombres aléatoires. Il existe une vaste gamme de Rng, et la conserve de Lehmer LCG que la plupart des système Rng se compose de n'est pas la meilleure, ni même forcément le plus rapide. Sur les vieux, lent systèmes, il était un excellent compromis. Ce compromis est rarement vraiment pertinent de nos jours. La chose persiste dans le jour présent systèmes de principalement parce que A) la chose est déjà construit, et il n'y a pas de véritable raison à "réinventer la roue" dans ce cas, et B) pour ce que la plupart des gens vont l'utiliser, c'est "suffisamment bonne".
En fin de compte, le choix d'un RNG revient à la relation Risque/rendement. Dans certaines applications, par exemple un jeu vidéo, il n'y a pas de risque que ce soit. Un Lehmer RNG est plus que suffisant, et est de petite taille, concis, rapide, bien comprise, et "dans la boîte".
Si l'application est, par exemple, une ligne de poker de jeu ou à une loterie où il y a les prix réels impliqués et de l'argent réel est en jeu à un certain moment dans l'équation, le 'dans la zone' de Lehmer n'est plus adéquat. Dans une version 32 bits, il n'a que 2^32 possibles sur les états avant qu'il ne commence à cycle au mieux. Ces jours-ci, c'est la porte ouverte à une attaque par force brute. Dans ce cas, le développeur vous voulez aller pour quelque chose comme un Très Longue Période RNG de certaines espèces, et probablement de semences à partir d'un point de vue cryptographique important fournisseur. Cela donne un bon compromis entre vitesse et sécurité. Dans un tel cas, la personne sera à la recherche de quelque chose comme la Mersenne Twister, ou un Plusieurs Récursive Générateur d'une certaine sorte.
Si la demande est quelque chose comme la communication de grandes quantités de l'information financière sur un réseau, il y a maintenant un risque énorme, et il fortement outweights toute récompense possible. Il y a encore des véhicules blindés parce que parfois, des hommes lourdement armés est le seul niveau de sécurité adéquat, et croyez-moi, si une brigade des opérations spéciales de gens avec des chars, des avions de chasse et les hélicoptères qui était financièrement réalisable, cela pourrait être la méthode de choix. Dans un cas comme celui-ci, à l'aide d'un cryptage fort RNG est logique, car quel que soit le niveau de sécurité que vous pouvez obtenir, ce n'est pas comme beaucoup que vous le souhaitez. De sorte que vous prendrez autant de comme vous pouvez le trouver, et le coût est un très, très éloignées de la deuxième place, soit dans le temps ou de l'argent. Et si cela signifie que chaque séquence aléatoire prend 3 secondes à réaliser sur un ordinateur très puissant, vous allez attendre les 3 secondes, parce que dans le schéma des choses, c'est d'un banal coût.
OriginalL'auteur
Pas tout le monde a besoin cryptographique sécurisé de nombres aléatoires, et qu'ils pourraient bénéficier de plus d'accélérer la plaine prng. Peut-être le plus important est que vous pouvez contrôler la séquence pour le Système.Nombres aléatoires.
Dans une simulation en utilisant des nombres aléatoires, vous pourriez vouloir recréer, vous relancez la simulation avec la même graine. Elle peut être utile pour le suivi des bogues lorsque vous voulez régénérer un défectueuse scénario - l'exécution de votre programme avec exactement la même séquence de nombres aléatoires qui s'est écrasé le programme.
OriginalL'auteur nos
Si je n'ai pas besoin de la sécurité, c'est à dire, je veux juste relativement une valeur indéterminée et non celui d'cryptage fort, Aléatoire a une très interface facile à utiliser.
OriginalL'auteur tvanfosson
Différents besoins différents Rng. Pour le cryptage, vous voulez que vos nombres aléatoires pour être aussi aléatoire que possible. Pour les simulations de Monte Carlo, vous les voulez pour remplir l'espace de façon uniforme et d'être en mesure de démarrer le générateur de nombres aléatoires à partir d'un état connu.
OriginalL'auteur quant_dev
Random
n'est pas un générateur de nombre aléatoire, c'est un déterministe de la séquence pseudo-aléatoire générateur, qui tire son nom pour des raisons historiques.La raison d'utiliser des
System.Random
est que si vous voulez ces propriétés, à savoir une séquence déterministe, qui est garanti pour produire la même séquence de résultats lorsqu'il est initialisé avec la même graine.Si vous voulez améliorer le "hasard", sans pour autant sacrifier l'interface, vous pouvez hériter de
System.Random
primordial de plusieurs méthodes.Pourquoi voulez-vous une séquence déterministe
Une raison d'avoir une séquence déterministe plutôt que de l'aléatoire véritable est parce qu'il est reproductible.
Par exemple, si vous exécutez une simulation numérique, vous pouvez initialiser la séquence avec un (vrai) nombre aléatoire, et enregistrer ce numéro a été utilisé.
Alors, si vous voulez répéter la exactement la même de simulation, par exemple à des fins de débogage, vous pouvez le faire par la place de l'initialisation de la séquence avec le enregistré valeur.
Pourquoi voudriez-vous ce particulier, pas très bon, la séquence
La seule raison pour laquelle je pense serait pour la compatibilité ascendante avec du code existant qui utilise cette classe.
En bref, si vous voulez améliorer la séquence sans changer le reste de votre code, aller de l'avant.
OriginalL'auteur Ben
J'ai écrit un jeu (Crystal Curseurs sur l'iPhone: Ici) qui permettrait de mettre en place un "aléatoire" de la série de gemmes (en images) sur la carte et vous la faire pivoter la carte de la façon dont vous le voulais et sélectionnez-les et ils s'en allèrent. - Semblable à Bejeweled. J'ai été à l'aide de Random(), et il a été ensemencé avec le nombre de 100ns tiques depuis le téléphone démarre, un assez aléatoire.
Je l'ai trouvé incroyable qu'il serait de générer des jeux qui ont été presque identiques les uns aux autres -de l'90 gemmes, de 2 couleurs, je voudrais obtenir deux EXACTEMENT le même, sauf pour 1 à 3 gemmes! Si vous retournez 90 pièces et obtenir le même modèle, sauf pour les 1-3 flips, c'est TRÈS rare! J'ai plusieurs captures d'écran qui montrent de la même manière. J'ai été choqué par la façon dont le mauvais Système.Random() a été! Je suppose que je dois avoir écrit quelque chose de terriblement mal dans mon code et a l'aide de ce mal. J'ai eu tort, c'était le générateur.
Comme une expérience et une solution finale, je suis de retour pour le générateur de nombre aléatoire que j'utilise depuis 1985 ou, ce qui est INFINIMENT mieux. Il est plus rapide, dispose d'un délai de 1.3 * 10^154 (2^521) avant qu'elle ne se répète. L'algorithme original a été ensemencé avec une 16 bits, mais j'ai changé pour un nombre 32 bits, et l'amélioration de l'amorçage initial.
L'original est ici:
ftp://ftp.grnet.gr/pub/lang/algorithms/c/jpl-c/random.c
Au fil des ans, j'ai jeté chaque nombre aléatoire de test, je pense à ce, et l'on a passé tous. Je n'attends pas qu'il est de toute valeur en tant que cryptographiques, mais il renvoie un nombre aussi vite que "de retour *p++;" jusqu'à épuisement de la 521 bits, et puis il exécute un processus rapide sur les bits pour créer de nouveaux aléatoires.
J'ai créé un C# wrapper - disant il JPLRandom() a mis en œuvre la même interface que Random() et changé tous les lieux où je l'ai appelé dans le code.
La différence était INFINIMENT mieux - OMG j'ai été étonné - il devrait y avoir aucun moyen que je pourrais dire de simplement en regardant les écrans de 90 gemmes dans un motif, mais j'ai fait un déverrouillage d'urgence de mon jeu en ce.
Et je voudrais ne jamais utiliser de Système.Random() pour quelque chose de nouveau. Je suis CHOQUÉ que leur version est bouleversé par quelque chose qui est maintenant de 30 ans!
-Traderhut Jeux
Random
trop souvent. Il ne doit être créé une fois que l'appel deNext
sur l'instance de nombreuses fois.Random
est pas mauvais, mais pas que mauvais. Pouvez-vous poster un exemple de programme avec une paire de graines qui présente ce problème?Le code serait de créer un Random() au début de chaque niveau (mais c'était un problème majeur avec le niveau 1 de plus que celles plus tard) Le code a été à peu près comme suit:
Rnd = new Random ((uint)GameSeed); NextGameSeed = Rnd.Prochaine (2000000000); Chaque niveau a utilisé une nouvelle Aléatoire qui a été créé avec une nouvelle graine, La Graine a été enregistré pour chaque niveau, afin d'être en mesure de recréer la carte, et aussi de confirmer la séquence aléatoire de graines de correspondance. Cela me permet de confirmer que le jeu est valable série de cartes qui ont été résolus et de recréer le jeu.
Et d'Abord, Aléatoire a été créé sur la base du Système.DateTime.Maintenant.Les tiques (ou 0), et puis le GameSeed a été choisi en utilisant le même appel que le Rnd.Next() ci-dessus. Si je ne peux pas faire cela, alors il y a un sérieux problème avec le semis du générateur de nombre aléatoire.
ce n'est pas une réponse à la question initiale!
OriginalL'auteur Traderhut Games