Is the following a good way to salt passwords?
hash('sha256', $_POST['password'], $_POST['email'])
I am using the user email as a salt. Some people do not use emails, some others say to use a random number.
Even if I use a random number then I will still need to store it on my MySQL table, so the salt will still be known anyway, and with the added benefit of using emails is that the possibility of rainbow tables is greatly decreased, even if I was to use a 16-bit integer?
The idea behind a salt is to prevent a hacker from using a rainbow table. For instance, if the hacker is able to compromise your database and figure out what the hashed password is he can't easily reverse engineer the hash to find a value that would generate the same hash.
However, there exist tables of already hashed words called rainbow tables. Some people have already gone through the trouble of calculating the hash of every word in the dictionary and other common passwords. If the hacker has one of these tables, plus the hashed password from your database, it makes it very easy to figure out what the password is.
However, a salt changes all that because now, instead of hashing the password, you are hashing the password plus some random value which means that the rainbow table is now useless. It does not matter if the hacker can compromise the salt.
It is perfectly fine to save the salt in clear text. You want to use something that is not uniform across all users either because, again, that defeats the purpose. I personally like to use the timestamp the account was created.
Does that make sense?
What happens if a user changes his email address? You won't be able to verify his/her password anymore because the salt value will be gone.
You shouldn't use anything as a salt that is likely to change over time. Generate a random salt (long enough to defeat rainbow tables) and use it together with the password to generate the hash.
Right now the best possible solution to use in PHP for password hashing is to use the bcrypt (blowfish) implementation. Why? There are several reasons:
variable 'work' parameter
built-in salt
Keep in mind that if you are not running php 5.3, then crypt_blowfish may not be available on your system.
Work Parameter
Blowfish/crypt is already has an expensive setup time but by setting the work factor you can increase the amount of time it takes to calculate a hash. In addition, you could easily change that work factor in the future as computers get faster and are able to compute hashes more easily. This makes the particular hashing method scale.
Built-in Salt
For me this is just laziness but I like that the salt & pass are stored together.
Implementation
To use blowfish you'd create a hash as follows
// salts must be 22 characters
$salt = "ejv8f0w34903mfsklviwos";
// work factor: 04-31 (string), each increase doubles the processing time.
// 12 takes my current home computer about .3 sec to hash a short string
$work = '12';
// $2a$ tells php to use blowfish
// you end up with a string like '$2a$12$mysalthere22charslong'
$options = '$2a$' . $work . '$' . $salt;
$hashedPass = crypt($plaintext, $options);
To verify a hashed password is simplicity:
if(crypt($user_input, $stored_password) == $stored_password) { echo "valid!"; }
Now, if at any given time you want to increase the work factor you could take the submitted pass after a successfull login, and rehash and save it. Because the work factor is saved along with the salt & password, the change is transparent to the rest of the system.
Edit
There seems to be some confusion in the comments about blowfish being a two way encryption cypher. It is not implemented as such in crypt. bcrypt is an adaptive password hashing algorithm which uses the Blowfish keying schedule, not a symmetric encryption algorithm.
you can read all about it here: http://www.usenix.org/events/usenix99/provos.html
or you can read even more about using bcrypt (the hashing implementation of blowfish) here: http://codahale.com/how-to-safely-store-a-password/
i suggest using iteration such as below. The crypt could be replaced with md5 or any other hashing algorithm. the 10 could be any number.
$pass=mysql_real_escape_string($_POST['pass']);
$iterations = 10;
$hash = crypt($pass,$salt);
for ($i = 0; $i < $iterations; ++$i)
{
$password = crypt($hash . $pass,$salt);
}
In addition, you could add any other variable. I hope this solve the problem
You could use this:
$salt='whatever';
$a=hash('sha256', $_POST['password'], $salt);
$b=hash('sha256', $_POST['email'], $salt);
$hash=$a.'-'.$b;
When the user changes the email, just do:
$old_a=substr($old_hash,0,strpos($old_hash,'-'));
$new_b=hash('sha256', $_POST['email'], $salt);
$new_hash=$old_a.'-'.$new_b;
Related
Since the PHP sha1() can be broken quite easily by comparing against a long list of hashes - would this be any better (basically - applying sha1() over and over again to try and make brute forcing impractical by slowing the hashing process down):
<?php
$iterations = 100000;
$pass = 'hyugf67rf76dt564d5r76';
$salt = '6t6755636459679guytfugiuhbguiygfytcdtresr5tdt5yfuybiugbuyfr56d45esertdcftyuuguy';
$hash = '';
for ($i=0; $i<$iterations;$i++) {
$hash = sha1($hash . $pass . $salt);
}
echo $salt . $hash;
?>
Instead of applying the sha1 over again and again , why not implement crypt() once with a stronger - salt ?
If you have PHP 5.5 +, you could simply go for password_hash()
A userland implementation of password_hash() is also available here
HINT : You could combine the examples #4 and #3 of the password_hash()documentation link above to creater a stronger hash.
or use phpass
The preferred (most secure) hashing method supported by phpass is the
OpenBSD-style Blowfish-based bcrypt, also supported with our public
domain crypt_blowfish package (for C applications), and known in PHP
as CRYPT_BLOWFISH, with a fallback to BSDI-style extended DES-based
hashes, known in PHP as CRYPT_EXT_DES, and a last resort fallback to
MD5-based salted and variable iteration count password hashes
implemented in phpass itself (also referred to as portable hashes).
A better way to approach the problem, is by using a hashing algorithm that has this cost-intensity built-in, instead of using a custom function. If the resulting hash is not truly random, this could be a security problem.
That doesn't answer your question though, so I'll try to do that now.
Cost-intensity
If applied correctly, algorithms that are more cost-intensive make it more cost-intensive for an attacker to crack all passwords from a database. If applied incorrectly though, most of this cost-intensity can be bypassed. This is why I recommend using an algorithm that is designed to be cost-intensive, rather than trying to create something yourself.
Salts
A database-wide salt only protects you from rainbow tables without a salt. When an attacker obtains your database with passwords, and knows the salt, they can make their own rainbow table with your salt, and crack every password in the database with this rainbow table. Users with the same password have the same hash in the database.
A per-account salt (a salt that is different for each account), an attacker has to crack each password individually. Users with the same password have a different hash in the database. Cracking passwords is much more costly now.
Iteration
What you should be wary of when reapplying, is that the attacker should not be able to create a lookup table for part of this iteration. In other words: The iteration should contain something that is different for every user, and even better, different for every password tried for an user. Since you re-use the password in the algorithm, this should be no problem.*
A little change to the algorithm could however allow an attacker to bypass most of the iteration. In the following code, the attacker could create a lookup table that translates a hash to a hash with sha1 applied 99.999. In fact, such a table can be created by applying it just once on every hash, then using that lookup table multiple times. Instead of needing to apply sha1 100.000 times for every password, this now has been reduced to creating a lookup table, applying sha1 exactly once for every password, and looking up a hash in a lookup table once for every password. Even with a per-user salt, this would make no difference to the lookup table.
If you would use a per-user salt and change the line with //here to sha1($hash . $salt), the attacker has to create such a table for every unique salt in the database. This is slightly more work, but still much less than the work an attacker has to do when he has to calculate every hash for every password they try out.
<?php
#Bad code below
$iterations = 100000;
$pass = 'hyugf67rf76dt564d5r76';
$salt = '6t6755636459679guytfugiuhbguiygfytcdtresr5tdt5yfuybiugbuyfr56d45esertdcftyuuguy';
$hash = sha1($hash . $pass . $salt);
for ($i=0; $i<$iterations;$i++) {
$hash = sha1($hash); //Here
}
echo $salt . $hash;
?>
* I am by no means a security expert. I am a student with some knowledge about algorithms, and some knowledge about security, but the fact I don't see a problem doesn't mean there isn't a problem.
I know that there are alots of questions about this subject but i really need to ask this.
Today I've been working on encrypting passwords with md5.
So what I've done is.
I got 4 salts. (they changes depending on user values)
from email id and substr then md5 them
from email and id substr other positions
a long string, substr it and then md5 it
another long string, substr it and then md5 it
Then i md5 salt1 and 3 and the password with salt 2 and salt4
After this I have to change the password automatically whenever a user changes his email or his id getting changed.
What do you guys think about this?
Nothing.
MD5 is broken and bad.
Using the mailaddress as salt is a good idea. But using md5 is not. Use instead bcrypt, scrypt or pbkdf2.
Don't invent your own ecryption, unless you really know what you are doing, and trust me, you don't
First, let us define a few terms.
Encryption is when you encode a message so that it cannot be read. Encryption involves a plaintext, a cipher and a key. It is like putting a book (the plaintext) in a locked room (cipher), which can only be opened using a known tool (a key). There are many kinds of encryption, but that is a simple description. Encryption is two-way, meaning that you can encode and decode the message.
Cryptographic hash is when you take any kind of data and generate a fixed size value for it (usually called a hash or a digest). Cryptographic hashes are one-way, which means that you cannot reverse the process.
A salt is a unique string, or a collection of bits, similar to a nonce (a unique number that is only used once). Salts are only used to make it infeasible for a cracker to process a list of hashes. They are not supposed to be used as a secret (i.e. like a cryptographic key). The only reason people usually talk about randomness when it comes to salts is because they want to generate a unique salt (if the randomness is not great enough they may get colliding salts, for instance).
Okay, now to how you should hash a password.
A relatively safe way of hashing a password is to simply tack on a unique hash onto a password, and then save the salt with the password:
$pass = 'this is my password';
$salt = uniqid('', true);
$hash = sha1($pass . $salt);
// INSERT INTO users ('hash', 'salt') VALUES ('$hash', '$salt') WHERE ...
That is an okay way of doing it if your website does not retrieve any sensitive data from its users.
If you deal with sensitive data, or if you just want to make sure that you are doing everything you can to keep stuff safe, then there is a PHP function that does the hashing for you. It is called crypt() (read the documentation to learn how it works). Here is an example of how to hash a password using the function:
$pass = 'this is my password';
$salt = 'unique string';
$hash = crypt($password, '$2y$07$'.$salt.'$');
echo $hash;
That will securely hash a password.
The thing to realize is that the crypt() function is much more secure than anything you can come up with (unless you are a specialist in the area).
In newer versions of PHP (5.5.0+) there is a password hashing API that makes it even simpler to hash a password.
There are also various hashing libraries out there. PHPass is a popular one.
It is bad, because it uses MD5.
MD5 is a very fast operation. It can be executed billion of times per second on graphic cards hardware. It is considered bad practice to use it for any password related things.
Use bcrypt. Use a random salt. Use the upcoming PHP API for hashing, verifying and rehashing passwords. This include file implements it for versions starting with PHP 5.3.7: https://github.com/ircmaxell/password_compat
Well, "MD5 is broken and bad" is a little exagerated. Even if it can be brute-forced with a lot of CPU, it is not "broken" and is still a very useful algorithm for a lot of things involving hashing.
So "MD5 should not be used for password encryption" sounds much better to me.
When using PHP, an easy and safe option is to rely on the password_hash() (which natively generates a random salt) and password_verify() functions.
The advantage is that the encryption algorithm will transparently be updated with each new PHP version (at the moment PASSWORD_DEFAULT is set to bcrypt, but should bcrypt be "broken" it can be set to a newer algorithm), which makes any code using those functions quite resilient.
I personally do not recommend involving of the user id and his email into the hashing of his password.
You can deal with the password by:
Dynamic salt per user based on random string generated on user registration
Prepend one part of the salt and append the other around the password
Double md5: md5(md5($password))
Etc.
a simple way would be to generate a random salt for each user and hash your password like this
public function encodePassword( $raw, $salt ) {
return hash('sha256', $salt.$raw);
}
For high security hash, you can check this link which explain how to implement PBKDF2:
http://crackstation.net/hashing-security.htm#phpsourcecode
Let's say I have thousands of users and I want to make the passwords very secure. Now, I've learned that md5() is not the safest to use, however what I think can be done to be safe is salt it (I know this is nothing new). So for this I was thinking of creating two tables, one called accounts which will have all information associated with accounts and a table column called salt and the second table would be called something like auth and have the fields account_id, password
to start, I create a salt upon registration (generated randomly)
$salt = "#52/sBsO8";
then all the provided information goes to accounts salt being one of them
then after successfully putting the information in database, I create the password that is going to be stored in auth table, this way the password is not the md5 of the password the user enters, rather its the md5 of the salt and the password user enters
so the password in auth is
$password = md5($user_entered_password . $salt);
Test strings:
PHP Code
$password = "123";
$salt = "#52/sBsO8";
echo md5($password) ." / ";
echo md5($password . $salt);
output: 202cb962ac59075b964b07152d234b70 / dfbf0b257c5182af0ae893c2680f4594
The question is: Is this a pretty safe way of dealing with passwords? Because of md5() decrypting websites, there are so many ways to guess the passwords. And the decrypting websites don't actually decrypt the md5() they just have the md5 hashes of millions of strings.
md5 is likely to be the least safe among "popular" hashing algorithms.
Since you're using PHP, a better option would be crypt: http://php.net/manual/en/function.crypt.php
crypt($password, $salt)
For a good comparison of various hashing methods, see Jeff Atwood's post about password hashing
Excerpt about brute forcing benchmarks:
MD5 23070.7 M/s
SHA-1 7973.8 M/s
SHA-256 3110.2 M/s
SHA-512 267.1 M/s
NTLM 44035.3 M/s
DES 185.1 M/s
WPA/WPA2 348.0 k/s
the lower, the better, although DES is too short to be considered nowadays (56bit, thanks #thebod).
EDIT:
Although it isn't listed in the benchmarked methods above, the best hashing method that crypt supports is blowfish, here's an example to use it:
// $salt has to be built with exactly these components:
// '$2a$' . $2DigitsNumberAroundTen . '$' . $TwentyTwoLetters
$salt = '$2a$07$somesillystringforsalt';
crypt( $password, $salt );
Hash functions for passwords should be slow (need some computing time). Most hash algorithms are designed to be fast, but this makes it easier to create rainbow tables for every salt.
The salt should be random, and should be generated separately for every stored password. This salt has to be stored together with the hash, but is not secret (can be plain text). The salt makes dictionary attacks more difficult, and different salts make rainbow tables impracticable.
Ideally, you can adjust the computing time later for new hardware, without breaking existing hashes.
That's why you should use bcrypt to hash your passwords, it was designed especially for hashing password. And don't be afraid to use bcrypt! It is not for high security sites only, and using it can be as easy, as using an md5 hash.
It's recommended to use a well established library like phpass, and if you want to understand how PHP can generate such hashes, you can read this article.
Why do you think that this is more secure? The user types in a password. One assumes that the user is not an idiot and choses something that (s)he only knows. How is that different if that individual typed it in with the salt?
This actually makes it more insecure because if a person gets hold of the table that person has something to work on.
You are better off spending your engergies on ensuring that the computer is secure, your network is secure and teaching your users on sensible and secure passwords.
I want to use SHA512 to store passwords. To do that, which of openssl_digest, hash and hash_hmac should I use and why?
What is the difference between SALT & HMAC?
I just read that HMAC is built on top of hash function.
So is SHA512+SALT+HMAC really necessary or SHA512+SALT or SHA512+HMAC?
So, first off, let's clear one thing up. openssl_digest() === hash(). It's just another function by a different name that does the exact same thing. It computes a cryptographic hash of the input.
So, now we have the question: When storing passwords, which is better: hash or hash_hmac?
Short Answer:
Neither
Long Answer:
As it turns out, The Rainbow Table Is Dead. Just using hash($password . $salt) or even hash_hmac($password, $salt) is not good enough for password storage. Period. If you're doing so, stop right now.
The reason is simple: computation time on a computer (or GPU) is incredibly cheap. It's so cheap, that to brute force a list of passwords is cheap enough that you need to worry about it. Remember, hash functions are designed to be fast. Not expensive...
But, as it also turns out, there is a way to make those fast hash functions more expensive. In fact, it's pretty simple: iterate.
Now, I know what you're thinking. You're going to just loop over the hash:
function hash_password($password, $salt) {
$hash = hash("sha512", $password . $salt);
for ($i = 0; $i < 1000; $i++) {
$hash = hash("sha512", $hash);
}
}
Surely that's good enough, right? Nope. As explained in Fundamental Difference Between Hashing and Encryption, that's not a good idea. So why not just feed back the password and salt in again?
function hash_password($password, $salt) {
$hash = hash("md5", $salt . $password);
for ($i = 0; $i < 1000; $i++) {
$hash = hash("md5", $hash . $password);
}
}
In fact, this is exactly what PHPASS uses (slightly tweaked, but this is the base algorithm)...
So now 1 call to hash_password executes 1000 hash cycles.
But can we improve on that?
Well, as it turns out, we can. The next logical thing to do would be to see if we can get more hash cycles for the same amount of time. And this is where hash_hmac() comes in. As it turns out, HMAC uses 2 hash cycles each time it's called. And because it's all C, it only takes about 1.5 times the amount of time that hash() takes to do a single round.
So that means if we replace hash with hash_hmac, we can instantly see a 33% increase in the amount of work being done in a specified time. So now we're here:
function hash_password($password, $salt) {
$hash = hash_hmac("md5", $salt, $password);
for ($i = 0; $i < 1000; $i++) {
$hash = hash_hmac("md5", $hash, $password);
}
}
And this is actually the basic inner-loop of PBKDF2.
But can we get better?
Yes, again, we can get better. If we look closely, we can see that -in addition to password and salt- all of the above algorithms use a very small amount of memory. In the case of sha512, they'll use on the order of 128 to 256 bytes (buffers and state) to hash the password. Since the memory use is so small, it's trivial to run a lot of them at once side-by-side in a GPU. If we could only increase the memory usage...
Well, as it turns out, we can simply use bcrypt, which is an adaptive hashing algorithm. It has an advantage that it uses more memory than the above algorithms (on the order of 4 to 5kb). So it's more resistent to parallelizing. And it's resistent to brute forcing since it's computationally expensive.
Luckily, it's available for PHP:
crypt($password, '$2y$07$usesomesillystringforsalt$')
Note that crypt() uses many algorithms, but the $2y$ and $2a$ algorithms are bcrypt.
But can we improve on this?
Kind-of. There is a relatively new algorithm called scrypt. It's better than bcrypt, because it's just as computationally expensive, but uses a LOT more memory (on the order of 20mb to 40mb to hash a single password). Therefore, it's even more resistent to parallelization...
Unfortunately, scrypt is not available in PHP yet (I'm working on changing that). Until then, use bcrypt...
Sidenote
After the recent lessons from LinkedIn, LastFM, Hotmail, Gawker, etc, the proof is apparent that a lot of people are doing it wrong. Don't do it wrong, use a library with a vetted algorithm. Use CRYPT_BLOWFISH (bcrypt), use PHPASS, use PasswordLib. But don't invent your own just because you don't want to pull a dependency... That's just negligence.
More reading:
Properly Salting Passwords - The Case Against Pepper
GPU Accelerated PBKDF2
Many Hash Iterations, Append Salt Every Time?
MD5 Decoding, How Do They Do It
HMAC is a specific way to use a hash algorithm (like SHA512). It's used to sign a message and you can then verify that the message is from a specific signer and has not been altered. So this isn't what you want.
A salt is used to add a bit of "randomness" to a text that should be encrypted or hashed. The point is that even if you encrypt the same text several times you'd get different results. This makes it harder to do some attacks. This is what you want: SHA512(salt+password).
For storing passwords, the most secure way I could imagine would be:
(disclaimer: I'm not very experienced with cryptography and there might be a better solution)
Client (JavaScript code?) would generate a salt value.
The client then combines salt and password, and run the result through your hashing algorithm.
The client then transmits both salt and hash value to the server which stores it (preferably in different locations).
To verify a password, you'd then do:
Pass the salt to the client.
Client combines salt and entered password, runs it through your hashing algorithm.
Client sends the hash value to the server.
Server compares the hash value with the stored hash value. If they match, it was the same password.
Of course you could transmit the password in plaintext and do the whole salting and hashing on the server, but this would weaken your solution dramatically. You should never transmit the password in plaintext.
But the "pass the salt to the client" part might be a problem. One way that I could imagine to solve this would be to somehow derive the salt from the username (easiest way: simply do lowercase(username) + password), but the problem with that would be that the salt would be predictable and thus weakening your solution a little bit. Yet, it's still way better than transmitting the "raw" hash and you wouldn't even need to store the salt as you could derive it from the username every time. Should your password DB get stolen it would still resist a rainbow table attack with this "salting with username" approach.
The problem is that a man-in-the-middle attack is still possible. If an attacker would intercept username and hash it has all the relevant infos and it wouldn't be any different than transmitting the plaintext password. So you might want to secure the connection with SSL (HTTPS).
According to IT Security experts:
Use Bcrypt Source: https://security.stackexchange.com/a/10905/7599.
I would give answer according to SO point of view.
openssl_digest vs hash vs hash_hmac
openssl_digest - Computes a digest.
hash Generate a hash value (message digest)
hash_hmac — Generate a keyed hash value using the HMAC method
And In cryptography, a hash-based message authentication code (HMAC) is a specific construction for calculating a message authentication code (MAC) involving a cryptographic hash function in combination with a secret key.
As said by ircmaxell, hash or hash_hmac are not better for storing passwords with SHA-512. I would rather say, you can use openssl_digest for storing passwords.
See SHA-512 library for PHP
SALT vs HMAC
A hash, in this context, is a one-way function - i.e. a function that makes it very easy to find the result from the argument (the password) but difficult (or impossible) to find any argument that generates a given result.
A salt is some auxiliary data that augments the argument to a hash function. This is useful as it prevents accidental discovery of passwords through observation that two hashed passwords have identical values. With a salt, the stored/transmitted value will only be identical if both the salt and the password match.
An HMAC refers to the application of a hash (and optional salt) to a "message authentication code" - which, depending upon context might be a password... or, at least, there's nothing stopping you passing a password into the HMAC as if it were the message authentication code.
HMAC is meant to be used in cases where you have a random and secret
key. For these cases, HMAC is usually better than other ways of
incorporating the key into the hash function. (For example, using HMAC
takes care of things like extension attacks, etc.)
Salt is usually a random value that is not secret. That is to say, when
you use the term salt you usually refer to situations where there is a
random value that may very well be known to the attacker. The security
of the system should therefore not depend on the salt being kept
secret. In these situations HMAC is often not a very good choice.
HMAC and Salt comparison is not logical. Personally I'd use a salt and a hash function... and I wouldn't be paranoid about the strength of the hash function as its unlikely to be the weak link in any practical system....
See http://www.derkeiler.com/Newsgroups/sci.crypt/2006-01/msg00321.html
I'm storing username and password in a MySQL database and have them hashed using MD5. However, I'm only using the standard PHP function without any modification. Now, I read that MD5 is broken. How are you doing it? Do you run it several times through a different hash mechanism or add some form of salt?
I'm amazed how people jump on the bandwagon of "damn, it's broken, I won't use it!", don't do the same mistake.
You can't make the MD5 better. Even using SHA-1 is vulnerable to same type of attacks as MD5.
Using bcrypt will use A LOT more CPU than MD5 and SHA algorithms.
MD5 is designed to be fast, same as SHA. bcrypt isn't and it allows for more permutations, which makes it harder for someone to try to decrypt the original string.
You need to know why MD5 is considered "broken".
Because it's fast to calculate a rainbow table of passwords up to 6 characters in length.
Using today's computing power, one can create an array of characters and MD5 all permutations and map them to the original string. That's how you get a rainbow table. If someone downloads your database and then compares passwords to their rainbow table - they can obtain users' original password. Reason why this is dangerous is because people use same passwords for many things - including paypal and other money processing service. That's why you use so-called salt. That makes it even harder to obtain the original string, so salting your users' passwords (let's say by reversing them and MD5-ing the reversed input) will make it harder for the attacker to revert the hash to original string.
Because of collisions.
What's a collision? If you give hashing function two different strings and it returns the same hash - that's a collision. How does it translate to web and hashing passwords for logins? If you have the same hash for user1/password1 and user2/password2 - they could log on as someone else. That's where collisions play the role in security.
Reason why MD5 is considered broken is because MD5 returns same hash for strings that differ in small percentage. And it's not easy to calculate what that string might be!
From mathematical point of view - yes, it's "broken" because if your string has 100 chars and it differs from other string in 10 chars (10% difference) - you get the same hash.
What applies for MD5 applies for ALL hashing algorithms. In the end, all of them don't have infinite number of possible hashes.
However, some of them (like MD5) have less possible hashes and execute faster.
In the end, if someone got to your database - you have a bigger problem than using MD5 instead of bcrypt or SHA1.
Add a salt to each password stored that's not equal for every password
Simply use MD5("yoursite.com".$string);
MD5 is not decryptable. The only possible way to crack it is through hash tables that brute force everything. If you add a random string that only you know they cant crack it.
If you're worried about password security then you should use SHA1() (or alternative) rather than MD5(). Whilst MD5 is not decryptable, it can be beaten by either rainbow tables or matching the hash.
Salts will work against rainbow table but not against matching the hash which has been achieved with MD5.
There are a couple of things you should do.
Use SHA instead of MD5. SHA is more cryptographically secure than MD5. The more bits the better!
Use a salt. This makes rainbow table attacks more difficult.
Strengthen your key by calculating the hash like as follows:
:
function strenghtened_hash( $password, $salt, $n ) {
$crypted = sha( $password . $salt );
for( $i = 0; $i < $n; $i++ ) {
$crypted = sha( $crypted . $password . $salt );
}
return $crypted;
}
Now you should be in good shape!
You might be better off using using bcrypt for password storage to prevent rainbow-table attacks in case the bad guys get hold of your DB.
At the very least, dump MD5 (although computationally fast, not very secure these days) and use something a little more secure like SHA256 with a long salt.
Switch to a different hash mechanism (you can do it incrementally as people log in) and definitely use a (different for each user) salt!
You can use a thing called a salt. It means that you also save this salt into you database. It's a random string which is more or less long and is unique for each user.
Then, to check the password, you do something like this:
<?php
$crypted = md5($salt.$passwordFromForm);
if($crypted == $passwordFromDB) {
// user logged on
}
?>
You can make MD5 or any hashing function more strong by a method called "loop-hashing" i wrote about , read it here ,Good method to encrypte data, , using a loop "for" or "while" to encrypte password a lot of times with a random generated key number , really it's strong and so easy , so won't be scare from crackers again , no one can crack an encrypted "loop-hash" at the moment with the available databases .