Argon2id spiegato: cosa significano m, t e p e quali valori scegliere

Argon2id è una funzione di hashing delle password che obbliga ogni tentativo a usare una certa quantità di memoria, rendendo costoso indovinare su larga scala con le GPU. Si impostano memoria (m), passate (t) e corsie (p). RFC 9106 raccomanda m=2 GiB, t=1, p=4, oppure m=64 MiB, t=3, p=4 con meno memoria. Il minimo di OWASP è m=19 MiB, t=2, p=1. Una password debole cade comunque.

Aggiornata il . Strumento a riga di comando argon2 e argon2-cffi 25.1.0 in un venv Python, su un Mac Apple M6.

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

NomeSignificatoEffetto
mMemoria, in KiBLa difesa principale. Alza prima questo.
tPassate sulla memoriaPiù tempo per ogni tentativo.
pCorsie, per thread paralleliPermette a un dispositivo con più core di riempire la memoria più in fretta. Non aggiunge memoria.
SaltValore casuale per ogni passwordStessa password, hash diverso. Non è segreto, si conserva in chiaro. 16 byte bastano per ogni uso, dice l'RFC.
Lunghezza del tagDimensione dell'output16 byte bastano per la maggior parte degli usi. 32 è comune quando diventa una chiave.

Quali valori usare

FontemtpTempo sul nostro Mac
RFC 9106, prima raccomandazione2 GiB141,43 s
RFC 9106, seconda raccomandazione, per meno memoria64 MiB340,11 s
OWASP, minimo nel suo riepilogo19 MiB210,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

Tutte le guide