Sécurité des nombres aléatoires : différence entre java.util.Random et java.security.SecureRandom

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.Randomsont 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.Randomsans 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é .RandomRandomRandomjava.util.Random

Il est recommandé de l'utiliser dans des scénarios de sécurité java.security.SecureRandom, SecureRandomen fournissant des générateurs de nombres aléatoires (RNG) forts cryptés, qui sont en fait SecureRandomhérités java.util.Randomet 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 SecureRandomla 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 Randomentraînera également une certaine surcharge de performances, donc le choix Randomet SecureRandomdépend du scénario d'utilisation réel.Dans le scénario de sécuritéUtiliser autant que possible SecureRandom.

java.security.SecureRandomExemple d'utilisation correcte :

  1. 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());
    }
}
  1. SecureRandomIl existe deux algorithmes de nombres aléatoires intégrés : NativePRNGet SHA1PRNG, vous pouvez spécifier un algorithme de nombres aléatoires pour générer SecureRandomune instance.
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");


Différence entre java.util.Random et java.security.SecureRandom

Il java.security.SecureRandoms'agit d'une version plus sécurisée java.util.Randomqui fournit un générateur de nombres pseudo-aléatoires cryptographiquement sécurisé (CSPRNG) en Java.

java.security.SecureRandomToujours préféré pour java.util.Randomgé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.SecureRandomil devrait être utilisé dans des applications sensibles :

  1. java.util.RandomL'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.SecureRandomdes 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.

  1. java.util.RandomUtilisez l’heure système de la graine. java.security.SecureRandomObtenez 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/randomet /dev/urandomles fichiers.

  2. Si deux instances java.util.Randomsont 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 cas java.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.

  3. java.util.RandomLes classes utilisent 48une graine -bit, alors que java.security.SecureRandomgénéralement un 128-bit ou 160bitseed est utilisé. Il suffit donc 248d'essayer de briser Randomla classe, ce qui peut ne même pas prendre une seconde sur un ordinateur moderne. D'un autre côté, 2128ou 2160il faudra essayer SecureRandom, il faudra des années pour atteindre la puissance de calcul actuelle du CPU.

  4. java.security.SecureRandomProduit 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.RandomD'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.

  5. Les LCG sont très rapides et ne nécessitent généralement 32-que ou 64-bits pour maintenir leur état. D'un autre côté, créer une java.security.SecureRandominstance est très coûteux que la création d'une java.util.Randominstance et environ 30-50plusieurs fois plus lent que Random.

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/randoml'appareil ne renverra que des octets aléatoires dans le nombre estimé de bits de bruit dans le pool d'entropie. /dev/randomDoit ê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/randomse bloque jusqu'à ce qu'un bruit ambiant supplémentaire soit collecté.

  1. Il s'agit notamment java.security.SecureRandomd'une sous-classe de java.util.Randomtoutes les méthodes et hérite de celles-ci nextX(), où X peut être booléen, double, flottant, gaussien, int et long.

  2. Initialisez java.util.Randomet java.security.SecureRandom:

RandomPeut être initialisé comme :

Random rand = new Random(System.nanoTime());

SecureRandomPeut être initialisé comme :

SecureRandom rand = new SecureRandom(SecureRandom.getSeed(20));

Ici, la 20représentation numérique 160-bit seed est 20octets = 160bits.

  1. Le Javadoc lui-même recommande d'utiliser java.security.SecureRandomun générateur de nombres pseudo-aléatoires cryptographiquement sécurisé dans les applications sensibles à la sécurité.

おすすめ

転載: blog.csdn.net/qq_43842093/article/details/132642237