

0 / 2 embers
0 / 3000 xp
click for more info
Complete a lesson to start your streak
click for more info
Difficulty: 9
click for more info
Not enough gems
Cost: 6 gems
1: Key Derivation Functions
incomplete
2: Argon2 – Storing Passwords
incomplete
3: Argon2 Phc Review
incomplete
4: Salts
incomplete
5: Why Are KDFs Slow?
incomplete
Back
ctrl+,
Next
ctrl+.
This lesson's interactive features are locked, please to keep using them
KDFs are the best way to store passwords in web applications! As a back-end developer, this is critical to understand.
Storing passwords in a database in plain text is a huge security risk. If someone gets access to your database, they can see all of your users' passwords.
No. SHA-256 is a hash function, but it's not a KDF. SHA-256 is very fast. Good KDFs like Argon2 are designed to be slow and memory-hard. That makes large-scale cracking far more expensive for attackers.
Argon2 is a modern memory-hard KDF that's resistant to GPU/ASIC cracking due to tunable memory use. It combines the benefits of Argon2i and Argon2d and is the generally recommended variant for password storage.
With bcrypt in Go, the library returns a self-contained string (algorithm + cost + salt + hash).
With Argon2 in Go, you just get the raw derived key. You must also store the salt and the parameters used to derive it.
The PHC string format solves this neatly: it's a standardized, self-describing string that encodes:
Because the parameters are embedded, you can tune them over time and still verify old hashes correctly.
Go's Argon2 returns only the derived key. The PHC string format is a self-describing container that also includes algorithm, version, parameters, and salt, so you can change parameters later and still verify old hashes.
PHC layout:
$argon2id$v=19$m=<memKiB>,t=<time>,p=<parallelism>$<saltBase64>$<hashBase64>
argon2id: the Argon2 variant to use during verification (must match exactly).
v=19: the Argon2 spec version (decimal 19 = version 1.3). This ensures the verifier applies the correct algorithm rules.
At Passly, we store passwords securely (it would be sad if we didn't). Each user has a master password that they use to log into their cloud account. That password is hashed with Argon2id before being stored.
Use the golang.org/x/crypto/argon2 package to complete the hashPassword() and checkPasswordHash() functions. You do not need to modify the function signatures – just implement the Argon2id API, and handle random salt generation.
Use the constants already provided.
hashPassword Functionsalt := make([]byte, 16)
// use crypto/rand.Read(salt)
b64 := base64.RawStdEncoding
$argon2id$v=19$m=32768,t=3,p=4$<saltBase64>$<hashBase64>
checkPasswordHash Function// Expect: ["", "argon2id", "v=19", "m=..,t=..,p=..", "<saltB64>", "<hashB64>"]
parts := strings.Split(hash, "$")
if len(parts) != 6 || parts[1] != "argon2id" || parts[2] != "v=19" { return false }
Parse the parameters
Use strconv.ParseUint to parse the values to the expected types:
m and t to uint32p to uint8Decode the information you have:
b64 := base64.RawStdEncoding
salt, err := b64.DecodeString(parts[4]); if err != nil { return false }
want, err := b64.DecodeString(parts[5]); if err != nil { return false }
Now you need to use IDKey again to recompute the data, and compare:
got := argon2.IDKey([]byte(password), salt, tU32, mU32, pU8, uint32(len(want)))
// Avoid timing leaks:
return subtle.ConstantTimeCompare(got, want) == 1