How Argon2 works
Argon2 makes attackers pay in RAM, not just CPU, by filling a big chunk of memory where each block depends on earlier ones.
Read first: Cryptographic hash functions
The idea
Password hashes get attacked with GPUs and ASICs that try billions of guesses per second. Those chips have lots of compute but little fast memory per core. Argon2 (winner of the 2015 Password Hashing Competition) makes every guess need a lot of memory, so parallel hardware stops helping much.
Filling memory
Memory of KiB is split into lanes of 1 KiB blocks. The first two blocks in each lane are seeded from your password and salt. Every block after that mixes the previous block with a reference block picked from memory that’s already been written. Hit run:
After the first pass, Argon2 makes more passes over the same memory. Each block gets XOR-ed with a new compression, and references can now point anywhere.
The compression step
Each block comes from a compression function built from the BLAKE2b round function:
where is the reference lane and is the reference index. How is chosen is what separates the variants:
| Variant | Reference index from | Good against |
|---|---|---|
| Argon2d | previous block’s data | GPU cracking (but leaks via timing) |
| Argon2i | a data-independent counter | side-channel attacks |
| Argon2id | i for the first half of pass 1, then d | both, and it’s the recommended default |
Why it’s expensive to cheat
An attacker could try to keep only a fraction of the memory and recompute dropped blocks when they’re needed. But recomputing a block means recomputing its previous block and its reference block, recursively. Cutting memory to already costs a large multiple in compute, so the trade is bad.
In code
from argon2 import PasswordHasher
ph = PasswordHasher(time_cost=2, memory_cost=65536, parallelism=2) # t=2, m=64 MiB, p=2
h = ph.hash("hunter2") # $argon2id$v=19$m=65536,t=2,p=2$...
ph.verify(h, "hunter2")
The parameters live in the hash string itself, so you can raise memory_cost later and rehash on the next login.
Recap
- Argon2 is memory-hard: every guess needs KiB of memory, touched in a data-dependent order.
- (memory), (passes), (lanes) are your knobs; use Argon2id.
- Trading memory for time is possible, but costly.