Key Derivation Functions
Key Derivation Functions (KDFs) for password hashing and key derivation.
Password-Based KDFs
PBKDF2 (Password-Based Key Derivation Function 2)
$$ DK = PBKDF2(password, salt, iterations, dkLen) $$
Algorithm:
$$ \begin{aligned} T_i &= F(password, salt, iterations, i) \ F(password, salt, c, i) &= U_1 \oplus U_2 \oplus \cdots \oplus U_c \end{aligned} $$
Where:
$$ \begin{aligned} U_1 &= PRF(password, salt | INT(i)) \ U_j &= PRF(password, U_{j-1}) \end{aligned} $$
Iterations: Minimum 100,000 for PBKDF2-HMAC-SHA256
Argon2 (Winner of Password Hashing Competition)
$$ H = Argon2(password, salt, t, m, p) $$
Parameters:
- $t$: Time cost (iterations)
- $m$: Memory cost (KB)
- $p$: Parallelism degree
Variants:
- Argon2d: Data-dependent (GPU-resistant)
- Argon2i: Data-independent (side-channel resistant)
- Argon2id: Hybrid (recommended)
Memory-hard: Requires large memory, making GPU/ASIC attacks expensive.
scrypt
$$ DK = scrypt(password, salt, N, r, p, dkLen) $$
Parameters:
- $N$: CPU/memory cost (power of 2)
- $r$: Block size
- $p$: Parallelization
Memory required: $\approx 128 \cdot N \cdot r$ bytes
Python Implementation
Argon2 (Recommended)
1from argon2 import PasswordHasher
2
3ph = PasswordHasher(
4 time_cost=2, # iterations
5 memory_cost=65536, # 64 MB
6 parallelism=4, # threads
7 hash_len=32, # output length
8 salt_len=16 # salt length
9)
10
11# Hash password
12password = "user_password"
13hash = ph.hash(password)
14
15# Verify password
16try:
17 ph.verify(hash, password)
18 print("✅ Password correct!")
19except:
20 print("❌ Password incorrect!")
21
22# Check if rehash needed (params changed)
23if ph.check_needs_rehash(hash):
24 hash = ph.hash(password)
PBKDF2
1from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
2from cryptography.hazmat.primitives import hashes
3import os
4
5password = b"user_password"
6salt = os.urandom(16)
7
8kdf = PBKDF2HMAC(
9 algorithm=hashes.SHA256(),
10 length=32,
11 salt=salt,
12 iterations=100000,
13)
14
15key = kdf.derive(password)
16
17# Verify
18kdf2 = PBKDF2HMAC(
19 algorithm=hashes.SHA256(),
20 length=32,
21 salt=salt,
22 iterations=100000,
23)
24
25try:
26 kdf2.verify(password, key)
27 print("✅ Password correct!")
28except:
29 print("❌ Password incorrect!")
scrypt
1from cryptography.hazmat.primitives.kdf.scrypt import Scrypt
2
3password = b"user_password"
4salt = os.urandom(16)
5
6kdf = Scrypt(
7 salt=salt,
8 length=32,
9 n=2**14, # CPU/memory cost
10 r=8, # block size
11 p=1, # parallelization
12)
13
14key = kdf.derive(password)
Extract-Expand KDFs
HKDF (HMAC-based KDF)
Extract:
$$ PRK = HKDF\text{-}Extract(salt, IKM) $$
Expand:
$$ OKM = HKDF\text{-}Expand(PRK, info, L) $$
Use case: Derive multiple keys from shared secret (e.g., after ECDH)
1from cryptography.hazmat.primitives.kdf.hkdf import HKDF
2from cryptography.hazmat.primitives import hashes
3
4# Shared secret from ECDH
5shared_secret = b"..."
6
7# Derive encryption and MAC keys
8hkdf = HKDF(
9 algorithm=hashes.SHA256(),
10 length=64, # 32 for enc + 32 for MAC
11 salt=None,
12 info=b'handshake data',
13)
14
15key_material = hkdf.derive(shared_secret)
16enc_key = key_material[:32]
17mac_key = key_material[32:]
Comparison
| Algorithm | Type | Memory-Hard | Speed | Use Case |
|---|---|---|---|---|
| Argon2id | Password | Yes | Slow | Password hashing (best) |
| scrypt | Password | Yes | Slow | Password hashing |
| PBKDF2 | Password | No | Slow | Legacy, still acceptable |
| bcrypt | Password | No | Slow | Password hashing |
| HKDF | Extract-expand | No | Fast | Key derivation from shared secret |
Security Recommendations
Password Hashing
- Use Argon2id (or scrypt if unavailable)
- Minimum parameters:
- Argon2:
time_cost=2, memory_cost=65536 (64MB), parallelism=4 - scrypt:
N=2^14, r=8, p=1 - PBKDF2:
iterations=100000+
- Argon2:
- Always use salt (random, unique per password)
- Salt length: 16+ bytes
Key Derivation
- Use HKDF for deriving keys from shared secrets
- Include context in
infoparameter - Separate keys for different purposes
Related Snippets
- Asymmetric Encryption & Key Exchange
Asymmetric (public-key) cryptography with mathematical foundations, including … - Cryptographic Hash Functions
Cryptographic hash functions with mathematical properties and practical … - Digital Signatures
Digital signature algorithms with mathematical foundations. Mathematical … - Encrypt/Decrypt with Key Pairs
Encrypt and decrypt data using public/private key pairs and derive symmetric … - Generate Public/Private Key Pairs
Generate public/private key pairs on Linux for various cryptographic purposes. … - Hash and Sign Text with Key Pairs
Hash and digitally sign text using public/private key pairs. Hash Text (OpenSSL) … - Homomorphic Encryption Schemes
Homomorphic encryption allows computation on encrypted data without decryption, … - Key Sharding (Secret Sharing)
Key sharding splits a secret into multiple shares where a threshold of shares is … - Multi-Signature (Multisig) Schemes
Multi-signature schemes require multiple parties to sign a transaction or … - PGP Signature Operations
PGP/GPG signature operations for files, emails, and git commits. Generate GPG … - Setup PGP with Git (Auto-sign Commits)
Setup GPG/PGP to automatically sign Git commits and tags. Generate GPG Key for … - Symmetric Encryption
Symmetric encryption algorithms with mathematical foundations and practical … - Threshold Signatures
Threshold signatures enable a group to sign messages without ever reconstructing …