Les générateurs de nombres pseudo-aléatoires utilisent un algorithme mathématique déterministe pour produire une séquence de nombres avec de bonnes propriétés statistiques, mais en réalité la séquence de nombres n'est pas véritablement aléatoire.
Les générateurs de nombres pseudo-aléatoires commencent généralement par une valeur de départ, et chaque calcul utilise la valeur de départ actuelle pour générer une sortie et une nouvelle valeur de départ, qui sera utilisée pour le calcul suivant.
Si différentes instances du générateur de nombres pseudo-aléatoires fourni par Java java.util.Random
sont créées avec la même valeur de départ, les nombres aléatoires suivants seront toujours répétés, tels que :
@Test
public void test() {
long seed = System.currentTimeMillis();
Random random1 = new Random(seed);
Random random2 = new Random(seed);
for (int i = 0; i < 10; i++) {
System.out.println(random1.nextInt() + "=" + random2.nextInt());
}
}
Résultats de test:
584397915=584397915
1101630039=1101630039
-1214277036=-1214277036
-119968434=-119968434
-262827225=-262827225
-1539565323=-1539565323
1391920860=1391920860
-922846780=-922846780
2080924613=2080924613
2114543521=2114543521
Le scénario ci-dessus simule simplement le scénario courant de . Lorsque vous utilisez le constructeur java.util.Random
sans aucun paramètre pour générer une instance, le système utilisera l'heure actuelle de l'horloge système comme valeur de départ. Ensuite, la valeur de départ de l'instance générée par le système pendant l'initialisation ou le redémarrage peuvent être identiques. Les attaquants peuvent implanter des moniteurs dans le système et créer des tables de recherche correspondantes pour prédire les valeurs de départ à utiliser, afin qu'elles ne puissent pas être utilisées dans des scénarios de sécurité .Random
Random
Random
java.util.Random
Il est recommandé de l'utiliser dans des scénarios de sécurité java.security.SecureRandom
, SecureRandom
en fournissant des générateurs de nombres aléatoires (RNG) forts cryptés, qui sont en fait SecureRandom
hérités java.util.Random
et essentiellement toujours basés sur le principe des générateurs de nombres pseudo-aléatoires. Il en va de même pour les nombres aléatoires générés lorsque le la valeur de départ est déterminée. La différence est que SecureRandom
la valeur de départ utilisée n'est pas seulement l'heure actuelle de l'horloge système, mais améliore également l'imprévisibilité de la valeur de départ, elle est donc plus sûre que , mais elle Random
entraînera également une certaine surcharge de performances, donc le choix Random
et SecureRandom
dépend du scénario d'utilisation réel.Dans le scénario de sécuritéUtiliser autant que possible SecureRandom
.
java.security.SecureRandom
Exemple d'utilisation correcte :
- Créez des instances à l'aide du constructeur sans argument
SecureRandom
.
@Test
public void test() {
SecureRandom random1 = new SecureRandom();
SecureRandom random2 = new SecureRandom();
for (int i = 0; i < 10; i++) {
System.out.println(random1.nextInt() + "!=" + random2.nextInt());
}
}
SecureRandom
Il existe deux algorithmes de nombres aléatoires intégrés :NativePRNG
etSHA1PRNG
, vous pouvez spécifier un algorithme de nombres aléatoires pour générerSecureRandom
une instance.
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
Différence entre java.util.Random et java.security.SecureRandom
Il java.security.SecureRandom
s'agit d'une version plus sécurisée java.util.Random
qui fournit un générateur de nombres pseudo-aléatoires cryptographiquement sécurisé (CSPRNG) en Java.
java.security.SecureRandom
Toujours préféré pour java.util.Random
générer des nombres aléatoires sensibles, comme la génération de clés de cryptage dans une application de mot de passe ou la génération d'ID de session sur un serveur Web ou dans un générateur de mots de passe pour créer des mots de passe hautement sécurisés.
Voici quelques raisons pour lesquelles java.security.SecureRandom
il devrait être utilisé dans des applications sensibles :
java.util.Random
L'implémentation utilise un générateur congruentiel linéaire (LCG) pour générer des valeurs pseudo-aléatoires hautement prévisibles.
D'un autre côté, la plupart java.security.SecureRandom
des implémentations utilisent un générateur de nombres pseudo-aléatoires (PRNG), qui utilise un algorithme déterministe pour générer une séquence pseudo-aléatoire à partir d'une véritable graine aléatoire.
-
java.util.Random
Utilisez l’heure système de la graine.java.security.SecureRandom
Obtenez des données aléatoires du système d'exploitation sous-jacent. Sous Linux/Solaris, des nombres aléatoires sont créés en lisant le pool d'entropie/dev/random
et/dev/urandom
les fichiers. -
Si deux instances
java.util.Random
sont créées avec la même graine et que la même séquence d'appels de méthode est effectuée pour chacune, elles généreront et renverront la même séquence de nombres. Ce n'est pas le casjava.security.SecureRandom
, il est généré à partir de sources d'entropie obtenues par le système d'exploitation, telles que le timing des événements d'E/S, qui est pratiquement indétectable. -
java.util.Random
Les classes utilisent48
une graine -bit, alors quejava.security.SecureRandom
généralement un128
-bit ou160
bitseed est utilisé. Il suffit donc248
d'essayer de briserRandom
la classe, ce qui peut ne même pas prendre une seconde sur un ordinateur moderne. D'un autre côté,2128
ou2160
il faudra essayerSecureRandom
, il faudra des années pour atteindre la puissance de calcul actuelle du CPU. -
java.security.SecureRandom
Produit une sortie indéterminée car elle ne dépend pas de la valeur de départ de l'horloge système. Il est donc impossible de prédire les nombres aléatoires passés et futurs.java.util.Random
D'un autre côté, l'utilisation de l'horloge système comme graine peut être facilement reproduite si l'heure à laquelle la graine a été générée est connue. -
Les LCG sont très rapides et ne nécessitent généralement
32-
que ou64-
bits pour maintenir leur état. D'un autre côté, créer unejava.security.SecureRandom
instance est très coûteux que la création d'unejava.util.Random
instance et environ30-50
plusieurs fois plus lent queRandom
.
De plus, les méthodes generateSeed()
et peuvent être bloquées sous Linux si l'entropie disponible n'est pas suffisante et que l'entropie est collectée dans le fichier. Voici ce que Wikipédia dit :nextBytes()
SecureRandom
/dev/random
Le générateur conserve une estimation du nombre total de bits de bruit dans le pool d'entropie. Créez des nombres aléatoires à partir de ce pool d'entropie. Lors de la lecture, /dev/random
l'appareil ne renverra que des octets aléatoires dans le nombre estimé de bits de bruit dans le pool d'entropie. /dev/random
Doit être adapté aux utilisations qui nécessitent un caractère aléatoire de très haute qualité, comme le remplissage unique ou la génération de clés. Lorsque le pool d'entropie est vide, l'esclave /dev/random
se bloque jusqu'à ce qu'un bruit ambiant supplémentaire soit collecté.
-
Il s'agit notamment
java.security.SecureRandom
d'une sous-classe dejava.util.Random
toutes les méthodes et hérite de celles-cinextX()
, où X peut être booléen, double, flottant, gaussien, int et long. -
Initialisez
java.util.Random
etjava.security.SecureRandom
:
Random
Peut être initialisé comme :
Random rand = new Random(System.nanoTime());
SecureRandom
Peut être initialisé comme :
SecureRandom rand = new SecureRandom(SecureRandom.getSeed(20));
Ici, la 20
représentation numérique 160
-bit seed est 20
octets = 160
bits.
- Le Javadoc lui-même recommande d'utiliser
java.security.SecureRandom
un générateur de nombres pseudo-aléatoires cryptographiquement sécurisé dans les applications sensibles à la sécurité.