This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Secure hash and salt for PHP passwords
I am making a website, and I need a secure algorithm to store passwords.
I was first thinking of bcrypt, but then I found out my host did not support it and I am not able to change host.
My host allow this encryption:
Standard DES
And these hashes:
MD5
md2, md4 & md5
sha1, sha256, sha384 & sha512
ripemd128, ripemd160, ripemd256 and ripemd360
whirlpool
tiger128,3, tiger160,3, tiger192,3, tiger128,4, tiger160,4 & tiger192,4
snefru
gost
adler32
crc32 & crc32b
haval128,3, haval160,3, haval192,3, haval224,3, haval256,3, haval128,4, haval160,4, haval192,4, haval224,3, haval256,4, haval128,5, haval160,5, haval192,5, haval224,5 & haval256,5
So, can anyone of you fix a good algorithm with that and a salt, please?
You shouldn't store encrypted (or even unencryped) passwords at all. Instead, use salted hashes (stretched, e.g. with PBKDF2), preferably SHA2-512.
For reference, here is a classification of the listed hashes (See wikipedia for details):
Encryption (not a hash function): DES
Non-cryptographic checksums (laughable): adler32, crc32, crc32b
Broken: MD2, MD4, MD5,SHA1
Probably broken: Tiger, snefru, GOST, HAVAL*
Probably safe: SHA2-256/384/512, RIPEMD-128/256, RIPEMD-160/320, WHIRLPOOL
Note that the strength refers to the attack of finding any password that matches a known hash (preimage attack). Also, the above sorting is paranoid, instantly discarding any hash with any known vulnerabilities.
crc32, adler32 etc. are not designed to be cryptographically secure -- they're merely fast checksum algorithms. I think salted SHA-256 should offer a good combination of security and compatibility.
On a somewhat less serious note, I once recall using salted MD5 on a slow server that was expected to tank moderate load. So I decided to pad it with a 32-bit random salt, and stored the whole thing as hexadecimal -- it gave off the impression the whole thing was unsalted SHA-1. I sincerely hope someone wasted precious time running rainbow tables on the stolen dump!
Security isn't really all about more expensive hashing :)
You should
Use a salt as part of your hash.
Use an iterative routine in the 10,000+ iteration range. For example, PBKDF#2.
Use a known strong hash (SHA-256, SHA-512)
You should store passwords as hashes as mentioned above, not encrypted.
A hash function is basically a one way transformation which always produces the same hash for the same input argument. It should not be possible to transform the hash back to its original form, or the hash function is to be considered broken.
An encryption is a two way transformation where you can transform the encrypted data back into its original form if you have the key.
By storing passwords as hashes, and as they are one way transformed, they can not be extracted even if someone were to get hold of the database.
When checking a password simply transform it with the same hash function you used on your stored password and check against the database.
As gnur said, you need to decide if you want to hash or encrypt passwords. If these are passwords for your own users and the passwords are only being used on your system, then hash them using salt and stretching. Of the hash algorithms you have available use SHA-256 or SHA-512. For salt use 128 random bits (16 bytes). Ideally use a cryptographic RNG though a non-crypto RNG will do in a pinch. The attacker is assumed to know the salts anyway. Stretch enough that it takes about 0.1 second to process a single password. This limits any attacker to ten attempts at breaking a password every second.
If you are storing passwords to log on to an external system then you will need to encrypt the passwords and decrypt them when needed. DES is your only real option here, unless you also have 3DES (aka Triple DES or DESede) available. I am surprised that AES/Rijndael is not available. If it is then us it in preference to DES.
Related
Today, I have a discussed with my friend about security with a website.
I am usually using a hash with random salts when saving a password of the user.
Because hash can't decompile, my friend often using md5() to encrypt password of the user.
Problem is:
I tried to explain to him, md5() can decryption, but he took:
" I can using md5(md5(md5('password'))) or md5() + random string ".
So, I also mention about this will have much time to save into database, when the user login, again to decryption.
But it also not enough to convince. Have anyone can suggest me how to explain easily to understand?
Thanks.
MD5 is a hash function (one way) and cannot be decrypted, the problems with MD5 for password storing are different.
MD5 is ways too fast for hashing passwords, one can calculate about 100 Giga MD5 per second with a good GPU. That makes brute-forcing too easy, testing a whole english dictionary is a matter of micro seconds.
Combining MD5 like md5(md5(md5('password'))) does not add much of security, password cracker tools often offer this out of the box.
That is why we should use a hash function with a cost factor like BCrypt. The cost factor determines how much time is used to calculate a single hash, it should be as much as your server can bear. PHP offers the function password_hash() to generate safe password hashes.
MD5 and SHA are hash functions (SHA is actually a family of hash functions) - they take a piece of data, compact it and create a suitably unique output that is very hard to emulate with a different piece of data. They don't encrypt anything - you can't take MD5 or SHA output and "unhash" it to get back to your starting point. The difference between the two lies in what algorithm they use to create the hash. Also note that MD5 is now broken as a way was discovered to easily generate collisions and should not be used nor trusted anymore.
RSA is an assymetric encryption algorithm. You have two keys (private and public) and you can perform a function with one key (encrypt or decrypt) and reverse with the other key. Which key you use depends on whether you are trying to do a digital signature or an encryption.
I am trying to understand password_hash fully in order to be able to explain it for an auditor.
Based on my searching for an answer, I understand that the password_hash() function is a wrapper for crypt(). While reading the PHP manual for predefined Constants I see that it uses PASSWORD_BCRYPT as the default integer value (basically it uses the CRYPT_BLOWFISH algorithm to hash a password).
What's confusing me is that the $options variable, if omitted, generates a random salt and the cost will be set to 10. If I supply a higher cost (for example: 12), will it still generate a random salt since I am not supplying a salt value? The reason why I am confused here is because I am not omitting the $options but instead supplying a different cost.
My other questions:
Why does increasing the cost value increase security?
How, since password_hash() is a one way hashing function, does password_verify() validate the password since the salt is random?
Is CRYPT_SHA512 stronger than CRYPT_BLOWFISH for hashing?
I find this article incredibly useful to understand how to correctly hash passwords. It explains how hashes can be cracked with various techniques if the hashes are weak, and how to hash passwords correctly to provide sufficient security.
If I supply a higher cost (say 12), will it still generate a random
salt since I am not supplying a salt value
Yes it will - as the documentation says if salt is omitted, a random salt will be generated by password_hash() for each password hashed (this means if you omit the salt value from your options array, it will be generated by password_hash() function defaultly). Moreover, the salt option has been deprecated since php 7.0.
why increases to the cost value increase security?
This is also explained in the above article in section Making Password Cracking Harder: Slow Hash Functions. The higher the cost is set to, the slower is the hash function. The idea is to make the hash function very slow, so that even with a fast GPU or custom hardware, dictionary and brute-force attacks are too slow to be worthwhile. The cost should be however set to reasonable value (based on the specs of your server), so that it doesn't cause significant time delays when verifying users' passwords.
More, is CRYPT_SHA512 stronger that CRYPT_BLOWFISH for hashing?
Read this post about their comparison.
Password hash works by using crypt() in basically a wrapper. It returns a string that contains the salt, the cost and the hash all in one. It is a one-way algorithm, in that you don't decrypt it to validate it, you simply pass the original string in with your password and if it generates the same hash for the provided password, you're authenticated.
It's best to omit the salt and let it generate one for you. If you use only one salt, it makes it easier to break all your passwords instead of just that one. Salts can be generated regardless of the cost.
Cost (an exponential value) refers to how much effort goes into generating the hash (where higher = more computing power to generate a hash). Don't set it too high or you will bog your login scripts down.
Generally speaking:
You always should apply a salt when hashing passwords, to have a different hash even if you have the same password. This increases security by "preventing" people from using rainbow tables to crack the password.
But bcrypt handles the salting on its own!
Back to your original question:
The cost is used to make it "costly" to crack the password with a dictionary/brute force attack.
Bcrypt basically hashes the password over and over, which makes it time consuming (=costly) to obtain the password to a given hash. If you try to find a password for a hash (brute force attack) you have to calculate billions of password hashes. When each hashing takes "$cost" times as long, then a brute force attack is not feasible. Even if you can calculate the hash for a potential password in milliseconds.
In simple terms:
If you have a password hash for SHA-1 (unsecure, don't use it!) with the salt (as this is usually contained in the hash) and you want to hack it then you have to hash all possible passwords + the salt and when you find the combination with the same hash, you found a possible password for this hash.
Let's say you use a good salt and a long enough password, then you need something like 1-5 seconds for a password hash. If you use the blowfish approach with cost=10 you need 10-50 seconds for a password hash.
For a single password, this is no big deal. So a directed attack for a single hash is still simple, but usually people obtain large lists of user and password combinations and they are interested to get the passwords for all of them quickly. Then this is much less lucrative for the bad guy, as he needs 10 times the CPU power to calculate all that stuff.
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.
So far I have been using md5 to hash passwords on my site, no salt.
Now I am building an application that will have to be more secure and I'm reading md5 can be easily brute-force attacked.
So I want to use crypt() to hash the passwords.
What I have not fully understood is:
Do I have to provide a salt or is the built-in generated one ok?
How many times (if more than one) should I iterate the crypt function to be safe?
With md5, no matter the length of the input string, the hash was 32-digit. Does crypt return a standard length of hashes too?
You need to provide a salt, if you want to specify encryption other than DES. Otherwise, you're good with the default salt.
You don't iterate the crypt function yourself, this is done internally with algorithms where it makes sense. Number of iterations is specified via the salt.
Yes, the hash length of a given hash algorithm is standard; different hash algorithms have different hash lengths, however.
crypt can use different hash algorytms. With md5 it returns 128 bit integer (with 32 chars hex representation). Using crypt with a salt once is safe enought. It's recommended the salt to be provided by the application
An optional salt string to base the hashing on. If not provided, the
behaviour is defined by the algorithm implementation and can lead to
unexpected results.
function oneWayEncrypt($string) {
$salt = md5($string."yHuJ#8&6%4#%([#d-]");
$salt2 = md5($string."#!#&+-)jU#[yT$#%");
$string = hash('sha512',"$salt$string$salt2");
return $string;
}
Using SHA-512 is a good idea to get a cryptographically strong hash, but your choice of a salt does not add much extra security. In particular, a salt is only good if its value is random and cannot be predicted in advance. This prevents an attacker from precomputing a table of known hashes with which to try to attack your database. If the salt is known, then the attacker can just precompute a table of hash values with the salt hardcoded in.
In your case, the salt is essentially known to the attacker because it's deterministically computed from the input string. If I wanted to attack your system, I could iterate across a bunch of known strings, (deterministically) compute the salt for each string, then compute the SHA-512 hash of the salted string and store it in a table. From this, I could invert a hash to a password for any string I happened to precompute.
If you want a better security system, instead consider using a salt that's randomly-generated and then stored alongside the resulting hash. That way, no matter what tables I precompute, there's a slim chance that the table will be useful because I won't necessarily have computed the tables for all possible salts. Essentially, each random bit in your salt doubles the amount of work I have to do, so if you pick a good random salt (say, 128 bits) then there's no feasible way I could do a precomputation attack. I'd have to attack SHA-512, a hash assumed to be cryptographically secure (the name means "Secure Hash Algorithm"), to break your system.
How secure for what?
For storing hashed passwords? - Use random salts, different for every password.
For signing cookies? - Use HMAC, a Hash-based Message Authentication Code.
You're saying that you want to use it for storing passwords in DB and cookies, both of which should be done using other proved techniques, see above. Don't try to reinvent the wheel.
When you ask how secure something is, you have to know not only what way are you going to use it but also what kind of attack do you want it to be secure against. Things are not secure in a vacuum.
Also, don't assume that SHA-512 is better for your application just because it has more bits. Read the paper Preimage Attacks on 41-Step SHA-256 and 46-Step SHA-512 by Yu Sasaki, Lei Wang, and Kazumaro Aoki (PDF) to see that for certain applications some shorter hashes can be actually more secure than SHA-256 and SHA-512 because there are no known preimage attacks that would brake so many rounds as for SHA-256 and SHA-512.
Although SHA-512 is a good choice for a cryptographic hash function in general, it still might be too easy to compute: SHA-512 is computationally fast enough to process 154 MB/s. You should better choose a cryptographic hash function that is computationally slower like bcrypt that can be slowed down with a cost factor.
Additionally, use a random and unique salt for each hash operation and store it together with the hash to be able to reproduce the hash for comparison.