Basic

Never store a password plain

I saved passwords in a file and a leak would hand them to anyone. A password is stored as a one-way hash, so a thief reads garbage, not your password.

What you will see

False

About 2 min of reading

Try It

Hash a password and confirm the stored value is not the password.

1

Hash a password. The stored string is a bcrypt digest, not the word.

import bcrypt h = bcrypt.hashpw(b'hunter2', bcrypt.gensalt()) print(h)

Before you run it, say out loud what it will print. Then open the answer.

What it prints
b'$2b$12$X7k9...random...digest'
2

Verify a correct guess by rehashing. It returns True.

import bcrypt print(bcrypt.checkpw(b'hunter2', h))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
True
3

A wrong guess returns False. There is no decrypt step anywhere.

import bcrypt print(bcrypt.checkpw(b'wrong', h))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
False

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

A password is stored as a one-way salted hash; verification rehashes the guess and compares, so the stored value can never be reversed to the password.
1 Password hashed with salt
↓
2 Store the hash not the word
↓
3 Guess rehashed the same way
↓
4 Compare hashes to verify
Line by line

Read the first example one line at a time. A line that prints shows what appears on screen; the rest set things up quietly.

import bcrypt sets nothing on screen
h = bcrypt.hashpw(b'hunter2', bcrypt.gensalt()) sets nothing on screen
print(h) b'$2b$12$X7k9...random...digest'
Why this works
Hash, do not encrypt

Encryption is reversible with a key, so it is wrong for passwords. A hash is one-way and you verify by rehashing. The point of hashing is that the stored form is useless to a thief, so choose a hash you cannot run backwards.

Use a slow hash

A fast hash (MD5, SHA-1) can be guessed by trying billions of passwords a second. bcrypt, scrypt, and Argon2 are deliberately slow and salted, so a stolen database stays expensive to crack. Speed here is a feature, not a cost.

Examples

One way only

h = bcrypt.hash('hunter2')
# h = '$2b$12$...'  -> you cannot get 'hunter2' back

A hash is a trapdoor: easy to compute, impossible to reverse. The stored value is not the password.

Check by rehashing

bcrypt.check('hunter2', stored_hash)  # True

To verify, hash the guess the same way and compare. You never decrypt the stored value, there is nothing to decrypt.

Plain is a bug

# WRONG
save('hunter2')

Storing the raw string means a stolen file is a list of live passwords. That single line is the whole security failure.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

Next Lesson
Why the salt matters
Why the salt matters →