MD5 Generator With Salt: Why Salting MD5 Is Still Not Enough
Adding a salt to MD5 is a genuine improvement over plain MD5 — and still not enough for passwords. Knowing exactly which problem a salt solves tells you why.
What a salt actually fixes
A salted MD5 is md5(salt + password) or md5(password + salt), with a random salt stored in the same row as the digest. Because every row has its own salt, two users who both chose letmein end up with unrelated digests, and a leaked table no longer shows which accounts share a password.
It also retires precomputed lookups. The rainbow table and "MD5 decrypt" databases are built from unsalted hashes, so a salted digest will not be in them; an attacker would need a separate table for every salt.
The order is part of the scheme. md5(salt + password) and md5(password + salt) give different digests for the same inputs, so when you port a legacy login to another language, check which one the old code used before you conclude the stored hashes are corrupt.
What it does not fix
Speed, and so the answer to whether a salted MD5 hash can be decrypted. It cannot be decrypted any more than a plain one, but it can be cracked the same way: the salt sits next to the hash, so a cracker simply adds it to every guess. Hashcat ships ready-made modes for this, 10 for md5($pass.$salt), 20 for md5($salt.$pass), 500 for $1$ md5crypt and 1600 for Apache $apr1$. The salt forces the attacker to work on each account separately, which costs time linearly, and MD5 is fast enough that they have it.
Password hashing needs a function that is deliberately slow, and ideally memory-hard as well. bcrypt provides the first; scrypt and Argon2id provide both. No amount of salting turns MD5 into one of them.
md5crypt and the Apache variant
Unix md5crypt ($1$) and the Apache variant ($apr1$) do try to slow MD5 down by iterating it 1000 times over the password and salt. In 1994 that was meaningful; today it is trivially parallel on a GPU, and its author, Poul-Henning Kamp, declared md5crypt no longer safe in 2012.
You still meet $apr1$ in .htpasswd files. If you control the server, switch to bcrypt — htpasswd has supported it for years:
htpasswd -B -c .htpasswd alice # bcrypt, recommended
htpasswd -m -c .htpasswd alice # apr1 (MD5), legacy
Where salted MD5 is fine
Non-security uses where you want a keyed-looking identifier: a cache key that should not collide across tenants, an anonymised analytics id, a deterministic shard selector. None of these break if someone reverses them.
For anything an attacker benefits from cracking, use password_hash() in PHP, bcrypt or argon2 libraries elsewhere, and let the library manage the salt for you — hand-rolled salting is where most implementations go wrong.
Frequently asked questions
Does a longer salt make MD5 safe?
No. Salt length affects lookup tables, not brute-force speed. MD5 stays too fast regardless.
Can a salted MD5 hash be decrypted?
No, but it can be cracked. The salt is stored next to the hash, so an attacker adds it to each guess, and common passwords behind a salted MD5 still fall quickly. Only the online lookup sites stop working.
What replaces salted MD5 for passwords?
Argon2id if available, otherwise bcrypt or scrypt. All three are slow by design and handle salting internally.