La lettura da / dev / random non produce alcun dato


19

Uso spesso il comando

cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' | head --bytes 32

per generare password pseudo-casuali. Questo non funziona con /dev/random.

In particolare

  • cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' produce output
  • cat /dev/random | strings --bytes 1 produce output
  • cat /dev/random | strings --bytes 1 | tr -d '\n\t ' non produce output

NB: durante l'utilizzo /dev/randompotrebbe essere necessario spostare il mouse o premere i tasti (ad es. Ctrl, shift, ecc.) Per generare entropia.

Perché l'ultimo esempio non funziona? Ha truna sorta di grande buffer interno che si /dev/urandomriempie rapidamente ma /dev/randomnon lo fa?

PS sto usando CentOS 6.5

cat /proc/version
Linux version 2.6.32-431.3.1.el6.x86_64 (mockbuild@c6b10.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) ) #1 SMP Fri Jan 3 21:39:27 UTC 2014

qual è la tua distribuzione, la tua versione del kernel? su Cygwin entrambi restituiscono valori.
Kiwy,

@Kiwy Vedi modifica.
Aaron J Lang,

1
Sai pwgen, in particolare pwgen -s?
MvG,

2
L' -sinterruttore li rende meno memorabili, più veramente casuali. @Boyd: è makepasswd ampiamente disponibili al di là delle distribuzioni basate su Debian? Per come la vedo io, pwgen è disponibile per CentOS mentre makepasswd non lo è .
MvG,

1
@BoydStephenSmithJr. Concordo con @ MvG che makepasswdnon è disponibile sulla mia piattaforma, grazie comunque
Aaron J Lang

Risposte:


27

Alla fine lo farà.

Nel:

cat /dev/random | strings --bytes 1 | tr -d '\n\t '

cat non sarà mai buffer, ma è comunque superfluo in quanto non c'è nulla da concatenare qui.

< /dev/random strings --bytes 1 | tr -d '\n\t '

stringstuttavia, poiché la sua uscita non è più un terminale bufferizzerà la sua uscita per blocchi (di qualcosa come 4 o 8kB) rispetto alle linee quando l'uscita va su un terminale.

Quindi inizierà a scrivere su stdout solo dopo aver accumulato 4kB di caratteri per l'output, il che /dev/randomimpiegherà un po 'di tempo.

trl'output va a un terminale (se lo stai eseguendo al prompt della shell in un terminale), quindi bufferizzerà il suo output in linea. Poiché stai rimuovendo il \n, non avrà mai una riga intera da scrivere, quindi scriverà non appena sarà stato accumulato un blocco completo (come quando l'uscita non va su un terminale).

Quindi, trè probabile che non scriva nulla fino a quando non stringsha letto abbastanza da /dev/randomscrivere 8kB (2 blocchi forse molto di più) di dati (poiché il primo blocco conterrà probabilmente qualche carattere di nuova riga o tab o spazio).

Su questo sistema ci sto provando, posso ottenere una media di 3 byte al secondo da /dev/random(invece di 12MiB on /dev/urandom), quindi nel migliore dei casi (i primi 4096 byte /dev/randomsono tutti stampabili), siamo parlare 22 minuti prima trinizia a produrre qualcosa. Ma è più probabile che siano ore (in un test rapido, posso vedere la stringsscrittura di un blocco ogni 1 o 2 blocchi letti, e i blocchi di output contengono circa il 30% dei caratteri di nuova riga, quindi mi aspetto che debba leggere almeno 3 blocchi prima trha 4096 caratteri da emettere).

Per evitarlo, potresti fare:

< /dev/random stdbuf -o0 strings --bytes 1 | stdbuf -o0 tr -d '\n\t '

stdbuf è un comando GNU (trovato anche su alcuni BSD) che altera il buffering stdio dei comandi tramite un trucco LD_PRELOAD.

Si noti che invece di strings, è possibile utilizzare tr -cd '[:graph:]'che escluderà anche tab, newline e spazio.

Potresti voler correggere anche le impostazioni locali per Cevitare possibili sorprese future con i caratteri UTF-8.


wow spiegazione impressionante.
Kiwy,

2
Sorprendente! Grande spiegazione e soluzione. Ho sempre usato cat'inutilmente' perché non mi è mai piaciuto reindirizzare lo stdin alla fine di una pipeline, ora posso 'salvare un processo' e avere ancora comandi leggibili. La mia soluzione finale fu< /dev/random stdbuf -o0 tr -Cd '[:graph:]' | stdbuf -o0 head --bytes 32
Aaron J Lang,

@AaronJLang, aspetto positivo [:graph:]. Me ne ero dimenticato.
Stéphane Chazelas,

@AaronJLang, non hai bisogno del stdbufper a head -c32meno che tu non voglia permettergli di scrivere i dati non appena li ha (come in diversi blocchi invece di un pezzo da 32 byte non appena li ha)
Stéphane Chazelas

2
Secondo me, / dev / urandom è ampiamente sufficiente per l'uso dell'autore. Se qualcuno fosse curioso di sapere come, nello specifico, urandom funzioni rispetto a random, suggerirei di leggere i commenti nella parte superiore del driver in drivers / char / random.c dell'albero dei kernel. I commenti menzionano un'analisi del PRNG e della sua implementazione. Spero che questo articolo risponda alla domanda "quanto è più o meno casuale un casuale rispetto al casuale?" Disponibile qui: eprint.iacr.org/2012/251.pdf
etherfish

5

La generazione di numeri casuali per molte applicazioni di sicurezza richiede un'entropia sufficiente: l'entropia misura l'imprevedibilità della casualità. Un processore deterministico non può generare entropia, quindi l'entropia deve provenire dall'esterno - da un componente hardware con un comportamento non deterministico, o da altri fattori che sono sufficientemente difficili da riprodurre, come i tempi delle azioni dell'utente (è qui che si agita il mouse entra). Una volta disponibile un'entropia sufficiente, la crittografia può essere utilizzata per generare un flusso praticamente illimitato di numeri casuali.

Linux funziona accumulando entropia in un pool, quindi usando la crittografia per produrre numeri casuali accettabili sia attraverso /dev/randomche /dev/urandom. La differenza è che /dev/randomapplica un calcolo entropico estremamente conservativo che riduce la stima dell'entropia nel pool per ogni byte che genera, mentre /dev/urandomnon riguarda la quantità di entropia nel pool.

Se la stima dell'entropia nel pool è troppo bassa, si /dev/randomblocca fino a quando è possibile accumulare più entropia. Ciò può compromettere gravemente la velocità con cui /dev/randompuò produrre output. Questo è ciò che stai osservando qui. Non ha nulla a che fare con tr; ma stringslegge l'output con il buffering, quindi deve leggere un buffer completo (pochi KB) /dev/randomsolo per produrre almeno un byte di input.

/dev/urandomè perfettamente accettabile per generare una chiave crittografica , perché l'entropia non diminuisce in alcun modo percettibile. (Se mantieni la tua macchina in funzione più a lungo di quanto non esistesse l'universo, non puoi trascurare queste considerazioni, ma per il resto stai bene.) C'è solo un caso in cui /dev/urandomnon va bene, che si trova su un sistema appena installato che non ha non ha ancora avuto il tempo di generare entropia o un sistema appena avviato che si avvia da supporti di sola lettura.

L'eliminazione stringsdalla catena di avvio probabilmente accelererà il processo. Di seguito trverranno filtrati i caratteri non stampabili:

</dev/random LC_ALL=C tr -dc '!-~'

Ma puoi usarlo /dev/urandomqui , fintanto che fai attenzione a non generare password su un sistema che non ha avuto il tempo di accumulare abbastanza entropia. È possibile controllare il livello del pool di entropia di Linux /proc/sys/kernel/random/entropy_avail(se si utilizza /dev/random, la figura in questo file sarà conservativa, forse molto).


1

Dovresti usare /dev/urandomper ottenere numeri casuali (pseudo) di alta qualità e /dev/randomsolo quando hai assolutamente bisogno di numeri casuali che sono davvero imprevedibili. Un utente malintenzionato di seguito le risorse della NSA avrà molto tempo difficile da rompere /dev/urandom(e non dimenticare di gomma tubo di crittografia ). Il kernel riempie un buffer di byte "veramente casuali", questo è ciò che /dev/randomdà. Purtroppo la velocità con cui vengono generati è bassa, quindi la lettura molto da da /dev/random si bloccherà in attesa di casualità.

Potresti prendere in considerazione l'uso di random.org o il suo generatore di password , o uno dei tanti, molti generatori di password casuali che fluttuano intorno, dai un'occhiata ad esempio a questa pagina per alcuni suggerimenti da riga di comando (non che consiglierei tutti , ma dovrebbero darti idee), oppure potresti usare qualcosa del genere mkpasswd(1)(qui su Fedora 19 parte di expect-5.45-8.fc19.x86_64).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.