If you have an old website or a web application with some user-base and you have encrypted user passwords with md5, sha1, sha256, etc. With the knowledge about md5 or that, old hashing techniques been compromised with brute force attacks, collision attacks, etc., you are searching for a way to convert your hashing technique to something more secure like bcrypt or crypt_blowfish. This article talks about how to do that.
Why it is impossible to do it in one go ? without the help of your users
If you need to change the hashing technique, you need to replace your current (old) hash with the new hash, which is generated by a new algorithm. For that, you need the user password (in plain text), which you do not have. So either you have to force users to renew their passwords or wait them to login with their password. Anyway, you need user initiation for this process.
Seamless hash regeneration at the user login
I will be using the password hashing techniques that made available through php 5. You can find more about these php functions from the php manual.
- Check if the user password is hashed with new technique or old technique (because after some time, there will be users with new hashes)
- If the user has a new hash, you can direct him to the normal login flow. If the user has an old hash, you need to generate a new hash with new algorithm.
- Store new hash in data base
PHP code example (this not an actual login function, only a example)
First, Get the user by user name
$user = getUserByUsername(username);
Need to identify whether user has a new hash or old hash, this can be identify thought the properties of the hash itself. I will use the following variable (a Boolean) to represent whether it is a new hash or old hash. Following method returns true if the given hash matches the given options.
$isNewHash = password_needs_rehash($hash, $algorithm, $options);
if (isNewHash) { // Normal login flow // Password verify doesn’t need any information about salt or algorithm // as they were added to the hash itself password_verify($password, $hash); } else { // check if the user is valid by verifying old password $hash = password_hash($password, $algorithm, $options); // Store new hash in db // To normal login flow }
With this method you will have new hashes for at least active users. However you need to take some actions about inactive users too. Because if the user doesn’t have unique password for each site, compromising this password can deal him a huge damage.