it-swarm.dev

Java SecureRandom non si blocca? Come?

So per esperienza che leggere da/dev/random blocchi quando il pool di entropia del kernel Linux esaurisce l'entropia. Inoltre, ho visto molti articoli e post di blog che affermano che quando si esegue su Linux, Java.security.SecureRandom usa/dev/random come sorgente entropia e quindi si blocca quando il pool entropico del kernel esaurisce l'entropia.

Tuttavia, non sono in grado di produrre un esperimento che causa il blocco di SecureRandom. Al contrario, sembra facile ottenere un semplice one-liner bash che legge da/dev/random per bloccare.

Ecco il Java che sto usando per questi esperimenti:

import Java.security.SecureRandom;

public class A {
    public static void main(String[] args) {
        SecureRandom sr = new SecureRandom();
        int out = 0;
        for (int i = 0; i < 1<<20 ; i++) {
            out ^= sr.nextInt();
        }
        System.out.println(out);
    }
}

Genera poco più di 1.000.000 di numeri interi casuali a 32 bit. Dovrebbero essere 2 ^ (20 + log2 (32)) = 2 ^ 25 bit o 2 ^ 22 (poco più di 4 milioni) byte di entropia, giusto? Tuttavia, non si blocca mai. Termina sempre in circa 1,2 secondi, non importa se muovo il mouse o meno.

Il bash one-liner che ho usato è:

head -c 100 /dev/random | xxd

Questo si blocca facilmente. Fintanto che terrò la mano lontana dal mouse e dalla tastiera, rimarrà lì senza fare nulla per diversi minuti. E sto solo chiedendo 100 byte di entropia.

Sicuramente mi manca qualcosa qui. Qualcuno potrebbe spiegare cosa sta succedendo?

Grazie!

22
user1483512

Sia OpenJDK che Sun leggono da /dev/urandom, non /dev/random, almeno sulla macchina su cui ho provato (OpenJDK JRE 6b27 e Sun JRE 6.26 su Debian squeeze AMD64). Per qualche motivo, entrambi aprono /dev/random ma non ne ho mai letto. Quindi gli articoli del blog che hai letto erano errati o applicati a una versione diversa dalla mia (e, a quanto pare, la tua).

Puoi verificare se il tuo legge da /dev/random o /dev/urandom tracciandolo:

strace -o a.strace -f -e file Java A

e cerca la parte rilevante della traccia:

21165 open("/dev/random", O_RDONLY)     = 6
…
21165 open("/dev/urandom", O_RDONLY)    = 7
…
21165 read(7, "\322\223\211\262Zs\300\345\3264l\254\354[\6wS\[email protected]", 20) = 20
…

Non ti preoccupare, /dev/urandom va benissimo per la crittografia.

Java SecureRandom fa usa/dev/random, ma solo brevemente.

In particolare, lo utilizza solo quando genera informazioni seed, chiamando esplicitamente SecureRandom.generateSeed() o dalla prima chiamata a nextInt()

Quindi, per ripetere il tuo esempio bash puoi fare quanto segue, e dovrebbe bloccare.

import Java.security.SecureRandom;

public class A {
    public static void main(String[] args) {
        SecureRandom sr;
        int out = 0;
        for (int i = 0; i < 1<<20 ; i++) {
            sr = new SecureRandom();
            out ^= sr.nextInt();
        }
        System.out.println(out);
    }
}
9
diedthreetimes

Non solo per mantenere vivo un vecchio thread, ma alcune persone potrebbero aver perso una parte importante della lunga storia dietro questo ... Si trattava di un noto bug infame e persistente quando si utilizzava/dev/urandom da Java versioni 1.4 alle versioni 1.7. Vedere i collegamenti seguenti:

http://bugs.Java.com/view_bug.do?bug_id=6202721

http://bugs.Java.com/view_bug.do?bug_id=470509

Per quello che so, questo è stato finalmente risolto in Java 8 come affermato da Oracle: https://docs.Oracle.com/javase/8/docs/technotes/guides /security/enhancements-8.html

SHA1PRNG e NativePRNG sono stati corretti per rispettare correttamente le proprietà dell'origine seme SecureRandom nel file Java.security. (L'oscura soluzione alternativa utilizzando file: /// dev/urandom e file:/dev /./ urandom non è più necessaria.)

4
ozys

$Java_HOME/lib/security/Java.security: securerandom.source La proprietà determina quale dispositivo utilizzare quando si utilizza SecureRandom. Il valore predefinito è /dev/urandom, che significa Java non si bloccherà mai.

Per i nuovi arrivati ​​sull'argomento, /dev/urandom è la versione speciale di /dev/random, che utilizzerà la vera entropia di /dev/random quando disponibile e quindi dati pseudo casuali hanno seminato entropia reale se era disponibile.

In headless, VM e ambienti Cloud, consiglio di eseguire il seeding di urandom da una fonte esterna, come http://random.org

3

Su Linux vintage recenti (negli ultimi 6 anni, diciamo) la differenza computazionale tra/dev/random (blocco) e/dev/urandom (non blocco) è molto marginale; l'entropia grezza viene riciclata attraverso un generatore di numeri casuali ed entrambi i dispositivi utilizzano gli stessi bit. L'unica differenza è che/dev/random ha un limitatore di velocità che gli impedisce di funzionare troppo a lungo senza effettuare il reseeding. La stessa stima dei tassi è piuttosto discutibile.

Questo è spiegato in http://www.2uo.de/myths-about-urandom/ che porta a casa il punto che/dev/urandom è sufficiente per eseguire il seeding degli algoritmi crittografici per le chiavi di sessione. Se non lo chiami troppo frequentemente, entrambi dovrebbero essere di qualità identica o quasi identica.

Ho visto il blocco tramite/dev/random durante l'esecuzione di un web crawler che aveva bisogno di effettuare oltre 1000 connessioni SSL simultanee (chiavi di sessione), e sì, siamo passati a/dev/urandom; per la generazione in blocco di coppie di chiavi pubbliche/private di lunga durata (una situazione rara), è preferibile un dispositivo entropia personalizzato.

3
Paul Baclace