Question

Si vous voulez un nombre aléatoire cryptographiquement fort en Java, utilisez SecureRandom . Malheureusement, SecureRandom peut être très lent. S'il utilise / dev / random sous Linux, il peut bloquer l'attente d'une suffisamment d'entropie pour se développer. Comment évitez-vous la pénalité de performance?

Quelqu'un a-t-il déjà utilisé Uncommon Maths pour résoudre ce problème?

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

Était-ce utile?

La solution

Si vous voulez de vraies données aléatoires, vous devez malheureusement les attendre. Cela inclut la valeur de départ pour un PRNG SecureRandom . Les mathématiques inhabituelles ne peuvent pas collecter des données véritablement aléatoires plus rapidement que SecureRandom , bien qu'il puisse se connecter à Internet pour télécharger des données de base à partir d'un site Web particulier. À mon avis, il est peu probable que cela soit plus rapide que / dev / random , là où c'est disponible.

Si vous voulez un PRNG, procédez comme suit:

SecureRandom.getInstance("SHA1PRNG");

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

Sun aime beaucoup SHA1PRNG, il est donc largement disponible. Ce n'est pas particulièrement rapide que les PRNG disparaissent, mais les PRNG ne feront que croquer les chiffres, pas pour bloquer 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 germera une fois la première fois que vous appelez next () ou nextBytes () . Pour ce faire, il utilise généralement 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 bien plus sécurisée que toute variante de "hachage de l'heure actuelle avec le PID, ajoutez 27, et espérons le meilleur". Si vous avez simplement besoin de chiffres aléatoires pour une partie, ou si vous souhaitez que le flux soit reproductible à l'avenir en utilisant la même graine à des fins de test, une graine non sécurisée est toujours utile.

Autres conseils

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

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

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

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

(notez le /./ supplémentaire)

Sous Linux, la mise en oeuvre par défaut de SecureRandom est NativePRNG (code source ici ), ce qui a tendance à être très lent. Sous Windows, la valeur par défaut est SHA1PRNG . Comme d'autres l'ont souligné, vous pouvez également l'utiliser sous Linux si vous le spécifiez explicitement.

NativePRNG diffère de SHA1PRNG et des mathématiques peu communes AESCounterRNG en ce qu'il reçoit en continu l'entropie du système d'exploitation (en lisant dans / dev / urandom ). Les autres PRNG n’acquièrent aucune entropie supplémentaire après l’ensemencement.

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

Si vous avez besoin d'un PRNG plus rapide qui acquiert 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 mise en commun entropique et de réensemencement automatique.

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

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

À partir de là, vous avez deux options pour le débloquer:

  1. Améliorer l'entropie ou
  2. Réduisez les exigences aléatoires.

Option 1, améliorer l'entropie

Pour obtenir plus d'entropie dans / dev / random , essayez la haveged . Il s’agit d’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 particulier, mais uniquement le processeur et une horloge.

Sur Ubuntu / Debian:

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

Sous 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 de l'aléatoire fort du point de vue cryptographique, vous pouvez passer à / dev / urandom , ce qui garantit de ne pas bloquer.

Pour le faire globalement, éditez le fichier jre / lib / security / java.security dans votre installation Java par défaut pour utiliser / dev / urandom (à cause d'un autre < Un bogue href = "https://bugs.openjdk.java.net/browse/JDK-6202721" rel = "noreferrer"> doit être spécifié sous la forme / dev /./urandom ).

Comme ceci:

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

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

Remarque: si vous utilisez la cryptographie, vous avez besoin d'une bonne entropie. Exemple: la problème PRNG d'Android a réduit la sécurité des portefeuilles Bitcoin.

J'ai eu un problème similaire avec les appels au blocage de SecureRandom pendant environ 25 secondes à la fois sur un serveur Debian sans tête. J'ai installé le démon haveged pour vous assurer que / dev / random est maintenu complet, sur les serveurs sans interface utilisateur, vous avez besoin de quelque chose comme ceci pour générer l'entropie requise. Mes appels à SecureRandom prennent maintenant peut-être quelques millisecondes.

Si vous voulez vraiment "forte cryptographiquement" le hasard, alors vous avez besoin d'une source d'entropie forte. / dev / random est lent car il doit attendre que les événements système rassemblent l'entropie (lectures sur disque, paquets réseau, mouvements de la souris, pressions sur les touches, etc.).

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

Si un système HRNG n’est pas disponible sur votre système et que vous êtes prêt à sacrifier la performance de l’entropie, vous souhaiterez créer un bon groupe PRNG avec les données de / dev / random et laissez le PRNG fait le gros du travail. Plusieurs PRNG approuvés par le NIST figurent dans la SP800-90 qui sont simples à mettre en œuvre.

Il existe un outil (au moins sur Ubuntu) qui alimentera l’aléatoire artificiel dans votre système. La commande est simplement:

rngd -r /dev/urandom

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

Source: matt vs world

J'ai rencontré le 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 compromettre la sécurité.

Je ne fais que citer la partie pertinente de l'article ici.

  

Basé sur le principe HAVEGE et précédemment sur ses principes associés   bibliothèque, hasged permet de générer un caractère aléatoire basé sur des variations de   temps d'exécution du code sur un processeur. Comme il est presque impossible pour   un morceau de code à prendre le même temps exact pour exécuter, même dans le   même environnement sur le même matériel, le moment d’exécuter une seule   ou plusieurs programmes devraient convenir pour ensemencer une source aléatoire. le   haveged implémente la source aléatoire de votre système (généralement   / dev / random) en utilisant des différences dans le compteur d'horodatage de votre processeur   (TSC) après avoir exécuté une boucle à plusieurs reprises

Comment installer le hasged

Suivez les étapes décrites dans cet article. www.digitalocean.com/community/tutorials/how-to-setup-addopy-entropy-for-cloud-servers-using-haveged

Je l'ai posté ici

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

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

Assurez-vous d'actualiser de temps en temps l'aléatoire sécurisé utilisé pour l'initialisation. Par exemple, vous pouvez générer un aléatoire sécurisé par client, en utilisant un générateur pseudo-aléatoire Mersenne Twister par client, en obtenant un degré de randomisation suffisant.

En utilisant Java 8, j’ai constaté que, sur Linux, l’appel SecureRandom.getInstanceStrong () me donnait l’algorithme NativePRNGBlocking . Cela bloquerait souvent plusieurs secondes pour générer quelques octets de sel.

Je suis passé à la demande explicite de demander NativePRNGNonBlocking , et comme attendu du nom, le nom 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 résumé, pour éviter le blocage, utilisez new SecureRandom () . Cela utilise / dev / urandom , ce qui ne bloque pas et est aussi sécurisé que / dev / random . A partir de la publication: "Le seul moment où vous souhaitez appeler / dev / random est lors du premier démarrage de la machine et que l'entropie ne s'est pas encore accumulée".

SecureRandom.getInstanceStrong () vous donne le RNG le plus puissant, mais son utilisation est sans danger uniquement dans les cas où aucun blocage ne vous affectera.

Le problème que vous avez évoqué à propos de / dev / random ne concerne pas l'algorithme SecureRandom , mais la source de caractère aléatoire qu'il utilise. Les deux sont orthogonaux. Vous devez déterminer lequel des deux vous ralentit.

La page Mathématiques peu commune que vous avez liée mentionne explicitement qu’elles ne traitent pas la source de l’aléatoire.

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

Une recherche brève révèle également les correctifs Linux qui remplacent ceux par défaut. mise en œuvre avec Fortuna. Je n'en sais pas beaucoup plus à ce sujet, mais vous êtes le bienvenu pour enquêter.

Je dois également mentionner que s'il est très dangereux d'utiliser un algorithme SecureRandom mal implémenté et / ou une source aléatoire, vous pouvez lancer votre propre fournisseur JCE avec une implémentation personnalisée de SecureRandomSpi . Vous devrez passer par un processus avec Sun pour faire signer votre fournisseur, mais le processus est plutôt simple. ils ont juste besoin que vous leur envoyiez par fax un formulaire indiquant que vous êtes au courant des restrictions d'exportation imposées par les États-Unis sur les bibliothèques de chiffrement.

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

Mon expérience ne concerne que l'initialisation lente du PRNG, et non la génération de données aléatoires par la suite. Essayez une stratégie d’initialisation plus rapide. Étant donné que leur création coûte cher, traitez-la 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 faites-en des threads locaux.

Ne compromettez pas la génération de nombres aléatoires. Une faiblesse de ce système compromet toute votre sécurité.

Je ne vois pas beaucoup de générateurs COTS basés sur la désintégration atomique, mais il existe plusieurs solutions pour les utiliser, si vous avez vraiment besoin de beaucoup de données aléatoires. Le Fourmilab de John Walker est un site qui présente toujours des éléments intéressants, y compris HotBits. "

Il semble que vous deviez préciser vos exigences en matière de GNA. La meilleure exigence en matière de RNG cryptographique (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 pouvez obtenir aucune information utile sur les nombres aléatoires générés dans le fichier. avenir, sans dépenser une quantité de puissance informatique peu pratique.

Si vous n’avez pas besoin de cette garantie totale d’aléatoire, il existe probablement des compromis de performances appropriés. Je suis plutôt d'accord avec la la réponse de Dan Dyer à propos de AESCounterRNG de Uncommons-Maths, ou Fortuna (l'un de ses auteurs est Bruce Schneier, expert en cryptographie). Je ne les ai jamais utilisées non plus, mais les idées semblent dignes de confiance à première vue.

J'aurais pensé que si vous pouviez générer périodiquement une graine aléatoire initiale (par exemple une fois par jour ou par heure), vous pourriez utiliser un chiffrement à flux rapide pour générer des nombres aléatoires à partir de morceaux successifs du fichier. stream (si le flux de chiffrement utilise XOR, il suffit de passer un flux de valeurs nulles ou de récupérer directement les bits XOR). Le projet eStream d'ECRYPT contient de nombreuses informations utiles, notamment des critères de performance. Cela ne maintiendrait pas l'entropie entre les instants où vous le réapprovisionniez. Si quelqu'un connaissait l'un des nombres aléatoires et l'algorithme que vous utilisiez, techniquement, il serait peut-ê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 devez décider si ce risque et ses conséquences sont suffisants pour justifier le coût de maintenance de l'entropie.

Modifier: voici quelques notes de cours cryptographiques sur RNG J'ai trouvé sur le net un aspect très pertinent pour ce sujet.

Si votre matériel le permet, essayez de utiliser l'utilitaire Java RdRand dont je suis l'auteur. .

Basé sur l'instruction RDRAND d'Intel, il est environ 10 fois plus rapide que SecureRandom et ne pose aucun problème de bande passante pour la mise en œuvre de gros volumes.

Notez que cette implémentation ne fonctionne que sur les CPU fournissant l'instruction (c'est-à-dire lorsque l'indicateur de processeur rdrand est défini). Vous devez l'instancier explicitement via le constructeur RdRandRandom () ; aucun fournisseur spécifique n'a été implémenté.

La propriété securerandom.source du fichier lib / security / java.security doit également être examinée.

Utiliser / dev / urandom plutôt que / dev / random peut présenter des avantages en termes de performances. N'oubliez pas que si la qualité des nombres aléatoires est importante, ne faites pas de compromis qui compromettrait la sécurité.

Vous pouvez essayer le projet Math commun Apache, qui a quelques implémentations d'algorithmes bien connus:

https://commons.apache.org/proper/commons- math / userguide / random.html

Cependant, soyez prudent avec la performance. Le constructeur par défaut de RandomDataGenerator crée une instance dédiée de Well19937c , ce qui représente une opération très coûteuse.

Selon la documentation, cette classe n'est pas thread-safe, mais si vous pouvez garantir qu'un seul thread accédera à cette classe, vous ne pourrez initialiser qu'une seule instance par thread.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top