How password hashing works: MD5, SHA-256, bcrypt, and Argon2 compared, salting explained, rainbow tables, and why the choice of algorithm is critical.

When you create an account on a website and choose a password, that password is not saved to the database as-is. If it were, a single database breach would be enough to expose the credentials of all users. Instead, a mathematical function called a hash is applied, transforming the password into an unrecognizable string. But not all hashes are equal — and the difference between a weak hash and a strong one can mean the difference between secure passwords and passwords crackable in minutes.
What is a hash function?
A hash function takes an input of any length and produces a fixed-length output, called a digest or hash. The fundamental properties that make hash functions useful for security:
Deterministic: the same input always produces the same hash. hash("hello") = abc123... every time.
One-way: from the hash you cannot reconstruct the original input (in theory — we'll look at exceptions). It's not like encryption; there's no "key" to decrypt.
Avalanche effect: even a tiny variation in the input completely changes the hash. hash("hello") and hash("helo") produce totally different digests.
Collision resistance: it is computationally impossible to find two different inputs that produce the same hash (with modern algorithms).
Practical example: SHA-256 in action
Let's try with SHA-256 — one of the most widely used algorithms today:
-
Input:
password123 -
Hash:
ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f -
Input:
password124(just one character different) -
Hash:
5a0e61b3b32e8a45ecdb50c06d5c1a38a9a6474e7f9e895fc3da5af3e9ad3e26
The two hashes have nothing visually in common, even though they come from nearly identical inputs. This is the avalanche effect.
You can try it directly with our hash calculator which supports MD5, SHA-1, SHA-256, and SHA-512.
How websites store passwords
The correct flow for password management in a modern system:
Registration
- User enters their password:
MyPassword2024! - The server generates a salt — a unique random string, e.g.:
7f3a9c2b - The server combines password + salt:
MyPassword2024!7f3a9c2b - Applies a slow algorithm (bcrypt, Argon2, etc.) to obtain the hash
- Saves to the database: salt + hash (not the password!)
Login
- User enters their password
- The server retrieves the user's salt from the database
- Combines the entered password + salt and computes the hash
- Compares with the saved hash
- If they match → access granted
The actual password is never saved and is never sent in plaintext after registration.
Algorithms: not all are equal
MD5 and SHA-1: avoid for passwords
MD5 is fast — extremely fast. A modern GPU can compute billions of MD5 hashes per second. This makes it completely inadequate for protecting passwords: an attacker can try billions of combinations per second.
SHA-1 has the same speed problems, plus known cryptographic vulnerabilities. Still used for file integrity checks, but never for passwords.
SHA-256 and SHA-512 are cryptographically secure but remain fast — the same problem as MD5 for passwords. They are excellent for digital signatures, certificates, and file integrity, but not for password hashing.
bcrypt: the historical standard
bcrypt was designed in 1999 specifically for password hashing, with a revolutionary principle: be slow by design. It includes a "cost factor" parameter that determines how many iterations to perform. Increasing it causes the time to generate a hash to grow exponentially.
With cost factor 12 (common in modern applications), computing a single bcrypt hash takes ~300ms. That seems short, but it means an attacker can only try ~3 passwords per second instead of billions. The same GPU that cracks billions of MD5 hashes per second cracks only a few thousand bcrypt hashes.
Argon2: the state of the art
Argon2 won the Password Hashing Competition in 2015 and is today considered the recommended algorithm for new implementations. It has three variants:
- Argon2i: optimized against side-channel attacks
- Argon2d: optimized against GPU attacks
- Argon2id: hybrid, the recommended variant for most use cases
Unlike bcrypt, Argon2 allows you to configure both the computation time and the required memory. Requiring 1GB of RAM to compute a hash makes it impossible to run parallel attacks on GPUs (which have limited memory per thread).
PBKDF2: the most compatible
PBKDF2 is the oldest "slow" algorithm still acceptable — used by iOS for the keychain and by many enterprise systems. It's not considered as cutting-edge as Argon2 but is widely supported and sufficiently secure with appropriate parameters.
Attacks on hashes: how they work in practice
Rainbow tables
Rainbow tables are precomputed databases that associate hashes with known passwords. Before the use of salts, they were devastating: you search for the hash in the database and immediately find the password.
The salt renders them useless: since each password has a different and random salt, you can't precompute anything. The attacker must compute the hash for each attempt including the user's specific salt.
Brute force and dictionary attacks
With fast hashes (MD5, SHA-256 without iterations), an attacker with modern hardware:
- Tries all 8-character passwords in a few hours
- Tries millions of dictionary passwords in seconds
With bcrypt or Argon2 with correct parameters:
- A single GPU would take decades to find a complex 12-character password
- Attacks become economically unfeasible
Credential stuffing
When a database is stolen with weak hashes (MD5), attackers crack the hashes and use the credentials across all other services (where many users reuse passwords). This is why the type of hash used by every site you use has a direct impact on your security on all other sites.
Check your site: does it use modern hashes?
You can do an empirical check: when you log in to a site, if you receive your password by email "to recover it," it means the site stores it in plaintext or encrypted (reversibly) — not hashed. Red flag.
Another check: if you click "forgot password" and the site sends you your old password (not a link to reset it), that's a serious problem. With proper hashing, no one can know your original password — they can only allow you to set a new one.
Frequently asked questions
Can I use SHA-256 for passwords in my application? Not directly. SHA-256 is too fast to protect passwords. Use bcrypt with cost factor ≥ 12, or Argon2id. Frameworks like Django, Laravel, Rails, and Node.js (Passport) use bcrypt or Argon2 by default.
What is the difference between hashing and encryption? Encryption is reversible with the right key: you encrypt and then decrypt. Hashing is irreversible: there's no key, you can't get the original back. Passwords use hashing precisely because you never need to "see" the original password — you always verify by comparing hashes.
If two users have the same password, do they have the same hash?
With a salt, no. Even if two users choose password123, their random salts are different, so their hashes are completely different. Without a salt, yes — and this allowed easy identification of common passwords in a stolen database.
← All articles
