Domain: Identity & Access Systems
๐ Used in: APIs, SaaS platforms, fintech, internal tools, developer platforms, enterprise SSO, mobile backends
โ One of the most practical cryptography domains: combines password hashing, token signing, authenticated sessions, randomness, and secure protocol design.
Identity systems answer two fundamental questions:
- Who are you? โ authentication
- What are you allowed to do? โ authorization
Modern identity systems are not built from a single primitive.
They are built from a composition of primitives:
- Argon2 protects passwords at rest
- HMAC protects tokens against tampering
- Ed25519 enables public verification
- AEAD protects confidential session state
- Randomness prevents replay and prediction
- Hashing enables safe logging and correlation
This chapter shows how those primitives are applied in a real domain.
Not as isolated theory. As a working security architecture.
Threat Model
Identity systems are constantly attacked.
Attackers try to:
- steal password databases
- brute-force leaked hashes
- forge tokens
- escalate privileges
- replay login challenges
- tamper with session state
- abuse weak randomness
- exploit overexposed long-term secrets
Identity Systems as Composition of Primitives
Cryptography is not used once. It appears at every layer of the identity system.
| Component | Primitive | Security Property | Why it matters |
|---|---|---|---|
| password storage | Argon2 | brute-force resistance | database leaks happen |
| internal stateless token | HMAC | integrity + authenticity | prevents privilege escalation |
| distributed token verification | Ed25519 | public verifiability | proves identity |
| session protection | AEAD | confidentiality + integrity | protects sensitive state |
| login challenges | CSPRNG | unpredictability | prevents reuse of captured messages |
| safe observability | BLAKE3 | non-reversible fingerprinting | limits blast radius1 |
| session lifecycle control | expiration policy | expiration enforcement | prevents long-lived compromise |
Password Storage โ Argon2
Passwords must never be stored directly.
If a database leaks and the server stored plaintext passwords, every account is immediately compromised. Even plain hashing is not enough.
General-purpose hashes are designed to be fast. Password hashing must be deliberately expensive.
Argon2 is designed for this exact purpose.
password + salt โ Argon2 โ password hash
This protects users even when the database is stolen.
The server stores only the derived hash, never the password itself.
๐งช Minimal Rust Example: password hashing and verification (source code)
Crates used: argon2 , rand_core
use argon2::{
Argon2,
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
};
use rand_core::OsRng;
use rsa::rand_core;
fn hash_password(password: &str) -> Result<String, Box<dyn std::error::Error>> {
let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();
let password_hash = argon2
.hash_password(password.as_bytes(), &salt)?
.to_string();
Ok(password_hash)
}
fn verify_password(password: &str, stored_hash: &str) -> Result<bool, Box<dyn std::error::Error>> {
let parsed_hash = PasswordHash::new(stored_hash)?;
let argon2 = Argon2::default();
Ok(argon2
.verify_password(password.as_bytes(), &parsed_hash)
.is_ok())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let password = "correct horse battery staple";
let stored_hash = hash_password(password)?;
println!("Stored hash:\n{stored_hash}\n");
let valid = verify_password(password, &stored_hash)?;
println!("Valid password: {valid}");
let invalid = verify_password("wrong password", &stored_hash)?;
println!("Wrong password accepted: {invalid}");
Ok(())
}
Output:
Stored hash:
$argon2id$v=19$m=19456,t=2,p=1$G1/J1ZCmovy3XioeKSPC1Q$RRoz1mRaShxHqnvpq3JiGR0xuScwdoO6MOcWkUw0cIU
Valid password: true
Wrong password accepted: false
๐ข Conclusion
Password hashing solves one specific problem: if the database leaks, raw passwords are not immediately exposed.