Comment gérer un générateur SecureRandom lent?

165

Si vous voulez des nombres aléatoires cryptographiquement forts en Java, vous utilisez SecureRandom. Malheureusement, cela SecureRandompeut être très lent. S'il utilise /dev/randomLinux, il peut bloquer l'attente d'une entropie suffisante pour s'accumuler. Comment éviter la pénalité de performance?

Quelqu'un a-t-il utilisé des mathématiques peu communes comme solution à ce problème?

Quelqu'un peut-il confirmer que ce problème de performances a été résolu dans JDK 6?

David G
la source
Il semble que cela soit lié à la lenteur de SecureRandom.generateSeed () . Il y a un défaut rejeté expliquant la lenteur et une solution de contournement: JDK-6521844: SecureRandom se bloque sur les systèmes Linux
AlikElzin-kilaka
Vérifiez / dev / urandom (pas / dev / random). Envisagez simplement d'obtenir une graine de générateur de nombres aléatoires d'urandom s'il y a un problème de blocage.
jcalfee314
Connexes

Réponses:

80

Si vous voulez de vraies données aléatoires, vous devez malheureusement l'attendre. Cela inclut la graine pour un SecureRandomPRNG. Uncommon Maths ne peut pas collecter de vraies données aléatoires plus rapidement que SecureRandom, bien qu'il puisse se connecter à Internet pour télécharger des données de départ à partir d'un site Web particulier. Je suppose que cela ne sera probablement pas plus rapide que /dev/randomlà où c'est disponible.

Si vous voulez un PRNG, faites quelque chose comme ceci:

SecureRandom.getInstance("SHA1PRNG");

Les chaînes prises en charge dépendent du SecureRandomfournisseur SPI, mais vous pouvez les énumérer à l'aide de Security.getProviders()et Provider.getService().

Sun aime SHA1PRNG, donc il est largement disponible. Ce n'est pas particulièrement rapide car les PRNG vont, mais les PRNG ne feront que croquer des nombres, pas bloquer pour la mesure physique de l'entropie.

L'exception est que si vous n'appelez pas setSeed()avant d'obtenir des données, le PRNG se déclenchera une fois la première fois que vous appelez next()ou nextBytes(). Il le fera généralement en utilisant une assez petite quantité de vraies données aléatoires du système. Cet appel peut bloquer, mais rendra votre source de nombres aléatoires beaucoup plus sécurisée que n'importe quelle variante de "hacher l'heure actuelle avec le PID, ajouter 27 et espérer le meilleur". Si tout ce dont vous avez besoin, ce sont des nombres aléatoires pour un jeu, ou si vous voulez que le flux soit répétable à l'avenir en utilisant la même graine à des fins de test, une graine non sécurisée est toujours utile.

Steve Jessop
la source
Uncommons Maths télécharge uniquement les données d'Internet pour l'amorçage, il ne renvoie pas ces données aléatoires lors de la génération de nombres aléatoires.
Dan Dyer le
Idem avec SecureRandom - le / dev / urandom est uniquement destiné à l'amorçage.
AviD du
Oui. Quand le questionneur dit "si vous voulez un nombre aléatoire, vous utilisez SecureRandom - cela peut être lent", j'ai pensé qu'il utilisait peut-être getSeed pour tout et vidait son bassin d'entropie. Le correctif n'est pas d'obtenir JDK 6, c'est d'utiliser SecureRandom comme prévu ;-)
Steve Jessop
@Dan Dyer - J'ai corrigé mon commentaire sur les mathématiques peu communes. J'ai jeté un coup d'œil à votre page, donc je savais que par "nombres aléatoires", je voulais dire "pour sa graine" plutôt que "pour revenir à l'utilisateur". Mais vous avez tout à fait raison ce n'est pas ce que j'ai dit ...
Steve Jessop
"il est largement disponible". N'est-il pas inclus avec chaque JDK conforme? C'est sur la liste des noms standard de sécurité java ... ( docs.oracle.com/javase/8/docs/technotes/guides/security/… )
Sean Reilly
177

Vous devriez pouvoir sélectionner le plus rapide mais légèrement moins sécurisé / dev / urandom sous Linux en utilisant:

-Djava.security.egd=file:/dev/urandom

Cependant, cela ne fonctionne pas avec Java 5 et versions ultérieures ( bogue Java 6202721 ). La solution suggérée consiste à utiliser:

-Djava.security.egd=file:/dev/./urandom

(notez le supplément /./)

Thomas Leonard
la source
24
Notez que le rapport de bogue Java indique "Pas un défaut". En d'autres termes, même si la valeur par défaut est /dev/urandom, Sun le traite comme une chaîne magique et l'utilise de /dev/randomtoute façon, vous devez donc le simuler. Quand une file:URL n'est-elle pas une file:URL? Chaque fois que Sun décide que ce n'est pas le cas :-(
Jim Garrison
6
Ayant juste passé beaucoup de temps à enquêter sur cela, il semble que le paramètre normal, même avec file:/dev/urandomset in -Djava.security.egdou in securerandom.sourcedans le fichier java.security, /dev/random/soit toujours lu à chaque fois SecureRandom.getSeed()(ou setSeed()est appelé). La solution de contournement avec les file:/dev/./urandomrésultats en ne lisant pas /dev/randomdu tout (confirmé avec strace)
matt b
7
/dev/urandomn'est pas moins sécurisé que /dev/randomlorsqu'il est implémenté avec un CSPRNG moderne: en.wikipedia.org/wiki//dev/random#FreeBSD
lapo
Je pense que la principale crainte /dev/urandom/est ce qui se passe si vous l'utilisez pour générer des secrets sur un nouveau matériel prêt à l'emploi, qui pourrait être dans un état tout à fait prévisible. /dev/urandom/ne bloquera pas l'entropie même si c'est un cas où vous devriez. La situation est encore pire si le secret est persistant, comme si la première chose que votre appareil fait au premier démarrage est de générer une paire de clés publique-privée. En dehors de ces situations effrayantes, un bien /dev/urandomvaut mieux que d'utiliser les SecureRandomalgorithmes courants de toute façon.
Steve Jessop
1
Laquelle est correcte ? -Djava.security.egd = file: / dev /./ urandom ou file: /// dev / urandom @mattb
Aarish Ramesh
35

Sous Linux, l'implémentation par défaut de SecureRandomest NativePRNG(code source ici ), qui a tendance à être très lente. Sous Windows, la valeur par défaut est SHA1PRNG, ce que, comme d'autres l'ont souligné, vous pouvez également utiliser sous Linux si vous le spécifiez explicitement.

NativePRNGdiffère de AESCounterRNG deSHA1PRNG Uncommons Maths en ce qu'il reçoit continuellement l'entropie du système d'exploitation (en lisant à partir de ). Les autres PRNG n'acquièrent aucune entropie supplémentaire après l'ensemencement./dev/urandom

AESCounterRNG est environ 10 fois plus rapide que SHA1PRNG, ce que l'IIRC est lui-même deux ou trois fois plus rapide que NativePRNG.

Si vous avez besoin d'un PRNG plus rapide qui acquiert de l'entropie après l'initialisation, voyez si vous pouvez trouver une implémentation Java de Fortuna . Le PRNG de base d'une implémentation Fortuna est identique à celui utilisé par AESCounterRNG, mais il existe également un système sophistiqué de regroupement d'entropie et de réensemencement automatique.

Dan Dyer
la source
Ce lien ne fonctionne pas. uncommons-maths.dev.java.net/nonav/api/org/uncommons/maths/… . Y a-t-il un endroit où je peux voir cela?
UVM
@Unni vient de mettre à jour le lien. Veuillez noter que les déclarations de performances que j'ai faites dans cette réponse peuvent ne plus être valides. Je pense que les choses se sont peut-être améliorées dans les versions récentes de Java et qu'il peut y avoir des différences de performances entre les plates-formes (par exemple Windows vs Liux).
Dan Dyer
J'étais juste en train d'exécuter un exemple de SecureRandom avec un MessageDigest et en ai fait un hexencodé. L'opération entière dans mon PC Windows 7 a pris 33 millisecondes. Est-ce un problème. J'ai utilisé SHA1PRNG.SecureRandom prng = SecureRandom.getInstance ("SHA1PRNG"); String randomNum = new Integer (prng.nextInt ()) .toString (); MessageDigest sha = MessageDigest.getInstance ("SHA-1"); result = sha.digest (randomNum.getBytes ()); str = hexEncode (résultat);
UVM
24

De nombreuses distributions Linux (principalement basées sur Debian) configurent OpenJDK à utiliser /dev/randompour l'entropie.

/dev/random est par définition lent (et peut même bloquer).

De là, vous avez deux options pour le débloquer:

  1. Améliorer l'entropie, ou
  2. Réduisez les exigences de caractère aléatoire.

Option 1, améliorer l'entropie

Pour obtenir plus d'entropie /dev/random, essayez le démon hasged . C'est un démon qui collecte en permanence l'entropie HAVEGE, et fonctionne également dans un environnement virtualisé car il ne nécessite aucun matériel spécial, seulement le processeur lui-même et une horloge.

Sur Ubuntu / Debian:

apt-get install haveged
update-rc.d haveged defaults
service haveged start

Sur RHEL / CentOS:

yum install haveged
systemctl enable haveged
systemctl start haveged

Option 2. Réduire les exigences relatives au caractère aléatoire

Si, pour une raison quelconque, la solution ci-dessus ne vous aide pas ou si vous ne vous souciez pas du hasard cryptographique fort, vous pouvez passer à la /dev/urandomplace, ce qui est garanti de ne pas bloquer.

Pour le faire globalement, modifiez le fichier jre/lib/security/java.securitydans votre installation Java par défaut à utiliser /dev/urandom(en raison d'un autre bogue, il doit être spécifié comme /dev/./urandom).

Comme ça:

#securerandom.source=file:/dev/random
securerandom.source=file:/dev/./urandom

Ensuite, vous n'aurez plus jamais à le spécifier sur la ligne de commande.


Remarque: si vous faites de la cryptographie, vous avez besoin d'une bonne entropie. Affaire au point - problème android PRNG réduit la sécurité des portefeuilles Bitcoin.

rustyx
la source
Vous avez voté pour votre réponse, mais " /dev/randomest par définition lent (et peut même bloquer)" est faux; cela dépend entièrement de la configuration du système. Les machines plus récentes peuvent avoir par exemple un RNG rapide dans le CPU qui peut être utilisé, et les machines BSD ont généralement la même implémentation pour /dev/randomet /devl/urandom. Pourtant, vous ne devriez probablement pas compter sur la /dev/random rapidité, nécessairement. Sur les machines virtuelles, vous souhaiterez peut-être installer l'ensemble d'outils client sur la machine virtuelle cliente afin qu'elle puisse utiliser le RNG du système d'exploitation hôte.
Maarten Bodewes
17

J'ai eu un problème similaire avec les appels au SecureRandomblocage pendant environ 25 secondes à la fois sur un serveur Debian sans tête. J'ai installé le havegeddémon pour m'assurer qu'il /dev/randomreste à jour, sur les serveurs sans tête, vous avez besoin de quelque chose comme ça pour générer l'entropie requise. Mes appels à SecureRandommaintenant prennent peut-être des millisecondes.

tonnerre
la source
4
apt-get install ont puis update-rc.d ont les valeurs par défaut
Rod Lima
11

Si vous voulez un caractère aléatoire vraiment "cryptographiquement fort", vous avez besoin d'une source d'entropie forte. /dev/randomest lent car il doit attendre que les événements système rassemblent l'entropie (lectures de disque, paquets réseau, mouvement de la souris, pressions de touches, etc.).

Une solution plus rapide est un générateur de nombres aléatoires matériel. Vous en avez peut-être déjà un intégré à votre carte mère; consultez la documentation hw_random pour savoir si vous l'avez et comment l'utiliser. Le paquet rng-tools comprend un démon qui alimentera l'entropie générée par le matériel /dev/random.

Si un HRNG n'est pas disponible sur votre système et que vous êtes prêt à sacrifier la force d'entropie pour la performance, vous voudrez semer un bon PRNG avec des données de /dev/random, et laisser le PRNG faire le gros du travail. Il existe plusieurs PRNG approuvés par le NIST répertoriés dans SP800-90 qui sont simples à mettre en œuvre.

Chris Kite
la source
Bon point, mais mon code fait partie d'une application commerciale. Je n'ai aucun contrôle sur l'environnement du serveur. Je pense que les serveurs cibles sont toujours sans souris ni clavier et dépendent entièrement des E / S disque et réseau pour l'entropie, ce qui est probablement le problème racine.
David G du
3
J'ai découvert que / dev / random dépendait des événements système, donc comme solution de contournement temporaire, j'ai simplement déplacé ma souris d'avant en arrière pendant que mon test s'exécutait ....
David K
Ce hub 82802 pour le chipset i820 était extrêmement lent (RIP). Je suis étonné que vous puissiez en tirer quelque chose d'utile. Je pense que j'ai passé plus de temps à bloquer dessus plutôt qu'à collecter des octets.
jww
6

En utilisant Java 8, j'ai trouvé que sur Linux, l'appel SecureRandom.getInstanceStrong()me donnerait l' NativePRNGBlockingalgorithme. Cela bloquait souvent pendant plusieurs secondes pour générer quelques octets de sel.

Je suis passé à demander explicitement à la NativePRNGNonBlockingplace, et comme prévu par le nom, il n'est plus bloqué. Je n'ai aucune idée de ce que cela implique pour la sécurité. Vraisemblablement, la version non bloquante ne peut pas garantir la quantité d'entropie utilisée.

Mise à jour : Ok, j'ai trouvé cette excellente explication .

En un mot, pour éviter de bloquer, utilisez new SecureRandom(). Cela utilise /dev/urandom, qui ne bloque pas et est fondamentalement aussi sécurisé que /dev/random. Extrait du message: "La seule fois où vous voudriez appeler / dev / random, c'est lorsque la machine démarre pour la première fois et que l'entropie ne s'est pas encore accumulée".

SecureRandom.getInstanceStrong() vous donne le RNG le plus puissant absolu, mais il n'est sûr à utiliser que dans les situations où un tas de blocages ne vous affectera pas.

Lachlan
la source
1
Je n'autoriserais getInstanceStrong() que les clés à long terme, telles que celles des certificats TLS. Et même dans ce cas, je préférerais utiliser new SecureRandom()un générateur de paires de clés compatible FIPS ou un générateur de nombres aléatoires. Alors oui, cela fournit une réponse, si /dev/urandom cela ne bloque pas: en fin de compte, il repose toujours sur l'entropie du système après tout; mais c'est un très bon conseil en général . Si /dev/urandomvous bloquez, vous devrez peut-être corriger la source du problème plutôt que votre application Java.
Maarten Bodewes
5

Il existe un outil (au moins sur Ubuntu) qui alimentera votre système de manière aléatoire artificielle. La commande est simplement:

rngd -r /dev/urandom

et vous aurez peut-être besoin d'un sudo à l'avant. Si vous n'avez pas de paquet rng-tools, vous devrez l'installer. J'ai essayé ça, et ça m'a vraiment aidé!

Source: matt vs monde

David K
la source
2
C'est quelque peu dangereux car cela désactive complètement l'estimation du niveau d'entropie du noyau Linux, à l'échelle du système. Je pense qu'à des fins de test (lit: Jenkins exécutant la suite de tests d'une application) en utilisant /dev/./urandom, c'est bien, mais en production, ce n'est pas le cas.
mirabilos le
C'est en fait la seule solution qui a fonctionné pour moi. J'ai eu un problème de «pas assez d'entropie» lors de la construction d'un projet Android avec Gradle sur Jenkins CI, et passer un paramètre à la construction n'a pas aidé.
Slav
Je devais combiner sudo rngd -r /dev/urandomavec sudo apt install rng-toolsin xenial
MrMesees
5

J'ai fait face au même problème . Après quelques recherches sur Google avec les bons termes de recherche, je suis tombé sur ce bel article sur DigitalOcean .

haveged est une solution potentielle sans compromis sur la sécurité.

Je cite simplement la partie pertinente de l'article ici.

Basé sur le principe HAVEGE, et précédemment basé sur sa bibliothèque associée, haveged permet de générer du hasard en fonction des variations de temps d'exécution de code sur un processeur. Puisqu'il est presque impossible qu'un morceau de code prenne exactement le même temps pour s'exécuter, même dans le même environnement sur le même matériel, le moment d'exécution d'un ou de plusieurs programmes devrait convenir pour amorcer une source aléatoire. L'implémentation de base amorce la source aléatoire de votre système (généralement / dev / random) en utilisant des différences dans le compteur d'horodatage (TSC) de votre processeur après avoir exécuté une boucle à plusieurs reprises

Comment installer haveged

Suivez les étapes de cet article. https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged

Je l'ai posté ici

mec tellement aléatoire
la source
5

Le problème auquel vous avez fait référence /dev/randomn'est pas lié à l' SecureRandomalgorithme, mais à la source du caractère aléatoire qu'il utilise. Les deux sont orthogonaux. Vous devez déterminer lequel des deux vous ralentit.

La page de mathématiques inhabituelles que vous avez liée mentionne explicitement qu'elles ne traitent pas la source du caractère aléatoire.

Vous pouvez essayer différents fournisseurs JCE, tels que BouncyCastle, pour voir si leur implémentation SecureRandomest plus rapide.

Une brève recherche révèle également les correctifs Linux qui remplacent l'implémentation par défaut avec Fortuna. Je n'en sais pas beaucoup plus à ce sujet, mais vous êtes invités à enquêter.

Je dois également mentionner que s'il est très dangereux d'utiliser un SecureRandomalgorithme mal implémenté et / ou une source d'aléatoire, vous pouvez déployer votre propre fournisseur JCE avec une implémentation personnalisée de SecureRandomSpi. Vous devrez passer par un processus avec Sun pour obtenir la signature de votre fournisseur, mais c'est en fait assez simple; ils ont juste besoin que vous leur faxiez un formulaire indiquant que vous êtes au courant des restrictions d'exportation américaines sur les bibliothèques de cryptographie.

Ykaganovich
la source
Ces différents fournisseurs JCE ne sont utiles que s'ils utilisent une autre source d'entropie, ce qui signifie essentiellement qu'ils doivent utiliser un matériel spécifique, tel qu'un HSM. Sinon, ils sont tout aussi susceptibles de connaître des ralentissements, en fonction de la quantité d'entropie qu'ils extraient du système.
Maarten Bodewes
3

Utilisez l'aléatoire sécurisé comme source d'initialisation pour un algorithme récurrent; vous pouvez alors utiliser un twister Mersenne pour le travail en vrac au lieu de celui de UncommonMath, qui existe depuis un certain temps et qui s'est avéré meilleur que les autres prng

http://en.wikipedia.org/wiki/Mersenne_twister

Assurez-vous de rafraîchir de temps en temps le aléatoire sécurisé utilisé pour l'initialisation, par exemple, vous pourriez avoir un aléatoire sécurisé généré par client, en utilisant un générateur pseudo aléatoire mersenne twister par client, obtenant un degré de randomisation suffisamment élevé

Lorenzo Boccaccia
la source
2
Cette réponse est fausse: le twister de Mersenne n'est pas un générateur de nombres aléatoires sécurisé. Ce serait un bon algorithme pour Random, mais pas pour SecureRandom.
Maarten Bodewes
3

Selon la documentation , les différents algorithmes utilisés par SecureRandom sont, par ordre de préférence:

  • Sur la plupart des systèmes * NIX
    1. NatifPRNG
    2. SHA1PRNG
    3. NatifPRNGBlocking
    4. NatifPRNGNonBlocking
  • Sur les systèmes Windows
    1. SHA1PRNG
    2. Windows-PRNG

Depuis que vous avez posé des questions sur Linux, j'ignore l'implémentation de Windows, ainsi que SunPKCS11 qui n'est vraiment disponible que sur Solaris, sauf si vous l'avez installé vous-même - et alors vous ne poseriez pas cette question.

Selon cette même documentation, ce que ces algorithmes utilisent sont

SHA1PRNG
L'amorçage initial est actuellement effectué via une combinaison d'attributs système et du périphérique de collecte d'entropie java.security.

NativePRNG
nextBytes() utilise des /dev/urandom
generateSeed()utilisations/dev/random

NativePRNGBlocking
nextBytes() et generateSeed()utilisation/dev/random

NativePRNGNonBlocking
nextBytes() et generateSeed()utilisation/dev/urandom

Cela signifie que si vous utilisez SecureRandom random = new SecureRandom(), il descend dans cette liste jusqu'à ce qu'il en trouve une qui fonctionne, qui sera généralement NativePRNG. Et cela signifie qu'il se lance à partir de /dev/random(ou l'utilise si vous générez explicitement une graine), puis utilise/dev/urandom pour obtenir les octets suivants, entiers, doubles, booléens, what-have-yous.

Puisqu'il /dev/randombloque (il bloque jusqu'à ce qu'il ait suffisamment d'entropie dans le pool d'entropie), cela peut nuire aux performances.

Une solution à cela consiste à utiliser quelque chose comme avoir pour générer suffisamment d'entropie, une autre solution utilise à la /dev/urandomplace. Bien que vous puissiez définir cela pour l'ensemble de jvm, une meilleure solution consiste à le faire pour cette instance spécifique de SecureRandom, en utilisant SecureRandom random = SecureRandom.getInstance("NativePRNGNonBlocking"). Notez que cette méthode peut lever une NoSuchAlgorithmException si NativePRNGNonBlocking, alors soyez prêt à revenir à la valeur par défaut.

SecureRandom random;
try {
    random = SecureRandom.getInstance("NativePRNGNonBlocking");
} catch (NoSuchAlgorithmException nsae) {
    random = new SecureRandom();
}

Notez également que sur d'autres systèmes * nix, /dev/urandompeut se comporter différemment .


Est-ce /dev/urandomassez aléatoire?

La sagesse conventionnelle veut que ce /dev/randomsoit assez aléatoire. Cependant, certaines voix diffèrent. Dans «La bonne façon d'utiliser SecureRandom» et «Mythes sur / dev / urandom» , on soutient que /dev/urandom/c'est tout aussi bien.

Les utilisateurs de la pile de sécurité de l'information sont d'accord avec cela . Fondamentalement, si vous devez demander, /dev/urandomc'est bien pour votre objectif.

SQB
la source
2

Je n'ai pas rencontré ce problème moi-même, mais je créerais un thread au démarrage du programme qui essaie immédiatement de générer une graine, puis meurt. La méthode que vous appelez pour Randoms se joindra à ce thread s'il est actif, donc le premier appel ne se bloque que s'il se produit très tôt dans l'exécution du programme.

pseudo
la source
C'est un hack plutôt extrême, mais cela pourrait fonctionner; il n'est pas dit que le PRNG utilisé ne peut pas utiliser de matériel de semence supplémentaire qui pourrait encore conduire à un blocage. L'utilisation d'un nombre aléatoire différent fournissant ou fixant l'entropie dans le système doit être fortement préférée. Comme cela peut au moins fournir une solution temporaire, j'ai néanmoins voté pour la réponse.
Maarten Bodewes
2

Mon expérience a été uniquement avec une initialisation lente du PRNG, pas avec la génération de données aléatoires par la suite. Essayez une stratégie d'initialisation plus rapide. Puisqu'ils sont coûteux à créer, traitez-le comme un singleton et réutilisez la même instance. S'il y a trop de conflits de threads pour une instance, regroupez-les ou rendez-les thread-locaux.

Ne faites pas de compromis sur la génération de nombres aléatoires. Une faiblesse là-bas compromet toute votre sécurité.

Je ne vois pas beaucoup de générateurs basés sur la désintégration atomique COTS, mais il existe plusieurs plans pour eux, si vous avez vraiment besoin de beaucoup de données aléatoires. Un site qui a toujours des choses intéressantes à regarder, y compris HotBits, est Fourmilab de John Walker.

Erickson
la source
1
Je me suis toujours posé des questions à ce sujet, puisque les produits de désintégration hadronique du tau atteignent presque l'idéal d'une source aléatoire, je ne peux tout simplement pas me débarrasser de mon souhait d'utiliser cela plutôt que des outils algorithmiques. Pour les besoins de l'opération, j'ai décidé il y a longtemps que certains temps frontaux sont endémiques pour tous les outils sécurisés. Si l'on a besoin d'un randomizer, qui peut être appelé dans le constructeur et n'oubliez pas d'en construire un au moment du chargement de la page, il est enterré sous le swap-in avl et même aussi pointilleux que je le suis, cela passe inaperçu.
Nicholas Jordan
Les chipsets Intel 8xx (et probablement beaucoup d'autres) ont un RNG matériel qui utilise le bruit thermique, un effet quantique vraiment imprévisible. Les modules Trusted Platform peuvent également contenir des RNG matériels, mais malheureusement, celui de mon ordinateur portable n'en contient pas.
erickson
Cela dépend du RNG spécifique s'il démarre une fois ou s'il se réensemence après un certain temps. Le NIST spécifie les PRNG qui réensemencent, mais de nombreuses implémentations logicielles ne le font pas. Restructurer le code autour d'un singleton est une idée horrible, en particulier sur les implémentations multithread; il vaut mieux corriger la source du problème: l'ensemencement lent dû au manque d'entropie. Si vous utilisez un singleton, utilisez-le pour fournir des graines pour d'autres implémentations SecureRandom qui sont entièrement déterministes. Cependant, ce type de conception nécessite probablement pas mal de connaissances.
Maarten Bodewes
@MaartenBodewes Ce sont de bons points. Si l'implémentation est celle qui bloque, en attendant l'entropie du système, je pense que le traiter comme un singleton dans votre application n'est pas une idée horrible puisque la source sous-jacente est en fait un singleton. Mais utiliser cette instance pour en semer d'autres est une bonne suggestion, même si elle est complexe. Je ne suis pas sûr, mais je pense que le fournisseur de Sun (puis Oracle) pour SecureRandoma changé plusieurs fois au cours des 10 dernières années dans sa collecte d'entropie.
erickson
Je suis très sûr que cela a changé plusieurs fois, à tel point que je n'essaierai pas de mettre tous les changements dans ce commentaire :). Il est moins probable qu'une lenteur SecureRandomsoit toujours un problème, mais une faible entropie dans un système sera toujours un problème. L'utilisation d'un singleton créera du code fortement couplé, qui est un anti-modèle de conception. Il doit donc être utilisé avec une extrême prudence; vous devriez de préférence inverser toutes les références dans le code si vous voulez résoudre le problème.
Maarten Bodewes
2

Il semble que vous devriez être plus clair sur vos exigences RNG. L'exigence RNG cryptographique la plus forte (si je comprends bien) serait que même si vous connaissez l'algorithme utilisé pour les générer et que vous connaissez tous les nombres aléatoires générés précédemment, vous ne pourriez pas obtenir d'informations utiles sur l'un des nombres aléatoires générés dans le futur, sans dépenser une quantité irréalisable de puissance de calcul.

Si vous n'avez pas besoin de cette garantie complète du caractère aléatoire, il existe probablement des compromis de performance appropriés. J'aurais tendance à être d'accord avec la réponse de Dan Dyer sur AESCounterRNG d'Uncommons-Maths, ou Fortuna (l'un de ses auteurs est Bruce Schneier, un expert en cryptographie). Je n'ai jamais utilisé non plus mais les idées semblent réputées à première vue.

Je penserais que si vous pouviez générer une graine aléatoire initiale périodiquement (par exemple une fois par jour ou heure ou autre), vous pourriez utiliser un chiffrement de flux rapide pour générer des nombres aléatoires à partir de morceaux successifs du flux (si le chiffrement de flux utilise XOR alors juste passer un flux de valeurs nulles ou saisir directement les bits XOR). ECRYPTEEStream projet a beaucoup de bonnes informations, y compris des repères de performance. Cela ne maintiendrait pas l'entropie entre les points dans le temps où vous le remplissez, donc si quelqu'un connaissait l'un des nombres aléatoires et l'algorithme que vous avez utilisé, techniquement, il pourrait être possible, avec beaucoup de puissance de calcul, de casser le chiffrement du flux et devinez son état interne pour pouvoir prédire les futurs nombres aléatoires. Mais vous devrez décider si ce risque et ses conséquences sont suffisants pour justifier le coût du maintien de l'entropie.

Edit: en voici quelques notes de cours cryptographiques sur RNG que j'ai trouvées sur le net qui semblent très pertinentes pour ce sujet.

Jason S
la source
1
"Fortuna (l'un de ses auteurs est Bruce Schneier, un expert en cryptographie)" - et l'autre est Niels Ferguson, un expert en cryptographie :-)
Steve Jessop
2

Si votre matériel le prend en charge, essayez d' utiliser l'utilitaire Java RdRand dont je suis l'auteur.

Il est basé sur les RDRANDinstructions d'Intel et est environ 10 fois plus rapide SecureRandomet sans problème de bande passante pour la mise en œuvre de gros volumes.


Notez que cette implémentation ne fonctionne que sur les CPU qui fournissent l'instruction (c'est-à-dire lorsque le rdranddrapeau du processeur est défini). Vous devez l'instancier explicitement via le RdRandRandom()constructeur; aucun spécifique Providern'a été mis en œuvre.

user2781824
la source
3
Vous voudrez peut-être lire people.umass.edu/gbecker/BeckerChes13.pdf et assurez-vous de ne jamais utiliser uniquement des données Intel RDRAND. Mélangez-le toujours avec d'autres données imprévisibles, telles que la sortie d'un chiffrement de flux aRC4 (amorcé à partir de / dev / urandom et avec les premiers KiB de sortie jetés pour leur biais connu).
mirabilos
+1 mirabilos. Je pense que RDRANDc'est une bonne source, mais c'est un peu indigne de confiance. Il doit certainement être une entrée parmi tant d'autres dans un collectionneur (sans offenser David Johnston).
jww
J'ai voté, corrigé le lien et fourni des informations générales. Si vous n'êtes pas d'accord, annulez la modification.
Maarten Bodewes
1

Il faut également examiner la propriété securerandom.source dans le fichier lib / security / java.security

Il peut y avoir un avantage en termes de performances à utiliser / dev / urandom plutôt que / dev / random. N'oubliez pas que si la qualité des nombres aléatoires est importante, ne faites pas de compromis qui brise la sécurité.

Diastrophisme
la source