Chapter 09 // Protocols

User
Authentication

Encryption hides messages. Signatures prove authorship. But before any of that, a system needs to answer a more basic question: who is this person? Authentication ties together nearly every primitive from the chapters before it.

Scroll to explore
01 // The Problem

Who goes there?

Encryption and signatures assume you already know who you are talking to. Authentication is the step before that: proving you are who you claim to be. In person, faces and voices work. Over a network, you need a protocol.

The identity problem

Everything in this course so far has assumed the hard part is already solved. Alice encrypts a message to Bob. Bob verifies Alice's signature. But how does the server know that the person typing a password is actually Alice, and not someone who guessed it? How does a website know the browser session belongs to you after you close the tab and come back?

Authentication is the answer. It is the process of proving an identity claim, and it sits at the foundation of every secure system. Without authentication, encryption protects messages nobody can trust, and signatures prove authorship nobody can verify.

Three ways to prove identity

Every authentication method falls into one of three categories. The rest of this chapter explores how each one works, why each one fails on its own, and how combining them creates real security.

Something you know

Passwords, PINs, security questions. A secret that only the legitimate user should know.

Something you have

A phone, a hardware security key, a smart card. A physical device that generates or stores credentials.

Something you are

Fingerprints, face scans, iris patterns. Biometrics that are unique to your body.

The simplest and oldest method is a password: something you know. Passwords have been the default since the 1960s, not because they are good, but because they are cheap and require nothing beyond a keyboard. The rest of this chapter shows why passwords alone are not enough, and what cryptography offers as alternatives.

02 // Password Storage

Never store the secret

If a server stores passwords in plaintext and gets breached, every user is compromised instantly. The solution: store a hash of the password, not the password itself. But plain hashing is not enough.

Plaintext is catastrophic

In 2009, RockYou stored 32 million passwords in plaintext. When attackers breached the database, every password was immediately readable. In 2013, Adobe lost 153 million encrypted (not hashed) passwords using the same encryption key for all of them, which is effectively the same as plaintext.

The solution comes from earlier chapters: hash the password before storing it. When a user logs in, hash the submitted password and compare it to the stored hash. The server never needs to know the actual password.

Why plain hashing is not enough

SHA-256 is fast. Too fast. An attacker with a modern GPU can compute billions of SHA-256 hashes per second. A 30-bit-entropy password (about a billion possibilities) falls in under a second.

Rainbow tables make it even worse. These are precomputed lookup tables mapping common passwords to their hashes. If two users have the same password, they have the same hash. An attacker who cracks one cracks both.

Salt: making every hash unique

A salt is a random value stored alongside the hash. Instead of H(password)H(\text{password}), you compute H(saltpassword)H(\text{salt} \| \text{password}). Same password, different salt, completely different hash. Rainbow tables become useless because each user's hash is unique even if their passwords are identical.

The salt does not need to be secret. It is stored in the database next to the hash. Its purpose is to force the attacker to brute-force each user individually, instead of attacking all users at once with a precomputed table.

Key stretching: making each guess expensive

Salting solves the rainbow table problem, but a fast hash function still lets an attacker make billions of guesses per second. Key stretching deliberately slows down the hashing process. PBKDF2 runs the hash function hundreds of thousands of times in a chain. bcrypt uses the Blowfish cipher with an expensive key schedule. Argon2 goes further by requiring large amounts of memory, which defeats GPU parallelism.

PBKDF2(password,salt,n)=H(H(H(H(n iterationssaltpassword))))\text{PBKDF2}(password, salt, n) = \underbrace{H(H(H(\cdots H(}_{n \text{ iterations}}salt \| password)\cdots)))

With 600,000 iterations, a single PBKDF2 computation takes roughly half a second. An attacker trying to brute-force a 48-bit keyspace now faces:

2482 hashes/sec4,500 years\frac{2^{48}}{2 \text{ hashes/sec}} \approx 4{,}500 \text{ years}

Key stretching does not make passwords unbreakable, but it shifts the economics decisively. Cracking one password takes serious hardware and time. Cracking millions becomes impractical.

Password Hashing Playground

Type a password and see how PBKDF2 derives a key. Adjust the iteration count to feel the computational cost, and toggle comparison mode to see how different salts produce completely different hashes from the same password.

00000000000000000000000000000000
100k
1k600k
0.0 ms
Waiting...

Modern best practice is Argon2id with at least 64 MB of memory and 3 iterations. PBKDF2 with 600,000+ iterations is the NIST recommendation when Argon2 is not available. Never use plain SHA-256 or MD5 for passwords.

03 // Multi-Factor Authentication

More than one proof

If your password is stolen through phishing, a data breach, or shoulder surfing, the attacker has everything they need. Multi-factor authentication requires proof from at least two different categories.

Why one factor is not enough

A password is a single point of failure. If it leaks, the attacker gets full access. Multi-factor authentication (MFA) adds a second barrier. Even if your password is compromised, the attacker also needs your phone or hardware key. Compromising two independent factors is exponentially harder than compromising one.

The key word is independent. Two passwords are not two-factor authentication. A password and a PIN stored on the same device is barely better than one factor. The factors must come from different categories: something you know, something you have, something you are.

TOTP: time-based one-time passwords

The most common second factor is a 6-digit code from an authenticator app. The protocol behind it is TOTP (RFC 6238), and it relies on cryptographic primitives you already know.

During setup, the server generates a random secret key and shares it with your authenticator app (usually via QR code). Both sides now hold the same secret. Every 30 seconds, both sides compute:

T=Unix time30T = \lfloor \frac{\text{Unix time}}{30} \rfloor
TOTP=Truncate(HMAC-SHA1(secret,T))mod106\text{TOTP} = \text{Truncate}(\text{HMAC-SHA1}(\text{secret}, T)) \bmod 10^6

The HMAC provides authentication. The time step ensures each code is valid for only 30 seconds. The truncation extracts a human-readable 6-digit number from the 20-byte HMAC output. Because both sides share the same secret and the same clock, they independently generate the same code.

TOTP Generator

Watch a time-based one-time password generate in real time. The same secret and the same 30-second window always produce the same 6-digit code. Below, you can see every step of the computation.

10s
--- ---
Current TOTP Code
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Computation Breakdown
1
Time Counter
T = floor(1775750900 / 30) = 59191696
2
HMAC-SHA1(secret, T)
3
Dynamic Truncation
Offset = last byte & 0x0f = 0
4 bytes at offset [0..3] =
Truncated value = 0
4
Final Code
0 mod 1,000,000 = ------

TOTP codes are vulnerable to phishing. If you type the code into a fake login page, the attacker can use it immediately (it is valid for 30 seconds). TOTP also requires a shared secret, which can be stolen from the server. This is why FIDO2 and passkeys are the modern replacement, as we will see next.

04 // Passkeys & WebAuthn

Beyond passwords

Passkeys replace passwords with public-key cryptography. Your device generates a key pair. The private key never leaves your device. Authentication is a challenge-response signed with your private key. No shared secret ever crosses the network.

The passkey revolution

Passkeys (FIDO2/WebAuthn) flip the authentication model entirely. Instead of proving you know a secret the server also knows, you prove you control a private key that the server has never seen. The server stores only your public key, exactly like the digital signature schemes from earlier chapters.

No password database to breach. No shared secret to phish. The credential is bound to the website's domain, so even a pixel-perfect phishing page cannot extract a valid response. The private key is protected on your device by biometrics or a local PIN.

How it works

The WebAuthn protocol has two phases: registration (creating the credential) and authentication (proving you hold it).

Registration
1

Server sends a random challenge to the device.

2

Device generates a new key pair (e.g., ECDSA P-256). The private key is stored in secure hardware on the device.

3

Device signs the challenge and sends the public key + signature back to the server.

4

Server verifies the signature and stores the public key. No secret is ever shared.

Authentication
1

Server sends a fresh random challenge.

2

Device signs the challenge with the stored private key.

3

Server verifies the signature with the stored public key. If valid, the user is authenticated.

Passkey Challenge-Response

Step through the WebAuthn authentication flow. The device generates a key pair, the server sends a challenge, and the device proves its identity by signing the challenge with its private key. No password is ever transmitted.

0
1
2
3
4
5
Ready
Server
Waiting for device registration...
Device
Ready to generate key pair...

Passkeys are supported in all major browsers and operating systems. Apple, Google, and Microsoft have all committed to passkey support through the FIDO Alliance. For new systems, passkeys are the recommended primary authentication method.

05 // Best Practices

Building authentication right

Authentication is where cryptographic theory meets real-world security. These guidelines reflect how modern systems handle identity safely.

🔑

Use Passkeys When Possible

Passkeys eliminate passwords, resist phishing, and remove the risk of credential database breaches. Support them as the primary authentication method for new systems.

🧂

Hash Passwords with Argon2id

If you must store passwords, use Argon2id with recommended parameters (64 MB memory, 3 iterations, 1 parallelism). PBKDF2 with 600,000+ iterations is the fallback when Argon2 is unavailable.

🛡️

Require MFA for Sensitive Operations

Even if the primary login uses passwords, require a second factor for account recovery, password changes, and high-value actions. TOTP is the minimum. FIDO2 hardware keys are the gold standard.

06 // What You Learned

From passwords to passkeys

This chapter traced the evolution of user authentication: from shared secrets to cryptographic challenge-response. Each method builds on primitives from earlier chapters, and each one exists because the previous generation was not enough.

The story so far

Password storage requires salting and key stretching. PBKDF2, bcrypt, and Argon2 make brute-force attacks computationally expensive. Never store passwords as plain hashes.

Multi-factor authentication adds a second barrier. TOTP uses HMAC and a shared time step to generate 6-digit codes. It is better than passwords alone, but still vulnerable to phishing.

Passkeys replace shared secrets entirely with public-key challenge-response. Phishing-resistant, breach-proof, and backed by all major platforms through the FIDO Alliance.

Authentication is where all the primitives come together. Hashing secures passwords. HMAC powers TOTP. Digital signatures enable passkeys. Randomness generates challenges. Next, we will look at what happens when cryptographic systems fail in practice.

Up Next

Chapter 10 // When Cryptography Fails

Continue Learning