JD's Blog: no, Scrubs non c'entra proprio niente.

Generare password casuali da console

Tango TerminalMi è capitato diverse volte di avere la necessità di generare una password casuale e in passato la soluzione più veloce che utilizzavo di solito era digitare in Google “random password generator”. Questa soluzione però oltre ad essere scomoda (richiede una connessione ad internet ed un browser web) non è neanche molto sicura.
In Ubuntu, e in genere in qualunque altra distribuzione GNU/Linux, esistono metodi molto più sicuri e pratici per generare una password.

Il più comodo e veloce consiste nell’installare il pacchetto pwgen:

sudo apt-get install pwgen

Questo software permette di generare password facili da ricordare, pur mantenendo alto il livello di sicurezza. Se invece non interessa generare password facilmente memorizzabili e si preferisce avere delle password completamente random si può utilizzare l’opzione -s. Sono presenti molte altre opzioni che permettono ad esempio di evitare caratteri simili (1 e l, 0 e O) e di impostare la lunghezza e il numero delle password generate. Per l’elenco di tutte le opzioni disponibili consiglio la lettura della manpage di pwgen:

man pwgen

Se non è possibile/non si vuole installare il pacchetto pwgen è possibile generare delle buone password casuali sfruttando i tools messi a disposizione dalla console.

Ad esempio per generare 4 password di 8 caratteri alfanumerici sarà sufficiente digitare in un terminale la seguente stringa:

cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 4

Per aumentare il livello di sicurezza della password è possibile aggiungere altri caratteri non alfanumerici, come ad esempio _!@#$%^&*()+[]|:<>?=:

cat /dev/urandom | tr -dc 'a-zA-Z0-9-_!@#$%^&*()+[]|:<>?=' | fold -w 8 | head -n 4

Se si vuole essere sicuri che la password contenga almeno un carattere speciale è necessario aggiungere un grep al comando precedente:

cat /dev/urandom | tr -dc 'a-zA-Z0-9-_!@#$%^&*()+[]|:<>?=' | fold -w 8 | grep -i '[_!@#$%^&*()+|:<>?=]' | head -n 4

Perché urandom al posto di random?

Qualcuno potrebbe domandarsi perché utilizzo il “meno sicuro” urandom al posto di random. Prima di spiegare il motivo riporto la manpage dei due dispositivi kernel:

I file speciali a caratteri /dev/random e /dev/urandom (presenti sin da
Linux 1.3.30) forniscono un'interfaccia al  generatore  del  kernel  di
numeri aleatori. Il file /dev/random ha numero primario 1 e numero sec‐
ondario 8. Il file /dev/urandom ha numero primario 1  e  numero  secon‐
dario 9.

Il  generatore  di numeri aleatori raccoglie rumore di fondo dai device
driver e da altre sorgenti nel pozzo d'entropia. Il generatore mantiene
anche  una  stima del numero di bit di rumore nel pozzo di entropia. Da
questo pozzo di entropia vengono creati i numeri aleatori.

Quando viene letto, /dev/random restituisce  solo  un  numero  di  byte
aleatori  compatibili  con  la  stima  dei  bit  di  rumore  nel  pozzo
d'entropia. /dev/random dovrebbe essere adatto ad usi che richiedono un
alto  grado  di  aleatorietà,  come la generazione di chiavi. Quando il
pozzo d'entropia è vuoto, le letture di  /dev/random  vengono  bloccate
finché non viene raccolto abbastanza rumore ambientale.

Quando  viene letto, /dev/urandom restituisce tanti byte quanti ne sono
stati richiesti. Di conseguenza, se non  c'è  abbastanza  entropia  nel
pozzo  d'entropia, i valori restituiti sono teoricamente vulnerabili ad
un attacco criptografico sull'algoritmo usato  dal  dispositivo.  Nella
letteratura  (non coperta da segreto militare) non c'è conoscenza di un
metodo per fare ciò, ma è in teoria  possibile  che  esista  un  simile
metodo.  Se questo è fonte di problemi per il proprio programma, si usi
invece /dev/random.

Leggendo la manpage si intuisce che urandom è più veloce perché «restituisce tanti byte quanti ne sono stati richiesti» a discapito del grado di aleatorietà, ma quanto è più veloce? Scopriamolo con un test pratico.

Prima proviamo a generare una password di 10 caratteri sfruttando urandom:

$ time cat /dev/urandom | tr -dc 'a-zA-Z0-9-_!@#$%^&*()+{}|:<>?=' | fold -w 10 | grep -i '[!@#$%^&*()_+{}|:<>?=]' | head -n 1
bzNHI}6w:h

real    0m0.024s
user    0m0.004s
sys 0m0.024s

E ora facciamo la stessa cosa con random:

$ time cat /dev/random | tr -dc 'a-zA-Z0-9-_!@#$%^&*()+{}|:<>?=' | fold -w 10 | grep -i '[!@#$%^&*()_+{}|:<>?=]' | head -n 1
^C

real    131m14.400s
user    0m0.012s
sys 0m0.036s

La differenza è abissale: urandom ha impiegato solamente 24 millesimi di secondo (0.024 secondi) mentre random dopo 2 ore 11 minuti e 14 secondi non aveva ancora terminato! Ho interrotto manualmente con un CTRL+C. E il test non è stato fatto su un 486SX a 25MHz, ma su un Intel Core2 Quad Processor Q9450.
Considerando che «nella letteratura (non coperta da segreto militare) non c’è conoscenza di un metodo» per effettuare un attacco criptografico sui valori generati da urandom, mi sento di consigliare urandom per la generazione di password :).