Are there any security pitfalls with using existing MD5 hashes with PHPass? - php

Before I knew better, I implemented a login system with md5 as the hashing algorithm. Now that I do know better, I'd like to move to using PHPass. My problem is that the system is already in production and asking all users to change their passwords would be the mother of all headaches.
I've come up with a simple enough solution, but given my previous mistake I'd like to make sure I'm not making an equally grievous mistake due to ignorance.
My solution is as follows:
Change
md5($_POST['pass'])
check md5 hashed password against database value
To
md5($_POST['pass'])
pass md5 hashed password to $hasher->HashPassword()
use $hasher->CheckPassword() to check the re-hashed password against value from DB
Just for clarity, I'm only re-hashing the md5 version because that's what I already have in the DB. It's not intended as an added security measure (although if it is, that's great!).

MD5() problem is WAY exaggerated on this enthusiast programmers community site. Nothing actually bad in this hashing algorithm, especially in comparison with other parts of usual newbie application. Using phpass techniques on a usual PHP site is like using a safe lock on a paper door of a straw hut.
Most important thing in keeping passwords safe against virtual possibility of being stolen and used against the same user on other sites (oh, my!) is password strength and salt. Not hashing algorithm itself. No hashing technique would protect silly pass like "1234" or "joe".
So, md5 + strong password + average salt is better than usual password + phpass
There is not a ingle reason to phpass existing md5 hash
A sensible migration algorithm is
check this user record for the new hashing flag.
if it's set -
go for phpass auth
if not:
md5($_POST['pass'])
check md5 hashed password against database value
if correct:
phpass($_POST['pass'])
save result in the database
set new hashing flag for this record
done

The problem you're talking about isn't really specific to PHPass, but hashing passwords in general. It's basically just double-hashing. This topic has been talked about already in another question: Is "double hashing" a password less secure than just hashing it once?
If you have a look there, you can see that there is still debate over whether double hashing is worse, since it reduces the range of characters passed into the second (or subsequent) hashing function. However, it slows down the hashing process, combating brute force attacks, but only doing it twice won't act as much of a speed bump.
If you didn't want to have to deal with the double hashing, what you could try doing was adding a flag field to your users database table, and set that to true for all new users who join after you setup the new PHPass form of hashing. Then, when a user log in, if they don't have the flag field set, use the old hashing system, or the modified version you have detailed in your question. If they do have the flag field, you can use whatever new hashing process you have set up.
Update: Actually, building on that, what you could try is having that flag setup, and once they go to log in under the old system, if it is a match, then you'll still have their unhashed password in your $_POST data, so you can then run that through your new hashing setup, save the new hash, then set the flag to true, since they've been upgraded to the new hashing method. From then on, they'll be using the new hashing method.

You're getting some pretty dubious advice here, so you might want to ask on IT Security. Contrary to what some folks have said, the password hashing algorithm does matter; you want to use salting and a slow hash such as bcrypt, scrypt, or PBKDF2. See: Which password hashing method should I use?, Do any security experts recommend bcrypt for password storage?, How to securely hash passwords?, Most secure password hash algorithm(s)?. PHPass is a good library.
To migrate your users over to PHPass, you'll want to have two password hash databases: the old one (with MD5 hashes), and the new one (with PHPass hashes). Initially, the new one will be empty. When a user logs in, check whether you have an entry for them in your old password hash database (with MD5 hashes), and if you don't find an entry there, look in the new password hash database (with PHPass hashes). If you find an entry in the old database, you'll want to use MD5 to hash and check their password. If it is correct, you'll want to hash their cleartext password using PHPass, insert it into the new password hash database, and remove them from the old password hash database. If you don't find an entry in the old database, you can check for an entry in the new database and check the validity of their password with PHPass. Basically, you gradually migrate each user over from old-style to new-style hash when they next log in. Does this make sense?

My method makes sure that the password is at least 8 characters long and contains non-random garbage characters ("garbage" meaning possibly unprintable/null characters):
function pass_hash ($password) {
# take first 8 characters of the raw md5 hash
$hashslice = substr(md5($password, true), 0, 8);
# add it to the password and hash again
return md5($password . $hashslice);
}
If you don't like md5, just use sha1, the principle is the same.

Related

PHP - MD5, SHA, Hashing security

I'm the developer of a new website built in PHP and I'm wondering what exactly is the best
thing to use for hashing. I've looked at md5 and sha1 but is there anything more secure.
I'm sorry if this is a nooby question but I'm new to PHP Security and I'm trying to make my
site as secure as possible. Also what is a salt?
Thanks,
Waseem
First off md5 and sha1 have been proven to be vunrable to collision attacks and can be rainbow
tabled easily (When they see if you hash is the same in their database of common passwords).
There are currently two things that are secure enough for passwords, that you can use.
The first being sha512. sha512 is a sub-version of SHA2. SHA2 has not yet been proven to be
vunrable to collision attacks and sha512 will generate a 512 bit hash. Here is an example of
how to use sha512:
<?php
hash('sha512',$password);
The other option is called bcrypt. bcrypt is famous for its secure hashes. Its
probably the most secure one out there and most customizable one too.
Before you want to start using bcrypt you need to check if your sever has it enabled, Enter
this code:
<?php
if (defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH) {
echo "CRYPT_BLOWFISH is enabled!";
}else {
echo "CRYPT_BLOWFISH is not available";
}
If it returns that it is enabled then the next step is easy, All you need to do to bcrypt a
password is (Note for more customizability you need to see this How do you use bcrypt for hashing passwords in PHP?):
crypt($password, $salt);
Now to answer your second question. A salt is usally a random string that you add at the end of
all you passwords when you hash them. Using a salt means if some one gets your database
they can not check the hashes for common passwords. Checking the database is called using a rainbow table. You should always use a salt when hashing!!
Here are my proofs for the SHA1 and MD5 collision attack vulnerabilities:
http://www.schneier.com/blog/archives/2012/10/when_will_we_se.html, http://eprint.iacr.org/2010/413.pdf, http://people.csail.mit.edu/yiqun/SHA1AttackProceedingVersion.pdf, http://conf.isi.qut.edu.au/auscert/proceedings/2006/gauravaram06collision.pdf and Understanding sha-1 collision weakness
The whole purpose of the salt is to slow down an attacker from comparing a list of pre-generated hashes against the target hash.
Instead of needing to pre-compute one "hashed" value for each plaintext password, an attacker needs to precompute 16384 "hashed" values for each plaintext password (2^7 * 2^7).
That kinda pales today but was pretty big when the crypt function was first developed - the computational power to pre-compute that many passwords times the number of plaintext password you suspect (dictionary) was pretty high.
Not so much today which is why we have things like shadow passwords, other core password functions besides crypt and every sysad wanting you to pick a password that would not show up in a dictionary.
If the hashes you want to generate are for passwords this is a well accepted method of implementing it.
http://www.openwall.com/phpass/
If you're planning to do this for passwords, then do not use MD5 or SHA1. They are known to be weak and insecure, even with salt.
If you're using them for other purposes (eg providing a hash of a file to confirm its authenticity, or a random hash database column to provide a pseudo-random sort order) then they are fine (up to a point), but not for passwords or anything else that you would consider needing to be kept secure.
The current best-practice algorithm for password hasing is BCrypt, with suitable salting.
And the best way to implement BCrypt password hashing in PHP is to use PHP's new password API. This API will be featured as a set of built-in functions in the next version of PHP, v5.5, due for release in the next few months. The good news is that they have also released a backward-compatibility version for users of current versions of PHP (5.3 and 5.4), so even though PHP 5.5 isn't released yet, you can start using the new API immediately.
You can download the compatibility library from here: https://github.com/ircmaxell/password_compat
Also: You asked what "salt" is. Since I've mentioned it a couple of times in this answer, I should address that part of the question too.
Salt is basically an additional string added to the password when hashing it, in order to make it harder to crack.
For example, an attacker may know in advance what the hashed value is for a given password string, or even a whole lot of given password strings. If he can get hold of your hashed data and you haven't used a salt, then he can just compare your hashes against his list of known passwords, and if any of your users are using an easy to guess password, they'll be cracked in seconds, regardless of what hashing method was used.
However, if you've added a secret extra string to the password when you hash it, then the hashed value won't match the standard hash for the original password, thus making it harder for the attacker to find the value.
The good news is that if you're using the API I mentioned above, then you don't need to worry too much about the details of this, as the API handles the salting for you.
Hope that helps.

Database encryption - php/mysql

I have some doubts about the best way to do a database with passwords. I need encryption in the passwords, but if i use MD5 i can't recover the pass, isn't it?
And the base64 encoder ? it is secure? with this encryption the recover isn't more a problem.
Suggestions? what is the best way? e prefer a solution that permit to remember the old pass, and not define a new one password.
Thanks!!!
If anybody know a good tutorial about secure passwords in a database i really appreciate that
if i use MD5 i can't recover the pass,
isn't it?
Indeed, if you hash your password using md5 or sha1 (adding a salt is a good idea, btw), you will not be able to recover the password ; and that's the goal of doing so !
The idea is if anyone is able to take a look at your database (be it some evil doer, or one of your employees -- who can be an evil-doer), he will not be able to find any usefull password.
what is the best way? e prefer a solution that permit to
remember the old pass, and not define
a new one password.
The best way is to do the opposite of what you want : not allow one to get his old password -- and develop some way of generating a new password.
This way, you will ensure that no-one is able to get a dump of your logins and corresponding password ; which will make your service safer for your users (especially considering that many people use the same login/password couple of several websites).
MD5 is not used for encryption (which implies that it can be decrypted) but rather for message digestion/hashing. Base64 is also not encryption but rather encoding, which can be decoded with no effort.
There is usually little point in storing encrypted passwords in a database if they can be easily decrypted.
The secure approach is to store only hashes and compare submitted passwords to stored hashes after hashing them on the fly.
You should be doing something along the lines of:
$salt = 'some2%string!!here1';
$hash = sha1( $salt . $_POST['password'] );
to create a hash of the password. You store that hash in the database. When a user wants to log in, you take his submitted function, hash it using the same process, and compare to the hash in the database. If they match, the password is correct.
First off, there's a Significant Difference Between Hashing and Encryption. I suggest that you give that a read before going on...
Now, as to your exact question, there are a few ways to go about it.
Encrypt your passwords with a strong cipher so that you can decrypt them when necessary. A solution such as the one in this post may work for that. However, please note that this isn't a great idea, since if your system is ever compromised, all the passwords will be leaked (never a good idea). There are very few use-cases where it makes sense to store them encrypted, but if you absolutely must, please use a strong cryptographic encryption routine to do it...
Store your passwords using a strong one-way hashing method. No, md5($password) is not good enough. But neither is sha1($salt . $password). The first is trivial to lookup most passwords, and the second can be brute-forced in a reasonable amount of time by simple trial and error. Instead, stretch your passwords iteratively. The best way is to use the standard PBKDF2 function to generate a strong one-way key from the password.
As far as how to recover if the user forgets a password, don't worry about it. If the user forgets his password, create a new one and give that one to the user. It's the industry standard way of dealing with forgotten passwords (Heck, both Windows and Mac do it that way). You may think that you're doing your users a favor by sending it to them, but all you're doing is turning off anyone who has a clue about security from every using your application (and making a lot of people mad if you get compromised).
base64 isn't "encryption". It's intended to convert binary data into a format that's safe for transmission through potentially "broken" email systems that can't process 8-bit binary data properly. It's a best the equivalent of a cereal box decoder ring.
If you want encryption, there's AES, DES, and various other functions available. Problem is, if your code can decrypt the password, the it's trivial for an attacker to figure out how you do it, and/or subvert your code to do it for them.
Passwords should never be stored in a format where the plaintext can be retrieved. If a user forgets their password, you wipe out the old one, generate a new temporary one, and force them to change this temporary password to something else on first login.
You should not ever need to remember the user's password - to do so is a violation of their trust and presents a security hole.
Normally you will hash the password with MD5 (these days it's better to use SHA-2), and when the user submits their password to try and log in, hash that password as well, and see if the hashes are a match.
For added security, you can create a "salt" column to the database and generate a random salt when the password is first submitted. Add the salt to the beginning of the password, and then hash it. Store the hash of the salt+password, and the salt together. Now when the user submits his password to log in, you would combine it with the salt, hash it, and check if the hash is a match.
The salt ensures that if multiple users have the same password (chances are they do), their password hashes will not be identical.
If the user forgets their password they will have to provide a new one, simply storing their password and sending it back to them when they forget is bad practice and a sign to the user that you aren't handling their privacy very well.
As mentioned, use a hash instead of encryption when saving passwords. I generally don't use a random salt since this means an extra field in the DB so that you can authenticate the user. The simplest solution is to use the password as the salt as shown below. Easy to use and easy to authenticate.
$salt = $_POST['password'];
$hash = sha1( $salt . $_POST['password'] );
Stop now and read this. Then go find an open source library to do user authentication. I'm not a PHP dev, so I can't refer you to one, but I'm sure they exist. They'll have had the security holes found already.
Also, for passwords, you should be looking at bcrypt or similarly slow hash functions for passwords anyways, instead of using a fast hash algorithm like MD5 or SHA.

What is md5() for?

I was reading this tutorial for a simple PHP login system.
In the end it recommends that you should encrypt your password using md5().
Though I know this is a beginners' tutorial, and you shouldn't put bank statements behind this login system, this got me thinking about encryption.
So I went ahead and went to (one of the most useful questions this site has for newbies): What should a developer know before building a public web site?
There it says (under security) you should:
Encrypt Hash and salt passwords rather
than storing them plain-text.
It doesn't say much more about it, no references.
So I went ahead and tried it myself:
$pass = "Trufa";
$enc = md5($pass);
echo $enc; #will echo 06cb51ce0a9893ec1d2dce07ba5ba710
And this is what got me thinking, that although I know md5() might not the strongest way to encrypt, anything that always produces the same result can be reverse engineered.
So what is the sense of encrypting something with md5() or any other method?
If a hacker gets to a password encrypted with md5(), he would just use this page!.
So now the actual questions:
How does password encryption work?
I know I have not discovered a huge web vulnerability here! :) I just want to understand the logic behind password encryption.
I'm sure I'm understanding something wrong, and would appreciate if you could help me set my though and other's (I hope) straight.
How would you have to apply password encryption so that it is actually useful?
What about this idea?
As I said, I may/am getting the whole idea wrong, but, would this method add any security in security to a real environment?
$reenc = array(
"h38an",
"n28nu",
"fw08d"
);
$pass = "Trufa";
$enc = chunk_split(md5($pass),5,$reenc[mt_rand(0,count($reenc)-1)]);
echo $enc;
As you see, I randomly added arbitrary strings ($reenc = array()) to my md5() password "making it unique". This of course is just a silly example.
I may be wrong but unless you "seed the encryption yourself" it will always be easily reversible.
The above would be my idea of "password protecting" and encrypted password, If a hacker gets to it he wont be able to decrypt it unless he gets access to the raw .php
I know this might not even make sense, but I can't figure out why this is a bad idea!
I hope I've made myself clear enough, but this is a very long question so, please ask for any clarification needed!
Thanks in advance!!
You should have an encryption like md5 or sha512. You should also have two different salts, a static salt (written by you) and then also a unique salt for that specific password.
Some sample code (e.g. registration.php):
$unique_salt = hash('md5', microtime());
$password = hash('md5', $_POST['password'].'raNdoMStAticSaltHere'.$unique_salt);
Now you have a static salt, which is valid for all your passwords, that is stored in the .php file. Then, at registration execution, you generate a unique hash for that specific password.
This all ends up with: two passwords that are spelled exactly the same, will have two different hashes. The unique hash is stored in the database along with the current id. If someone grab the database, they will have every single unique salt for every specific password. But what they don't have is your static salt, which make things a lot harder for every "hacker" out there.
This is how you check the validity of your password on login.php for example:
$user = //random username;
$querysalt = mysql_query("SELECT salt FROM password WHERE username='$user'");
while($salt = mysql_fetch_array($querysalt)) {
$password = hash('md5',
$_POST['userpassword'].'raNdoMStAticSaltHere'.$salt[salt]);
}
This is what I've used in the past. It's very powerful and secure. Myself prefer the sha512 encryption. It's actually just to put that inside the hash function instead of md5 in my example.
If you wanna be even more secure, you can store the unique salt in a completely different database.
Firstly, "hashing" (using a cryptographic one way function) is not "encrypting". In encryption, you can reverse the process (decryption). In hashing, there is (theoretically) no feasible way of reversing the process.
A hash is some function f such that v cannot be determined from f(v) easily.
The point of using hashing for authentication is that you (or someone seeing the hash value) do not have any feasible way (again, theoretically) of knowing the password. However, you can still verify that the user knows his password. (Basically, the user proves that he knows v such that f(v) is the stored hash).
The weakness of simply hashing (aside from weak hash functions) is that people can compile tables of passwords and their corresponding hash and use them to (effectively) get the inverse of the hash function. Salting prevents this because then a part of the input value to the hash is controlled and so tables have to be compiled for that particular salt.
So practically, you store a salt and a hash value, and authenticate by hashing a combination of the salt and the password and comparing that with your hash value.
MD5 is a one way hashing function which will guard your original password more or less safely.
So, let's say your password is "Trufa", and its hashed version is 06cb51ce0a9893ec1d2dce07ba5ba710.
For example, when you sign in to a new webpage, they ask you for your username and password. When you write "Trufa" as your password, the value 06cb51ce0a9893ec1d2dce07ba5ba710 is stored in the database because it is hashed.
The next time you log in, and you write "Trufa", the hashed value will be compared to the one in the database. If they are the same, you are authenticated! Providing you entered the right username, of course.
If your password wasn't stored in its hashed form in database, some malicious person might run a query somehow on that database and see all real passwords. And that would be compromising.
Also, since MD5 is a 128 bit cryptographic function, there are 2^128-1 = 340282366920938463463374607431768211455 possible combinations.
Since there are more possible strings than this, it is possible that 2 strings will generate the same hash value. This is called a collision. And it makes sure that a hashed password cannot be uniquely reverse engineered.
The only vulnerability with salting is that you need to know what the salt is in order to reconstruct the hash for testing the password. This is gotten around by storing the entry in the authdb in the form <algorithm>$<salt>$<hash>. This way the authdb entry can be used by any code that has access to it.
You're missing the important step - the salt. This is a unique (per user, ideally) bit of extra data that you add to the password before hashing it.
http://en.wikipedia.org/wiki/Salt_%28cryptography%29
Your idea (salting) is well known and is actually well-implemented in the PHP language. If you use the crypt() function it allows you to specify a string to hash, a method to encrypt (in some cases), and a salt. For example,
$x = crypt('insecure_password', $salt);
Returns a hashed and salted password ready for storage. Passwords get cracked the same way that we check if they're right: we check the hash of what the user inputs against the hash of their password in the database. If they match, they're authenticated (AFAIK this is the most common way to do this, if not the only). Insecure passwords (like password) that use dictionary words can be cracked by comparing their hash to hashes of common passwords. Secure passwords cannot be cracked this way, but can still be cracked. Adding a salt to the password makes it much more difficult to crack: since the hacker most likely doesn't know what the salt is, his dictionary attack won't work.
For a decent hash the attacker won't be reversing the hash, they'll be using a rainbow table, which is essentially a brute-force method made useful if everyone uses the same hash function.
The idea of a rainbow table is that since hashing is fast I can hash every possible value you could use as a password, store the result, and have a map of which hash connects to which password. If everyone just takes their passwords and hashes them with MD5 then my hash table is good for any set of password hashes I can get my hands on!
This is where salting comes in. If I take the password the user enters and add some data which is different for every user, then that list of pre-determined hashes is useless since the hash is of both the password and some random data. The data for the salt could be stored right beside the password and even if I get both it doesn't help me get the password back since I still have to essentially brute force the hash separately for every single user - I can't form a single rainbow table to attack all the hashes at once.
Of course, ideally an attacker won't get the list of hashed passwords in the first place, but some employees will have access so it's not possible to secure the password database entirely.
In addition to providing salt (or seed), the md5 is a complex hashing algorithm which uses mathematical rules to produce a result that is specifically not reversable because of the mathematical changes and dataloss in throughput.
http://en.wikipedia.org/wiki/Cryptographic_hash_function
md5 (or better put: hash algorithms in general) are used to safely store passwords in database. The most important thing to know about hashes is: Hashes are not encryptions per se. (they are one-way-encryptions at most). If you encrypt something, you can get the data back with the key you used. A hash generates a fixed-length value from an arbitrary input (like a string), which can be used to see if the same input was used.
Hashes are used to store sensitive, repeatly entered data in a storage device. Doing this, nobody can recreate the original input from the hash data, but you can hash an incoming password and compare it to the value in the database, and see if both are the same, if so, the password was correct.
You already pointed out, that there possibilites to break the algorithm, either by using a database of value/hash pairs or producing collisions (different values resulting in the hash value). You can obscure this a bit by using a salt, thus modifying the algorithm. But if the salt is known, it can be used to break the algorithm again.
I like this question. But I think you've really answered yourself.
The site you referenced uses dictionary lookups of known, unsalted, md5's - it doesn't "crack" anything.
Your example is almost good, except your application needs to be able to regenerate the md5 using the same salt every time.
Your example appears to use one of the random salts, which will fail 2 of 3 times if you try to compare a users password hash to something input.
People will tell you to also use SHA1 or SHA256 to be have a 'stronger' hash - but people will also argue that they're all 'broken.'
That documentation is misleading -- it teaches a "vulnerable" concept and presents it as somehow being "secure" because it (the saved password) looks like gibberish. Just internet junk that won't die. The following link should clear things up (you have already found a good bit of it though, it seems. Good work.)
Enough With The Rainbow Tables: What You Need To Know About Secure Password Schemes talks about MD5 (and why it should not be used) along with salt (e.g. how to thwart rainbow attacks) as well as provides useful insights (such as "Use someone else’s password system. Don’t build your own"). It is a fairly good overview.
This is my question about the aspects of md5 collision, slightly related to your question:
Is there any difference between md5 and sha1 in this situation?
The important part is in the first 3 rows, that is: you must put your salt before the password, if you want to achieve stronger protection, not after.
To simply answer the title of your question, md5's only real use nowadays is for hashing large strings (such as files) to produce checksums. These are typically used to see if both strings are identical (in terms of files, checksums are frequently used for security purposes to ensure a file being distributed hasn't been tampered with, for example).
To address each of your inline questions:
How does password encryption work?
How would you have to apply password encryption so that it is actually useful?
Secure password hashing works by taking the password in plain text form, and then applying a costly hashing function to it, salted with a cryptographically secure random salt to it. See the Secure hash and salt for PHP passwords question for more detail on this.
What about this idea?
Password hashing does not need to be complicated like that, and nor should it be. Avoid thinking up your own algorithms and stick with the tried and tested hashing algorithms already out there. As the question linked above mentions, md5() for password hashing has been obsolete for many years now, and so it should be avoided.
Your method of generating a "random" salt from an array of three different salts is not the randomness you're looking for. You need unique randomness that is suitable for cryptographically secure (i.e. using a cryptically secure pseudo-random number generator (CSPRNG)). If you're using PHP 7 and above, then the random_bytes function can be used to generate a cryptographically secure salt (for PHP 5 users, the random_compat library can be used).

Pitfalls of encrypting (with salt) of a md5-hashed-password (php)

A client has a huge userbase and I'm required to encrypt/hash passwords in a secure manner. The problem is I can't ask every user to change their password and the passwords are already hashed with md5() without a salt. One way of doing this is to encrypt the current passwords with a salt and when a user changes or resets the password i just encrypt it with the salt.
Are there any pitfalls or more or less obvious dangers of doing so [ i mean sha1(md5(password) with salt) ]?
Thank you for your time
Add a new field to the user table for storing the new securely hashed passwords - for this, please do something safe involving per-user salt and multiple rounds. Check what other people are doing (ie., bcrypt) instead of rolling your own.
When doing a password check, if the newPass field is null, use the old password lookup, but urge users to do a password reset once authenticated.
Modifying the current (old) password scheme to be hash(perUserSalt + existingPassWordHash) should work fine.
if you plan to use sha1(md5(password).$salt) it's all right.
You can use this system even further. No need to take any special action when user changes a password. Just encrypt it the same way: sha1(md5(new password).$salt)
It depends on what attack you are attempting to defend against. If the attack is someone viewing the database, then you could use a symmetric encryption method (like AES) with a key defined outside the database. Using this method requires the authentication procedure know the encryption key and you update all the rows in the database by encrypting the hashed password with the encryption key.
If the above is not an option, you have a problem. ;) The problem is that right now you don't know what any user's password actually is. All you have is the hashed version. Your routine for verifying a login is to take the input supplied by the user, hash it, and compare the computed hash with the stored hash.
Your option would be to store the old hash and create a new field to store the new algorithm. Then as people log into the system, perform the upgraded salted-hash and delete the old hash. This will work as you expect, but if a person never logs back in (or changes their password) they will never upgrade to the salted version of the hash.
My personal opinion is to use the AES encrypted option since that prevents the casual viewing of hashed passwords and it covers all the passwords in the database.

Going from unsalted to salted MD5 passwords

I have a LAMP (PHP) website which is becoming popular.
I played it safe by storing the user passwords as md5 hashes.
But I now see that's not secure; I should have salted the md5 hash - because it's currently possible to decode unsalted md5 hashes using rainbow tables.
What can I do?
I don't want to make everyone type a new password.
You can do a "2 step hashing" instead of creating a hash in a single step.
You could append each password hash to the username, and then hash it again. This will create an undecryptable hash thats salted with unique informations.
The usual process of salting is
salt+PWD -> hash
You could do something like:
PWD -> Hash -> UserID+Hash -> Hash
(Note the UserID was only picked so a unique salt for each double hash exists... Feel free to make your salt more complex)
You can salt them on the fly. Add a piece of code so that, when someone logs in, it does the normal process (computes the MD5 sum of the password and checks it against the stored hash) and if that succeeds, recompute a salted version of the hash from the clear-text password they entered, and store it in the password file.
The only wrinkle is that you'll need to add an indicator for whether each MD5 is salted or not, since you'll have a mix of both for a while. Or, for a minor loss of security, you can check each password salted and unsalted and if either one hits, accept the login. Of course, if you detect that it was unsalted, then you upgrade at that point.
The answer is simple, make sure the keep a record or some sort of flag of which users have passwords on the new system of hashing, when they next login, authenticate them, calculate the new hash, flip the flag.
Now whenever someone logs in and the flag is set, authenticate them with the new hash.
Why not add a new column new_pwd to your user table, which stores the result of md5($originallyHashOfPwd . $salt). You can then precompute new_pwd and once that's done adjust your login checking to compare the result of md5(md5($entered_pwd) . $salt) to what's in new_pwd. Once you're done switching your login checking, delete the old column.
That should stop rainbow-table style attacks.
You can still use a salt. Just calculate another hash from the current hash together with a salt:
$newHash = md5($salt.$oldHash);
For new passwords you then need to use:
$hash = md5($salt.md5($password));
A great way to update the passwords while also making them more secure is to change to using a salted SHA1 for passwords. A SHA1 is harder to create a collision against, and it also has a different string length to MD5. A MD5 is 32 characters long, while a SHA1 is 40 characters long.
To convert these in PHP, you first check the string length of the stored password. If it is 32 characters long, check the password using your old method and afterwards, write a new one using SHA1 to the database.
If I remember correctly, this is precisely how WordPress handled this issue.
Dynamically re-encrypt the passwords when the users log in the next time, i.e. first check whether it’s correct, afterwards encrypt it with a salt and store it again.
You can migrate the passwords by adding a column in your tables to store the new format.
When a user logs in successfully, if the new column is empty, put the stronger password in there and empty out the original column. If the new column has an entry, compare the input to the value in there.
Two options here
Decode the passwords yourself, and re-encode them with a salt (I recommend something a little more fancy than MD5). You should inform the users that you're viewing their passwords unencrypted. It'll probably take a lot of time as well.
Make them retype their passwords, and store those salted and encrypted.
As far as I can see, there is no other way of recovering the passwords.
EDIT:
Although MD5 is a hash and should not be decodable, it can be broken using rainbow tables: with probability almost one, you can find a unique (here's the probability) string of at most, say, 20 characters with a given hash, especially if your character set is limited, say, to alphanumeric. Strictly speaking, this is not decoding. For all practical purposes, it is.
Extra note: producing the rainbow tables, and looking up 1000 password is still going to take a lot of time.
Salt the original hash as mentioned by others. Just a few pointers here:
Salts are better the longer they are. Also if they contain more then just [a-z0-9] but length is better first of all.
If someone already has a copy of your DB and you rehash the same passwords with salt, the rehash the old hash with salt will not work. Instead you really should force users to make a new password.
You should match new passwords (and passwords to be salted) up against various lists of the most commonly used passwords. These are used in "brute force" attacks. Prompt/force the user to change the password.
If you're moving away from MD5, you should go skip simply salting and go to an even better technique called stretching. In particular you should use bcrypt (implemented as PHPASS with php).
Here is a great link on why bcrypt: http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html
And here is a short How To:
1. Download the phpass package: http://www.openwall.com/phpass/
2. Look at test.php for examples like the one below:
require 'PasswordHash.php';
$t_hasher = new PasswordHash(8, FALSE);
$correct = 'plaintextpassword';
$hash = $t_hasher->HashPassword($correct);
$check = $t_hasher->CheckPassword($correct, $hash);
If $check===true (which is the case above) then the password is correct.
If your password is 'hello', you would hash it using HashPassword, put the hash in a database, and when a user logs in, call CheckPassword(userenteredpassword,hashInDb) to see if the password is correct
sadly, your only way is to tell your users to renew their passwords.
you could also generate random passwords, but that is the same hassle.
edit
you could just double encode your stored passwords. so your new salted hashing algorithm would be:
md5(md5($new_password).$salt).':'.$salt
to update your old passwords use
md5($old_password.$salt).':'.$salt
to check if a provided password is correct simply use
list($stored_password, $salt) = explode(':', $salted_password);
if(md5(md5($provided_password).$salt) == $stored_password) {
// you are now logged in
}

Categories