Pourquoi la mémoire compte
Quand un attaquant vole des hachages de mots de passe ou un coffre chiffré, il fait ses essais hors ligne, aussi vite que son matériel le permet. Un GPU a des milliers de petits cœurs : une fonction qui demande peu de mémoire, comme PBKDF2, tourne donc sur beaucoup d'entre eux à la fois.
Argon2 exige un bloc de mémoire pour chaque essai, et on ne peut pas s'en dispenser à bas prix. Or la mémoire est ce qui manque sur un GPU. En simple arithmétique, pas en benchmark : une carte de 24 GiB loge environ 96 essais simultanés à 256 MiB chacun, et environ 1 290 à 19 MiB. PBKDF2 ne fixe aucune limite de ce genre.
Il existe trois variantes. Argon2d résiste le mieux aux GPU, mais ses accès mémoire dépendent du mot de passe, ce qui peut fuiter par des canaux auxiliaires. Argon2i évite cela, au prix d'une moindre résistance aux GPU. Argon2id commence comme Argon2i pendant la première moitié de la première passe, puis fonctionne comme Argon2d. La RFC 9106 le recommande par défaut.
Les paramètres
| Nom | Signification | Effet |
|---|---|---|
m | Mémoire, en KiB | La défense principale. À augmenter en premier. |
t | Passes sur la mémoire | Plus de temps pour chaque essai. |
p | Voies, pour les threads parallèles | Permet à un appareil avec plus de cœurs de remplir la mémoire plus vite. N'ajoute pas de mémoire. |
| Sel | Valeur aléatoire par mot de passe | Même mot de passe, hachage différent. Pas secret, stocké en clair. 16 octets suffisent pour tous les usages, dit la RFC. |
| Longueur du tag | Taille de la sortie | 16 octets suffisent pour la plupart des usages. 32 est courant quand cela devient une clé. |
Quelles valeurs utiliser
| Source | m | t | p | Durée sur notre Mac |
|---|---|---|---|---|
| RFC 9106, première recommandation | 2 GiB | 1 | 4 | 1,43 s |
| RFC 9106, seconde recommandation, pour moins de mémoire | 64 MiB | 3 | 4 | 0,11 s |
| OWASP, minimum de son résumé | 19 MiB | 2 | 1 | 0,02 s |
OWASP liste plusieurs réglages qu'il juge équivalents en défense, comme 46 MiB avec t=1, et 12 MiB avec t=3. Ce sont tous des minimums pour un serveur qui doit connecter beaucoup d'utilisateurs. Une application qui dérive une seule clé sur votre propre appareil peut se permettre bien plus, car l'utilisateur n'attend qu'une fois par déverrouillage.
Une bonne méthode : prenez le maximum de mémoire que chaque appareil pris en charge peut céder, gardez t à 3 ou moins, et vérifiez la durée sur votre appareil le plus lent. N'oubliez pas que si un téléphone manque de mémoire, le déverrouillage échoue.
Essayez
L'outil en ligne de commande argon2 s'installe avec brew install argon2 sur macOS, ou sudo apt install argon2. La mémoire se donne en KiB avec -k. Le sel doit faire au moins 8 caractères. N'utilisez pas de vrais mots de passe de cette façon, car ils peuvent rester dans l'historique du 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 chaîne encodée contient tout ce qu'il faut pour vérifier un mot de passe plus tard : la variante, la version (v=19 est la 1.3), les paramètres, le sel et le hachage, ces deux derniers en Base64. Vous pouvez donc augmenter les paramètres plus tard, et les anciens hachages se vérifient toujours.
En Python, avec argon2-cffi dans un environnement virtuel :
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
Il crée un sel aléatoire pour vous. N'écrivez pas votre propre gestion du sel.
Argon2id ou PBKDF2
PBKDF2 répète un hachage de nombreuses fois et ne demande presque aucune mémoire. OWASP demande 600 000 itérations avec HMAC-SHA256, ce qui a pris 0,04 seconde sur notre Mac. C'est une attente acceptable pour vous, mais chaque essai est bon marché à exécuter en parallèle. Utilisez PBKDF2 quand une norme comme FIPS l'exige, et Argon2id sinon.
Un mot de passe faible tombe quand même
Argon2id ralentit chaque essai. Il ne transforme pas un mauvais mot de passe en bon. Les attaquants essaient d'abord les mots de passe courants : un mot de passe proche du haut de leur liste demande très peu d'essais.
La façon dont un coffre combine mot de passe, Argon2id et une clé séparée est expliquée dans ce que veut dire chiffré de bout en bout pour un coffre-fort.
Questions
Quelle variante d'Argon2 choisir ?
Argon2id. La RFC 9106 la recommande par défaut, car elle résiste à la fois aux essais sur GPU et aux attaques par canal auxiliaire.
Que signifie $argon2id$v=19$m=65536,t=3,p=4 ?
Argon2id, version 1.3, 65536 Kio (64 Mio) de mémoire, 3 passes et 4 voies. Le sel et le hash suivent en Base64.
Argon2id est-il meilleur que bcrypt ?
Pour un nouveau système, oui. L'OWASP place Argon2id en premier et garde bcrypt pour l'existant. bcrypt utilise peu de mémoire, toujours la même, et la plupart des implémentations ne lisent que les 72 premiers octets du mot de passe.
Sources
- RFC 9106 : Argon2 Memory-Hard Function
- OWASP Password Storage Cheat Sheet
- RFC 8018 : PKCS #5, dont PBKDF2
- Documentation d'argon2-cffi