Argon2


Argon2 is a key derivation function that was selected as the winner of the 2015 Password Hashing Competition. It was designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich from the University of Luxembourg. The reference implementation of Argon2 is released under a Creative Commons CC0 license or the Apache License 2.0.
The Argon2 function uses a large, fixed-size memory region to make brute-force attacks computationally expensive. The three variants differ in how they access this memory:
  • Argon2d maximizes resistance to GPU cracking attacks. It accesses the memory array in a password-dependent order, which reduces the possibility of time–memory trade-off attacks, but introduces possible side-channel attacks.
  • Argon2i is optimized to resist side-channel attacks. It accesses the memory array in a password-independent order.
  • Argon2id is a hybrid version. It follows the Argon2i approach for the first half pass over memory and the Argon2d approach for subsequent passes. recommends using Argon2id if one does not know the difference between the types or if side-channel attacks are considered to be a viable threat.
All three modes allow specification by three parameters that control:
  • execution time
  • memory required
  • degree of parallelism

Cryptanalysis

While there is no public cryptanalysis applicable to Argon2d, there are two published attacks on the Argon2i function. The first attack is applicable only to the old version of Argon2i, while the second has been extended to the latest version.
The first attack shows that it is possible to compute a single-pass Argon2i function using between a quarter and a fifth of the desired space with no time penalty, and compute a multiple-pass Argon2i using only / space with no time penalty. According to the Argon2 authors, this attack vector was fixed in version 1.3.
The second attack shows that Argon2i can be computed by an algorithm which has complexity O) for all choices of parameters,, and thread-count such that =∗. The Argon2 authors claim that this attack is not efficient if Argon2i is used with three or more passes. However, Joël Alwen and Jeremiah Blocki improved the attack and showed that in order for the attack to fail, Argon2i v1.3 needs more than 10 passes over memory.
To address these concerns, RFC9106 recommends using Argon2id to largely mitigate such attacks.

Algorithm

Source:
Function Argon2
Inputs:
password : Bytes Password to be hashed
salt : Bytes Salt
parallelism : Number Degree of parallelism
tagLength : Number Desired number of returned bytes
memorySizeKB : Number Amount of memory to use
iterations : Number Number of iterations to perform
version : Number The current version is 0x13
key : Bytes Optional key
associatedData : Bytes Optional arbitrary extra data
hashType : Number
Output:
tag: Bytes The resulting generated bytes, tagLength bytes long
Generate initial 64-byte block H0.
All the input parameters are concatenated and input as a source of additional entropy.
Errata: RFC says H0 is 64-bits; PDF says H0 is 64-bytes.
Errata: RFC says the Hash is H^, the PDF says it's ℋ. It's actually Blake2b.
Variable length items are prepended with their length as 32-bit little-endian integers.

buffer ← parallelism ∥ tagLength ∥ memorySizeKB ∥ iterations ∥ version ∥ hashType
∥ Length ∥ Password
∥ Length ∥ salt
∥ Length ∥ key
∥ Length ∥ associatedData
H0 ← Blake2b //default hash size of Blake2b is 64-bytes
Calculate number of 1 KB blocks by rounding down memorySizeKB to the nearest multiple of 4*parallelism kibibytes
blockCount ← Floor
Allocate two-dimensional array of 1 KiB blocks
columnCount ← blockCount / parallelism; //In the RFC, columnCount is referred to as q
Compute the first and second block of each lane
for i ← 0 to parallelism-1 do for each row
Bi ← Hash //Generate a 1024-byte digest
Bi ← Hash //Generate a 1024-byte digest
Compute remaining columns of each lane
for i ← 0 to parallelism-1 do //for each row
for j ← 2 to columnCount-1 do //for each subsequent column
//i' and j' indexes depend if it's Argon2i, Argon2d, or Argon2id
i′, j′ ← GetBlockIndexes //the GetBlockIndexes function is not defined
Bi = G //the G hash function is not defined
Further passes when iterations > 1
for nIteration ← 2 to iterations do
for i ← 0 to parallelism-1 do for each row
for j ← 0 to columnCount-1 do //for each subsequent column
//i' and j' indexes depend if it's Argon2i, Argon2d, or Argon2id
i′, j′ ← GetBlockIndexes
if j 0 then
Bi = Bi xor G
else
Bi = Bi xor G
Compute final block C as the XOR of the last column of each row
C ← B0
for i ← 1 to parallelism-1 do
C ← C xor Bi
Compute output tag
return Hash

Variable-length hash function

Argon2 makes use of a hash function capable of producing digests up to 232 bytes long. This hash function is internally built upon Blake2.

Recommended minimum parameters

The Request for Comments document standardizing Argon2, which was published in September 2021, recommends:
  • Memory: 2 GiB, Iterations: 1, Parallelism: 1; for "a default setting for all environments"
  • Memory: 64 MiB, Iterations: 3, Parallelism: 1; for "memory-constrained environments"