<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>bruteforce &amp;mdash; Cyberdyne Systems</title>
    <link>https://noblogo.org/aytin/tag:bruteforce</link>
    <description>&#34;Fare o non fare. Non c&#39;è provare!&#34;</description>
    <pubDate>Thu, 30 Apr 2026 07:19:37 +0000</pubDate>
    <item>
      <title>Archiviare le password in sicurezza con KDF/password-hashing (Trilogia Della Password - 3 di 3)</title>
      <link>https://noblogo.org/aytin/archiviare-le-password-in-sicurezza-con-kdf-password-hashing-trilogia-della</link>
      <description>&lt;![CDATA[password hashing&#xA;&#xA;Dopo aver capito come creare password inviolabili anche avendo a disposizione tutta l&#39;energia termica dell&#39;universo, pensiamo al modo migliore per archiviarle.&#xA;&#xA;Pensare di lasciare la password raw in un database, rappresenta un grosso rischio in virtù di un possibile attacco offline.&#xA;!--more--&#xA;&#xA;Rainbow Table&#xA;Come ti blocco la Rainbow Table: Il “Salt” (sale)&#xA;Il livello successivo: Il Pepper&#xA;Final step: L’hashing&#xA;  PBKDF2&#xA;  Bcrypt&#xA;  Scrypt&#xA;  yescrypt&#xA;  Argon2&#xA;Un piccolo esempio: hashing di una password con Argon2&#xA;Gestione del pepper&#xA;HSM&#xA;Key / Algo Rotation&#xA;  Caso A: Algo rotation&#xA;  Caso B: Pepper rotation&#xA;&#xA;Una prima linea di difesa consiste nel memorizzare il digest della password, una stringa alfanumerica univoca generata da un apposito algoritmo, così da lasciare nelle mani dell&#39;attaccante degli oggetti che, per la loro non invertibilità, non permettono di risalire alle password.&#xA;&#xA;La scelta dell&#39;algoritmo di hashing diventa critica al fine di scongiurare altri tipi di attacchi. Ad es. SHA-256, pur essendo ottimo e molto efficiente per il digest e la firma anche di file di grandi dimensioni, mostra il fianco, proprio in virtù della sua velocità, nel caso di attacchi con:&#xA;&#xA;brute-force: si calcola l’hash di password casuali fino a trovare una corrispondenza,&#xA;dizionario: un&#39;alternativa intelligente alla forza bruta. Si punta alle password più comuni, si calcola l&#39;hash e si controlla se c&#39;è corrispondenza.&#xA;Rainbow Table: l&#39;attacco al dizionario più insidioso di tutti&#xA;&#xA;Oltre al fatto che, la funzione di hashing , essendo deterministica, permette di capire chi sono gli utenti che hanno la stessa password, dal momento che avranno lo stesso digest.&#xA;Rainbow Table&#xA;Una Rainbow Table è un enorme dizionario pre-calcolato che contiene:&#xA;&#xA;Milioni di password comuni.&#xA;Il relativo hash corrispondente.&#xA;&#xA;Invece di calcolare l’entropia di ogni tentativo, l’attaccante ruba il database degli hash e fa un semplice “Cerca e Trova”. Se l’hash della tua password è nella tabella, la tua password è violata in millisecondi, indipendentemente da quanto fosse alta la sua entropia teorica.&#xA;&#xA;smallOss.: Una password totalmente casuale, generata da un CSPRNG affidabile, con un&#39;alta entropia (  120), rimarrebbe comunque inviolabile anche dalla rainbow table perché la probabilità che quella password si trovi nel dizionario, sarebbe equivalente ad indovinarla./small&#xA;Come ti blocco la Rainbow Table: Il “Salt” (sale)&#xA;Per rendere inutili le Rainbow Table, i sistemi sicuri utilizzano il Salt. Il salt è una stringa di dati casuali (generati da una sorgente d’entropia affidabile ovviamente) che viene aggiunta alla password prima di calcolarne il digest.&#xA;&#xA;In questo modo le rainbow table vengono vanificate perché gli hash precalcolati sulle password raccolte, mancando il salt, non valgono più. Anche se due utenti avessero la stessa password, avrebbero degli hash completamente diversi.&#xA;&#xA;Anche per questo motivo non è un problema che il salt sia pubblico, perché il suo obiettivo non è nascondere quello che è un pezzetto di password a tutti gli effetti, ma di impedire economie di scala degli attacchi perché, pur potendo disporre offline di un database di decine di milioni di utenti, gli hash della mia Rainbow Table (che può arrivare a pesare anche decine di GB) andrebbero tutti ricalcolati per ogni utente, con un costo computazionale e di archiviazione inimmaginabile.&#xA;&#xA;Per riassumere, gli ingredienti di base sono:&#xA;&#xA;una buona sorgente d’entropia: una fonte di casualità certificata per generare un salt unico;&#xA;entropia della password: sempre buona norma, ove possibile, come sappiamo ormai fare (https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di). Evita attacchi brute-force o al dizionario in cui l’attaccante prova a indovinare;&#xA;salt: protegge la password dagli attacchi basati su database pre-calcolati (Rainbow Table).&#xA;&#xA;Il livello successivo: Il Pepper&#xA;È vero che col salt andiamo a complicare lo sfruttamento di un attacco offline ma possiamo fare di meglio.&#xA;&#xA;Il punto d&#39;attenzione è che il salt protegge le password di tutti gli utenti.&#xA;Ma un attaccante potrebbe non essere affatto interessato a violare ogni singolo utente (niente economia di scala) ma solo alcuni. E allora l&#39;attacco attraverso Ranbow Table potrebbe essere di nuovo praticabile.&#xA;&#xA;Ma gli informatici sono dei gran giocherelloni, si sa.&#xA;Visto che abbiamo già il &#34;sale&#34;, perché non finire aggiustando con un po’ di “pepe”? Detto, fatto!&#xA;&#xA;Il pepper, come il salt, è un&#39;altra password generata con gli stessi criteri del salt ma le analogie finiscono qua perché:&#xA;&#xA;a differenza del salt che si trova nel database, il pepper è separato da ques&#39;ultimo. L&#39;ideale sarebbe un HSM;&#xA;Il salt è visibile a tutti, attaccante compreso. Il pepper è segreto. Un eventuale data breach che permette all&#39;attaccante di disporre offline di tutto il database degli utenti, &#34;vedrà&#34; certamente gli eventuali salt ma sarà ignaro del fatto che gli mancherà sempre un pezzo di chiave;&#xA;il salt è diverso per ogni utente, il pepper, di solito, è unico;&#xA;il salt serve a rendere uniche la password degli utenti, il pepper protegge l&#39;intero database da attacchi offline.&#xA;&#xA;Il pepper è la chiave di un HMAC, o di un meccanismo di cifratura simmetrica, applicato al digest della password (che ricordo essere salt+password in realtà), che sarà ciò che verrà archiviato.&#xA;&#xA;Va detto che l&#39;uso del &#34;pepper&#34; complica ulteriormente lo scenario di archiviazione.&#xA;Nella stragrande maggioranza dei casi è sufficiente scegliere un buon algoritmo di password hashing (vedi paragrafo successivo) per scoraggiare gli attaccanti.&#xA;&#34;Pepare&#34; le password prevederebbe, come detto sopra, l&#39;uso di un HSM per es, e tutta una serie di riflessioni di contorno che evidenzierò più avanti.&#xA;Final step: L&#39;hashing&#xA;L&#39;ultimo punto da dettagliare è l&#39;hash della password.&#xA;&#xA;L&#39;hash crittografico, in uso in questi casi, deve soddisfare le seguenti proprietà:&#xA;&#xA;resistenza alla pre-immagine: dato un hash h, deve essere impossibile trovare una password p t.c. H(p) = h (non invertibilità della funzione hash)&#xA;resistenza alla pre-immagine secondaria: dato una password psub1/sub, deve essere impossibile trovare un&#39;altra password psub2/sub t.c. H(psub1/sub) = H(psub2/sub) (resistenza debole alle collisioni)&#xA;resistenza alle collisioni: è impossibile trovare due password diverse, psub1/sub e psub2/sub, t.c. H(psub1/sub) = H(psub2/sub) (resistenza forte alle collisioni)&#xA;effetto valanga: il cambio di un solo bit della password deve cambiare radicalmente l&#39;intero hash&#xA;&#xA;In un sistema moderno, l&#39;hash non può essere delegato a funzioni di tipo SHA perché nascono per altri compiti,&#xA;&#xA;SHA-2 e SHA-3 nascono per il digest veloce, per verificare l&#39;integrità di file anche molto grossi o firmare documenti. La loro eccellente velocità diventa il loro più grosso difetto quando si parla di password.&#xA;Negli scenari precedenti di attachi offline, l&#39;hacker che dispone di una grossa potenza di calcolo, può ricostituire velocemente le rainbow table per n utenti. Magari non di tutti ma di quelli attenzionati.&#xA;&#xA;Le funzioni di derivazione della chiave (KDF) come pbkdf2 e quelle ancora più estreme come B/Scrypt, Argon2, oltre che soddisfare tutti i punti precedentemente elencati tipici di funzioni di password hashing, sono progettate per essere computazionalmente pesantissime da calcolare perché il loro scopo non è il digest ma la protezione di un segreto contro il brute-force.&#xA;E mentre le vecchie KDF come pbdfk2 sono CPU bound, ma non GPU bound, le KDF più moderne come Bcrypt, Scrypt ma soprattutto Argon2, agiscono pesantemente su tempo, memoria e parallelismo e l&#39;attacco offline di cui sopra diventa impraticabile.&#xA;PBKDF2&#xA;È il decano delle KDF. Applica iterativamente una funzione pseudorandomica, come HMAC con uno SHA, con salt alla password.&#xA;Il conteggio delle iterazioni è un parametro configurabile.&#xA;&#xA;PBDKF2 è uno standard di lunga data ampiamente adottato. Se non ci sono necessità stringenti di sicurezza o requisiti legacy, è una buona scelta.&#xA;&#xA;Il fatto di essere solo CPU bound però non la rende la scelta ideale in scenari dove gli attaccanti possono attingere a risorse di calcolo considerevoli&#xA;Bcrypt&#xA;Basato su Blowfish, anche Bcrypt usa un hash crittografico sulla password con parametri il salt e un fattore di costo.&#xA;&#xA;Il fattore di costo aumenta esponenzialmente il numero di iterazioni per adattarsi all&#39;aumento di potenza di calcolo dell&#39;hardware.&#xA;&#xA;Bcrypt è stato progetto per essere lento e resistente a semplici attacchi di forzat bruta.&#xA;Tuttavia, il basso utilizzo di ram richiesto dal calcolo lo rendono poco resistente ad attacchi sferrati usando hardware specializzato.&#xA;&#xA;Bcrypt ha dalla sua una storia solidissima in ragione della quale da 20 anni a questa parte non sono state trovate vulnerabilità critiche nel suo design.&#xA;&#xA;Per questo motivo Bcrypt cifra le password di sistema di OpenBSD dal 1999, come pure ha cifrato quelle di tante distro Linux per anni, prima che passassero ad Argon2 o yescrypt (default di Fedora).&#xA;&#xA;Domina nei framework web (\[Python\] Django, \[Ruby\] Ruby on Rails, \[PHP\] Laravel), \[Java\] Spring, Node.js), nelle applicazioni (Ansible / Terraform, Docker), nel web (la cifratura in .htpasswd di Apache e Nginx) visto che la sua semplcitià di implementazione gli ha permesso di trovarsi praticamente in ogni linguaggio.&#xA;&#xA;È presente come alternativa anche nei password manager benché molti di essi abbiano spostato il default verso Argon2 o PBKDF2 per conformità agli standard FIPS.&#xA;&#xA;È molto semplice implementare e anche da usare perché bisogna agire solo sul fattore di costo (consigliato almeno 10-12, altrimenti diventa troppo vulnerabile ad attacchi sferrati attraverso la GPU)&#xA;Scrypt&#xA;Rilasciato nel 2009, Scrypt è stato il primo algoritmo a introdurre il concetto di Memory Hardness ed è stato progettato per rendere economicamente poco conveniente il ricorso ad hardware specializzato come gli ASIC o i FPGA e incidere pesantemente su CPU, ram e parallelismo.&#xA;&#xA;Il suo alveo principale sono state le cripto-valute, molte monete lo usano per il mining.&#xA;&#xA;Scrypt lo troviamo in quasi tutti i linguaggi di programmazione, in Tarsnap, servizio di baclup online creato dallo stesso autore di Scrypt, è stato usato da LastPass ed è presente come opzione in VeraCrypt per derivare la chiave dalla password.&#xA;Fino ad Android 9 era l&#39;algoritmo usato per la FDE del dispositvio (passato poi al FBE) .&#xA;Presente anche su FreeBSD come opzione per la cifratura delle password di sistema e come opzione su LUKS per la cifratura degli slot delle chiavi.&#xA;&#xA;Su Scrypt i parametri da configurare sono:&#xA;&#xA;Costro CPU/Memoria (N): un parametro che aumenta i costi computazionali di cpu e memoria&#xA;DImensione del blocco (R): influenza la larghezza di banda della memoria&#xA;Parallelizzazione (p): indica quanto deve incidere sul calcolo parallelo&#xA;&#xA;In questo modo riesce ad essere sia CPU bound che GPU bound che, a differenza di Bcrypt, lo rende resistente anche ad attacchi facenti uso di hardware specializzato..&#xA;&#xA;Di contro, in ambiente in cui siamo vincolati dalle risorse disponibili, la sua potenza diventa un fattore limitante.&#xA;Quasi paragonabile ad Argon2 in quanto a robustezza, il suo unico tallone d&#39;Achille è la permeabilità ad attacchi di tipo side-channel. &#xA;yescrypt&#xA;Piccola menzione per yescrypt, appartenente alla famiglia &#34;Scrypt&#34;, pensato per essere ancora più resistente di Scrypt agli attacchi GPU e FPGA ma con una gestione più intelligente delle risorse.&#xA;&#xA;Grazie alle sue peculiarità, di fatto, è diventato il successore spirituale di Bcrypt nei sistemi operativi gnu/linux dove, a cominciare da Fedora, passando per Debian, Ubuntu, Arch, Kali, è il default per la cifratura delle password di sistema in /etc/shadow.&#xA;&#xA;È talmente incardinato ormai nei sistemi operativi, che è la libreria libxcrypt di yescrypt a gestire la tipica funzione crypt() di C che è la base della crittografia su tutti i sistemi gnu/linux moderni.&#xA;&#xA;La sua robustezza unita alla gestione intelligente delle risorse lo rende un coltellino svizzero di riferimento utile per es. per versione custom di LUKS su sistemi embedded, che magari fanno uso di cpu meno recenti,  oppure come opzione per strumenti di backup specialistici&#xA;&#xA;Di fatto, sui sistemi operativi, yescrypt s&#39;è guadagnato un consenso amplissimo dovuto alla sua scalabilità, alla sua capacità di usare anche la ROM per rendere il cracking ancora più difficile e senza pesare sulla RAM e alla sua compatibilità potendosi inserire perfettamente nella storica funzione crypt() di C come detto prima.&#xA;&#xA;Se Argon2 è il vincitore accademico avendo vinto il Password Hashing Competition del 2015, yescrypt per la sua robustezza, efficienza e flessibilità si ritaglia un profilo di indispensabilità nei sistemi operativi,&#xA;Argon2&#xA;E veniamo al dominatore indiscusso di questa che non è una llista esaustiva di KDF.&#xA;&#xA;Argon2 è LO standard moderno per il password hashing raccomandato da OWASP e IETF.&#xA;&#xA;È il riferimento per praticamente ogni password manager: Bitwarden, KeppasXC, 1Password, a cui assegnanp la protezione della Master Password&#xA;&#xA;È la scelta principale per la cifratura degli hard disk anche con impostazioni molto aggressive, in ragione delle quali un ritardo di mezzo secondo (un tempo enorme se venisse scalato esponenzialmente) nell&#39;apertura di un HD è assolutamente accettabile.&#xA;È il default di LUKS2 (LUKS1 usava PBKDF2) e di VeraCrypt, con cui ha sostituito SHA-512.&#xA;&#xA;Come Bcrypt, è implementato estensivamente su praticamente ogni frameword web e backend, da PHP, Django (Python), Laravel fino a Node.js.&#xA;&#xA;Nei sistemi operativi, laddove yescrytpt domina nella gestione delle password utente, Argon2 è usato per compiti più critici.&#xA;Dal kernel Linux per gestire internamente le chiavi crittografiche o da macOS / iOS, dove algoritmi proprietari ispirati fortemente ad Argon2, proteggono i dati nel Secure Enclave.&#xA;&#xA;Argon2  setta 3 parametri principali per regolare la sua forza:&#xA;&#xA;t: iterazioni, quante volte vengono rimescolati i dati (default Bitwarden = 3)&#xA;m: memoria, quanta ram deve occupare il calcolo. Questa è la misura anti-GPU (default Bitwarden = 16 (64MB))&#xA;p: parallelismo, quanti core della cpu usare. Questa è la misura anti-CPU (default Bitwarden = 4)&#xA;&#xA;La variante id è anche resistente agli attacchi side-channel perché impediscono a un attaccante di capire la password osservando i tempi di accesso alla memoria.&#xA;&#xA;Un piccolo esempio: hashing di una password con Argon2&#xA;Il grosso vantaggio degli algoritmi di kdf è che sono naturalmente resilienti rispetto all&#39;evoluzione tecnologica che produce macchine con sempre maggiore potenza di calcolo.&#xA;Da pbkdf2 in poi, il salt implicito che invalida le rainbow table precalcolate e la possibilità di calibrare il key stretching in moda da agire intensivamente su ram e cpu, permettono all&#39;algoritmo di adeguarsi per conservare la sua robustezza.&#xA;&#xA;Mini-script per l&#39;hashing di una password fornita dall&#39;utente con argon2 settato al default di Bitwarden:&#xA;echo -n &#34;Password: &#34;; read -s PASSWORD&#xA;Genero un Salt casuale di 128 bit&#xA;SALT=$(openssl rand -base64 128)&#xA;PASSWORDHASH=$(echo &#34;${PASSWORD}&#34; | argon2 &#34;${SALT}&#34; -m 16 -t 3 -p 4 -id -e)&#xA;&#xA;PASSWORDHASH e SALT sono i dati che verranno archiviati e, poiché argon2 &#34;frulla&#34; la password con un salt, è praticamente impossibile risalire alla password originale.&#xA;&#xA;La verifica è tuttavia banale perché, avendo il salt e la password da verificare, si ricrea l&#39;hash con argon2 e si confronta con l&#39;hash memorizzato.&#xA;&#xA;Per maggior sicurezza salt e digest possono essere memorizzati in punti differenti. L&#39;importante è che possano essere recuperate a partire dall&#39;utente.&#xA;Gestione del pepper&#xA;Col pepper le cose cambiano un pochino perché:&#xA;&#xA;deve essere archiviato con tutte le paranoie possibili in un punto diverso dal database degli utenti&#xA;il key rotation del pepper non è banale&#xA;&#xA;Mini-script che mostra come applicare salt e pepper all&#39;hashing di una password:&#xA;L&#39;utente inserisce la password&#xA;echo -n &#34;Password: &#34;; read -s PASSWORD&#xA;&#xA;Genero un Salt casuale di 128 bit unico per ogni utente&#xA;SALT=$(openssl rand -base64 128)&#xA;&#xA;Anche PEPPER sarà qualcosa del tipo &#34;openssl rand -base64 128&#34;&#xA;e si troverà in un punto esterno al database degli utenti.&#xA;PEPPER=$(getpepperfromext)&#xA;&#xA;Digest della password+salt&#xA;PASSWORDHASH=$(echo &#34;${PASSWORD}&#34; | argon2 &#34;${SALT}&#34; -m 16 -t 3 -p 4 -id -e)&#xA;&#xA;HMAC del digest con PEPPER come chiave&#xA;PASSWORDPEPPER=$(echo &#34;${PASSWORDHASH}&#34; | openssl dgst -sha256 -hmac &#34;${PEPPER}&#34; -binary | base64)&#xA;HSM&#xA;Quella vista prima è una versione molto edulcorata di ciò che avviene nella realtà.&#xA;Il pepper, non può essere gestito con leggerezza visto che è un segreto che protegge non un singolo oggetto ma intere classi, come db di utenti.&#xA;&#xA;L&#39;apparato che gestisce chiavi di questo tipo e di questa importanza, deve essere robusto, praticamente inattaccabile, quasi completamente isolato dal resto dei sistemi a meno delle applicazioni, e solo di quelle, che hanno il permesso di richiedere una chiave,&#xA;&#xA;Apparati hardware specializzati che assolvono a tutte queste funzioni e anche di più, sono gli HSM (Hardware Security Module) che garantiscono il ciclo di vita delle chiavi, dalla generazione alla distruzione, includendo versionamento, rotazione e backup.&#xA;Sono concepiti per resistere anche a manipolazioni forzate che possono innescare un meccanismo di autodistruzione e, particolare rilevante, le operazioni crittografiche basate sulle chiavi protette vengono svolte dall&#39;hsm che consegna al client il risultato delle operazioni, non le chiavi. Nel nostro caso, l&#39;HSM dovrebbe restituirci l&#39;hmac del digest della password che gli inviamo.&#xA;Key / Algo Rotation&#xA;Cosa succede se cambio pepper o algoritmo (anche la sua configurazione)?&#xA;Non avendo disponibilità in alcun modo della password dovrò adottare una strategia ad-hoc.&#xA;Fra tutti gli scenari possibili, il miglior compromesso fra sicurezza e comodità secondo me, è quello basato sul wrapping.&#xA;&#xA;È necessario innanzitutto che vengano conservate le versioni delle chiavi per i servizi che le richiedono. E a questo dovrebbe pensarci l&#39;HSM, se ce n&#39;è uno o qualcosa di custom che abbia funzionalità analoghe.&#xA;Inoltre dovrebbero esserci dei flag che indichino quali sono gli utenti a cui sono state applicate le nuove configurazioni.&#xA;&#xA;Caso A: Algo rotation&#xA;Supponiamo che l&#39;algoritmo di hashing venga cambiato o vengano cambiate le sue configurazioni.&#xA;&#xA;Premessa:&#xA;Nel mio DB degli utenti, in corrispondenza di ogni utente, avrò:&#xA;&#xA;il digest della password &#34;pepato&#34;: HMAC ( pepper, HASH ( salt, password ) ) &#xA;il salt&#xA;&#xA;Il wrapping:&#xA;La strategia sarà quello di &#34;avvolgere&#34; la password di ogni utente col nuovo algoritmo, settare un qualche flag che mi indichi l&#39;operazione compiuta e archiviare il tutto.&#xA;&#xA;Imponiamo il nuovo algoritmo a tutti gli utenti &#34;imbustando&#34; il digest attuale (in questo caso &#39;HMAC in realtà, visto che abbiamo a che fare anche col pepper) con il nuovo digest HASH\NEW:&#xA;HASH\NEW ( salt\new, HMAC ( pepper, HASH ( salt, password ) ) ).&#xA;Per ogni utente averemo dunque:&#xA;&#x9;il nuovo digest al posto di quello vecchio,&#xA;&#x9;il nuovo salt &#xA;&#x9;il vecchio salt&#xA;Settiamo il flag del cambio algoritmo a true (o quello che è)&#xA;Quando l&#39;utente effettuerà il login con successo e il flag sarà a &#34;true&#34;, abbiamo la password che ci permetterà di eliminare il vecchio &#34;involucro&#34; e ripristinare l&#39;HMAC del nuovo digest: HMAC ( pepper, HASH\NEW ( salt\new, password ) ) e il flag ritornerà a &#34;false&#34;&#xA;&#xA;Considerazioni:&#xA;&#xA;La sicurezza non viene compromessa perché il digest di un digest, con KDF configurate a dovere, non comporta alcun rischio.&#xA;La fase di verifica è quella che si complica di più perché in base al valore del flag, dovrà essere effettuata in maniera differente.&#xA;   Se il flag è &#34;true&#34; (nella nostra convenzione), dopo il login devo avere gli elementi per calcolare il digest in questo modo: HASH\NEW ( salt\new, HMAC ( pepper, HASH ( salt, password ) ) ).&#xA;   Se il flag è a false, calcolerò al solito: HMAC ( pepper, HASH\NEW ( salt\new, password ) )&#xA;&#xA;Caso B: Pepper rotation&#xA;Supponiamo che a ruotare sia il pepper.&#xA;Procediamo sempre con il wrapping massivo su tutti gli utenti incapsulando il digest :&#xA;&#xA;HMAC ( pepper, HASH ( salt, password ) )&#xA;&#xA;con quello nuovo:&#xA;&#xA;HMAC ( pepper\new, HMAC ( pepper, HASH ( salt, password ) ) )&#xA;&#xA;mettendo il flag a &#34;true&#34;.&#xA;&#xA;Come prima, una volta che gli utenti cominceranno a fare il login, se il flag è &#34;true&#34; innanzitutto verificherò che:&#xA;&#xA;HMAC ( pepper\new, HMAC ( pepper, HASH ( salt, password ) ) ) &#xA;&#xA;sia uguale a ciò che è stato archiviato.&#xA;Se così fosse, ora che sono di nuovo in possesso della password, ripristinerò l&#39;HMAC con:&#xA;&#xA;HMAC ( pepper\new, HASH ( salt, password ) )_&#xA;&#xA;memorizzandolo al posto di quello vecchio e rimettendo il flag a false.&#xA;&#xA;Considerazioni:&#xA;La modifica massiva delle password degli utenti, stavolta passa dall&#39;HSM e potrebbe essere un problema perché un HSM è progettato per scoraggiare flooding di richieste.&#xA;&#xA;È vero che il pepper è sempre lo stesso per tutti gli utenti ma, come ricordavo prima, di solito un HSM non fornisce i suoi segreti ma solo i risultati crittografici delle loro applicazioni.&#xA;&#xA;#kdf #pbkdf2 #bcrypt #scrypt #yescrypt #argon2 #luks #cryptography #aes #sha #digest #RainbowTable #BruteForce #salt #pepper #entropy #hsm #hmac #hash]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/ffe7c43a6-a8b5f2/dnumO91UA8rS/L0t7UvdH6Z7pYPEvBDVb3aulMdNhW1WPBRIRKHMF.jpg" alt="password hashing"></p>

<p>Dopo aver capito come creare password inviolabili anche avendo a disposizione tutta l&#39;energia termica dell&#39;universo, pensiamo al modo migliore per archiviarle.</p>

<p>Pensare di lasciare la password raw in un database, rappresenta un grosso rischio in virtù di un possibile attacco offline.
</p>
<ul><li><a href="#rainbow-table" rel="nofollow">Rainbow Table</a></li>
<li><a href="#come-ti-blocco-la-rainbow-table-il-salt-sale" rel="nofollow">Come ti blocco la Rainbow Table: Il “Salt” (sale)</a></li>
<li><a href="#il-livello-successivo-il-pepper" rel="nofollow">Il livello successivo: Il Pepper</a></li>
<li><a href="#final-step-l-hashing" rel="nofollow">Final step: L’hashing</a>
<ul><li><a href="#pbkdf2" rel="nofollow">PBKDF2</a></li>
<li><a href="#bcrypt" rel="nofollow">Bcrypt</a></li>
<li><a href="#scrypt" rel="nofollow">Scrypt</a></li>
<li><a href="#yescrypt" rel="nofollow">yescrypt</a></li>
<li><a href="#argon2" rel="nofollow">Argon2</a></li></ul></li>
<li><a href="#un-piccolo-esempio-hashing-di-una-password-con-argon2" rel="nofollow">Un piccolo esempio: hashing di una password con Argon2</a></li>
<li><a href="#gestione-del-pepper" rel="nofollow">Gestione del pepper</a></li>
<li><a href="#hsm" rel="nofollow">HSM</a></li>
<li><a href="#key-algo-rotation" rel="nofollow">Key / Algo Rotation</a>
<ul><li><a href="#caso-a-algo-rotation" rel="nofollow">Caso A: Algo rotation</a></li>
<li><a href="#caso-b-pepper-rotation" rel="nofollow">Caso B: Pepper rotation</a></li></ul></li></ul>

<p>Una prima linea di difesa consiste nel memorizzare il <strong>digest della password</strong>, una stringa alfanumerica univoca generata da un apposito algoritmo, così da lasciare nelle mani dell&#39;attaccante degli oggetti che, per la loro non invertibilità, non permettono di risalire alle password.</p>

<p>La <strong>scelta</strong> dell&#39;algoritmo di hashing diventa critica al fine di scongiurare altri tipi di attacchi. Ad es. SHA-256, pur essendo ottimo e molto efficiente per il digest e la firma anche di file di grandi dimensioni, mostra il fianco, proprio in virtù della sua velocità, nel caso di attacchi con:</p>
<ul><li><strong>brute-force:</strong> si calcola l’hash di password casuali fino a trovare una corrispondenza,</li>
<li><strong>dizionario:</strong> un&#39;alternativa intelligente alla forza bruta. Si punta alle password più comuni, si calcola l&#39;hash e si controlla se c&#39;è corrispondenza.</li>
<li><strong>Rainbow Table:</strong> l&#39;attacco al dizionario più insidioso di tutti</li></ul>

<p>Oltre al fatto che, la funzione di hashing , essendo deterministica, permette di capire chi sono gli utenti che hanno la stessa password, dal momento che avranno lo stesso digest.</p>

<h2 id="rainbow-table">Rainbow Table</h2>

<p>Una <strong>Rainbow Table</strong> è un enorme dizionario pre-calcolato che contiene:</p>
<ul><li>Milioni di password comuni.</li>
<li>Il relativo hash corrispondente.</li></ul>

<p>Invece di calcolare l’entropia di ogni tentativo, l’attaccante ruba il database degli hash e fa un semplice “Cerca e Trova”. Se l’hash della tua password è nella tabella, la tua password è violata in millisecondi, indipendentemente da quanto fosse alta la sua entropia teorica.</p>

<p><small><strong>Oss.:</strong> Una password totalmente casuale, generata da un CSPRNG affidabile, con un&#39;alta entropia (&gt;120), rimarrebbe comunque inviolabile anche dalla rainbow table perché la probabilità che quella password si trovi nel dizionario, sarebbe equivalente ad indovinarla.</small></p>

<h2 id="come-ti-blocco-la-rainbow-table-il-salt-sale">Come ti blocco la Rainbow Table: Il “Salt” (sale)</h2>

<p>Per rendere inutili le Rainbow Table, i sistemi sicuri utilizzano il <strong>Salt</strong>. Il salt è una stringa di dati casuali (generati da una sorgente d’entropia affidabile ovviamente) che viene aggiunta alla password prima di calcolarne il digest.</p>

<p>In questo modo le rainbow table vengono vanificate perché gli hash precalcolati sulle password raccolte, mancando il salt, non valgono più. Anche se due utenti avessero la stessa password, avrebbero degli hash completamente diversi.</p>

<p>Anche per questo motivo non è un problema che il salt sia pubblico, perché il suo obiettivo non è nascondere quello che è un pezzetto di password a tutti gli effetti, ma di impedire <strong>economie di scala</strong> degli attacchi perché, pur potendo disporre offline di un database di decine di milioni di utenti, gli hash della mia Rainbow Table (che può arrivare a pesare anche decine di GB) <strong>andrebbero tutti ricalcolati per ogni utente</strong>, con un costo computazionale e di archiviazione inimmaginabile.</p>

<p>Per riassumere, gli ingredienti di base sono:</p>
<ol><li><strong>una buona sorgente d’entropia:</strong> una fonte di casualità certificata per generare un salt unico;</li>
<li><strong>entropia della password:</strong> sempre buona norma, ove possibile, come sappiamo ormai fare (<a href="https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di" rel="nofollow">https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di</a>). Evita attacchi brute-force o al dizionario in cui l’attaccante prova a indovinare;</li>
<li><strong>salt:</strong> protegge la password dagli attacchi basati su database pre-calcolati (Rainbow Table).</li></ol>

<h2 id="il-livello-successivo-il-pepper">Il livello successivo: Il Pepper</h2>

<p>È vero che col salt andiamo a complicare lo sfruttamento di un attacco offline ma possiamo fare di meglio.</p>

<p>Il punto d&#39;attenzione è che il salt protegge le password di <strong>tutti gli utenti</strong>.
Ma un attaccante potrebbe non essere affatto interessato a violare <strong>ogni singolo utente</strong> (niente economia di scala) ma solo alcuni. E allora l&#39;attacco attraverso Ranbow Table potrebbe essere di nuovo praticabile.</p>

<p>Ma gli informatici sono dei gran giocherelloni, si sa.
Visto che abbiamo già il “sale”, perché non finire aggiustando con un po’ di “pepe”? Detto, fatto!</p>

<p>Il <strong>pepper</strong>, come il salt, è un&#39;altra password generata con gli stessi criteri del salt ma le analogie finiscono qua perché:</p>
<ul><li>a differenza del <strong>salt</strong> che si trova nel database, il <strong>pepper</strong> è separato da ques&#39;ultimo. L&#39;ideale sarebbe un <strong>HSM</strong>;</li>
<li>Il <strong>salt</strong> è visibile a tutti, attaccante compreso. Il <strong>pepper</strong> è segreto. Un eventuale data breach che permette all&#39;attaccante di disporre offline di tutto il database degli utenti, “vedrà” certamente gli eventuali salt ma sarà ignaro del fatto che gli mancherà sempre un pezzo di chiave;</li>
<li>il <strong>salt</strong> è diverso per ogni utente, il <strong>pepper</strong>, di solito, è unico;</li>
<li>il <strong>salt</strong> serve a rendere uniche la password degli utenti, il <strong>pepper</strong> protegge l&#39;intero database da attacchi offline.</li></ul>

<p><strong>Il pepper è la chiave di un HMAC, o di un meccanismo di cifratura simmetrica, applicato al digest della password</strong> (che ricordo essere salt+password in realtà), che sarà ciò che verrà archiviato.</p>

<p>Va detto che l&#39;uso del “pepper” complica ulteriormente lo scenario di archiviazione.
Nella stragrande maggioranza dei casi è sufficiente scegliere un buon algoritmo di password hashing (vedi paragrafo successivo) per scoraggiare gli attaccanti.
“Pepare” le password prevederebbe, come detto sopra, l&#39;uso di un HSM per es, e tutta una serie di riflessioni di contorno che evidenzierò più avanti.</p>

<h2 id="final-step-l-hashing">Final step: L&#39;hashing</h2>

<p>L&#39;ultimo punto da dettagliare è l&#39;hash della password.</p>

<p>L&#39;<strong>hash crittografico</strong>, in uso in questi casi, deve soddisfare le seguenti proprietà:</p>
<ol><li><strong>resistenza alla pre-immagine:</strong> dato un hash <em>h</em>, deve essere impossibile trovare una password <em>p</em> t.c. <em>H(p) = h</em> (non invertibilità della funzione hash)</li>
<li><strong>resistenza alla pre-immagine secondaria:</strong> dato una password <em>p<sub>1</sub></em>, deve essere impossibile trovare un&#39;altra password <em>p<sub>2</sub></em> t.c. <em>H(p<sub>1</sub>) = H(p<sub>2</sub>)</em> (resistenza debole alle collisioni)</li>
<li><strong>resistenza alle collisioni:</strong> è impossibile trovare due password diverse, <em>p<sub>1</sub></em> e <em>p<sub>2</sub></em>, t.c. <em>H(p<sub>1</sub>) = H(p<sub>2</sub>)</em> (resistenza forte alle collisioni)</li>
<li><strong>effetto valanga:</strong> il cambio di un solo bit della password deve cambiare radicalmente l&#39;intero hash</li></ol>

<p>In un sistema moderno, l&#39;hash non può essere delegato a funzioni di tipo SHA perché nascono per altri compiti,</p>

<p><strong>SHA-2</strong> e <strong>SHA-3</strong> nascono per il digest veloce, per verificare l&#39;integrità di file anche molto grossi o firmare documenti. La loro eccellente velocità diventa il loro più grosso difetto quando si parla di password.
Negli scenari precedenti di attachi offline, l&#39;hacker che dispone di una grossa potenza di calcolo, può ricostituire velocemente le rainbow table per <em>n</em> utenti. Magari non di tutti ma di quelli attenzionati.</p>

<p>Le funzioni di derivazione della chiave (<strong>KDF</strong>) come <strong>pbkdf2</strong> e quelle ancora più estreme come <strong>B/Scrypt</strong>, <strong>Argon2</strong>, oltre che soddisfare tutti i punti precedentemente elencati tipici di funzioni di password hashing, sono progettate per essere computazionalmente pesantissime da calcolare perché il loro scopo non è il digest ma la protezione di un segreto contro il brute-force.
E mentre le vecchie KDF come <strong>pbdfk2</strong> sono CPU bound, ma non GPU bound, le KDF più moderne come <strong>Bcrypt</strong>, <strong>Scrypt</strong> ma soprattutto <strong>Argon2</strong>, agiscono pesantemente su tempo, memoria e parallelismo e l&#39;attacco offline di cui sopra diventa impraticabile.</p>

<h3 id="pbkdf2">PBKDF2</h3>

<p>È il decano delle KDF. Applica iterativamente una funzione pseudorandomica, come HMAC con uno SHA, con salt alla password.
Il conteggio delle iterazioni è un parametro configurabile.</p>

<p>PBDKF2 è uno standard di lunga data ampiamente adottato. Se non ci sono necessità stringenti di sicurezza o requisiti legacy, è una buona scelta.</p>

<p>Il fatto di essere solo CPU bound però non la rende la scelta ideale in scenari dove gli attaccanti possono attingere a risorse di calcolo considerevoli</p>

<h3 id="bcrypt">Bcrypt</h3>

<p>Basato su Blowfish, anche Bcrypt usa un hash crittografico sulla password con parametri il salt e un fattore di costo.</p>

<p>Il fattore di costo aumenta esponenzialmente il numero di iterazioni per adattarsi all&#39;aumento di potenza di calcolo dell&#39;hardware.</p>

<p>Bcrypt è stato progetto per essere lento e resistente a semplici attacchi di forzat bruta.
Tuttavia, il basso utilizzo di ram richiesto dal calcolo lo rendono poco resistente ad attacchi sferrati usando hardware specializzato.</p>

<p>Bcrypt ha dalla sua una storia solidissima in ragione della quale da 20 anni a questa parte non sono state trovate vulnerabilità critiche nel suo design.</p>

<p>Per questo motivo Bcrypt cifra le password di sistema di OpenBSD dal 1999, come pure ha cifrato quelle di tante distro Linux per anni, prima che passassero ad Argon2 o <strong>yescrypt</strong> (default di Fedora).</p>

<p>Domina nei framework web ([Python] Django, [Ruby] Ruby on Rails, [PHP] Laravel), [Java] Spring, Node.js), nelle applicazioni (Ansible / Terraform, Docker), nel web (la cifratura in .htpasswd di Apache e Nginx) visto che la sua semplcitià di implementazione gli ha permesso di trovarsi praticamente in ogni linguaggio.</p>

<p>È presente come alternativa anche nei password manager benché molti di essi abbiano spostato il default verso Argon2 o PBKDF2 per conformità agli standard FIPS.</p>

<p>È molto semplice implementare e anche da usare perché bisogna agire solo sul <strong>fattore di costo</strong> (consigliato almeno 10-12, altrimenti diventa troppo vulnerabile ad attacchi sferrati attraverso la GPU)</p>

<h3 id="scrypt">Scrypt</h3>

<p>Rilasciato nel 2009, Scrypt è stato il primo algoritmo a introdurre il concetto di <strong>Memory Hardness</strong> ed è stato progettato per rendere economicamente poco conveniente il ricorso ad hardware specializzato come gli ASIC o i FPGA e incidere pesantemente su CPU, ram e parallelismo.</p>

<p>Il suo alveo principale sono state le cripto-valute, molte monete lo usano per il mining.</p>

<p>Scrypt lo troviamo in quasi tutti i linguaggi di programmazione, in <strong>Tarsnap</strong>, servizio di baclup online creato dallo stesso autore di Scrypt, è stato usato da <strong>LastPass</strong> ed è presente come opzione in <strong>VeraCrypt</strong> per derivare la chiave dalla password.
Fino ad Android 9 era l&#39;algoritmo usato per la <strong>FDE</strong> del dispositvio (passato poi al <strong>FBE</strong>) .
Presente anche su FreeBSD come opzione per la cifratura delle password di sistema e come opzione su <strong>LUKS</strong> per la cifratura degli slot delle chiavi.</p>

<p>Su Scrypt i parametri da configurare sono:</p>
<ul><li><strong>Costro CPU/Memoria <em>(N)</em>:</strong> un parametro che aumenta i costi computazionali di cpu e memoria</li>
<li><strong>DImensione del blocco <em>®</em>:</strong> influenza la larghezza di banda della memoria</li>
<li><strong>Parallelizzazione <em>(p)</em>:</strong> indica quanto deve incidere sul calcolo parallelo</li></ul>

<p>In questo modo riesce ad essere sia CPU bound che GPU bound che, a differenza di Bcrypt, lo rende resistente anche ad attacchi facenti uso di hardware specializzato..</p>

<p>Di contro, in ambiente in cui siamo vincolati dalle risorse disponibili, la sua potenza diventa un fattore limitante.
Quasi paragonabile ad Argon2 in quanto a robustezza, il suo unico tallone d&#39;Achille è la permeabilità ad attacchi di tipo <strong>side-channel</strong>.</p>

<h3 id="yescrypt">yescrypt</h3>

<p>Piccola menzione per <strong>yescrypt</strong>, appartenente alla famiglia “Scrypt”, pensato per essere ancora più resistente di Scrypt agli attacchi GPU e FPGA ma con una gestione più intelligente delle risorse.</p>

<p>Grazie alle sue peculiarità, di fatto, è diventato il successore spirituale di Bcrypt nei sistemi operativi gnu/linux dove, a cominciare da Fedora, passando per Debian, Ubuntu, Arch, Kali, è il default per la cifratura delle password di sistema in <code>/etc/shadow</code>.</p>

<p>È talmente incardinato ormai nei sistemi operativi, che è la libreria <code>libxcrypt</code> di <strong>yescrypt</strong> a gestire la tipica funzione <code>crypt()</code> di C che è la base della crittografia su tutti i sistemi gnu/linux moderni.</p>

<p>La sua robustezza unita alla gestione intelligente delle risorse lo rende un coltellino svizzero di riferimento utile per es. per versione custom di LUKS su sistemi embedded, che magari fanno uso di cpu meno recenti,  oppure come opzione per strumenti di backup specialistici</p>

<p>Di fatto, sui sistemi operativi, <strong>yescrypt</strong> s&#39;è guadagnato un consenso amplissimo dovuto alla sua scalabilità, alla sua capacità di usare anche la ROM per rendere il cracking ancora più difficile e senza pesare sulla RAM e alla sua compatibilità potendosi inserire perfettamente nella storica funzione <code>crypt()</code> di C come detto prima.</p>

<p>Se Argon2 è il vincitore accademico avendo vinto il Password Hashing Competition del 2015, <strong>yescrypt</strong> per la sua robustezza, efficienza e flessibilità si ritaglia un profilo di indispensabilità nei sistemi operativi,</p>

<h3 id="argon2">Argon2</h3>

<p>E veniamo al dominatore indiscusso di questa che non è una llista esaustiva di KDF.</p>

<p>Argon2 è LO standard moderno per il password hashing raccomandato da OWASP e IETF.</p>

<p>È il riferimento per praticamente ogni password manager: <strong>Bitwarden</strong>, <strong>KeppasXC</strong>, <strong>1Password</strong>, a cui assegnanp la protezione della <strong>Master Password</strong></p>

<p>È la scelta principale per la cifratura degli hard disk anche con impostazioni molto aggressive, in ragione delle quali un ritardo di mezzo secondo (un tempo enorme se venisse scalato esponenzialmente) nell&#39;apertura di un HD è assolutamente accettabile.
È il default di <strong>LUKS2</strong> (LUKS1 usava PBKDF2) e di <strong>VeraCrypt</strong>, con cui ha sostituito SHA-512.</p>

<p>Come Bcrypt, è implementato estensivamente su praticamente ogni frameword web e backend, da PHP, Django (Python), Laravel fino a Node.js.</p>

<p>Nei sistemi operativi, laddove <strong>yescrytpt</strong> domina nella gestione delle password utente, <strong>Argon2</strong> è usato per compiti più critici.
Dal kernel Linux per gestire internamente le chiavi crittografiche o da macOS / iOS, dove algoritmi proprietari ispirati fortemente ad Argon2, proteggono i dati nel Secure Enclave.</p>

<p>Argon2  setta 3 parametri principali per regolare la sua forza:</p>
<ul><li><strong>t: iterazioni</strong>, quante volte vengono rimescolati i dati <em>(default Bitwarden = 3)</em></li>
<li><strong>m: memoria</strong>, quanta ram deve occupare il calcolo. Questa è la misura anti-GPU <em>(default Bitwarden = 16 (64MB))</em></li>
<li><strong>p: parallelismo</strong>, quanti core della cpu usare. Questa è la misura anti-CPU <em>(default Bitwarden = 4)</em></li></ul>

<p>La variante <em>id</em> è anche resistente agli <strong>attacchi side-channel</strong> perché impediscono a un attaccante di capire la password osservando i tempi di accesso alla memoria.</p>

<h2 id="un-piccolo-esempio-hashing-di-una-password-con-argon2">Un piccolo esempio: hashing di una password con Argon2</h2>

<p>Il grosso vantaggio degli algoritmi di kdf è che sono naturalmente resilienti rispetto all&#39;evoluzione tecnologica che produce macchine con sempre maggiore potenza di calcolo.
Da pbkdf2 in poi, il salt implicito che invalida le rainbow table precalcolate e la possibilità di calibrare il key stretching in moda da agire intensivamente su ram e cpu, permettono all&#39;algoritmo di adeguarsi per conservare la sua robustezza.</p>

<p>Mini-script per l&#39;hashing di una password fornita dall&#39;utente con argon2 settato al default di Bitwarden:</p>

<pre><code class="language-bash">echo -n &#34;Password: &#34;; read -s PASSWORD
# Genero un Salt casuale di 128 bit
SALT=$(openssl rand -base64 128)
PASSWORD_HASH=$(echo &#34;${PASSWORD}&#34; | argon2 &#34;${SALT}&#34; -m 16 -t 3 -p 4 -id -e)
</code></pre>

<p><code>PASSWORD_HASH</code> e <code>SALT</code> sono i dati che verranno archiviati e, poiché argon2 “frulla” la password con un salt, è praticamente impossibile risalire alla password originale.</p>

<p>La verifica è tuttavia banale perché, avendo il salt e la password da verificare, si ricrea l&#39;hash con argon2 e si confronta con l&#39;hash memorizzato.</p>

<p>Per maggior sicurezza salt e digest possono essere memorizzati in punti differenti. L&#39;importante è che possano essere recuperate a partire dall&#39;utente.</p>

<h2 id="gestione-del-pepper">Gestione del pepper</h2>

<p>Col pepper le cose cambiano un pochino perché:</p>
<ul><li>deve essere archiviato con tutte le paranoie possibili in un punto diverso dal database degli utenti</li>
<li>il key rotation del pepper non è banale</li></ul>

<p>Mini-script che mostra come applicare salt e pepper all&#39;hashing di una password:</p>

<pre><code class="language-bash"># L&#39;utente inserisce la password
echo -n &#34;Password: &#34;; read -s PASSWORD

# Genero un Salt casuale di 128 bit unico per ogni utente
SALT=$(openssl rand -base64 128)

# Anche PEPPER sarà qualcosa del tipo &#34;openssl rand -base64 128&#34;
# e si troverà in un punto esterno al database degli utenti.
PEPPER=$(get_pepper_from_ext)

# Digest della password+salt
PASSWORD_HASH=$(echo &#34;${PASSWORD}&#34; | argon2 &#34;${SALT}&#34; -m 16 -t 3 -p 4 -id -e)

# HMAC del digest con PEPPER come chiave
PASSWORD_PEPPER=$(echo &#34;${PASSWORD_HASH}&#34; | openssl dgst -sha256 -hmac &#34;${PEPPER}&#34; -binary | base64)
</code></pre>

<h2 id="hsm">HSM</h2>

<p>Quella vista prima è una versione molto edulcorata di ciò che avviene nella realtà.
Il pepper, non può essere gestito con leggerezza visto che è un segreto che protegge non un singolo oggetto ma intere classi, come db di utenti.</p>

<p>L&#39;apparato che gestisce chiavi di questo tipo e di questa importanza, deve essere robusto, praticamente inattaccabile, quasi completamente isolato dal resto dei sistemi a meno delle applicazioni, e solo di quelle, che hanno il permesso di richiedere una chiave,</p>

<p>Apparati hardware specializzati che assolvono a tutte queste funzioni e anche di più, sono gli <strong>HSM</strong> (<strong>H</strong>ardware <strong>S</strong>ecurity <strong>M</strong>odule) che garantiscono il ciclo di vita delle chiavi, dalla generazione alla distruzione, includendo versionamento, rotazione e backup.
Sono concepiti per resistere anche a manipolazioni forzate che possono innescare un meccanismo di autodistruzione e, particolare rilevante, <strong>le operazioni crittografiche basate sulle chiavi protette vengono svolte dall&#39;hsm che consegna al client il risultato delle operazioni, non le chiavi</strong>. Nel nostro caso, l&#39;HSM dovrebbe restituirci l&#39;hmac del digest della password che gli inviamo.</p>

<h2 id="key-algo-rotation">Key / Algo Rotation</h2>

<p>Cosa succede se cambio pepper o algoritmo (anche la sua configurazione)?
Non avendo disponibilità in alcun modo della password dovrò adottare una strategia ad-hoc.
Fra tutti gli scenari possibili, il miglior compromesso fra sicurezza e comodità secondo me, è quello basato sul wrapping.</p>

<p>È necessario innanzitutto che vengano conservate le versioni delle chiavi per i servizi che le richiedono. E a questo dovrebbe pensarci l&#39;HSM, se ce n&#39;è uno o qualcosa di custom che abbia funzionalità analoghe.
Inoltre dovrebbero esserci dei flag che indichino quali sono gli utenti a cui sono state applicate le nuove configurazioni.</p>

<h3 id="caso-a-algo-rotation">Caso A: Algo rotation</h3>

<p>Supponiamo che <strong>l&#39;algoritmo di hashing venga cambiato</strong> o vengano cambiate le sue configurazioni.</p>

<p><strong>Premessa:</strong>
Nel mio DB degli utenti, in corrispondenza di ogni utente, avrò:</p>
<ol><li>il digest della password “pepato”: <em>HMAC ( pepper, HASH ( salt, password ) )</em></li>
<li>il salt</li></ol>

<p><strong>Il wrapping:</strong>
La strategia sarà quello di “avvolgere” la password di ogni utente col nuovo algoritmo, settare un qualche flag che mi indichi l&#39;operazione compiuta e archiviare il tutto.</p>
<ol><li>Imponiamo il nuovo algoritmo a tutti gli utenti “imbustando” il digest attuale (in questo caso &#39;HMAC in realtà, visto che abbiamo a che fare anche col pepper) con il nuovo digest <em><strong>HASH_NEW</strong></em>:
<em><strong>HASH_NEW</strong> ( <strong>salt_new</strong>, HMAC ( pepper, HASH ( salt, password ) ) )</em>.</li>
<li>Per ogni utente averemo dunque:
<ol><li>il nuovo digest al posto di quello vecchio,</li>
<li>il nuovo salt</li>
<li>il vecchio salt</li></ol></li>
<li>Settiamo il flag del cambio algoritmo a <em>true</em> (o quello che è)</li>
<li>Quando l&#39;utente effettuerà il login con successo e il flag sarà a “<em>true</em>”, abbiamo la password che ci permetterà di eliminare il vecchio “involucro” e ripristinare l&#39;HMAC del nuovo digest: <em>HMAC ( pepper, <strong>HASH_NEW</strong> ( <strong>salt_new</strong>, password ) )</em> e il flag ritornerà a “<em>false</em>“</li></ol>

<p><strong>Considerazioni:</strong></p>
<ul><li>La sicurezza non viene compromessa perché il digest di un digest, con KDF configurate a dovere, non comporta alcun rischio.</li>
<li>La fase di verifica è quella che si complica di più perché in base al valore del flag, dovrà essere effettuata in maniera differente.
<ul><li>Se il flag è “<em>true</em>” (nella nostra convenzione), dopo il login devo avere gli elementi per calcolare il digest in questo modo: <em><strong>HASH_NEW</strong> ( <strong>salt_new</strong>, HMAC ( pepper, HASH ( salt, password ) ) )</em>.</li>
<li>Se il flag è a <em>false</em>, calcolerò al solito: <em>HMAC ( pepper, <strong>HASH_NEW</strong> ( <strong>salt_new</strong>, password ) )</em></li></ul></li></ul>

<h3 id="caso-b-pepper-rotation">Caso B: Pepper rotation</h3>

<p>Supponiamo che a ruotare sia il pepper.
Procediamo sempre con il wrapping massivo su tutti gli utenti incapsulando il digest :</p>

<p><em>HMAC ( pepper, HASH ( salt, password ) )</em></p>

<p>con quello nuovo:</p>

<p><em>HMAC ( <strong>pepper_new</strong>, HMAC ( pepper, HASH ( salt, password ) ) )</em></p>

<p>mettendo il flag a “<em>true</em>”.</p>

<p>Come prima, una volta che gli utenti cominceranno a fare il login, se il flag è “<em>true</em>” innanzitutto verificherò che:</p>

<p><em>HMAC ( <strong>pepper_new</strong>, HMAC ( pepper, HASH ( salt, password ) ) )</em></p>

<p>sia uguale a ciò che è stato archiviato.
Se così fosse, ora che sono di nuovo in possesso della password, ripristinerò l&#39;HMAC con:</p>

<p><em>HMAC ( <strong>pepper_new</strong>, HASH ( salt, password ) )</em></p>

<p>memorizzandolo al posto di quello vecchio e rimettendo il flag a false.</p>

<p><strong>Considerazioni:</strong>
La modifica massiva delle password degli utenti, stavolta passa dall&#39;HSM e potrebbe essere un problema perché un HSM è progettato per scoraggiare flooding di richieste.</p>

<p>È vero che il pepper è sempre lo stesso per tutti gli utenti ma, come ricordavo prima, di solito un HSM non fornisce i suoi segreti ma solo <strong>i risultati crittografici delle loro applicazioni.</strong></p>

<p><a href="/aytin/tag:kdf" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">kdf</span></a> <a href="/aytin/tag:pbkdf2" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">pbkdf2</span></a> <a href="/aytin/tag:bcrypt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">bcrypt</span></a> <a href="/aytin/tag:scrypt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">scrypt</span></a> <a href="/aytin/tag:yescrypt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">yescrypt</span></a> <a href="/aytin/tag:argon2" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">argon2</span></a> <a href="/aytin/tag:luks" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">luks</span></a> <a href="/aytin/tag:cryptography" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">cryptography</span></a> <a href="/aytin/tag:aes" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">aes</span></a> <a href="/aytin/tag:sha" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">sha</span></a> <a href="/aytin/tag:digest" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">digest</span></a> <a href="/aytin/tag:RainbowTable" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">RainbowTable</span></a> <a href="/aytin/tag:BruteForce" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">BruteForce</span></a> <a href="/aytin/tag:salt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">salt</span></a> <a href="/aytin/tag:pepper" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">pepper</span></a> <a href="/aytin/tag:entropy" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">entropy</span></a> <a href="/aytin/tag:hsm" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">hsm</span></a> <a href="/aytin/tag:hmac" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">hmac</span></a> <a href="/aytin/tag:hash" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">hash</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/archiviare-le-password-in-sicurezza-con-kdf-password-hashing-trilogia-della</guid>
      <pubDate>Thu, 29 Jan 2026 17:49:50 +0000</pubDate>
    </item>
    <item>
      <title>Come valutare la resistenza di una password (Trilogia Della Password - 2 di 3)</title>
      <link>https://noblogo.org/aytin/come-valutare-la-resistenza-di-una-password-trilogia-della-password-2-di-3</link>
      <description>&lt;![CDATA[ent,zxcvb,diceware&#xA;&#xA;In &#34;Come generare una password o un keyfile sicuri&#34; abbiamo visto come generare password e keyfile che si basassero su dati il più possibile casuali.&#xA;La verifica matematica di una password si basa sulla determinazione del numero di tentativi necessari a un attaccante per indovinarla.&#xA;!--more--&#xA;Esistono due approcci: quello teorico (brute force) e quello realistico (pattern matching).&#xA;&#xA;Calcolo teorico (Entropia di Shannon)&#xA;  Spiegazione dell’entropia di Shannon&#xA;  Esempi d’uso&#xA;Calcolo realistico (pattern matching)&#xA;  Ent&#xA;  zxcvbn&#xA;  Riassumendo&#xA;Metodo Diceware&#xA;&#xA;Calcolo teorico (Entropia di Shannon)&#xA;Un primo strumento per la valutazione di una password è dato dall&#39;entropia di Shannon, che chiunque abbia usato un password manager certamente conoscerà.&#xA;&#xA;Questo calcolo assume che l&#39;attaccante non sappia nulla della nostra password e debba provare ogni possibile combinazione (forza bruta).&#xA;&#xA;Dato un alfabeto di R simboli e una password di lunghezza L, l&#39;entropia E sarà pari a: &#xA;&#xA;E = logsub2/sub ( RsupL/sup ) = L  \ logsub2/sub ( R )&#xA;&#xA;L&#39;entropia è un valore numerico espresso in bit (gli &#34;Shannon&#34;) che rappresenta una misura, non tanto della robustezza, quanto della &#34;densità&#34; della password, ossia di quanto lavoro richieda ad un calcolatore per essere indovinata. Più è alta, meglio è.&#xA;Spiegazione dell&#39;entropia di Shannon&#xA;Innanzitutto notiamo che RsupL/sup è la dimensione dello spazio di possibilità in cui esiste la mia password e, per R e L sufficientemente grandi, è un numero talmente enorme da essere difficilmente comprensibile.&#xA;&#xA;L&#39;equivalente E, che non è altro che l&#39;esponente della potenza di 2 tale per cui 2supE/sup = RsupL/sup, risulta invece molto più gestibile e confrontabile.&#xA;&#xA;Semplificando, se alla mia password lunga L corrisponde quindi un&#39;analoga chiave in bit lunga E, un attaccante che voglia scoprire la mia password, invece che indovinare gli L simboli da un alfabeto R, compirà lo stesso sforzo rispondendo correttamente ad un numero di domande binarie (SI / NO) pari a E, per ricostruire la giusta sequenza binaria.&#xA;&#xA;Quanto costa ricostruire la sequenza?&#xA;O, in altre parole, qual è lo sforzo computazionale richiesto?&#xA;&#xA;Si parla di  caso medio ottimale corrispondente ad una ricerca binaria in cui ogni domanda dimezza lo spazio di possibilità fino ad azzerarlo completamente.&#xA;&#xA;E = L \ logsub2/sub ( R ), è quel numero di bit che mi dice quant&#39;è profondo l&#39;albero delle decisioni che il calcolatore deve percorrere, albero in cui il numero dei possibili cammini radice-foglia (equivalenti a tutte le possibili password) è 2supE/sup = RsupL/sup.&#xA; &#xA;Nel caso migliore, rispondo correttamente a tutte le E domande al primo tentativo (trovo subito il mio cammino sull&#39;albero).&#xA;Nel caso peggiore, mi occorreranno 2supE/sup risposte (percorro tutti i cammini dell&#39;albero) equivalente proprio a RsupL/sup.&#xA;&#xA;Possiamo allora definire formalmente l&#39;entropia come quella quantità minima di informazione necessaria ad azzerare l&#39;incertezza legata all&#39;identificazione della password. Per questo motivo è espressa in bit.&#xA;&#xA;Una misurazione di questo tipo ha senso solo se ipotizziamo che i simboli siano tutti equiprobabili.&#xA;&#xA;La formula di Shannon misura, sì, l&#39;entropia, ma al suo massimo potenziale, quando la distribuzione dei simboli nella sequenza è omogenea e assolutamente casuale.&#xA;Esempi d&#39;uso&#xA;Facciamo l&#39;esempio di una password lunga 20, costruita su un alfabeto di 66 simboli (alfanumerico con maiuscole e minuscole più 4 simboli speciali).&#xA;La dimensione di questo spazio di possibilità è pari a:&#xA;&#xA;Ssubp/sub = RsupL/sup = 66sup20/sup = 2,46 \ 10sup36/sup&#xA;&#xA;Tentare un attacco di forza bruta su un oggetto del genere è semplicemente impensabile.&#xA;Faccio un esempio.&#xA;&#xA;Per forzare la nostra password, supponiamo di avere a disposizione il più potente supercomputer del mondo, El Capitan ad oggi, dotato di una potenza di calcolo spaventosa, in media 2.000 exaFLOPS con picchi di 2.746 exaFLOPS, dove 1 exaFLOPS è un quintilione (10sup18/sup) di operazioni al secondo.&#xA;&#xA;Il calcolo di una password si misura in Hash al secondo, H/s per usare una notazione compatta, che è più dispendiosa della singola operazione.&#xA;&#xA;Approssimando per eccesso con molto ottimismo e nell&#39;ipotesi di usare algoritmi estrememente deboli e poco costosi dal punto di vista computazionale come NTLM o MD5, possiamo pensare che il nostro sistema possa arrivare a calcolare, in queste condizioni, circa 1,5 quintilioni  ( 1,5 \ 10sup18/sup ) H/s.&#xA;Per algoritmi come bcrypt o argon2, progettati per essere molto dispendiosi, tale potenza si riduce drasticamente di molti ordini di grandezza. Da 10sup18/sup a 10sup9/sup - 10sup6/sup. Ma consideriamo il caso più favorevole perché sembra appunto una potenza enorme.&#xA;&#xA;Ma anche questa tremenda esibizione di potenza annichilisce di fronte al numero di calcoli da compiere nel nosro spazio di possibilità.&#xA;Dato Ssubp/sub lo spazio di possibilità (il numero di possibili combinazioni), il tempo T espresso in secondi necessario ad eseguire tutte le operazioni sarà:&#xA;&#xA;Ssubp/sub = 66sup20/sup = 2,46 \ 10sup36/sup&#xA;&#xA;T = 2,46 \ sup36/sup / 1,5 \ 10sup18/sup = 1,64 \ 10sup18/sup&#xA;&#xA;Che equivale a circa 52 miliardi di anni.&#xA;&#xA;Per avere un&#39;idea di questa grandezza cosmica, si pensi che l&#39;età del nostro universo è di circa 13,8 miliardi di anni. Quindi il calcolo della nostra password potrebbe richiedere un tempo che è grossomodo 3,8 volte l&#39;età dell&#39;universo.&#xA;&#xA;I 120 bit di entropia, sono dunque la misura di questo sforzo potenziale, interpretabile equivalentemente in due modi differenti:&#xA;&#xA;la probabilità di riuscire a trovare la password tirando a indovinare, probabilità che è 1 su 2sup120/sup&#xA;&#xA;oppure&#xA;&#xA;la capacità di rispondere correttamente e consecutivamente a 120 domande di tipo (SI / NO) (ricerca del giusto cammino in un albero decisionale binario profondo 120 livelli)&#xA;&#xA;Allungando la nostra password di altri due caratteri, l&#39;entropia arriva a circa 133 e il calcolo delle possibili combinazioni, posto che fosse possibile ignorando le leggi della termodinamica, richiederebbe circa 16.500 di volte l&#39;età dell&#39;universo.&#xA;&#xA;Considerazione a margine: è la lunghezza della password ad incidere più che la complessità dell&#39;alfabeto. E lo vediamo dalla formula dell&#39;entropia, perché, in una funzione di elevamento a potenza RsupL/sup, aumentare l&#39;esponente L fa crescere molto più rapidamente la funzione che non aumentando la base R.&#xA;Calcolo realistico (pattern matching)&#xA;L&#39;entropia di Shannon fornisce un riscontro utilizzabile solo ipotizzando che:&#xA;&#xA;le scelte siano indipendenti &#xA;la distribuzione sia uniforme&#xA;&#xA;e in uno scenario di questo tipo, l&#39;attacco di forza bruta non è una via percorribile.&#xA;&#xA;Allo stesso tempo, se non vengono rispettati questi vincoli, l&#39;entropia dà una falsa sicurezza perché la formula di Shannon &#34;standard&#34; non tiene conto della ridondanza:&#xA;&#xA;Consideriamo questa password: Password12345678&#xA;&#xA;teoria: la formula E = L  log2R direbbe che la sua entropia sia 95, ottima.&#xA;realtà: poiché è una sequenza ovvia, l&#39;attaccante la proverà per prima. La sua entropia reale sarà vicina a 0 bit.&#xA;&#xA;L&#39;entropia quindi misura la &#34;densità&#34; della password, la sua imprevedibilità potenziale ma non dà nessuna informazione sulla presenza di schemi ripetuti e sul pattern matching.&#xA;&#xA;Ent&#xA;L&#39;essere umano come generatore di entropia fa schifo.&#xA;Ecco perché, per un attaccante, prima ancora di provare tutte le possibili combinazioni di caratteri, un attacco a dizionario può far risparmiare un sacco di tempo.&#xA;Infatti sempre Shannon ci dice che nelle parole dei linguaggi naturali alcune lettere ricorrono più di altre, non serve lo stesso numero di domanda ma molto meno e così l&#39;entropia media diminuisce.&#xA;Per prevenire questi effetti collaterali, il nostro metodo di generazione e quindi ciò che viene generato, deve essere testato con qualcos&#39;altro che non sia la semplice entropia.&#xA;&#xA;ent è un tool a linea di comando che fa 4 valutazioni differenti:&#xA;&#xA;entropia&#xA;Chi-quadrato&#xA;Media aritmetica&#xA;Monte Carlo Pi&#xA;&#xA;N.B. ent non è adatto alla valutazione della singola password perché ha bisogno di migliaia di dati (almeno 1K). Una singola password di 24 caratteri per es. (24 byte) non ha materiale casuale sufficiente affinché ent converga verso un giudizio oggettivo.&#xA;&#xA;Entropia&#xA;L&#39;entropia misura la densità di informazione. In ent, viene calcolata in bit per carattere (byte).&#xA;&#xA;Il valore: Si analizza il file byte per byte, il valore massimo è 8.0 (ogni byte è totalmente imprevedibile).&#xA;Interpretazione: Più il valore è vicino a 8, più la casualità è &#34;densa&#34; e difficile da indovinare tramite attacchi basati su dizionario. Se il valore è basso (es. 2.0 o 3.0), significa che ci sono molte ripetizioni o uno schema prevedibile.&#xA;Compressione: ent ti dice anche quanto il file potrebbe essere compresso. Un&#39;entropia di 8.0 significa che il file è già &#34;puro caos&#34; e non può essere compresso ulteriormente.&#xA;&#xA;Chi-quadrato&#xA;Il test del chi-quadrato prova a capire se il disordine presente nel file sia veramente equo o se si preferiscono certi caratteri ad altri. Esamina la distribuzione dei caratteri e la confronta con una distribuzione uniforme teorica. Il risultato viene presentato come percentuale con questi scaglioni:&#xA;&#xA;10% \ chi&lt;sup2/sup \&lt; 90%: La sequenza è considerata casuale. Il 50% è il valore &#34;perfetto&#34;.&#xA;chisup2/sup \ 1% o chi&lt;sup2/sup \  99%: È quasi certamente non casuale.&#xA;&#x9;chisup2/sup = 99.99%: i dati sono sospettosamente regolari;&#xA;&#x9;chisup2/sup = 0.01%: i dati sono &#34;troppo&#34; casuali per essere naturali (sospetta manipolazione)&#xA;&#xA;Media aritmetica&#xA;Per capire se la distribuzione è sufficientemente omogenea, si fa la somma dei valori dei byte del file e si fa una media.&#xA;&#xA;Poiché i byte vanno da 0 a 255, il valore ideale della media sarebbe 127,5.&#xA;Se è troppo lontano dalla media avvcinandosi ad uno dei due estremi (ad es. 50 o 190), vuol dire che si sta usando solo un piccola parte dei caratteri a disposizione e questo, a suo modo di vedere, rende le password più prevedibili.&#xA;&#xA;Monte Carlo Pi&#xA;È il metodo più fantasioso di tutti.&#xA;I dati casuali vengono trasformati in una serie di &#34;dardi&#34; virtuali che vanno a colpire un bersaglio. L&#39;obiettivo non è quello di colpire un ipotico centro ma di verificare che i &#34;dardi&#34; si distribuiscano uniformemente nel bersaglio.&#xA;&#xA;Tutto ciò si realizza immaginando di avere un quadrato 1x1 e 1/4 di cerchio al suo interno di raggio 1 e area π/4&#xA;I dati della sequenza casuale vengono prelevati a gruppi di n byte e supponiamo n = 3 per ora.&#xA;Ogni gruppo di 3 byte sarà un numero compreso tra 0 e 2sup24/sup-1.&#xA;Se normalizziamo questo numero dividendolo per  2sup24/sup, otteniamo un numero compreso fra 0 e 1.&#xA;Calcolando le coordinate in questo modo, col teorema di Pitagora possiamo verificare se la coordinata (X,Y) &#34;cada&#34; nel quarto di cerchio oppure no e ciò succede se:&#xA;&#xA;Xsup2/sup + Ysup2/sup ≤ 1&#xA;&#xA;Lanciando un migliaio di queste &#34;frecce&#34;, accumuliamo dati sufficiente per fare una stima.&#xA;&#xA;Se indichiamo con In il numero di &#34;lanci&#34; con successo e con Total il numero totale di lanci effettuati:&#xA;&#xA;4 \ (ln/Total) si avvicinerà a π solo se la distribuzione dei caratteri sarà uniforme (indice di una casualità omogenea), altrimenti divergerà in maniera significativa (indice della presenza di pattern o di ripetizioni).&#xA;&#xA;zxcvbn&#xA;ent fa un&#39;analisi statistica della distribuzione dei bit in un generatore di casualità.&#xA;&#xA;zxcvbn invece fa un&#39;analisi di tipo euristico, è verticale sulla verifica delle password in particolare nel rilevare se vi sono schemi o ripetizioni di caratteri che renderebbero le password violabili.&#xA;&#xA;Il suo algoritmo scompone le password in pezzi dei quali cerca corrispondenze in dizionari o schemi come:&#xA;&#xA;dizionari: controlla la presenza di parole di uso comune&#xA;sequenze: controlla la presenza di serie di caratteri prevedibili come &#34;123456&#34;, &#34;abcde&#34;&#xA;pattern spaziali: controlla la presenza di percorsi sulla tastiera come &#34;qwerty&#34;, &#34;asdfg&#34;, &#34;zcvbn&#34; o sequenze diagonali&#xA;ripetizioni: ripetizione di caratteri come &#34;kkkkkkkkkk&#34; o &#34;12121212&#34;&#xA;l33t: una parola come &#34;p4$$w0rd&#34; viene subito riconosciuta come &#34;password&#34;&#xA;date: riconosce giorni, mesi, anni, anche composti come &#34;15062026&#34;&#xA;&#xA;Il suo uso è molto semplice.&#xA;Le si dà in pasto la password e zxcvbn restituisce diverse informazioni utili:&#xA;&#xA;uno score da &#34;0&#34; (terribile) a &#34;4 (ottima);&#xA;la stima di quanto tempo impiegherebbe un hacker a violarla in base a vari scenari di attacco;&#xA;suggerimenti su come migliorare eventualmente la password.&#xA;&#xA;zxcvbn era una libreria javascript orginariamente sviluppata da Dropbox e ora disponibile in tante forme: go, python, c++.&#xA;&#xA;L&#39;originale Dropbox in javascript, non più manutenuto, può essere trovata qui: https://github.com/dropbox/zxcvbn.&#xA;&#xA;Benché esistano diversi porting in python, se c&#39;è l&#39;esigenza di usare la versione legacy, gli stessi sviluppatori dell&#39;originale zxcvbn consigliano questa versione: https://github.com/dwolfhub/zxcvbn-python, che può essere installata con pip.&#xA;&#xA;In realtà la versione migliore è un fork in typescript, zxcvbn-ts che offre modularità (a differenza della versione python che è monolitica), maggior sicurezza, risoluzione di bug, aggiornamento continuo dizionari compresi.&#xA;&#xA;Per capirci, mentre ent usa l&#39;entropia di Shannon per valutare la probabilità statistica dei byte, zxcvbn cerca di calcolare una stima dei tempi necessari per indovinare la password.&#xA;&#xA;Una passphrase su ent avrebbe un punteggio risibile perché le entropie di parole comuni sono molto basse. Su zxcvbn invece avrebbe un punteggio molto alto perché l&#39;entropia di una parola viene calcolata sulla posizione del dizionario che la contiene per cui un hacker dovrebbe provare milioni di combinazioni prima di trovarla.&#xA;&#xA;Allo stesso modo, password che per ent sarebbero ottime, per zxcvbn sarebbero da evitare perché legate a pattern o a ripetizioni.&#xA;&#xA;Riassumendo&#xA;Se si deve testare una password / passphrase, sicuramente zxcvbn.&#xA;Se si deve testare un generatore di casualità o un keyfile di almeno 2k, sicuramente ent.&#xA;&#xA;Metodo Diceware&#xA;Visto che nell&#39;ultima parte abbiamo evidenziato l&#39;anomalia che sorge nel momento in cui si valuta un oggetto casuale o dal punto di vista puramente statistico o dal punto di vista euristico, vale la pena di spendere due parole sulla modalità di creazione delle passphrase usando il metodo Diceware.&#xA;&#xA;Usando come password parole estratte dal linguaggio naturale bisogna fare i conti col problema della prevedibilità.&#xA;Shannon ha dimostrato che la lingua italiana (o inglese) ha un&#39;entropia molto bassa (circa 1-1.5 bit per lettera) perché dopo una &#34;q&#34; ci si aspetta quasi sempre una &#34;u&#34;, e dopo un soggetto ci si aspetta un verbo. E così via.&#xA;Ecco perché, piuttosto che valutare l&#39;entropia nel suo complesso e provare ogni possibile combinazione, un moderno calcolatore inzia col far ricorso a &#34;pattern&#34; umani per violare password in pochi minuti invece che millenni.&#xA;&#xA;Per unire la sicurezza del calcolo casuale alla comodità di una password menmonica, si ricorre al metodo Diceware che consiste nel far uso di un dizionario di migliaia di parole.&#xA;&#xA;Quello classico, di 7776 parole inglesi, curato dall EFF si può trovare qui:&#xA;curl -L https://www.eff.org/files/2016/07/18/efflargewordlist.txt   dicdiceware.txt&#xA;Altrimenti Tarin Gamberini espone il suo dizionario diceware , aggiornato al 2019, qui: https://www.taringamberini.com/downloads/dicewareitIT/lista-di-parole-diceware-in-italiano/4/wordlistdicewareit-IT-4.txt.&#xA;&#xA;Questo dizionario contiene 6sup5/sup parole numerate da 11111 a 66666.&#xA;La passphrase è composta da n di queste parole il cui indice è ricavato lanciando un dado (o un analogo virtuale) per 5 volte.&#xA;In questo modo le parole non sono correlate fra di loro come si potrebbero trovare in una frase, vanificando ogni possibile speculazione sulla sua composizione.&#xA;&#xA;Volendo fare un calcolo dell&#39;entropia, supponendo di costruire una passphrase di 6 parole:&#xA;&#xA;E = L \ logsub2/sub R = 6 \ logsub2/sub 7776 ~ 77,6 &#xA;&#xA;Nella password classiche basate su un alfabeto di R simboli, il mattoncino è rappresentato dal singolo carattere che ha una probabilità 1/R di essere estratto.&#xA;&#xA;Con Diceware, il mattoncino è la parola che ha una probabilità su 7776 di essere estratta. Ogni parola in più, aggiunge una quantità enorme di incertezza.&#xA;&#xA;Ecco perché con sole 6 parole abbiamo già una passphrase molto robusta e con 10 parole siamo di fronte ad una passphrase inattacabile, almeno dal punto di vista dell&#39;analisi statistica (E   129_) e imperforabile anche ricorrendo ad analisi euristiche.&#xA;&#xA;Regola aurea: la scelta delle parole deve essere realmente casuale e non seguire regole grammaticali o preferenze personali. Altrimenti sarà un gioco da ragazzi violarla con un approccio a-là zxcvbn.&#xA;&#xA;#entropy #shannon #bruteforce #ent #zxcvbn #diceware #passphrase #PatternMatching]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/ffe7c43a6-a8b5f2/dgaPhFXQtnxH/E2m9YHqhOVs4GDAjNBVqJmqOE2yoFdq8S1IjuD96.jpg" alt="ent,zxcvb,diceware"></p>

<p>In <a href="https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di" rel="nofollow">“Come generare una password o un keyfile sicuri”</a> abbiamo visto come generare password e keyfile che si basassero su dati il più possibile casuali.
La verifica matematica di una password si basa sulla determinazione del numero di tentativi necessari a un attaccante per indovinarla.

Esistono due approcci: quello teorico (<strong>brute force</strong>) e quello realistico (<strong>pattern matching</strong>).</p>
<ul><li><a href="#calcolo-teorico-entropia-di-shannon" rel="nofollow">Calcolo teorico (Entropia di Shannon)</a>
<ul><li><a href="#spiegazione-dell-entropia-di-shannon" rel="nofollow">Spiegazione dell’entropia di Shannon</a></li>
<li><a href="#esempi-d-uso" rel="nofollow">Esempi d’uso</a></li></ul></li>
<li><a href="#calcolo-realistico-pattern-matching" rel="nofollow">Calcolo realistico (pattern matching)</a>
<ul><li><a href="#ent" rel="nofollow">Ent</a></li>
<li><a href="#zxcvbn" rel="nofollow">zxcvbn</a></li>
<li><a href="#riassumendo" rel="nofollow">Riassumendo</a></li></ul></li>
<li><a href="#metodo-diceware" rel="nofollow">Metodo Diceware</a></li></ul>

<h2 id="calcolo-teorico-entropia-di-shannon">Calcolo teorico (Entropia di Shannon)</h2>

<p>Un primo strumento per la valutazione di una password è dato dall&#39;<strong>entropia di Shannon</strong>, che chiunque abbia usato un password manager certamente conoscerà.</p>

<p>Questo calcolo assume che l&#39;attaccante non sappia nulla della nostra password e debba provare ogni possibile combinazione (forza bruta).</p>

<p>Dato un alfabeto di <em>R</em> simboli e una password di lunghezza <em>L</em>, l&#39;entropia <em>E</em> sarà pari a:</p>

<p><em>E = log<sub>2</sub></em> ( <em>R<sup>L</sup></em> ) <em>= L  * log<sub>2</sub></em> ( <em>R</em> )</p>

<p>L&#39;entropia è un valore numerico espresso in bit (gli “Shannon”) che <strong>rappresenta una misura, non tanto della robustezza, quanto della “densità” della password</strong>, ossia di quanto lavoro richieda ad un calcolatore per essere indovinata. Più è alta, meglio è.</p>

<h3 id="spiegazione-dell-entropia-di-shannon">Spiegazione dell&#39;entropia di Shannon</h3>

<p>Innanzitutto notiamo che <em>R</em><sup>L</sup> è la <strong>dimensione dello spazio di possibilità in cui esiste la mia password</strong> e, per <em>R</em> e <em>L</em> sufficientemente grandi, è un numero talmente enorme da essere difficilmente comprensibile.</p>

<p>L&#39;equivalente <em>E</em>, che non è altro che l&#39;esponente della potenza di 2 tale per cui <em>2<sup>E</sup> = R<sup>L</sup></em>, risulta invece molto più gestibile e confrontabile.</p>

<p>Semplificando, se alla mia password lunga <em>L</em> corrisponde quindi un&#39;analoga chiave in bit lunga <em>E</em>, un attaccante che voglia scoprire la mia password, invece che indovinare gli <em>L</em> simboli da un alfabeto <em>R</em>, compirà lo stesso sforzo rispondendo correttamente ad un numero di <strong>domande binarie (SI / NO)</strong> pari a <em>E</em>, per ricostruire la giusta sequenza binaria.</p>

<p>Quanto costa ricostruire la sequenza?
O, in altre parole, qual è lo sforzo computazionale richiesto?</p>

<p>Si parla di  <strong>caso medio ottimale</strong> corrispondente ad una ricerca binaria in cui <strong>ogni domanda dimezza</strong> lo spazio di possibilità fino ad azzerarlo completamente.</p>

<p><em>E = L * log<sub>2</sub></em> ( <em>R</em> ), è quel numero di bit che mi dice <strong>quant&#39;è profondo</strong> l&#39;albero delle decisioni che il calcolatore deve percorrere, albero in cui il numero dei possibili cammini radice-foglia (equivalenti a tutte le possibili password) è <em>2<sup>E</sup> = R<sup>L</sup></em>.</p>
<ul><li>Nel <strong>caso migliore</strong>, rispondo correttamente a <strong>tutte le <em>E</em> domande</strong> al primo tentativo (trovo subito il mio cammino sull&#39;albero).</li>
<li>Nel <strong>caso peggiore</strong>, mi occorreranno <em>2<sup>E</sup></em> risposte (percorro tutti i cammini dell&#39;albero) equivalente proprio a <em>R<sup>L</sup></em>.</li></ul>

<p>Possiamo allora definire formalmente l&#39;entropia come <strong>quella quantità minima di informazione necessaria ad azzerare l&#39;incertezza legata all&#39;identificazione della password</strong>. Per questo motivo è espressa in bit.</p>

<p>Una misurazione di questo tipo <strong>ha senso solo se ipotizziamo che i simboli siano tutti equiprobabili</strong>.</p>

<p>La formula di Shannon misura, sì, l&#39;entropia, ma <strong>al suo massimo potenziale</strong>, quando la distribuzione dei simboli nella sequenza è omogenea e assolutamente casuale.</p>

<h3 id="esempi-d-uso">Esempi d&#39;uso</h3>

<p>Facciamo l&#39;esempio di una password lunga 20, costruita su un alfabeto di 66 simboli (alfanumerico con maiuscole e minuscole più 4 simboli speciali).
La dimensione di questo spazio di possibilità è pari a:</p>

<p><em>S<sub>p</sub> = R<sup>L</sup> = 66<sup>20</sup> = 2,46 * 10<sup>36</sup></em></p>

<p>Tentare un attacco di forza bruta su un oggetto del genere è semplicemente impensabile.
Faccio un esempio.</p>

<p>Per forzare la nostra password, supponiamo di avere a disposizione il più potente supercomputer del mondo, <strong>El Capitan</strong> ad oggi, dotato di una potenza di calcolo spaventosa, in media 2.000 exaFLOPS con picchi di 2.746 exaFLOPS, dove 1 exaFLOPS è <strong>un quintilione (10<sup>18</sup>) di operazioni al secondo</strong>.</p>

<p>Il calcolo di una password si misura in <strong>Hash al secondo</strong>, H/s per usare una notazione compatta, che è più dispendiosa della singola operazione.</p>

<p>Approssimando per eccesso con molto ottimismo e nell&#39;ipotesi di usare algoritmi estrememente deboli e poco costosi dal punto di vista computazionale come <strong>NTLM</strong> o <strong>MD5</strong>, possiamo pensare che il nostro sistema possa arrivare a calcolare, in queste condizioni, circa <strong>1,5 quintilioni</strong>  ( 1,5 * 10<sup>18</sup> ) <strong>H/s</strong>.
Per algoritmi come <strong>bcrypt</strong> o <strong>argon2</strong>, progettati per essere molto dispendiosi, tale potenza si riduce drasticamente di molti ordini di grandezza. Da 10<sup>18</sup> a 10<sup>9</sup> – 10<sup>6</sup>. Ma consideriamo il caso più favorevole perché sembra appunto una potenza enorme.</p>

<p>Ma anche questa tremenda esibizione di potenza annichilisce di fronte al numero di calcoli da compiere nel nosro spazio di possibilità.
Dato <em>S<sub>p</sub></em> lo spazio di possibilità (il numero di possibili combinazioni), il tempo <em>T</em> espresso in secondi necessario ad eseguire tutte le operazioni sarà:</p>

<p><em>S<sub>p</sub> = 66<sup>20</sup> = 2,46 * 10<sup>36</sup></em></p>

<p><em>T = 2,46 * <sup>36</sup> / 1,5 * 10<sup>18</sup> = 1,64 * 10<sup>18</sup></em></p>

<p>Che equivale a circa <strong>52 miliardi di anni</strong>.</p>

<p>Per avere un&#39;idea di questa grandezza cosmica, si pensi che l&#39;età del nostro universo è di circa <strong>13,8 miliardi di anni.</strong> Quindi il calcolo della nostra password potrebbe richiedere un tempo che è grossomodo <strong>3,8 volte l&#39;età dell&#39;universo</strong>.</p>

<p>I 120 bit di entropia, sono dunque <strong>la misura di questo sforzo potenziale</strong>, interpretabile equivalentemente in due modi differenti:</p>
<ul><li>la <strong>probabilità</strong> di riuscire a trovare la password tirando a indovinare, probabilità che è 1 su 2<sup>120</sup></li></ul>

<p>oppure</p>
<ul><li>la <strong>capacità</strong> di rispondere <strong>correttamente e consecutivamente</strong> a 120 domande di tipo (SI / NO) (ricerca del giusto cammino in un albero decisionale binario profondo <strong>120 livelli</strong>)</li></ul>

<p>Allungando la nostra password di altri due caratteri, l&#39;entropia arriva a circa 133 e il calcolo delle possibili combinazioni, posto che fosse possibile ignorando le leggi della termodinamica, richiederebbe circa <strong>16.500 di volte l&#39;età dell&#39;universo</strong>.</p>

<p><strong>Considerazione a margine:</strong> è la lunghezza della password ad incidere più che la complessità dell&#39;alfabeto. E lo vediamo dalla formula dell&#39;entropia, perché, in una funzione di elevamento a potenza <em>R<sup>L</sup></em>, aumentare l&#39;esponente <em>L</em> fa crescere molto più rapidamente la funzione che non aumentando la base <em>R</em>.</p>

<h2 id="calcolo-realistico-pattern-matching">Calcolo realistico (pattern matching)</h2>

<p>L&#39;entropia di Shannon fornisce un riscontro utilizzabile solo ipotizzando che:</p>
<ul><li>le scelte siano indipendenti</li>
<li>la distribuzione sia uniforme</li></ul>

<p>e in uno scenario di questo tipo, l&#39;attacco di forza bruta non è una via percorribile.</p>

<p>Allo stesso tempo, se non vengono rispettati questi vincoli, l&#39;entropia dà una falsa sicurezza perché la formula di Shannon “standard” non tiene conto della ridondanza:</p>

<p>Consideriamo questa password: <code>Password12345678</code></p>
<ul><li><strong>teoria</strong>: la formula <em>E = L * log2R</em> direbbe che la sua entropia sia 95, ottima.</li>
<li><strong>realtà</strong>: poiché è una sequenza ovvia, l&#39;attaccante la proverà per prima. La sua entropia reale sarà vicina a <strong>0 bit</strong>.</li></ul>

<p>L&#39;entropia quindi misura la “densità” della password, la sua imprevedibilità potenziale ma non dà nessuna informazione sulla presenza di schemi ripetuti e sul <strong>pattern matching</strong>.</p>

<h3 id="ent">Ent</h3>

<p>L&#39;essere umano come generatore di entropia fa schifo.
Ecco perché, per un attaccante, prima ancora di provare tutte le possibili combinazioni di caratteri, un attacco a dizionario può far risparmiare un sacco di tempo.
Infatti sempre Shannon ci dice che nelle parole dei linguaggi naturali alcune lettere ricorrono più di altre, non serve lo stesso numero di domanda ma molto meno e così l&#39;entropia media diminuisce.
Per prevenire questi effetti collaterali, il nostro metodo di generazione e quindi ciò che viene generato, deve essere testato con qualcos&#39;altro che non sia la semplice entropia.</p>

<p><code>ent</code> è un tool a linea di comando che fa 4 valutazioni differenti:</p>
<ul><li>entropia</li>
<li>Chi-quadrato</li>
<li>Media aritmetica</li>
<li>Monte Carlo Pi</li></ul>

<p><strong>N.B.</strong> <code>ent</code> non è adatto alla valutazione della singola password perché ha bisogno di migliaia di dati (almeno 1K). Una singola password di 24 caratteri per es. (24 byte) non ha materiale casuale sufficiente affinché <code>ent</code> converga verso un giudizio oggettivo.</p>

<p><strong>Entropia</strong>
L&#39;entropia misura la densità di informazione. In ent, viene calcolata in bit per carattere (byte).</p>
<ul><li><strong>Il valore</strong>: Si analizza il file byte per byte, il valore massimo è 8.0 (ogni byte è totalmente imprevedibile).</li>
<li><strong>Interpretazione</strong>: Più il valore è vicino a 8, più la casualità è “densa” e difficile da indovinare tramite attacchi basati su dizionario. Se il valore è basso (es. 2.0 o 3.0), significa che ci sono molte ripetizioni o uno schema prevedibile.</li>
<li><strong>Compressione</strong>: ent ti dice anche quanto il file potrebbe essere compresso. Un&#39;entropia di 8.0 significa che il file è già “puro caos” e non può essere compresso ulteriormente.</li></ul>

<p><strong>Chi-quadrato</strong>
Il test del chi-quadrato prova a capire se il disordine presente nel file sia veramente equo o se si preferiscono certi caratteri ad altri. Esamina la distribuzione dei caratteri e la confronta con una distribuzione uniforme teorica. Il risultato viene presentato come percentuale con questi scaglioni:</p>
<ul><li><strong>10% &lt; chi<sup>2</sup> &lt; 90%</strong>: La sequenza è considerata casuale. Il 50% è il valore “perfetto”.</li>
<li><strong>chi<sup>2</sup> &lt; 1% o chi<sup>2</sup> &gt; 99%</strong>: È quasi certamente non casuale.
<ul><li><strong>chi<sup>2</sup> = 99.99%</strong>: i dati sono sospettosamente regolari;</li>
<li><strong>chi<sup>2</sup> = 0.01%</strong>: i dati sono “troppo” casuali per essere naturali (sospetta manipolazione)</li></ul></li></ul>

<p><strong>Media aritmetica</strong>
Per capire se la distribuzione è sufficientemente omogenea, si fa la somma dei valori dei byte del file e si fa una media.</p>

<p>Poiché i byte vanno da 0 a 255, il valore ideale della media sarebbe 127,5.
Se è troppo lontano dalla media avvcinandosi ad uno dei due estremi (ad es. 50 o 190), vuol dire che si sta usando solo un piccola parte dei caratteri a disposizione e questo, a suo modo di vedere, rende le password più prevedibili.</p>

<p><strong>Monte Carlo Pi</strong>
È il metodo più fantasioso di tutti.
I dati casuali vengono trasformati in una serie di “dardi” virtuali che vanno a colpire un bersaglio. L&#39;obiettivo non è quello di colpire un ipotico centro ma di verificare che i “dardi” si distribuiscano uniformemente nel bersaglio.</p>

<p>Tutto ciò si realizza immaginando di avere un quadrato <em>1x1</em> e ¼ di cerchio al suo interno di raggio 1 e area π/4
I dati della sequenza casuale vengono prelevati a gruppi di <em>n</em> byte e supponiamo <em>n = 3</em> per ora.
Ogni gruppo di 3 byte sarà un numero compreso tra <em>0 e 2<sup>24</sup>-1</em>.
Se normalizziamo questo numero dividendolo per  <em>2<sup>24</sup></em>, otteniamo un numero compreso fra 0 e 1.
Calcolando le coordinate in questo modo, col teorema di Pitagora possiamo verificare se la coordinata (X,Y) “cada” nel quarto di cerchio oppure no e ciò succede se:</p>

<p><em>X<sup>2</sup> + Y<sup>2</sup> ≤ 1</em></p>

<p>Lanciando un migliaio di queste “frecce”, accumuliamo dati sufficiente per fare una stima.</p>

<p>Se indichiamo con <em>In</em> il numero di “lanci” con successo e con <em>Total</em> il numero totale di lanci effettuati:</p>

<p><em>4 * (ln/Total)</em> si avvicinerà a π solo se la distribuzione dei caratteri sarà uniforme (indice di una casualità omogenea), altrimenti divergerà in maniera significativa (indice della presenza di pattern o di ripetizioni).</p>

<h3 id="zxcvbn">zxcvbn</h3>

<p><code>ent</code> fa un&#39;analisi statistica della distribuzione dei bit in un generatore di casualità.</p>

<p><code>zxcvbn</code> invece fa un&#39;analisi di tipo euristico, è verticale sulla verifica delle password in particolare nel rilevare se vi sono schemi o ripetizioni di caratteri che renderebbero le password violabili.</p>

<p>Il suo algoritmo scompone le password in pezzi dei quali cerca corrispondenze in dizionari o schemi come:</p>
<ul><li><strong>dizionari</strong>: controlla la presenza di parole di uso comune</li>
<li><strong>sequenze</strong>: controlla la presenza di serie di caratteri prevedibili come “123456”, “abcde”</li>
<li><strong>pattern spaziali</strong>: controlla la presenza di percorsi sulla tastiera come “qwerty”, “asdfg”, “zcvbn” o sequenze diagonali</li>
<li><strong>ripetizioni</strong>: ripetizione di caratteri come “kkkkkkkkkk” o “12121212”</li>
<li><strong>l33t</strong>: una parola come “p4$$w0rd” viene subito riconosciuta come “password”</li>
<li><strong>date</strong>: riconosce giorni, mesi, anni, anche composti come “15062026”</li></ul>

<p>Il suo uso è molto semplice.
Le si dà in pasto la password e <code>zxcvbn</code> restituisce diverse informazioni utili:</p>
<ul><li>uno score da “0” (terribile) a “4 (ottima);</li>
<li>la stima di quanto tempo impiegherebbe un hacker a violarla in base a vari scenari di attacco;</li>
<li>suggerimenti su come migliorare eventualmente la password.</li></ul>

<p><code>zxcvbn</code> era una libreria javascript orginariamente sviluppata da Dropbox e ora disponibile in tante forme: go, python, c++.</p>

<p>L&#39;originale Dropbox in javascript, non più manutenuto, può essere trovata qui: <a href="https://github.com/dropbox/zxcvbn" rel="nofollow">https://github.com/dropbox/zxcvbn</a>.</p>

<p>Benché esistano diversi porting in python, se c&#39;è l&#39;esigenza di usare la versione legacy, gli stessi sviluppatori dell&#39;originale <code>zxcvbn</code> consigliano questa versione: <a href="https://github.com/dwolfhub/zxcvbn-python" rel="nofollow">https://github.com/dwolfhub/zxcvbn-python</a>, che può essere installata con <code>pip</code>.</p>

<p>In realtà la versione migliore è un fork in typescript, <strong>zxcvbn-ts</strong> che offre modularità (a differenza della versione python che è monolitica), maggior sicurezza, risoluzione di bug, aggiornamento continuo dizionari compresi.</p>

<p>Per capirci, mentre <code>ent</code> usa l&#39;entropia di Shannon per valutare la probabilità statistica dei byte, <code>zxcvbn</code> cerca di calcolare una stima dei tempi necessari per indovinare la password.</p>

<p>Una passphrase su ent avrebbe un punteggio risibile perché le entropie di parole comuni sono molto basse. Su <code>zxcvbn</code> invece avrebbe un punteggio molto alto perché l&#39;entropia di una parola viene calcolata sulla posizione del dizionario che la contiene per cui un hacker dovrebbe provare milioni di combinazioni prima di trovarla.</p>

<p>Allo stesso modo, password che per <code>ent</code> sarebbero ottime, per <code>zxcvbn</code> sarebbero da evitare perché legate a pattern o a ripetizioni.</p>

<h3 id="riassumendo">Riassumendo</h3>

<p>Se si deve testare una password / passphrase, sicuramente <code>zxcvbn</code>.
Se si deve testare un generatore di casualità o un keyfile di almeno 2k, sicuramente <code>ent</code>.</p>

<h2 id="metodo-diceware">Metodo Diceware</h2>

<p>Visto che nell&#39;ultima parte abbiamo evidenziato l&#39;anomalia che sorge nel momento in cui si valuta un oggetto casuale o dal punto di vista puramente statistico o dal punto di vista euristico, vale la pena di spendere due parole sulla modalità di creazione delle passphrase usando il <strong>metodo Diceware</strong>.</p>

<p>Usando come password parole estratte dal linguaggio naturale bisogna fare i conti col problema della <strong>prevedibilità</strong>.
Shannon ha dimostrato che la lingua italiana (o inglese) ha un&#39;entropia molto bassa (circa 1-1.5 bit per lettera) perché dopo una “q” ci si aspetta quasi sempre una “u”, e dopo un soggetto ci si aspetta un verbo. E così via.
Ecco perché, piuttosto che valutare l&#39;entropia nel suo complesso e provare ogni possibile combinazione, un moderno calcolatore inzia col far ricorso a “pattern” umani per violare password in pochi minuti invece che millenni.</p>

<p>Per unire la sicurezza del calcolo casuale alla comodità di una password menmonica, si ricorre al <strong>metodo Diceware</strong> che consiste nel far uso di un dizionario di migliaia di parole.</p>

<p>Quello classico, di 7776 parole inglesi, curato dall EFF si può trovare qui:</p>

<pre><code class="language-bash">curl -L https://www.eff.org/files/2016/07/18/eff_large_wordlist.txt &gt; dic_diceware.txt
</code></pre>

<p>Altrimenti Tarin Gamberini espone il suo dizionario diceware , aggiornato al 2019, qui: <a href="https://www.taringamberini.com/downloads/diceware_it_IT/lista-di-parole-diceware-in-italiano/4/word_list_diceware_it-IT-4.txt" rel="nofollow">https://www.taringamberini.com/downloads/diceware_it_IT/lista-di-parole-diceware-in-italiano/4/word_list_diceware_it-IT-4.txt</a>.</p>

<p>Questo dizionario contiene 6<sup>5</sup> parole numerate da 11111 a 66666.
La passphrase è composta da <em>n</em> di queste parole il cui indice è ricavato lanciando un dado (o un analogo virtuale) per 5 volte.
In questo modo le parole non sono correlate fra di loro come si potrebbero trovare in una frase, vanificando ogni possibile speculazione sulla sua composizione.</p>

<p>Volendo fare un calcolo dell&#39;entropia, supponendo di costruire una passphrase di 6 parole:</p>

<p><em>E = L * log<sub>2</sub> R = 6 * log<sub>2</sub> 7776 ~ 77,6</em></p>

<p>Nella password classiche basate su un alfabeto di <em>R</em> simboli, il mattoncino è rappresentato dal <strong>singolo carattere</strong> che ha una probabilità <em>1/R</em> di essere estratto.</p>

<p>Con Diceware, il mattoncino è <strong>la parola</strong> che ha <strong>una probabilità su 7776</strong> di essere estratta. Ogni parola in più, aggiunge una quantità enorme di incertezza.</p>

<p>Ecco perché con sole 6 parole abbiamo già una passphrase molto robusta e con 10 parole siamo di fronte ad una passphrase inattacabile, almeno dal punto di vista dell&#39;analisi statistica (<em>E &gt; 129</em>) e imperforabile anche ricorrendo ad analisi euristiche.</p>

<p><strong>Regola aurea</strong>: la scelta delle parole deve essere <strong>realmente</strong> casuale e non seguire regole grammaticali o preferenze personali. Altrimenti sarà un gioco da ragazzi violarla con un approccio a-là <code>zxcvbn</code>.</p>

<p><a href="/aytin/tag:entropy" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">entropy</span></a> <a href="/aytin/tag:shannon" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">shannon</span></a> <a href="/aytin/tag:bruteforce" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">bruteforce</span></a> <a href="/aytin/tag:ent" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ent</span></a> <a href="/aytin/tag:zxcvbn" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">zxcvbn</span></a> <a href="/aytin/tag:diceware" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">diceware</span></a> <a href="/aytin/tag:passphrase" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">passphrase</span></a> <a href="/aytin/tag:PatternMatching" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">PatternMatching</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/come-valutare-la-resistenza-di-una-password-trilogia-della-password-2-di-3</guid>
      <pubDate>Thu, 22 Jan 2026 19:04:39 +0000</pubDate>
    </item>
    <item>
      <title>Come generare una password o un keyfile sicuri (Trilogia Della Password - 1 di 3)</title>
      <link>https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di</link>
      <description>&lt;![CDATA[password&#xA;&#xA;La generazione di una password o di un keyfile si basa sulla casualità ossia sulla capacità del sistema di generare sequenze di simboli non prevedibili.&#xA;In questo contesto bisogna avere chiari 3 concetti legati fra loro: casualità, sorgente d&#39;entropia, entropia della password.&#xA;!--more--&#xA;&#xA;Definizioni varie&#xA;Entropia del kernel (CSPRNG)&#xA;Come generare password e keyfile&#xA;   Analisi&#xA;   Valutazione&#xA;   Conclusione&#xA;Bonus - Modalità paranoia&#xA;   Generazione password&#xA;   Generazione keyfile&#xA;   GPG Random&#xA;Riepilogo finale&#xA;   2) Keyfile binario&#xA;   3) Password complessa con caratteri stampabili&#xA;   5) Keyfile binario con openssl&#xA;&#xA;Definizioni varie&#xA;Casualità&#xA;In generale, posso parlare di casualità quando non riesco ad individuare un pattern o un&#39;organizzazione deterministica in una sequenza di dati.&#xA;&#xA;Da un punto di vista crittografico, una sequenza è considerata &#34;casuale&#34; se non esiste un algoritmo che possa prevedere il bit successivo con una probabilità superiore al 50% (puro caso).&#xA;&#xA;Sorgente d&#39;entropia&#xA;La casualità è resa possibile dalla sorgente d&#39;entropia che è il dispositivo o il processo fisico che genera il rumore grezzo per produrre dati casuali. È l&#39;origine dell&#39;incertezza e il suo grado di &#34;purezza&#34; è fondamentale per la produzione della casualità.&#xA;&#xA;Le sorgenti di entropia possono essere fisiche (TRNG) o software (PRNG). In quest&#39;ultimo caso si parla di pseudo-casualità perché si tratta di algoritmi che espandono un seed (un seme) casuale in una sequenza anche arbitrariamente lunga che sembra casuale.&#xA;&#xA;Bit di entropia di una sequenza&#xA;O entropia della sequenza, è la misura numerica di quanto sia imprevedibile la sequenza casuale di dati.&#xA;&#xA;Quindi:&#xA;&#xA;la sorgente di entropia è il nostro generatore di incertezza;&#xA;la casualità, la cui qualità dipende totalmente dalla prima, è il processo che produce la sequenza di dati;&#xA;l&#39;entropia, in termini di bit, che è funzione della lunghezza della sequenza e del set di simboli a disposizione, è la misura di quanto la sequenza sia crittograficamente non prevedibile.&#xA;&#xA;Entropia del kernel (CSPRNG)&#xA;Su una qualunque linuxbox il protagonista per la generazione dell&#39;entropia necessaria è ovviamente sua maestà il kernel, che è fatto per essere anche un CSPRNG, impronunciabile acronimo che sta per Cryptographically Secure Pseudo-Random Number Generator.&#xA;&#xA;Il kernel infatti, già dall&#39;avvio, raccoglie entropia (entropy harvesting), rumore casuale direttamente dall&#39;hardware (interrupt del disco, tastiera, mouse, istruzioni CPU come RDRAND). Questi dati grezzi vengono mescolati in un serbatoio (l&#39;entropy pool) da cui l&#39;algoritmo (ChaCha20) pesca per espandere questi dati in un flusso infinito di dati pseudo casuali.&#xA;&#xA;Per avere una misura di quanta casualità abbia il sistema possiamo ricorrere al seguente costrutto:&#xA;cat /proc/sys/kernel/random/entropyavail&#xA;un valore da 256 in poi ci dice abbiamo entropia sufficiente per generare chiavi e quant&#39;altro.&#xA;&#xA;Finita la parte di teoria, vediamo in quanti modi possiamo generare una password bella robusta o un keyfile.&#xA;Come generare password e keyfile&#xA;Per generare sequenze di dati casuali possiamo seguire 2 vie:&#xA;&#xA;attingere direttamente alla sorgente di entropia fornita dal kernel;&#xA;usare la sorgente per prelevare un seme e generare la sequenza casuale via software che è la via di openssl e di pwgen.&#xA;&#xA;Modalità&#xA;&#xA;dd if=/dev/urandom of=mykey.bin bs=4096 count=1 iflag=fullblock status=none&#xA;head -c 4K /dev/urandom   mykey.bin&#xA;tr -dc &#39;[:graph:]&#39;  /dev/urandom | head -c 4096  mykey.txt&#xA;pwgen -s 4095 1   mykey.txt&#xA;openssl rand -out mykey.bin 4096&#xA;&#xA;Analisi&#xA;Come si comportano questi procedimenti? Proviamo ad analizzarli.&#xA;&#xA;Casualità&#xA;Una prima distinzione va fatta sulla modalità di creazione della casualità.&#xA;&#xA;I primi 3 metodi fanno riferimento direttamente alla sorgente senza introdurre altre stratificazioni software. Sul piano teorico, rappresentano il punto più vicino alla casualità fisica che si possa avere su un computer.&#xA;&#xA;Openssl e pwgen no, sono due consumatori per /dev/urandom. &#xA;Devono prima pescare un seme da /dev/urandom.&#xA;Una volta ottenuto il seme, usano i propri algoritmi (quelli di openssl sono solitamente basati su AES-CTR o SHA2) per generare una sequenza infinita di numeri casuali.&#xA;Pwgen fa una cosa simile ma è stato progettato di base per costruire password pronunciabili (minore entropia intrinseca).&#xA;&#xA;Velocità&#xA;Openssl, fra tutti, è il più veloce, soprattutto se si ha l&#39;esigenza di produrre casualità per volumi di decine di giga o di tera.&#xA;Ciò è dovuto al fatto che openssl effettua pochissime syscall per prelevare il seme per poi spremere solo la cpu che, supportando quasi certamente le istruzioni hardware AES-NI, rende il processo poco impegnativo per la cpu stessa e brutalmene efficiente.&#xA;Agire solo sul kernel, pur conservando la purezza della casualità, causa un rallentamento notevole dovuto al grandissimo numero di syscall necessarie e dalla corrispondente attivazione degli algoritmi di cifratura. Inoltre, mentre dd può contare su un buffer relativamente più capiente, cat, tr, head o qualuque altro oggetto che &#34;beva&#34; direttamente da /dev/urandom, hanno dei buffer molto più piccoli a disposizione, 1MB vs 8-16KB, il cui rapporto funge da moltiplicatore sul numero di operazioni necessarie.&#xA;&#xA;Sicurezza&#xA;Tutti i procedimenti indicati, sono estremamente sicuri, anzi, crittograficamente sicuri. Fermo restando che vale sempre l&#39;osservazione fatta sopra sulla metrica dell&#39;entropia di una sequenza casuale: è funzione del set di caratteri e della lunghezza della sequenza. Conti alla mano, con un alfabeto di una settantina di caratteri, una sequenza di almeno 20 caratteri possiederà un&#39;entropia di circa 120 bit che la rendono impenetrabile per gli attuali sistemi di calcolo.&#xA;&#xA;Usare direttamente la sorgente d&#39;entropia, è sicuramente più vantaggioso perché ci fidiamo del kernel.&#xA;Inoltre è più isolato perché lavora a livello del kernel dove i processi utente, anche quelli malevoli, non possono accedere alle sue zone di memoria.&#xA;&#xA;Openssl, pwgen e tutti quelli che sono generatori secondari, possono incorrere in quella che si diefinisce duplicazione della casualità.&#xA;Se l&#39;applicazione non è scritta bene, c&#39;è il rischio che il processo, forkandosi, possa &#34;duplicare&#34; la casualità. In sostanza, i processi padre e figlio finiranno per produrre la stessa sequenza di simboli casuali. Una catastrofe.&#xA;Vecchie versioni di openssl, ante 1.1.1 per es., hanno sofferto di questa anomalia.&#xA;Valutazione&#xA;I metodi 1,2,5 producono un keyfile di dati binari, quindi con un entropia enorme quasi vicina all&#39;ottimo teorico.&#xA;Come detto, openssl è mostruosamente più veloce.&#xA;&#xA;Volendo essere purista, per un keyfile i metodi 1 e 2 (praticamente equivalenti) sono da preferire.&#xA;Per produrre tera di dati casuali (storage, test di rete) sicuramente openssl. Se il volume non dovesse essere esagerato e siamo paranoici, anche il metodo 1 può andare bene.&#xA;&#xA;Per la produzione di una password complessa con simboli stampabili (non necessariamente pronunciabile altrimenti l&#39;entropia sarebbe ancora più bassa) il metodo 3 è da preferire da un punto di vista matematico.&#xA;&#xA;Mettendo da parte openssl che fa comunque un ottimo lavoro (universalmente riconosciuto con tanto di certificazioni FIPS-2), voglio spendere due parole su pwgen.&#xA;pwgen, con il flag -s, crea delle sequenze completamente randomiche su un alfabeto di 62 caratteri.&#xA;Se la lunghezza della sequenza è   = 20, e quindi con un&#39;entropia teorica di ~115-120, avremo delle password abbastanza inviolabili dagli attuali sistemi di calcolo.&#xA;Usare il flag -y potrebbe sembrare una buona idea perché si forza ad estendere il set di caratteri.&#xA;Sicuramente da una parte aumenta l&#39;entropia della sequenza generata, visto che l&#39;alfabeto è molto più vasto. Dall&#39;altra però la forzatura va a compromettere l&#39;uniformità della distribuzione casuale dei simboli.&#xA;Conclusione&#xA;&#xA;password/keyfile stampabile: tr -dc &#39;[:graph:]&#39;  /dev/urandom | head -c [n]  mykey.txt&#xA;password/keyfile binario: head -c [n] /dev/urandom   mykey.bin (equivalentemente dd if=/dev/urandom of=mykey.bin bs=4096 count=1 iflag=fullblock status=none)&#xA;cancellazione disco: openssl rand [dimdisco] | dd of=/dev/sdX bs=1M status=progress&#xA;&#xA;Bonus - Modalità paranoia&#xA;Generazione password&#xA;Se non ci fidassimo della sorgente di casualità, possiamo aggiungere alla sorgente di entropia un nostro segreto personale e &#34;mescolarli&#34; attraverso una funzione sha256 o sha512 rendendo il tutto ancora crittograficamente sicuro.&#xA;&#xA;(head -c 4K /dev/urandom ; read -s -p &#34;Per aumentare l&#39;entropia inserisci una frase segreta o premi tasti a caso: &#34; secret) | sha512sum | cut -d&#39; &#39; -f1   mykey.txt.&#xA;&#xA;È certamente una password molto robusta per violare la quale occorrerebbe compromettere la sorgente d&#39;entropia e indovinare il segreto personale (N.B. stiamo facendo l&#39;ipotesi che si provi a rompere il meccanismo di generazione della chiave non che si provi l&#39;enumerazione attraverso un attacco brute-force).&#xA;&#xA;Generazione keyfile&#xA;Per produrre un keyfile di 4096 bytes con la stessa premessa, faremo uso di openssl.&#xA;&#xA;si genera esplicitamente un seme dalla sorgente di entropia del kernel&#xA;come prima, con sha2 si mescola  il seme con un nostro segreto&#xA;si dà in pasto ad openssl.&#xA;&#xA;Creiamo un seme unico mescolando /dev/urandom e il mio input con sha512&#xA;Usiamo quel seme per generare 4KB di dati casuali &#34;espansi&#34;&#xA;(head -c 256 /dev/urandom; read -s -p &#34;Per aumentare l&#39;entropia inserisci una frase segreta o premi tasti a caso: &#34; secret; echo &#34;$secret&#34;) | sha512sum | cut -d &#34; &#34; -f1 | openssl enc -aes-256-ctr -pbkdf2 -pass stdin -nosalt -in /dev/zero | head -c 4096   mykey.bin&#xA;L&#39;errore che compare alla fine è un falso negativo, dovuto al fatto che openssl sta ancora provando a scrivere dati e head li tronca all&#39;improvviso. &#xA;&#xA;Giusto due righe di spiegazione:&#xA;&#xA;head -c 256 /dev/urandom: preleva un po&#39; di dati casuali &#34;puri&#34;&#xA;read -sp secret: si inserisce una password, una frase o tasti schiacciati a caso per aumentare l&#39;entropia&#xA;sha512sum | cut -d &#34; &#34; -f1: si mescola tutto e si preleva solo l&#39;esadecimale di 64 bytes&#xA;openssl enc -aes-256-ctr -pbkdf2 -pass stdin -nosalt -in /dev/zero: openssl, che riceve il seme sullo stdin, fa la sua magia producendo un fiume di dati casuali&#xA;head -c 4096: tronca il &#34;fiume&#34; alla lunghezza voluta per il nostro keyfile&#xA;&#xA;Quindi:&#xA;&#xA;Contro i bug del kernel: se la nostra sorgente d&#39;entropia fosse compromessa e diventasse deterministica, occorrerebbe comunque conoscere il nostro segreto&#xA;Contro il keylogging: anche se il nostro segreto potesse essere svelato, la sorgente d&#39;entropia garantirebbe comunque l&#39;inviolabilità della nostra password&#xA;&#xA;GPG Random&#xA;Quando si parla di paranoia, un altro ottimo candidato per produrre password e keyfile è certamente GPG.&#xA;GPG non si llimita a copiare dati da /dev/urandom ma utilizza una propria libreria crittografica chiamata Libgcrypt, che implementa un generatore di numeri pseudocasuali, crittograficamente sicuro, molto sofisticato.&#xA;&#xA;A differenza di ciò che abbiamo visto finora, GPG permette di impostare un livello di qualità per la casualità da produrre.&#xA;&#xA;livello 0 (Debole): per scopi didatti, usato raramente.&#xA;livello 1 (Avanzato): adatto per chiavi di sessione e cifratura standard. Corrisponde ad una casualità di alta qualità&#xA;livello 2 (Forte): utilizzato per le chiavi a lungo termine (le chiavi private di GPG). È un livello estremamente conservativo. Se GPG valuta di non avere entropia sufficientemente fresca, si mette in attesa.&#xA;&#xA;GPG non si fida ciecamente del kernel e così Libgcrypt crea un proprio pool di entropia in user space.&#xA;&#xA;Libgcrypt pesca al solito un seme da /dev/urandom&#xA;il seme viene rimescolato con sha2 o aes&#xA;per evitare che i dati casuali finiscano sullo swap, libgcrypt usa pagine di memoria protetta (mlock)&#xA;&#xA;Impostando il livello 2, libgcrypt può decidere di scartare molti più dati se ritiene che il pool di entropia non sia abbastanza &#34;fresco&#34;. Inoltre, in virtù della sua diffidenza, non consegna mai tutto ciò che arriva dal pool di entropia del kernel così come viene, ma viene rimescolato con sha2 o simili e al livello 2 tutto questo, oltre che avvenire con molta più intensità, avviene anche con molta più frequenza (GPG &#34;chiede&#34; spesso bit freschi al kernel) per scongiurare l&#39;eventualità che un attaccante possa prevedere i bit successivi basandosi su quelli passati&#xA;&#xA;Inoltre, GPG salva una parte di questa entropia &#34;pregiata&#34; in ~/.gnupg/randomseed per avere una base di casualità sicura dalle sessioni precedenti nel caso in cui un computer, appena avviato, non avesse ancora accumulato sufficiente entropia.&#xA;&#xA;Si capisce bene come il livello di paranoia di GPG sia fuori scala ma per fortuna tutta questa potenza è totalmente nascosta sotto il cofano di GPG. Infatti per produrre il nostro keyfile binario basta:&#xA;gpg --dev-random 2 4096&#xA;Riepilogo finale&#xA;E dunque, 3 delle 5 modalità sopra descritte, la 2, la 3 e la 5, possono essere ripensate con l&#39;entropia di GPG invee che con quella tipica del kernel.&#xA;2) Keyfile binario&#xA;Kernel entropy&#xA;head -c 4K /dev/urandom   mykey.bin&#xA;&#xA;Libgcrypt entropy&#xA;gpg --dev-random 2 4096 -o mykeygpg.bin&#xA;&#xA;3) Password complessa con caratteri stampabili&#xA;Kernel entropy&#xA;tr -dc &#39;[:graph:]&#39;  /dev/urandom | head -c 4096  mykey.txt&#xA;&#xA;Libgcrypt entropy&#xA;gpg --gen-random 1 10000 | tr -dc &#39;A-Za-z0-9&#39; | head -c 4096   mykeygpg.txt&#xA;&#xA;5) Keyfile binario con openssl&#xA;Kernel entropy&#xA;openssl rand -out mykey.bin 4096&#xA;&#xA;Libgcrypt entropy&#xA;(gpg --gen-random 2 128) | openssl rand -out mykey_gpg.bin -rand /dev/stdin 4096&#xA;&#xA;#entropy #shannon #csprng #password #keyfile #dd #openssl #pwgen #AesCtr #AesNi #sha2 #gpg #bruteforce]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/ffe7c43a6-a8b5f2/hEKmIBrqD2NJ/bA54jpqPlJRapj7UnTRIhqtjGgMEgwrDWtH75WNu.jpg" alt="password"></p>

<p>La generazione di una password o di un keyfile si basa sulla <strong>casualità</strong> ossia sulla capacità del sistema di generare sequenze di simboli non prevedibili.
In questo contesto bisogna avere chiari 3 concetti legati fra loro: <strong>casualità</strong>, <strong>sorgente d&#39;entropia</strong>, <strong>entropia</strong> della password.
</p>
<ul><li><a href="#definizioni-varie" rel="nofollow">Definizioni varie</a></li>
<li><a href="#entropia-del-kernel-csprng" rel="nofollow">Entropia del kernel (CSPRNG)</a></li>
<li><a href="#come-generare-password-e-keyfile" rel="nofollow">Come generare password e keyfile</a>
<ul><li><a href="#analisi" rel="nofollow">Analisi</a></li>
<li><a href="#valutazione" rel="nofollow">Valutazione</a></li>
<li><a href="#conclusione" rel="nofollow">Conclusione</a></li></ul></li>
<li><a href="#bonus-modalit%C3%A0-paranoia" rel="nofollow">Bonus – Modalità paranoia</a>
<ul><li><a href="#generazione-password" rel="nofollow">Generazione password</a></li>
<li><a href="#generazione-keyfile" rel="nofollow">Generazione keyfile</a></li>
<li><a href="#gpg-random" rel="nofollow">GPG Random</a></li></ul></li>
<li><a href="#riepilogo-finale" rel="nofollow">Riepilogo finale</a>
<ul><li><a href="#2-keyfile-binario" rel="nofollow">2) Keyfile binario</a></li>
<li><a href="#3-password-complessa-con-caratteri-stampabili" rel="nofollow">3) Password complessa con caratteri stampabili</a></li>
<li><a href="#5-keyfile-binario-con-openssl" rel="nofollow">5) Keyfile binario con openssl</a></li></ul></li></ul>

<h2 id="definizioni-varie">Definizioni varie</h2>

<p><strong>Casualità</strong>
In generale, posso parlare di <strong>casualità</strong> quando non riesco ad individuare un pattern o un&#39;organizzazione deterministica in una sequenza di dati.</p>

<p>Da un punto di vista crittografico, una sequenza è considerata “casuale” se non esiste un algoritmo che possa prevedere il bit successivo con una probabilità superiore al 50% (puro caso).</p>

<p><strong>Sorgente d&#39;entropia</strong>
La casualità è resa possibile dalla sorgente d&#39;entropia che è il dispositivo o il processo fisico che genera il rumore grezzo per produrre dati casuali. È l&#39;origine dell&#39;incertezza e il suo grado di “purezza” è fondamentale per la produzione della casualità.</p>

<p>Le sorgenti di entropia possono essere fisiche (<strong>TRNG</strong>) o software (<strong>PRNG</strong>). In quest&#39;ultimo caso si parla di <strong>pseudo-casualità</strong> perché si tratta di algoritmi che espandono un seed (un seme) casuale in una sequenza anche arbitrariamente lunga che <strong>sembra</strong> casuale.</p>

<p><strong>Bit di entropia di una sequenza</strong>
O <strong>entropia della sequenza</strong>, è la misura numerica di quanto sia imprevedibile la sequenza casuale di dati.</p>

<p>Quindi:</p>
<ul><li>la <strong>sorgente di entropia</strong> è il nostro <strong>generatore</strong> di incertezza;</li>
<li>la <strong>casualità</strong>, la cui qualità dipende totalmente dalla prima, è il <strong>processo</strong> che produce la sequenza di dati;</li>
<li>l&#39;<strong>entropia</strong>, in termini di bit, che è funzione della lunghezza della sequenza e del set di simboli a disposizione, è la <strong>misura</strong> di quanto la sequenza sia crittograficamente non prevedibile.</li></ul>

<h2 id="entropia-del-kernel-csprng">Entropia del kernel (CSPRNG)</h2>

<p>Su una qualunque linuxbox il protagonista per la generazione dell&#39;entropia necessaria è ovviamente sua maestà il kernel, che è fatto per essere anche un <strong>CSPRNG</strong>, impronunciabile acronimo che sta per <strong>C</strong>ryptographically <strong>S</strong>ecure <strong>P</strong>seudo-<strong>R</strong>andom <strong>N</strong>umber <strong>G</strong>enerator.</p>

<p>Il kernel infatti, già dall&#39;avvio, raccoglie entropia (<strong>entropy harvesting</strong>), rumore casuale direttamente dall&#39;hardware (interrupt del disco, tastiera, mouse, istruzioni CPU come <strong>RDRAND</strong>). Questi dati grezzi vengono mescolati in un serbatoio (l&#39;<strong>entropy pool</strong>) da cui l&#39;algoritmo (<strong>ChaCha20</strong>) pesca per espandere questi dati in un flusso infinito di dati pseudo casuali.</p>

<p>Per avere una misura di quanta casualità abbia il sistema possiamo ricorrere al seguente costrutto:</p>

<pre><code class="language-bash">cat /proc/sys/kernel/random/entropy_avail
</code></pre>

<p>un valore da <strong>256</strong> in poi ci dice abbiamo entropia sufficiente per generare chiavi e quant&#39;altro.</p>

<p>Finita la parte di teoria, vediamo in quanti modi possiamo generare una password bella robusta o un keyfile.</p>

<h2 id="come-generare-password-e-keyfile">Come generare password e keyfile</h2>

<p>Per generare sequenze di dati casuali possiamo seguire 2 vie:</p>
<ol><li>attingere direttamente alla sorgente di entropia fornita dal kernel;</li>
<li>usare la sorgente per prelevare un seme e generare la sequenza casuale via software che è la via di openssl e di pwgen.</li></ol>

<p><strong>Modalità</strong></p>
<ol><li><code>dd if=/dev/urandom of=mykey.bin bs=4096 count=1 iflag=fullblock status=none</code></li>
<li><code>head -c 4K /dev/urandom &gt; mykey.bin</code></li>
<li><code>tr -dc &#39;[:graph:]&#39; &lt; /dev/urandom | head -c 4096 &gt; mykey.txt</code></li>
<li><code>pwgen -s 4095 1 &gt; mykey.txt</code></li>
<li><code>openssl rand -out mykey.bin 4096</code></li></ol>

<h3 id="analisi">Analisi</h3>

<p>Come si comportano questi procedimenti? Proviamo ad analizzarli.</p>

<p><strong>Casualità</strong>
Una prima distinzione va fatta sulla modalità di creazione della casualità.</p>

<p>I primi 3 metodi fanno riferimento direttamente alla sorgente senza introdurre altre stratificazioni software. Sul piano teorico, rappresentano il punto più vicino alla casualità fisica che si possa avere su un computer.</p>

<p><strong>Openssl</strong> e <strong>pwgen</strong> no, sono due <strong>consumatori</strong> per <code>/dev/urandom</code>.
Devono prima pescare un seme da /dev/urandom.
Una volta ottenuto il seme, usano i propri algoritmi (quelli di openssl sono solitamente basati su <strong>AES-CTR</strong> o <strong>SHA2</strong>) per generare una sequenza infinita di numeri casuali.
Pwgen fa una cosa simile ma è stato progettato di base per costruire password pronunciabili (minore entropia intrinseca).</p>

<p><strong>Velocità</strong>
<strong>Openssl</strong>, fra tutti, è il più veloce, soprattutto se si ha l&#39;esigenza di produrre casualità per volumi di decine di giga o di tera.
Ciò è dovuto al fatto che openssl effettua pochissime syscall per prelevare il seme per poi spremere solo la cpu che, supportando quasi certamente le istruzioni hardware <strong>AES-NI</strong>, rende il processo poco impegnativo per la cpu stessa e brutalmene efficiente.
Agire solo sul kernel, pur conservando la purezza della casualità, causa un rallentamento notevole dovuto al grandissimo numero di syscall necessarie e dalla corrispondente attivazione degli algoritmi di cifratura. Inoltre, mentre dd può contare su un buffer relativamente più capiente, cat, tr, head o qualuque altro oggetto che “beva” direttamente da <code>/dev/urandom</code>, hanno dei buffer molto più piccoli a disposizione, 1MB vs 8-16KB, il cui rapporto funge da moltiplicatore sul numero di operazioni necessarie.</p>

<p><strong>Sicurezza</strong>
Tutti i procedimenti indicati, sono estremamente sicuri, anzi, crittograficamente sicuri. Fermo restando che vale sempre l&#39;osservazione fatta sopra sulla metrica dell&#39;entropia di una sequenza casuale: è funzione del set di caratteri e della lunghezza della sequenza. Conti alla mano, con un alfabeto di una settantina di caratteri, una sequenza di almeno 20 caratteri possiederà un&#39;entropia di circa 120 bit che la rendono impenetrabile per gli attuali sistemi di calcolo.</p>

<p>Usare direttamente la sorgente d&#39;entropia, è sicuramente più vantaggioso perché ci fidiamo del kernel.
Inoltre è più isolato perché lavora a livello del kernel dove i processi utente, anche quelli malevoli, non possono accedere alle sue zone di memoria.</p>

<p>Openssl, pwgen e tutti quelli che sono <strong>generatori secondari</strong>, possono incorrere in quella che si diefinisce <strong>duplicazione della casualità</strong>.
Se l&#39;applicazione non è scritta bene, c&#39;è il rischio che il processo, forkandosi, possa “duplicare” la casualità. In sostanza, i processi padre e figlio finiranno per produrre la stessa sequenza di simboli casuali. Una catastrofe.
Vecchie versioni di openssl, ante 1.1.1 per es., hanno sofferto di questa anomalia.</p>

<h3 id="valutazione">Valutazione</h3>

<p>I metodi 1,2,5 producono un keyfile di dati binari, quindi con un entropia enorme quasi vicina all&#39;ottimo teorico.
Come detto, openssl è mostruosamente più veloce.</p>

<p>Volendo essere purista, per un keyfile i metodi 1 e 2 (praticamente equivalenti) sono da preferire.
Per produrre tera di dati casuali (storage, test di rete) sicuramente openssl. Se il volume non dovesse essere esagerato e siamo paranoici, anche il metodo 1 può andare bene.</p>

<p>Per la produzione di una password complessa con simboli stampabili (non necessariamente pronunciabile altrimenti l&#39;entropia sarebbe ancora più bassa) il metodo 3 è da preferire da un punto di vista matematico.</p>

<p>Mettendo da parte openssl che fa comunque un ottimo lavoro (universalmente riconosciuto con tanto di certificazioni FIPS-2), voglio spendere due parole su <strong>pwgen</strong>.
<strong>pwgen</strong>, con il flag <code>-s</code>, crea delle sequenze completamente randomiche su un alfabeto di 62 caratteri.
Se la lunghezza della sequenza è &gt;= 20, e quindi con un&#39;entropia teorica di ~115-120, avremo delle password abbastanza inviolabili dagli attuali sistemi di calcolo.
Usare il flag <code>-y</code> potrebbe sembrare una buona idea perché si forza ad estendere il set di caratteri.
Sicuramente da una parte aumenta l&#39;entropia della sequenza generata, visto che l&#39;alfabeto è molto più vasto. Dall&#39;altra però la forzatura va a compromettere l&#39;uniformità della distribuzione casuale dei simboli.</p>

<h3 id="conclusione">Conclusione</h3>
<ol><li><strong>password/keyfile stampabile</strong>: <code>tr -dc &#39;[:graph:]&#39; &lt; /dev/urandom | head -c [n] &gt; mykey.txt</code></li>
<li><strong>password/keyfile binario</strong>: <code>head -c [n] /dev/urandom &gt; mykey.bin</code> (equivalentemente <code>dd if=/dev/urandom of=mykey.bin bs=4096 count=1 iflag=fullblock status=none</code>)</li>
<li><strong>cancellazione disco</strong>: <code>openssl rand [dim_disco] | dd of=/dev/sdX bs=1M status=progress</code></li></ol>

<h2 id="bonus-modalità-paranoia">Bonus – Modalità paranoia</h2>

<h3 id="generazione-password">Generazione password</h3>

<p>Se non ci fidassimo della sorgente di casualità, possiamo aggiungere alla sorgente di entropia un nostro segreto personale e “mescolarli” attraverso una funzione sha256 o sha512 rendendo il tutto ancora crittograficamente sicuro.</p>

<pre><code class="language-bash">(head -c 4K /dev/urandom ; read -s -p &#34;Per aumentare l&#39;entropia inserisci una frase segreta o premi tasti a caso: &#34; secret) | sha512sum | cut -d&#39; &#39; -f1 &gt; mykey.txt.
</code></pre>

<p>È certamente una password molto robusta per violare la quale occorrerebbe compromettere la sorgente d&#39;entropia e indovinare il segreto personale (<strong>N.B.</strong> stiamo facendo l&#39;ipotesi che si provi a rompere il meccanismo di generazione della chiave non che si provi l&#39;enumerazione attraverso un attacco brute-force).</p>

<h3 id="generazione-keyfile">Generazione keyfile</h3>

<p>Per produrre un keyfile di 4096 bytes con la stessa premessa, faremo uso di openssl.</p>
<ol><li>si genera esplicitamente un seme dalla sorgente di entropia del kernel</li>
<li>come prima, con sha2 si mescola  il seme con un nostro segreto</li>
<li>si dà in pasto ad openssl.</li></ol>

<pre><code class="language-bash"># Creiamo un seme unico mescolando /dev/urandom e il mio input con sha512
# Usiamo quel seme per generare 4KB di dati casuali &#34;espansi&#34;
(head -c 256 /dev/urandom; read -s -p &#34;Per aumentare l&#39;entropia inserisci una frase segreta o premi tasti a caso: &#34; secret; echo &#34;$secret&#34;) | sha512sum | cut -d &#34; &#34; -f1 | openssl enc -aes-256-ctr -pbkdf2 -pass stdin -nosalt -in /dev/zero | head -c 4096 &gt; mykey.bin
</code></pre>

<p>L&#39;errore che compare alla fine è un falso negativo, dovuto al fatto che openssl sta ancora provando a scrivere dati e <code>head</code> li tronca all&#39;improvviso.</p>

<p>Giusto due righe di spiegazione:</p>
<ol><li><code>head -c 256 /dev/urandom</code>: preleva un po&#39; di dati casuali “puri”</li>
<li><code>read -sp secret</code>: si inserisce una password, una frase o tasti schiacciati a caso per aumentare l&#39;entropia</li>
<li><code>sha512sum | cut -d &#34; &#34; -f1</code>: si mescola tutto e si preleva solo l&#39;esadecimale di 64 bytes</li>
<li><code>openssl enc -aes-256-ctr -pbkdf2 -pass stdin -nosalt -in /dev/zero</code>: openssl, che riceve il seme sullo stdin, fa la sua magia producendo un fiume di dati casuali</li>
<li><code>head -c 4096</code>: tronca il “fiume” alla lunghezza voluta per il nostro keyfile</li></ol>

<p>Quindi:</p>
<ol><li><strong>Contro i bug del kernel</strong>: se la nostra sorgente d&#39;entropia fosse compromessa e diventasse deterministica, occorrerebbe comunque conoscere il nostro segreto</li>
<li><strong>Contro il keylogging</strong>: anche se il nostro segreto potesse essere svelato, la sorgente d&#39;entropia garantirebbe comunque l&#39;inviolabilità della nostra password</li></ol>

<h3 id="gpg-random">GPG Random</h3>

<p>Quando si parla di paranoia, un altro ottimo candidato per produrre password e keyfile è certamente <strong>GPG</strong>.
GPG non si llimita a copiare dati da <code>/dev/urandom</code> ma utilizza una propria libreria crittografica chiamata <strong>Libgcrypt</strong>, che implementa un generatore di numeri pseudocasuali, crittograficamente sicuro, molto sofisticato.</p>

<p>A differenza di ciò che abbiamo visto finora, GPG permette di impostare un livello di qualità per la casualità da produrre.</p>
<ol><li><strong>livello 0 (Debole)</strong>: per scopi didatti, usato raramente.</li>
<li><strong>livello 1 (Avanzato)</strong>: adatto per chiavi di sessione e cifratura standard. Corrisponde ad una casualità di alta qualità</li>
<li><strong>livello 2 (Forte)</strong>: utilizzato per le chiavi a lungo termine (le chiavi private di GPG). È un livello estremamente conservativo. Se GPG valuta di non avere entropia sufficientemente fresca, si mette in attesa.</li></ol>

<p>GPG non si fida ciecamente del kernel e così <strong>Libgcrypt crea un proprio pool di entropia</strong> in user space.</p>
<ol><li>Libgcrypt pesca al solito un seme da <code>/dev/urandom</code></li>
<li>il seme viene rimescolato con sha2 o aes</li>
<li>per evitare che i dati casuali finiscano sullo swap, libgcrypt usa <strong>pagine di memoria protetta</strong> (<strong>mlock</strong>)</li></ol>

<p>Impostando il livello 2, libgcrypt può decidere di scartare molti più dati se ritiene che il pool di entropia non sia abbastanza “fresco”. Inoltre, in virtù della sua diffidenza, <strong>non consegna mai</strong> tutto ciò che arriva dal pool di entropia del kernel così come viene, ma viene rimescolato con sha2 o simili e al livello 2 tutto questo, oltre che avvenire con molta più intensità, avviene anche con molta più frequenza (GPG “chiede” spesso bit freschi al kernel) per scongiurare l&#39;eventualità che un attaccante possa prevedere i bit successivi basandosi su quelli passati</p>

<p>Inoltre, GPG salva una parte di questa entropia “pregiata” in <code>~/.gnupg/random_seed</code> per avere una base di casualità sicura dalle sessioni precedenti nel caso in cui un computer, appena avviato, non avesse ancora accumulato sufficiente entropia.</p>

<p>Si capisce bene come il livello di paranoia di GPG sia fuori scala ma per fortuna tutta questa potenza è totalmente nascosta sotto il cofano di GPG. Infatti per produrre il nostro keyfile binario basta:</p>

<pre><code class="language-bash">gpg --dev-random 2 4096
</code></pre>

<h2 id="riepilogo-finale">Riepilogo finale</h2>

<p>E dunque, 3 delle 5 modalità sopra descritte, la 2, la 3 e la 5, possono essere ripensate con l&#39;entropia di GPG invee che con quella tipica del kernel.</p>

<h3 id="2-keyfile-binario">2) Keyfile binario</h3>
<ul><li><p><strong>Kernel entropy</strong></p>

<pre><code class="language-bash">head -c 4K /dev/urandom &gt; mykey.bin
</code></pre></li>

<li><p><strong>Libgcrypt entropy</strong></p>

<pre><code class="language-bash">gpg --dev-random 2 4096 -o mykey_gpg.bin
</code></pre></li></ul>

<h3 id="3-password-complessa-con-caratteri-stampabili">3) Password complessa con caratteri stampabili</h3>
<ul><li><p><strong>Kernel entropy</strong></p>

<pre><code class="language-bash">tr -dc &#39;[:graph:]&#39; &lt; /dev/urandom | head -c 4096 &gt; mykey.txt
</code></pre></li>

<li><p><strong>Libgcrypt entropy</strong></p>

<pre><code class="language-bash">gpg --gen-random 1 10000 | tr -dc &#39;A-Za-z0-9&#39; | head -c 4096 &gt; mykey_gpg.txt
</code></pre></li></ul>

<h3 id="5-keyfile-binario-con-openssl">5) Keyfile binario con openssl</h3>
<ul><li><p><strong>Kernel entropy</strong></p>

<pre><code class="language-bash">openssl rand -out mykey.bin 4096
</code></pre></li>

<li><p><strong>Libgcrypt entropy</strong></p>

<pre><code class="language-bash">(gpg --gen-random 2 128) | openssl rand -out mykey_gpg.bin -rand /dev/stdin 4096
</code></pre></li></ul>

<p><a href="/aytin/tag:entropy" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">entropy</span></a> <a href="/aytin/tag:shannon" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">shannon</span></a> <a href="/aytin/tag:csprng" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">csprng</span></a> <a href="/aytin/tag:password" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">password</span></a> <a href="/aytin/tag:keyfile" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">keyfile</span></a> <a href="/aytin/tag:dd" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">dd</span></a> <a href="/aytin/tag:openssl" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">openssl</span></a> <a href="/aytin/tag:pwgen" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">pwgen</span></a> <a href="/aytin/tag:AesCtr" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">AesCtr</span></a> <a href="/aytin/tag:AesNi" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">AesNi</span></a> <a href="/aytin/tag:sha2" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">sha2</span></a> <a href="/aytin/tag:gpg" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">gpg</span></a> <a href="/aytin/tag:bruteforce" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">bruteforce</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di</guid>
      <pubDate>Mon, 12 Jan 2026 14:39:55 +0000</pubDate>
    </item>
  </channel>
</rss>