1
CS 161, Summer 2026 @ UC Berkeley
Slides credit: Nick Weaver, Nicholas Ngai, Peyrin Kao, Henry Corrigan-Gibbs, Jonah Bedouch
Cryptographic Hashes
Lecture 9 (Authentication 2)
SU26 Announcement:
Please fill out midterm logistics form ASAP if you need adjustments.
What is Cryptography?
Lecture 9, CS 161, Summer 2026
Intro to Cryptography
Cryptographic Hashes
Hash Applications
Goodbye, Passwords
Last time, we saw that passwords and session tokens had a major flaw:
To do better, we need to learn about cryptography.
Cryptography Definition
Cryptography: Secure communication and computation against adversarial behavior.
Why study cryptography?
Cryptography draws on algorithms, complexity, architecture, number theory…
Cryptography is a "success story" within computer security.
What You Will (and Won't) Learn in this class
What are the common causes of security failure?
This class will make you a more informed user of crypto tools.
This class will not teach you how to design or write your own crypto tools.
Don't Roll Your Own Crypto
Crypto algorithms are secure because they have been analyzed by experts for years.
Implementations of these algorithms are exceptionally subtle and hard-to-test.
If you remember nothing else from this course: Don't roll your own crypto.
Definitions
Lecture 9, CS 161, Summer 2026
Intro to Cryptography
Cryptographic Hashes
Hash Applications
Cryptography Definitions
Warning: Math approaching.
Cryptography: A Common Problem
Cryptography: Secure communication and computation against adversarial behavior.
Where might you use cryptography?
To summarize all these scenarios, we often use a common cast of characters.
You
Your friend
You
Amazon
ATM
Bank
Your phone
App Store
Meet Alice, Bob, Eve, and Mallory
The heroes: Alice and Bob are two users who want to communicate securely over a channel.
The villain: Mallory is an active attacker ("man-in-the-middle") who can read and modify data on the channel.
Alice
Bob
Mallory
Authenticity
Goal: Alice and Bob need to know that they're talking to each other.
Alice
Bob
Mallory
Efficient (PPT) Attackers
Mallory models real-world attackers, so we give her real-world limitations.
We will only consider efficient attackers.
Many ways to define efficient. One is Probabilistic Polynomial Time (PPT):
The sun would burn out before they finished.
What N is depends on the specific scheme being discussed.
Quantifying Efficiency: Brute-Force Attacks
Another way to define "efficient" is by counting operations:
Punchline: If an attack requires >2128 operations, it is impossible.
Negligible Probabilities
Mallory models real-world attackers, so we give her real-world limitations.
To model this, we introduce negligible and non-negligible probabilities:
In many of our definitions:
Smaller than the probability of winning the Powerball lottery jackpot every single day of your life.
Cryptography Roadmap
How do we teach cryptography?
Along the way, we’ll develop some insights into how cryptographic systems work.
Collision-Resistant Hash Functions (CRHFs)
Lecture 9, CS 161, Summer 2026
Intro to Cryptography
Cryptographic Hashes
Hash Applications
Hashes
A hash function is a function that deterministically compresses a long input to a fixed-length output.
Hash Function H : {0,1}* → {0,1}n | |
Input: | Arbitrary-length bitstring |
Output: | Fixed-length n-bit hash |
Properties: | Efficiently computable, Deterministic |
Read this as: Function mapping (→) an arbitrary number (*) of zeroes and ones, to n zeroes and ones.
Same input gives same output every time.
n is a fixed number, commonly 256.
Collisions
Collision: Two distinct values x and x' such that H(x) = H(x').
Can a hash function have no collisions at all?
There are way more inputs than outputs.�By the pigeonhole principle, there must be�collisions. (In fact, there are infinitely many.)
Reminder: {0,1}* means arbitrary-length bitstring, {0,1}256 means 256-bit string.
{0,1}*
{0,1}256
When mapping from large input space to small output space, collisions occur.
Collision Resistance
Preventing collisions is impossible. But we can make them hard to find.
Intuition: I give you a hash function. Can you find two inputs with the same output?
If the output space is small like {0,1}2, finding collisions would be easy.�How big should the output space be?
A hash function H is collision resistant if
no efficient adversary can find distinct x and x' such that H(x) = H(x').
"no efficient adversary" = finding collisions is theoretically possible, but not actually feasible.
Two inputs with the same output = a collision.
Collision resistance = it's hard to find collisions.
Breaking Collision-Resistance: Birthday Paradox
The birthday paradox: If you pick 2n/2 elements independently at random from a set of size 2n, with probability > ⅓ you will pick at least one element twice.
We can think of computing H(random input) as picking a random n-bit hash output.
By birthday paradox, after hashing 2n/2 random inputs, we're likely to find a collision.
Therefore: If a hash function has n-bit output, an attacker picking inputs at random (brute-force attack) finds a collision in roughly 2n/2 tries.
Building CRHFs
Lecture 9, CS 161, Summer 2026
Intro to Cryptography
Cryptographic Hashes
Hash Applications
Examples of Non-Collision-Resistant Hash Functions
Some hash functions that are not collision-resistant:
H(M) := Output the first n bits of M.
Collision: x = 0n, x' = 0n || 0n
Because the first n bits of both x and x' are all zeroes.
H(M) := Chop M into n-bit blocks. Output the XOR of all blocks.
Collision: x = 0n || 0n, x' = 1n || 1n
Because XORing together two all-zero blocks yields all zeroes,�and XORing together two all-one blocks also yields all zeroes.
:= means "is defined as."
0n means "0 repeated n times."
|| is concatenation, so this is 0 repeated 2n times.
Examples of Non-Collision-Resistant Hash Functions
Some hash functions that are not collision-resistant:
Let H be a collision-resistant hash function.
H'(M) := H(M)[:64]
Since H' has 64-bit output, it takes roughly 264/2 = 232 tries for a brute-force attacker to find a collision. This is a feasible number!
Brackets are for slicing, so [:64] means the first 64 bits of the H(M) value.
Building Collision-Resistant Hash Functions
We don't know how to prove that a function is actually collision-resistant.
Examples of standard hashes:
Modern CPUs have hardware specially designed to do SHA-2 computations quickly.
Building Collision-Resistant Hash Functions
Common method of creating CRHFs:
The Merkle-Damgard construction lets you build a big CRHF from a small CRHF.
You can prove that if h is a CRHF, then H is a CRHF.
Can't prove h is a CRHF. Rely on cryptanalysis.
Merkle-Damgard Construction
Merkle-Damgard uses h : {0,1}2n → {0,1}n to construct H : {0,1}* → {0,1}n like this:
Input M (arbitrary length)
M0
M1
M2
MN
…
Pad
Split M into n-bit chunks. Add padding bytes if the last chunk is < n bits.
Initial fixed value
h
h
h
h
At every step, input the previous output and the next chunk into h.
Notice: This is 2n bits of input.
Output H(M)
…
Other Cryptographic Hash Properties
Lecture 9, CS 161, Summer 2026
Intro to Cryptography
Cryptographic Hashes
Hash Applications
Collision Resistance Implies Nothing Else
Collision resistance doesn’t say anything about other properties.
We will (briefly) look at a few other properties of some cryptographic hashes.
Length Extension Attacks
Many hash functions are vulnerable to length-extension attacks.
H(X)
Input X (arbitrary length)
X0
X1
X2
XN
…
pad_x
Initial fixed value
h
h
h
h
…
h
y'
pad_y'
H(x||pad_x||y')
H(x||y) where y=pad_x||y'.
The output of H(x) is the internal �state of the hash function.
One-Wayness
�Intuitively, think of one-wayness as a challenge:
Can you find some x' such that H(x') = y?
Informally: "It is hard to invert H on random inputs."
A hash function H is one-way if given H(x) but not x,
no efficient adversary can find an x' such that H(x) = H(x').
One-Wayness vs. Collision Resistance
The subtle difference between one-wayness and collision resistance:
| One-wayness | Collision Resistance |
I give you: | The function H and a target y. | Only the function H. |
…and ask you to find: | A single x such that H(x) = y. | Any two x and x' that hash to the same output. |
I give you the green target y.
You must find a red input that hashes to y.
I don't give you a green target.
You must find any two red inputs with the same output.
Do Cryptographic Hashes Prove Authenticity?
Lecture 9, CS 161, Summer 2026
Intro to Cryptography
Cryptographic Hashes
Hash Applications
Cryptographic Hashes Can Sometimes Prove Authenticity
A scenario with no security:
Today: You store a file in the cloud.
Tomorrow: You download the file.
File f
File f
Malicious file f'
Compromised cloud!
Cryptographic Hashes Can Sometimes Prove Authenticity
You can use hashes to check that the file is unmodified!
Today: You store a file in the cloud, �and you store a hash of the file locally.
Tomorrow: You download the file.
Re-compute the hash and compare with h.
File f
File f
Malicious file f'
Compromised cloud!
I remember h = H(f).
h ≠ H(f'). Reject!
Real-World Cryptographic Hashes
WhatsApp and Signal safety numbers:
Downloading large files from mirrors:
Hashes Don't Always Prove Authenticity
What about the original setting?
Main problem: If the attacker can modify the hash value, checking the hash does not provide authenticity.
Main issue we must solve: Hashes are not authenticated. Anybody can compute them.
Alice
Bob
Mallory
M and H(M)
M' and H(M')
I hashed M' and it matches the hash I received. Looks good.
Application: Merkle Trees
Lecture 9, CS 161, Summer 2026
Intro to Cryptography
Cryptographic Hashes
Hash Applications
Scenario: Sharing Large Files
Scenario: I want to share a 40 GB movie with many people.
Solution: I split the movie up into 1 KB chunks, and give the chunks to many people.
Issue: If even one person sends the wrong chunk, people aren't going to be able to recover the movie.
Hash List
Bad idea 1: I publish a hash of the entire file.
Bad idea 2: I publish a hash of each chunk.
Merkle Trees (1/2)
Better idea: Build a Merkle Tree of hashes.
C0
C1
C2
C3
h0=H(C0)
h1=H(C1)
h2=H(C2)
h3=H(C3)
h01=H(h0||h1)
h23=H(h2||h3)
h0123=H(h01||h23)
C4
C5
C6
C7
h4=H(C4)
h5=H(C5)
h6=H(C6)
h7=H(C7)
h45=H(h4||h5)
h67=H(h6||h7)
h4567=H(h45||h67)
h0…7=H(h0123||h4567)
Merkle Trees (2/2)
Once I've constructed this tree, I can publish the root, and ask other people sharing the file to also send the hashes of every sibling in the hash tree.
C0
C1
C2
C3
h0=H(C0)
h1=H(C1)
h2=H(C2)
h3=H(C3)
h01=H(h0||h1)
h23=H(h2||h3)
h0123=H(h01||h23)
O(logN) siblings shared alongside C3.
O(logN) hashes computed by the user downloading C3.
Most of the tree can be ignored when checking one node.
Merkle Tree Tradeoffs
Now, people only have to download the root from me. No more bandwidth issues!
Interesting takeaway: Untrusted parties can prove that a chunk of data is legitimate relatively cheaply, as long as the root comes from somewhere you trust.
Application: Password Hashing
Lecture 9, CS 161, Summer 2026
Intro to Cryptography
Cryptographic Hashes
Hash Applications
Password Hashing
To check passwords, the server must store each user's password.
Storing plaintext passwords is a really bad idea.
If an attacker steals the passwords file, they know everybody's password.
Storing the hash of each user's password is better.
If a one-way hash is used, the attacker cannot easily learn the plaintext password.
User | Password |
EvanBot | pancake123 |
CodaBot | gobears! |
... | ... |
User | H(Password) |
EvanBot | 0x20A2CBC5... |
CodaBot | 0xCFDD6DC9... |
... | ... |
When a user enters a password, hash it and compare against database.�Works because hashes are deterministic.
Mitigating Brute-Force: Slow Hashes
Problem: People pick weak passwords, so brute-force attacks are feasible.
Solution 1: Use a slow hash, e.g. 0.1sec instead of 0.001sec.
Not an asymptotic change;�it's an extra large constant factor.
Mitigating Brute-Force: Salted Hashes
Solution 2: Salting. For each user, include a different value in the hash.
User | Salt | H(Password || Salt) |
EvanBot | 40dAGZxxQj | 0x91E32C74... |
CodaBot | Es6x4Hzpv7 | 0xD3BFDD6A... |
... | ... | ... |
Offline vs. Online Attacks
There are two ways to perform brute-force attacks:
Offline brute-force attacks:
Online brute-force attacks: