Le applicazioni Java possono e devono utilizzare la classe java.security.SecureRandom per produrre valori casuali crittograficamente forti utilizzando un generatore di numeri pseudo-casuali crittograficamente forte ( CSPRNG ). Le implementazioni JDK standard della classe java.util.Random non sono considerate crittograficamente forti.
I sistemi operativi simili a Unix dispongono di /dev/random
un file speciale che serve numeri pseudo casuali che accedono al rumore ambientale raccolto dai driver di dispositivo e da altre fonti. Tuttavia, si blocca se è disponibile meno entropia di quanto richiesto ; /dev/urandom
in genere non si blocca mai, anche se il seme del generatore di numeri pseudocasuali non è stato completamente inizializzato con entropia dall'inizio. Esiste ancora un terzo file speciale, /dev/arandom
che si blocca dopo l'avvio fino a quando il seme non è stato inizializzato in modo sicuro con abbastanza entropia e quindi non si blocca mai più.
Per impostazione predefinita, JVM esegue il seeding della classe SecureRandom utilizzando /dev/random
, pertanto il codice Java può bloccarsi in modo imprevisto . L'opzione -Djava.security.egd=file:/dev/./urandom
nell'invocazione della riga di comando utilizzata per avviare il processo Java indica /dev/urandom
invece a JVM di utilizzare .
Il supplemento /./
sembra fare in modo che la JVM utilizzi l' algoritmo SHA1PRNG che utilizza SHA-1 come base del PRNG (Pseudo Random Number Generator). È più forte dell'algoritmo NativePRNG utilizzato quando /dev/urandom
è specificato.
Infine, esiste un mito che /dev/urandom
è un generatore di numeri pseudo casuali, un PRNG, mentre /dev/random
è un generatore di numeri casuali "vero" . Questo semplicemente non è vero, entrambi /dev/random
e /dev/urandom
sono alimentati dallo stesso CSPRNG (generatore di numeri pseudocasuali crittograficamente sicuro). Solo il comportamento quando il rispettivo pool esaurisce l'entropia, secondo alcune stime, differisce: /dev/random
blocchi, mentre /dev/urandom
non lo è.
Che dire dell'entropia che sta per finire? Non importa
Si scopre che "apparire casuali" è il requisito di base per molti dei nostri blocchi crittografici. E se prendi l'output di un hash crittografico, deve essere indistinguibile da una stringa casuale in modo che le cifre lo accettino. Questo è il motivo dell'utilizzo dell'algoritmo SHA1PRNG, in quanto utilizza una funzione hash e un contatore, insieme a un seme.
Quando dovrebbe essere applicato?
Direi sempre.
Fonti:
https://gist.github.com/svrc/5a8accc57219b9548fe1
https://www.2uo.de/myths-about-urandom
MODIFICA 04/2020:
Un commento menziona una modifica al comportamento della classe SecureRandom in Java 8.
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.)
Ciò era già stato sottolineato dai test citati nella sezione Fonti sopra. Il supplemento /./
è necessario per modificare l'algoritmo utilizzato da SecureRanom in Java 8 da NativePRNG a SHA1PRNG.
Tuttavia, ho alcune notizie che vorrei condividere. Secondo JEP-273 , da Java 9 la classe SecureRandom implementa i tre meccanismi deterministici di generazione casuale di bit (DRBG) descritti nel NIST 800-90Ar1 . Questi meccanismi implementano algoritmi moderni forti come SHA-512 e AES-256.
Il JDK aveva due tipi di implementazioni SecureRandom :
- Uno è dipendente dalla piattaforma e basato su chiamate native o dispositivi OS come la lettura
/dev/{u}random
su Unix o l'utilizzo di CryptoAPI su Windows. Le ultime versioni di Linux e Windows supportano già DRBG, ma le versioni precedenti e i sistemi integrati potrebbero non esserlo .
- L'altro tipo è un'implementazione Java pura che utilizza un'implementazione RNG basata su SHA1 precedente, che non è così forte come gli algoritmi utilizzati dai meccanismi approvati DRBG.
Nel frattempo, la Guida per gli sviluppatori di Java 13 Security continua a leggere
Su Linux e macOS, se il dispositivo di raccolta entropia in java.security è impostato su file:/dev/urandom
o file:/dev/random
, NativePRNG è preferito a SHA1PRNG. Altrimenti, è preferito SHA1PRNG.
Per chiarire come i nuovi meccanismi DRBG giocano insieme ai PRNG precedenti, eseguo alcuni test su macOS (Darwin) con AdoptOpenJDK (build 13.0.2 + 8). Ecco i risultati:
file: / dev / random
Ordine di preferenza per i provider:
SecureRandom.NativePRNG
SecureRandom.DRBG
SecureRandom.SHA1PRNG
file: / dev / urandom
Ordine di preferenza per i provider:
SecureRandom.NativePRNG
SecureRandom.DRBG
SecureRandom.SHA1PRNG
file: / dev /./ urandom
Ordine di preferenza per i provider:
SecureRandom.DRBG
SecureRandom.SHA1PRNG
SecureRandom.NativePRNG
Conclusione:
Consiglio di utilizzare -Djava.security.egd=file:/dev/./urandom
per assicurarsi di sfruttare l' implementazione SecureRandom più potente disponibile indipendentemente dalla piattaforma utilizzata, evitando al contempo di bloccare il codice in modo imprevisto.