web-dev-qa-db-fra.com

SecureRandom avec NativePRNG vs SHA1PRNG

J'ai besoin de générer des nombres aléatoires et des tableaux d'octets cryptographiquement forts. À cette fin, j'utilise la classe SecureRandom de Java. Mais je ne suis pas sûr de choisir quel algorithme PRNG en termes de force cryptographique.

Laquelle des instances suivantes génère un nombre plus imprévisible? Ou sont-ils égaux?

SecureRandom nativePrng = SecureRandom.getInstance("NativePRNG")
SecureRandom sha1Prng = SecureRandom.getInstance("SHA1PRNG")

De plus, nous pouvons générer ces instances avec le fournisseur "Sun" (par exemple SecureRandom.getInstance("SHA1PRNG", "Sun")). Cela fait-il une différence?

Merci d'avance.

33
ovunccetin

TL; DR: utilisez new SecureRandom() lorsque vous n'êtes pas sûr et laissez le système le comprendre. Utilisez éventuellement SecureRandom.getInstanceStrong() pour la génération de clés à long terme.

Ne vous attendez pas à ce qu'un générateur de nombres aléatoires génère une séquence de sortie spécifique dans une application d'exécution, même si vous l'amorcez vous-même.


Avec les générateurs de nombres aléatoires, il est toujours difficile de dire lequel est le meilleur. Linux et la plupart des Unix ont un générateur de nombres aléatoires assez bien pensé, donc cela ne fait pas de mal d'utiliser /dev/random Ou /dev/urandom, C'est-à-dire "NativePRNG" . Le problème avec l'utilisation de /dev/random Est qu'il bloque jusqu'à ce que suffisamment d'entropie soit disponible. Je vous déconseille donc, sauf si vous avez des exigences particulières en ce qui concerne la génération de clés.


"SHA1PRNG" Utilise une fonction de hachage et un compteur, avec une graine. L'algorithme est relativement simple, mais il n'a pas été bien décrit. Il est généralement considéré comme sûr. Comme il ne germe que l'un des générateurs du système au démarrage et nécessite donc moins d'appels au noyau, il est probablement moins gourmand en ressources - sur mon système, il fonctionne environ 9 fois plus rapidement que le "NativePRNG" (Qui est configuré pour utiliser /dev/urandom). Les deux semblent taxer un seul cœur de mon ordinateur portable Ubuntu double cœur (à la fois, il passait souvent d'un cœur à un autre, c'est probablement la planification du noyau qui est à blâmer). Si vous avez besoin de hautes performances, choisissez celui-ci, surtout si le périphérique /dev/urandom Est lent sur la configuration système spécifique.

Notez que le "SHA1PRNG" Présent dans retiré l'implémentation d'Apache Harmony est différent de celui du fournisseur Sun (utilisé par Oracle dans la norme Java SE). La version dans Jakarta était également utilisée dans les anciennes versions de Android. Bien que je n'ai pas pu le faire un examen complet, il ne semble pas être très sécurisé.

EDIT: et je ne me trompais pas à ce sujet, SHA1PRNG s'est avéré ne pas être pseudo-aléatoire pour les versions <4.2.2 et plus ici .

Attention, "SHA1PRNG" N'est pas pas une exigence d'implémentation pour Java SE. Sur la plupart des runtimes ce sera présent, mais le référencer directement à partir du code rendra votre code moins portable.


En général, ce n'est pas une bonne idée d'exiger un fournisseur spécifique non plus. La spécification d'un fournisseur peut nuire à l'interopérabilité; tous les Java runtime peuvent avoir accès au fournisseur Sun par exemple - Android certainement pas. Cela rend également votre application moins flexible au moment de l'exécution, c'est-à-dire que vous ne peut pas mettre un fournisseur plus haut dans la liste et l'utiliser à la place.

N'indiquez donc un fournisseur que si vous dépendez de l'une des fonctionnalités qu'il fournit. Par exemple, vous voudrez peut-être spécifier un fournisseur si vous avez un périphérique matériel spécifique qui génère les aléas, ou une bibliothèque cryptographique qui a été FIPS certifiée. C'est probablement une bonne idée de faire l'algorithme/provider une option de configuration pour votre application si vous devez spécifier un fournisseur.

L'idée de ne pas spécifier de fournisseur est également présente dans ce Blog des développeurs Android sur la sécurité .


Essayez donc de vous abstenir de choisir un générateur aléatoire spécifique. À la place, optez simplement pour le constructeur d'arguments vides: new SecureRandom() et laissez le système choisir le meilleur générateur de nombres aléatoires. Il est possible d'utiliser le nouveau configurable SecureRandom.getInstanceStrong() dans Java 8 et plus si vous avez des exigences spécifiques pour par exemple la génération de clés à long terme.

Ne mettez pas en cache les instances de SecureRandom , laissez-les simplement se semer initialement et laissez le VM les gérer. Je n'ai pas vu de différence notable dans opération.


Quand ne pas utiliser SecureRandom du tout:

Comme avertissement général, je déconseille fortement d'utiliser le générateur de nombres aléatoires pour autre chose que la génération de nombres aléatoires. Même si vous pouvez le semer vous-même et même si vous choisissez SHA1PRNG de Sun, ne comptez pas pouvoir extraire la même séquence de nombres aléatoires du générateur de nombres aléatoires. Il ne faut donc pas ne pas l'utiliser pour dériver des clés à partir de mots de passe, pour ne citer qu'un exemple.

Si vous avez besoin d'une séquence répétée, utilisez un chiffrement de flux et utilisez les informations de départ pour la clé et IV. Chiffrez le texte en clair composé de zéros pour récupérer le flux de clés de valeurs pseudo aléatoires. Vous pouvez également utiliser une fonction de sortie extensible (XOF) telle que SHAKE128 ou SHAKE256 (si disponible).

Vous pouvez envisager un générateur de nombres aléatoires différent et non sécurisé au lieu de SecureRandom si les RNG disponibles offrent des performances insuffisantes et si la sécurité n'est pas un problème. Aucune implémentation de SecureRandom ne sera aussi rapide que les générateurs de nombres aléatoires non sécurisés tels que l'algorithme de Mersenne Twister ou l'algorithme implémenté par la classe Random . Ceux-ci ont été optimisés pour la simplicité et la vitesse plutôt que pour la sécurité ou la qualité.

Il est possible d'étendre la classe SecureRandom et d'insérer une implémentation aléatoire déterministe et amorcée dans un appel de bibliothèque. De cette façon, la bibliothèque récupère un générateur de nombres pseudo-aléatoires avec une sortie bien définie. Il convient toutefois de noter que le générateur de nombres aléatoires peut être utilisé de différentes manières par des algorithmes. Par exemple. RSA peut basculer vers une manière mieux optimisée de trouver des nombres premiers et des clés DES peuvent être générées avec des bits de parité ajustés ou directement calculés.

52
Maarten Bodewes

A partir d'une réf. ici :

Native PRNG implémentation pour Solaris/Linux. Il interagit avec/dev/random et/dev/urandom, il n'est donc disponible que si ces fichiers sont présents. Sinon, SHA1PRNG est utilisé à la place de cette classe .

Le fournisseur Sun peut être utilisé par défaut (principalement en fonction de l'ordre du fournisseur présent).

4
nitishagar