Domanda

Se si desidera un numero casuale crittograficamente forte in Java, utilizzare SecureRandom . Sfortunatamente, SecureRandom può essere molto lento. Se utilizza / dev / random su Linux, può bloccare l'attesa di una entropia sufficiente da costruire. Come evitare la penalità prestazionale?

Qualcuno ha usato Uncommon Maths come soluzione a questo problema?

Qualcuno può confermare che questo problema di prestazioni è stato risolto in JDK 6?

È stato utile?

Soluzione

Se vuoi veri dati casuali, sfortunatamente devi aspettarli. Ciò include il seme per un PRNG SecureRandom . La matematica non comune non può raccogliere dati casuali reali più velocemente di SecureRandom , sebbene possa connettersi a Internet per scaricare i dati seed da un determinato sito Web. Suppongo che è improbabile che questo sia più veloce di / dev / random dove è disponibile.

Se vuoi un PRNG, fai qualcosa del genere:

SecureRandom.getInstance("SHA1PRNG");

Le stringhe supportate dipendono dal provider SPI SecureRandom , ma puoi enumerarle utilizzando Security.getProviders () e Provider.getService () .

Sun ama SHA1PRNG, quindi è ampiamente disponibile. Non è particolarmente veloce come vanno i PRNG, ma i PRNG scricchioleranno semplicemente i numeri, non bloccheranno la misurazione fisica dell'entropia.

L'eccezione è che se non si chiama setSeed () prima di ottenere i dati, il PRNG eseguirà il seeding una volta la prima volta che si chiama next () o nextBytes () . Di solito lo farà usando una quantità abbastanza piccola di dati casuali reali dal sistema. Questa chiamata potrebbe essere bloccata, ma renderà la tua fonte di numeri casuali molto più sicura rispetto a qualsiasi variante dell'hash dell'ora corrente insieme al PID, aggiungi 27 e spera per il migliore ". Se tutto ciò di cui hai bisogno sono numeri casuali per un gioco, o se vuoi che lo stream sia ripetibile in futuro usando lo stesso seme a scopo di test, un seme insicuro è comunque utile.

Altri suggerimenti

Dovresti essere in grado di selezionare il più veloce ma leggermente meno sicuro / dev / urandom su Linux usando:

-Djava.security.egd=file:/dev/urandom

Tuttavia, questo non funziona con Java 5 e versioni successive ( Bug Java 6202721 ). La soluzione suggerita è di usare:

-Djava.security.egd=file:/dev/./urandom

(notare il /./ ) extra

Su Linux, l'implementazione predefinita per SecureRandom è NativePRNG (codice sorgente qui ), che tende ad essere molto lento. Su Windows, il valore predefinito è SHA1PRNG , che come altri hanno sottolineato, è possibile utilizzare anche su Linux se lo si specifica esplicitamente.

NativePRNG differisce da SHA1PRNG e Uncommons Maths ' AESCounterRNG in quanto riceve continuamente entropia dal sistema operativo (leggendo da / dev / urandom ). Gli altri PRNG non acquisiscono alcuna entropia aggiuntiva dopo la semina.

AESCounterRNG è circa 10 volte più veloce di SHA1PRNG , che IIRC è esso stesso due o tre volte più veloce di NativePRNG .

Se hai bisogno di un PRNG più veloce che acquisisca entropia dopo l'inizializzazione, vedi se riesci a trovare un'implementazione Java di Fortuna . Il PRNG di base di un'implementazione di Fortuna è identico a quello utilizzato da AESCounterRNG, ma esiste anche un sofisticato sistema di pooling di entropia e reseeding automatico.

Molte distribuzioni Linux (principalmente basate su Debian) configurano OpenJDK per usare / dev / random per entropia.

/ dev / random è per definizione lento (e può persino bloccare).

Da qui hai due opzioni su come sbloccarlo:

  1. Migliora l'entropia o
  2. Riduzione dei requisiti di casualità.

Opzione 1, Migliora l'entropia

Per ottenere più entropia in / dev / random , prova haveged demone. È un demone che raccoglie continuamente l'entropia di HAVEGE e funziona anche in un ambiente virtualizzato perché non richiede alcun hardware speciale, solo la CPU stessa e un clock.

Su Ubuntu / Debian:

apt-get install haveged
update-rc.d haveged defaults
service haveged start

Su RHEL / CentOS:

yum install haveged
systemctl enable haveged
systemctl start haveged

Opzione 2. Ridurre i requisiti di casualità

Se per qualche ragione la soluzione sopra non aiuta o non ti interessa la casualità crittograficamente forte, puoi invece passare a / dev / urandom , che è garantito per non bloccare.

Per farlo a livello globale, modifica il file jre / lib / security / java.security nella tua installazione Java predefinita per usare / dev / urandom (a causa di un altro < a href = "https://bugs.openjdk.java.net/browse/JDK-6202721" rel = "noreferrer"> bug deve essere specificato come /dev/./urandom).

In questo modo:

#securerandom.source=file:/dev/random
securerandom.source=file:/dev/./urandom

Quindi non dovrai mai specificarlo sulla riga di comando.


Nota: se si esegue la crittografia, è necessario una buona entropia. Caso in questione - problema PRNG Android ha ridotto la sicurezza dei portafogli Bitcoin.

Ho avuto un problema simile con il blocco delle chiamate a SecureRandom per circa 25 secondi alla volta su un server Debian senza testa. Ho installato il demone haveged per assicurarmi che / dev / random sia mantenuto pieno, su server senza testa è necessario qualcosa del genere per generare l'entropia richiesta. Le mie chiamate a SecureRandom ora forse impiegano millisecondi.

Se vuoi veramente "crittograficamente forte" casualità, quindi hai bisogno di una forte fonte di entropia. / dev / random è lento perché deve attendere che gli eventi di sistema raccolgano entropia (letture del disco, pacchetti di rete, spostamento del mouse, pressioni dei tasti, ecc.).

Una soluzione più veloce è un generatore di numeri casuali hardware. Potresti già averne uno integrato nella scheda madre; consulta la documentazione hw_random per istruzioni su come capire se ce l'hai, e come usarlo. Il pacchetto rng-tools include un demone che alimenterà l'entropia generata dall'hardware in / dev / random .

Se un HRNG non è disponibile sul tuo sistema e sei disposto a sacrificare la forza dell'entropia per le prestazioni, vorrai seminare un buon PRNG con i dati da / dev / random e lasciare che il PRNG svolge la maggior parte del lavoro. Esistono diversi PRNG approvati dal NIST elencati in SP800-90 che sono facili da implementare.

Esiste uno strumento (almeno su Ubuntu) che alimenterà la casualità artificiale nel tuo sistema. Il comando è semplicemente:

rngd -r /dev/urandom

e potresti aver bisogno di un sudo nella parte anteriore. Se non hai il pacchetto rng-tools, dovrai installarlo. Ci ho provato e sicuramente mi ha aiutato!

Fonte: matt vs world

Ho riscontrato lo stesso problema . Dopo aver cercato su Google i giusti termini di ricerca, mi sono imbattuto in questo simpatico articolo su DigitalOcean .

hasged è una potenziale soluzione senza compromettere la sicurezza.

Sto semplicemente citando la parte pertinente dall'articolo qui.

  

Basato sul principio HAVEGE e precedentemente basato sui suoi associati   libreria, hasged consente di generare casualità in base alle variazioni di   tempo di esecuzione del codice su un processore. Dal momento che è quasi impossibile per   un pezzo di codice per eseguire lo stesso tempo esatto per l'esecuzione, anche in   stesso ambiente sullo stesso hardware, i tempi di esecuzione di un singolo   o più programmi dovrebbero essere adatti per seminare una fonte casuale. Il   l'implementazione avanzata semina la fonte casuale del sistema (di solito   / dev / random) utilizzando le differenze nel contatore del timestamp del processore   (TSC) dopo aver eseguito ripetutamente un ciclo

Come installare l'hasged

Segui i passaggi in questo articolo. https: // www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged

L'ho pubblicato qui

Usa il random sicuro come sorgente di inizializzazione per un algoritmo ricorrente; potresti usare un twister di Mersenne per il lavoro di massa invece di quello in UncommonMath, che è in circolazione da un po 'e si è dimostrato migliore di altri prng

http://en.wikipedia.org/wiki/Mersenne_twister

Assicurati di aggiornare di tanto in tanto il casuale sicuro usato per l'inizializzazione, ad esempio potresti avere un casuale casuale generato per client, usando un generatore pseudo casuale di mersenne twister per client, ottenendo un grado di randomizzazione abbastanza alto

Usando Java 8, ho scoperto che su Linux la chiamata di SecureRandom.getInstanceStrong () mi avrebbe dato l'algoritmo NativePRNGBlocking . Questo spesso si bloccherebbe per molti secondi per generare qualche byte di sale.

Sono invece passato a chiedere esplicitamente NativePRNGNonBlocking e, come previsto dal nome, non è più bloccato. Non ho idea di quali siano le implicazioni di sicurezza di questo. Presumibilmente la versione non bloccante non può garantire la quantità di entropia utilizzata.

Aggiornamento : Ok, ho trovato questa eccellente spiegazione .

In poche parole, per evitare il blocco, utilizzare new SecureRandom () . Questo utilizza / dev / urandom , che non blocca ed è sostanzialmente sicuro come / dev / random . Dal post: " L'unica volta che vorresti chiamare / dev / random è quando la macchina si avvia per la prima volta e l'entropia non si è ancora accumulata " ;.

SecureRandom.getInstanceStrong () ti dà il RNG più forte in assoluto, ma è sicuro da usare solo in situazioni in cui un sacco di blocchi non ti influenzerà.

Il problema a cui hai fatto riferimento su / dev / random non è con l'algoritmo SecureRandom , ma con l'origine della casualità che utilizza. I due sono ortogonali. Dovresti capire quale dei due ti sta rallentando.

La pagina Matematica non comune che hai collegato menziona esplicitamente che non stanno affrontando la fonte di casualità.

Puoi provare diversi provider JCE, come BouncyCastle, per vedere se la loro implementazione di SecureRandom è più veloce.

Una breve search rivela anche patch Linux che sostituiscono l'impostazione predefinita implementazione con Fortuna. Non ne so molto di più, ma siete invitati a indagare.

Dovrei anche menzionare che mentre è molto pericoloso utilizzare un algoritmo SecureRandom e / o una casualità mal implementati, puoi creare il tuo provider JCE con un'implementazione personalizzata di SecureRandomSpi . Per ottenere la firma del tuo provider dovrai eseguire un processo con Sun, ma in realtà è piuttosto semplice; hanno solo bisogno che tu gli invii un modulo via fax in cui dichiari di essere a conoscenza delle restrizioni all'esportazione degli Stati Uniti sulle biblioteche crittografiche.

Non ho affrontato questo problema da solo, ma genererei un thread all'avvio del programma che tenta immediatamente di generare un seme, quindi muore. Il metodo che chiamate randoms si unirà a quel thread se è attivo, quindi la prima chiamata si blocca solo se si verifica molto presto nell'esecuzione del programma.

La mia esperienza è stata solo con l'inizializzazione lenta del PRNG, non con la generazione di dati casuali successivamente. Prova una strategia di inizializzazione più entusiasta. Dal momento che sono costosi da creare, trattalo come un singleton e riutilizzi la stessa istanza. Se c'è troppa contesa di thread per un'istanza, raggruppali o rendili thread-local.

Non scendere a compromessi sulla generazione di numeri casuali. Una debolezza compromette tutta la tua sicurezza.

Non vedo molti generatori basati su decadimento atomico COTS, ma ci sono diversi piani là fuori per loro, se hai davvero bisogno di molti dati casuali. Un sito che ha sempre cose interessanti da guardare, tra cui HotBits, è Fourmilab di John Walker.

Sembra che dovresti essere più chiaro riguardo ai tuoi requisiti RNG. Il requisito crittografico di RNG più forte (a quanto ho capito) sarebbe che anche se si conosce l'algoritmo utilizzato per generarli e si conoscono tutti i numeri casuali generati in precedenza, non è possibile ottenere informazioni utili su nessuno dei numeri casuali generati nel futuro, senza spendere una quantità impraticabile di potenza di calcolo.

Se non hai bisogno di questa piena garanzia di casualità, probabilmente ci sono compromessi prestazionali appropriati. Vorrei essere d'accordo con la risposta di Dan Dyer su AESCounterRNG di Uncommons-Maths o Fortuna (uno dei suoi autori è Bruce Schneier, un esperto di crittografia). Nemmeno io l'ho mai usato, ma le idee sembrano affidabili a prima vista.

Vorrei pensare che se potessi generare periodicamente un seme casuale iniziale (ad esempio una volta al giorno o all'ora o altro), potresti utilizzare un codice di flusso veloce per generare numeri casuali da blocchi successivi del stream (se il codice di flusso utilizza XOR, passa semplicemente un flusso di valori null o prendi direttamente i bit XOR). Il progetto eStream contiene molte buone informazioni tra cui parametri di riferimento delle prestazioni. Ciò non manterrebbe l'entropia tra i punti nel tempo in cui lo si riempie, quindi se qualcuno conoscesse uno dei numeri casuali e l'algoritmo che hai usato, tecnicamente potrebbe essere possibile, con molta potenza di calcolo, rompere il codice di flusso e indovina il suo stato interno per essere in grado di prevedere i numeri casuali futuri. Ma dovresti decidere se quel rischio e le sue conseguenze sono sufficienti per giustificare il costo di mantenimento dell'entropia.

Modifica: ecco alcune note sul corso crittografico su RNG Ho trovato sulla rete un aspetto molto rilevante per questo argomento.

Se il tuo hardware lo supporta, prova utilizzando Java RdRand Utility di cui sono l'autore .

Si basa sull'istruzione Intel RDRAND ed è circa 10 volte più veloce di SecureRandom e non presenta problemi di larghezza di banda per l'implementazione di grandi volumi.


Nota che questa implementazione funziona solo su quelle CPU che forniscono le istruzioni (cioè quando è impostato il flag del processore rdrand ). È necessario creare un'istanza esplicita tramite il costruttore RdRandRandom () ; non è stato implementato alcun provider specifico.

Qualcos'altro da guardare è la proprietà securerandom.source nel file lib / security / java.security

Potrebbe esserci un vantaggio in termini di prestazioni nell'uso di / dev / urandom piuttosto che / dev / random. Ricorda che se la qualità dei numeri casuali è importante, non scendere a compromessi che rompono la sicurezza.

Puoi provare il progetto Math commons di Apache, che ha alcune implementazioni di algoritmi ben noti:

https://commons.apache.org/proper/commons- math / userguide / random.html

Tuttavia, fai attenzione alle prestazioni. Il costruttore predefinito di RandomDataGenerator crea un'istanza dedicata di Well19937c , un'operazione molto costosa.

Secondo la documentazione, questa classe non è protetta da thread, ma se puoi garantire che solo un thread accederà a questa classe, puoi inizializzare solo un'istanza per thread.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top