Perché conta la memoria
Quando un attaccante ruba gli hash delle password o un vault cifrato, prova a indovinare offline, alla massima velocità del suo hardware. Una GPU ha migliaia di piccoli core, quindi una funzione che richiede poca memoria, come PBKDF2, gira su molti di essi contemporaneamente.
Argon2 richiede un blocco di memoria per ogni tentativo e non si può saltare a buon mercato. La memoria è ciò che scarseggia su una GPU. Come semplice aritmetica, non come benchmark: una scheda con 24 GiB ospita circa 96 tentativi alla volta a 256 MiB ciascuno, e circa 1.290 a 19 MiB. PBKDF2 non pone alcun limite del genere.
Le varianti sono tre. Argon2d resiste meglio alle GPU, ma i suoi accessi in memoria dipendono dalla password, il che può trapelare tramite canali laterali. Argon2i lo evita, a prezzo di una certa resistenza alle GPU. Argon2id parte come Argon2i per la prima metà della prima passata, poi funziona come Argon2d. RFC 9106 lo raccomanda come scelta predefinita.
I parametri
| Nome | Significato | Effetto |
|---|---|---|
m | Memoria, in KiB | La difesa principale. Alza prima questo. |
t | Passate sulla memoria | Più tempo per ogni tentativo. |
p | Corsie, per thread paralleli | Permette a un dispositivo con più core di riempire la memoria più in fretta. Non aggiunge memoria. |
| Salt | Valore casuale per ogni password | Stessa password, hash diverso. Non è segreto, si conserva in chiaro. 16 byte bastano per ogni uso, dice l'RFC. |
| Lunghezza del tag | Dimensione dell'output | 16 byte bastano per la maggior parte degli usi. 32 è comune quando diventa una chiave. |
Quali valori usare
| Fonte | m | t | p | Tempo sul nostro Mac |
|---|---|---|---|---|
| RFC 9106, prima raccomandazione | 2 GiB | 1 | 4 | 1,43 s |
| RFC 9106, seconda raccomandazione, per meno memoria | 64 MiB | 3 | 4 | 0,11 s |
| OWASP, minimo nel suo riepilogo | 19 MiB | 2 | 1 | 0,02 s |
OWASP elenca diverse impostazioni che considera equivalenti come difesa, come 46 MiB con t=1 e 12 MiB con t=3. Sono tutti minimi per un server che deve far accedere molti utenti. Un'app che deriva una sola chiave sul tuo dispositivo può permettersi molto di più, perché l'utente aspetta solo una volta a ogni sblocco.
Un buon modo per scegliere: prendi la massima memoria che ogni dispositivo supportato può permettersi, tieni t a 3 o meno e controlla il tempo sul dispositivo più lento. Ricorda che se un telefono esaurisce la memoria, lo sblocco fallisce.
Provalo
Lo strumento a riga di comando argon2 si installa con brew install argon2 su macOS, oppure sudo apt install argon2. La memoria si indica in KiB con -k. Il salt deve avere almeno 8 caratteri. Non usare password reali in questo modo, perché possono restare nella cronologia della shell:
$ printf 'correct horse battery staple' | argon2 examplesalt12345 -id -t 3 -k 262144 -p 1 -l 32
Type: Argon2id
Iterations: 3
Memory: 262144 KiB
Parallelism: 1
Hash: e2c39f45f62dd7bddc5b6eff815f32fae69748a05f4c6f9875dd0e06bb9b2934
Encoded: $argon2id$v=19$m=262144,t=3,p=1$ZXhhbXBsZXNhbHQxMjM0NQ$4sOfRfYt173cW27/gV8y+uaXSKBfTG+Ydd0OBrubKTQ
0.356 seconds
Verification ok
La stringa codificata contiene tutto ciò che serve per verificare una password in seguito: la variante, la versione (v=19 è la 1.3), i parametri, il salt e l'hash, questi ultimi due in Base64. Così puoi alzare i parametri in seguito e i vecchi hash si verificano ancora.
In Python, con argon2-cffi in un ambiente virtuale:
from argon2 import PasswordHasher, Type
ph = PasswordHasher(time_cost=3, memory_cost=262144, parallelism=1,
hash_len=32, salt_len=16, type=Type.ID)
stored = ph.hash("correct horse battery staple")
ph.verify(stored, "correct horse battery staple") # True; a wrong password raises VerifyMismatchError
ph.check_needs_rehash(stored) # False until you raise the parameters
Crea lui un salt casuale per te. Non scrivere una tua gestione del salt.
Argon2id o PBKDF2
PBKDF2 ripete molte volte un hash e non richiede quasi memoria. OWASP chiede 600.000 iterazioni con HMAC-SHA256, che sul nostro Mac hanno richiesto 0,04 secondi. Per te è un'attesa trascurabile, ma ogni tentativo è economico da eseguire in parallelo. Usa PBKDF2 quando uno standard come FIPS lo impone, e Argon2id negli altri casi.
Una password debole cade comunque
Argon2id rende più lento ogni tentativo. Non trasforma una cattiva password in una buona. Gli attaccanti provano prima le password comuni, quindi una password in cima alla loro lista richiede pochissimi tentativi.
Come un vault combina password, Argon2id e una chiave separata è spiegato in cosa significa end to end per un vault di password.
Domande
Quale variante di Argon2 conviene usare?
Argon2id. La RFC 9106 la raccomanda come predefinita, perché resiste sia ai tentativi su GPU sia agli attacchi side channel.
Cosa significa $argon2id$v=19$m=65536,t=3,p=4?
Argon2id, versione 1.3, 65536 KiB (64 MiB) di memoria, 3 passate e 4 corsie. Seguono salt e hash in Base64.
Argon2id è meglio di bcrypt?
Per i sistemi nuovi, sì. OWASP mette Argon2id al primo posto e tiene bcrypt per i sistemi esistenti. bcrypt usa poca memoria, sempre la stessa, e la maggior parte delle implementazioni legge solo i primi 72 byte della password.
Fonti
- RFC 9106: Argon2 Memory-Hard Function
- OWASP Password Storage Cheat Sheet
- RFC 8018: PKCS #5, incluso PBKDF2
- Documentazione di argon2-cffi