No, I’m not mad. Hear me out
It is now good practise not to use MD5 for secure hashes. There have been published rainbow tables of the most common password hashes available online for years, and there are even websites available to let you search these rainbow tables for matches.
Hopefully, any password hashes you are utilising are in at least SHA256 – not SHA1, as even that has issues for security now.
An MD5 hash is 32 hexedecimal characters in length. That is a nice size, and databases and most applications support MD5 hashes or 32-character UID’s with relative ease. But your more secure SHA hash is likely to be 40 characters or more, so that is not something that will be anywhere near as easy to store and handle like the shorter MD5 hash.
So why not MD5 it?
Your SHA hash is secure. So why not take your hashing process one step further, and turn your SHA hash into an MD5 hash? By adding an extra hashing step to MD5, you will lose no strength in security, and you will be able to utilise your programming language and storage technology’s native support for 32-byte md5 or uuid objects, and generally save space.
The major benefit
Besides the saving of at least 8 bytes per record (assuming a SHA hash of at least 40 characters), along with whatever benefits a 32-character uid provides on your storage mechanism, you will also add a lair of obfuscation to your security hashes. If your database is ever compromised, hackers will see your 32 byte MD5 hashes and their first port of call will be to the available rainbow tables to see if they can easily decrypt them. It is very unlikely there will even be a match in the published MD5 rainbow tables, given most only store those hashes derived from plain-text strings. If the hacker is determined and turns to CPU farms to try and decrypt the MD5 strings, all they will be rewarded for by their efforts is discovering that your MD5 hash is in fact a nonsensical more secure hash of some sort.
So storing password hashes as MD5 is still a good idea
That is of course, provided that you first generate a secure SHA-type hash, then use MD5 as the final step in the hash generation process!
Some example code
Here are some code examples which illustrate generating a strong Password and Salt as MD5 values.
Use these examples to grasp the concept of the approach, but do not use this exact method for generating your passwords, as a single SHA hash inside an Md5 hash isn’t the most secure. Consider implementing multiple SHA cycles, and/or throwing in an extra environment-based or external salt to really strengthen the hash.
$salt = md5(hash(“sha256”, md5(microtime()), false));
$password = md5(hash(“sha256”, “MySecurePasswordRocks4Ever!”.$salt, false));
salt = hashlib.md5(hashlib.sha256(str(round(time.time() * 1000)).encode(‘utf-8’)).hexdigest().encode(‘utf-8’)).hexdigest()
password = hashlib.md5(hashlib.sha256((str(“MySecurePasswordRocks4Ever!”)+str(salt)).encode(‘utf-8’)).hexdigest().encode(‘utf-8’)).hexdigest()
import org.apache.commons.codec.digest.DigestUtils; //Using third-party library: org.apache.commons
… class/method definition here …
String salt = DigestUtils.md5Hex(DigestUtils.sha256Hex(DigestUtils.md5Hex(Long.toString(System.currentTimeMillis()))));
String password = DigestUtils.md5Hex(DigestUtils.sha256Hex(“MySecurePasswordRocks4Ever!”+salt));
A little more on Salt Security
It is generally good practise to have a unique salt per user record. Using a unique salt makes password cracking harder – as if a hacker is lucky enough to decrypt just one user’s password using any stored salt, having a unique salt makes their task of breaking other user passwords exponentially harder.
You can store your salt as an MD5, but this gives you no security benefit. If you want to save space on your database and improve security, consider not storing the salt at all – but having it computed from fields in the user record itself.
You could generate a salt using whatever static fields are in your user record. For example; Username, Name, Email address, Record Created Date, Date of Birth, Gender… any combination of these fields could be used as the ingredients to a Salt to encrypt the password with.
If a user then changed one of these fields – you then just re-calculate the Salt and update the stored password based on the new salt value.
Please note; If you adopt this approach, you need to collect the existing password to validate the change to the user record, then you can validate using the old computed salt, then update the fields, then calculate a new salt and encrypt the submitted password using the new salt. For Admin users changing user records, you would need to force a change of password for the user (I’ll leave you to consider the design of this workflow).