Skip to content

Spiegare BCrypt come se avessi 5 anni

Questo articolo è stato approvato dai nostri esperti in modo da poter essere sicuri dell'accuratezza di questa divisione.

Soluzione:

Hashing contro crittografia

La differenza maggiore tra bcrypt e blowfish è che blowfish è un algoritmo di crittografia simmetrica e bcrypt è un algoritmo di hashing. (Si tratta di un tipo speciale di algoritmo di hashing, ma lo vedremo più avanti).

Crittografia (cosa fa Blowfish)

Un algoritmo di crittografia simmetrica prende una chiave segreta e un testo in chiaro (si usa regolarmente il termine "messaggio" e la variabile m è tipicamente usata per riferirsi ad esso) e produce un testo cifrato, c. L'idea è che il testo cifrato possa essere ritrasformato nel messaggio originale solo con lo stesso valore di[^same] .[^same]chiave segreta utilizzata per la cifratura.

[^same]: Sto dando risposte approssimativamente vere per concentrarmi sulle idee e sui concetti centrali. Spero che coloro che riconoscono dove le mie risposte non sono precisamente vere mi diano un po' di tregua per scopi espositivi.

Quindi Alice potrebbe criptare il messaggio "Attacco all'alba" con la chiave 13 (che è non blowfish, ma è una crittografia simmetrica) e produrre il testo cifrato "Nggnpx ng qnja". Può inviare il testo cifrato a Bob e, se Bob sa che la chiave è 13, può ritrasformare il testo cifrato nei messaggi originali. A volte Alice non vuole inviare un messaggio a un'altra persona, ma vuole conservarlo per leggerlo in un secondo momento. In questi casi possiamo pensare che Alice invii un messaggio all'Alice del futuro.

Con Blowfish (invece della crittografia che ho usato nel mio esempio), è effettivamente impossibile per chiunque non abbia la chiave imparare qualcosa sul messaggio originale (a parte la sua lunghezza e la sua esistenza) dal testo cifrato. Per inciso, AES è un algoritmo di crittografia simmetrica preferibile a Blowfish, ma continuerò a usare Blowfish nelle mie descrizioni perché è quello che mi è stato chiesto.

Hashing

Un algoritmo di hash crittografico (bcrypt è un tipo speciale, con alcuni extra, ma inizierò con un caso più semplice) non richiede una chiave e non è praticamente reversibile. Quindi un algoritmo di hash crittografico come SHA256 prende un messaggio (diciamo una password) come "JaguarsRule!" e lo trasforma in un hash.

$ echo -n 'JaguarsRule!' | shasum -a256
13f26e5a60e402d895c5ce1d9492d080563c5079a8b5f52a25953fd24a2cb1da  

Una delle diverse proprietà di un hash crittografico è che non è possibile calcolare "JaguarsRule!" a partire da 13f26e5a60e402d895c5ce1d9492d080563c5079a8b5f52a25953fd24a2cb1da. In questo caso non esiste una chiave.

Un meccanismo di hashing semplice come questo potrebbe sembrare un buon modo per controllare le password su un server. Supponiamo di gestire un servizio web che richiede l'accesso alle persone. Avete un utente, diciamo con nome utente jason che imposta il suo account con la password JaguarsRule!. Poiché non si vuole che chiunque possa leggere il contenuto del server apprenda la password di Jason, non si memorizza la password stessa. Si memorizza invece il suo hash.

Quando Jason (o qualcuno che finge di essere Jason) accede, il server prende la password inserita, esegue l'operazione di hashing su di essa e confronta l'hash memorizzato. Se gli hash corrispondono, il sistema sa che è stata inserita la password corretta.

Sali e cottura lenta

Lo schema descritto sopra, che utilizza un hash crittografico generico come SHA256, funzionerebbe benissimo, tranne che per una cosa: le persone scelgono password indovinabili. Se le persone avessero la stessa probabilità di usare password del tipo wZFoO_SKrgEw come lo sono per JaguarsRule! allora non avremmo bisogno di funzioni di hashing specializzate come bcrypt. Ma le persone, essendo umane, non sceglieranno le password in modo casuale e uniformemente su uno spazio sufficientemente ampio. Al contrario, è molto più probabile che scelgano alcune possibili password piuttosto che altre.

Sale

Considerate un altro utente del vostro sistema, pillboy. Anche Pill Boy è un tifoso dei Jacksonville Jaguars e si dà il caso che abbia anche scelto JaguarsRule! come password. Utilizzando l'hash (non salato), l'hash della password di Pill Boy sarà uguale a quello della password di Jason. Un aggressore deve solo confrontare gli hash per vedere che questi due utenti hanno la stessa password.

Inoltre, se un utente malintenzionato scopre in un modo o nell'altro che la password di Jason è JaguarsRule!`, conosce immediatamente la password di Pill Boy. Inoltre, potrebbe creare un grande elenco di hash per le password più comuni.

La soluzione a questo problema consiste nel salare la password con qualcosa di univoco prima di eseguire l'hash. Quindi, quando si crea l'hash della password di Jason (quando Jason si iscrive per la prima volta e crea la password), si aggiunge qualcosa di casuale. Supponiamo che a questo punto il sistema crei il sale 9cb3779f69e271c1. Quindi lo inserisce davanti alla password prima di eseguire l'hash, in modo da eseguire l'hash di qualcosa come 9cb3779f69e271c1JaguarsRule! (Questo non è il modo in cui il sale viene effettivamente aggiunto, ma è abbastanza simile per spiegare a cosa serve il sale). L'hash di 9cb3779f69e271c1JaguarsRule! sarà completamente diverso dall'hash di JaguarsRule!.

Il sistema avrà bisogno di sapere qual è il sale quando sarà il momento di verificare una password. Quindi memorizzerà il sale e l'hash insieme al nome utente di Jason. Quando Pill Boy creerà il suo account, sarà impostato con un sale generato in modo casuale diverso e quindi la sua combinazione di sale e password produrrà un hash diverso.

Quindi ciò che viene memorizzato sul server potrebbe essere simile a questo

[
    {
        "algorithm": "sha256",
        "username": "jason",
        "salt": "9cb3779f69e271c1",
        "hash": "37a932267ed055facf03cc5d09ca90f927a1eed47a8cd4856e57cd67434426be"
    },
    {
        "algorithm": "sha256",
        "username": "pillboy",
        "salt": "0a19471dab710025",
        "hash": "4be637a8c85455dce0cdc1c7670f062764100276b6ed64141c06fbef4578f185"
    },

]

Avendo sali diversi per questi utenti, non possiamo vedere che hanno la stessa password e l'attaccante non sarà in grado di confrontare gli hash con un elenco precompilato di hash di password comuni.

Quindi bcrypt, essendo progettato per l'hashing delle password, prende un sale.

Con calma

La salatura è assolutamente essenziale, ma non impedisce a un aggressore che entra in possesso di ciò che è memorizzato sul server di indovinare automaticamente. Può prendere il sale e combinarlo con password comuni e calcolare gli hash fino a trovare una corrispondenza. Potrebbe essere in grado di eseguire decine o centinaia di milioni di indovinelli di password al secondo.

Uno dei motivi per cui è in grado di calcolare così velocemente un numero così elevato di ipotesi è che gli algoritmi di hash crittografici come sha256 sono progettati per essere veloci ed efficienti pur rispettando le loro proprietà di sicurezza. Quindi cose come bcrypt sono "hashing lenti". L'idea è che passare da un messaggio (sale e password) a un hash possa richiedere così tanti calcoli che un computer tipico impiegherà un quarto di secondo per eseguire l'hash.

L'utente non noterà il ritardo di un quarto di secondo, ma se l'aggressore utilizza lo stesso tipo di computer, si riduce a fare quattro ipotesi al secondo invece di 10 milioni. (In pratica, l'utente disporrà di apparecchiature di calcolo appositamente configurate, ma il rallentamento da milioni di ipotesi al secondo a decine di migliaia di ipotesi al secondo è una buona cosa).

bcrypt è uno dei numerosi "hash lenti". Gli altri sono PBBKDF2, scrypt e Argon2. Questi ultimi due non solo richiedono molti calcoli per creare l'hash, ma richiedono anche molta memoria.

Bcrypt è ottimo, ma...

La salatura e l'hashing lento sono qualcosa che ogni sistema di hashing delle password dovrebbe fare. Ma produce anche rendimenti decrescenti. L'hashing lento può fare molto per il difensore e quindi dobbiamo ancora (finché esisteranno le password) far sì che le persone usino password più difficili da indovinare. Ho scritto di più su questo argomento in Bcrypt is great, ma...

NB: Grazie a https://security.stackexchange.com/users/6253/schroeder per aver cancellato correttamente la mia risposta precedente in cui prendevo alla lettera "come se avessi 5 anni". E mi scuso con l'autore della risposta per essere stato sprezzante invece che utile.

Bcrypt utilizza il cifrario a blocchi a chiave simmetrica Blowfish e accetta 3 parametri: costo, sale e password.

  • Il costo è determinato a livello di sistema in modo che l'amministratore possa decidere i tempi dell'attacco di ricerca della password, vedi hashcat. Determina il numero di iterazioni come iter= 2^cost dove il costo è compreso tra 2 e 31.

  • Il sale è un 16 byte casuale. Può essere generato da qualsiasi buona fonte casuale come devurandom

  • La password è la password dell'utente da elaborare. La dimensione delle password va da 1 a 72 byte.

  • L'output di Bcrypt è di 24 byte.

Il Bcrypt cripta il testo OrpheanBeholderScryDoubt in modalità BCE concatenata.

 state = EksBlowfishSetup(cost, salt, password) //Special key scheduling 
 ctext = "OrpheanBeholderScryDoubt"
 repeat (64)
      ctext = EncryptECB(state, ctext)
 return Concatenate(cost, salt, ctext)

aggiornamento sul costo

EksBlowfishSetup ( Extensive Key Setup ) brevemente come segue;

state = InitialState()
state = ExpandKey(state, salt, password)
repeat (2^cost)
    state = ExpandKey(state, 0, password)
    state = ExpandKey(state, 0, salt)

Il costo ha un ruolo nella funzione di BCrypt sopra descritta. Con l'aumento del costo, il ciclo di ripetizione verrà eseguito in modo esponenziale. Questo aumenterà il tempo di attacco, come si può vedere dalla tabella di questa risposta. Se si vuole fare un confronto con hashcat, vedere un benchmark per Tesla K80

Nota: che Bcrypt è vecchio (1999), si dovrebbe usare Argon2i come vincitore della gara di hashing delle password.



Utilizzate il nostro motore di ricerca

Ricerca
Generic filters

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.