MD5 isn't encryption, it's a one-way hash.
The only purpose of using a better one-way hash is to delay reversing the password. As computers have become more powerful and vulnerabilities in various hashing algorithms have been discovered, better hashes must be developed.
In which case they must have the
password hash and so will have already
comprimised my database right?
The purpose of salting and hashing passwords is to protect the password itself, even in the event of database compromise. Many (most) users use the same password for multiple logins, so if it's compromised, so is every account it's linked to.
SHA-256 should be more than sufficient, but make sure you're also salting the passowrd. Your functions should look like this (pseudo-code):
fun store_password(plaintext):
salt = random_alphanumeric(40) # maybe put 40 in a config, or #define somewhere
hashed = sha256_digest(salt + plaintext)
return "sha256!" + salt + "!" + hashed
fun check_password(plaintext, stored):
algo, salt, hashed = stored.split("!")
if algo == "sha256"
return (sha256_digest(salt + plaintext) == hashed)
else if ... # other supported password schemes here
A commenter below pointed out that with a sufficiently powerful attacker (or, weak passwords), storing the full salt might allow the plaintext to be brute-forced. If you're concerned about that, use a two-part salt. Generate part of it every time (saltA
), and store the other in a config file (saltB
). Then combine them to generate/check passwords:
import my_config
fun store_password(plaintext):
saltA = random_alphanumeric(40)
hashed = sha256_digest(saltA + my_config.saltB + plaintext)
return "sha256!" + saltA + "!" + hashed
fun check_password(plaintext, stored):
algo, saltA, hashed = stored.split("!")
if algo == "sha256"
return (sha256_digest(saltA + my_config.saltB + plaintext) == hashed)
# ...
Note that if you choose this system, changing your saltB
will invalidate every stored password.