Using 512-hash before Bcrypt? - php

I want to use Bcrypt for the password encryption in my systems. But all the examples are something like this:
$password = $_POST['password'];
$salt = substr(str_replace('+', '.', base64_encode(sha1(microtime(true), true))), 0, 22);
$hash = crypt($password, '$2a$12$'.$salt);
This looks pretty safe to me, but I was wondering, in each example, nobody hashes the password before using Bcrypt.
Due to the unique salt, Rainbow tables shouldn't be able to crack all the passwords at once. But in case the hacker takes one record and creates a rainbow table with the salt of that particular record, he should be able to crack a weak password.
So if someone takes a weak password (let's say 'foo'), it would be safer to hash it first with SHA-512 before using Bcrypt. Am I right? Or is this just looking safer?

Actually the answer has to be no, it doesn't make the hash significant stronger in a cryptographically sense. As you probably know, bcrypt (although the function to use is named crypt) is a hash function itself, not an encryption function.
In bcrypt you pass a cost factor, which defines, how many iterations will be done (normally hundreds of them). That slows down calculation of the hash, what makes brute force attacks impracticable. Using SHA-512 before, will only add one iteration more.
What you said about the salt is correct, but of course if you have to build a rainbow table for each password, you will simply brute force until you have found a match, no need to build the whole rainbow table.
If the attacker has control over database and code, an additional SHA-512 will help nothing at all (only a single iteration more). If he has only the database without code (SQL-Injection), then he will recognize the bcrypt hash. He can now brute force with bcrypt, but because of the SHA-512 there aren't any weak passwords. It's like the SHA-512 hash would be the password to crack, so a dictionary is of no use. This is security by obscurity, but will be effective as long as the code is not known. You can get the same effect easier, by adding a fix hard coded salt (key), before using bcrypt with the unique salt.

crypt() is a one-way string hash, not an encryption mechanism. To use an SHA-512 hash, you have to use the hash() function. Bcrypt requires a PHP extension. For storing passwords, why do you want to make them reversible, rather than just hashing them? That's less secure -- if someone gets your key and DB, they have all the passwords, but a table of SHA512 hashes is pretty useless.

Hashing first won't help. A bad password is one that is deemed more probable by an attacker and placed earlier in his list of passwords to try.
Bcrypt incorporates salt to eliminate pre-computed lookup tables (a Rainbow Table is one example). Why would an attacker build a rainbow table for a single record? No, when attacking a salted password, an attacker simply works through his ordered list of most likely passwords, repeating the hash algorithm to see if it matches.
How far he can work through that list depends on how long the hash algorithm takes to execute. Bcrypt controls that with the "cost" factor—12 in your example (which is okay, but probably the minimum I'd use). An extra SHA-512 round doesn't add anything to that. You are already performing 4096 expensive bcrypt iterations. Adding 1 cheap SHA-512 iteration is negligible.
If you choose the first password on the list, it will be broken in a fraction of a second. If you pick the billionth password, the attacker won't break it for a few decades.

bcrypt already uses salt, and what it's doing internally is quite a bit stronger than SHA512. Adding an iteration of SHA512 (and/or an extra layer of salt) on top of bcrypt will not give you a significantly stronger result. If the two functions interact in the wrong way, combining them in this way may in fact give you a hash function that is weaker.

Related

How does password_hash really work?

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.

Do I need unique salts with bcrypt in PHP?

I understand that bcrypt is more secure than other methods but still puts you the same situation where you need to salt passwords!
If the salt is included in the hash string it's not needed to store it separately in the DB. Everytime I need to create a new hash, meaning a new salt as well, do I have to get all the passwords, extract the salts and check the new one doesn't exist already against my DB passwords?
Wouldn't be easier to store directly the salts separately for easy compare? If yes then I don't get:
the point of storing the salt in plain text
why bcrypt is more secure than manually use sha256 with salted passwords
I'm actually going to disagree with Curtis Mattoon's answer on a couple of things.
When you hash using bcrypt, the salt is stored directly inside the hash, so you don't need to store it separately. I'm not sure what he means by not having to store it at all, because the hash without the salt is completely useless. The salt is needed to verify the password against the hash.
I agree on this point. If you are updating one password, you don't need to update them all. In fact, it would be impossible because you (hopefully) don't know the passwords for any other users.
You don't need to go through pains to get a unique salt. If that were the case, you could use uniqid, but the problem with that is its output is predictable. Predictability is a bad thing in cryptography. Instead, what you want to do is use a pseudo random salt as close to random as possible (i.e. using /dev/random instead of /dev/urandom). If you have a billion users, you may get one or two that have exactly the same salt, but seriously, is this such a big problem? All it does is doubles someone's chance of brute forcing the password for those two particular passwords out of a billion, and I doubt it's even that high of a chance of a collision occurring. Don't strain yourself over this. Make the salts random, not unique. Using things like last login time or IP address is only going to take away from randomness.
As for a comparison between SHA512 and Blowfish, see here SHA512 vs. Blowfish and Bcrypt
This site seems to do a decent job at a brief explanation: http://michaelwright.me/php-password-storage
Quick answer:
1) You don't need to store the salt.
2) You don't need to update all the hashes, if you use a unique salt for each password.
3) I'm no crypto expert, but when you're using a unique salt for each user/password, an attacker would have to use a different set of rainbow tables for EACH user. Using the same salt value across the site means that every user's password would be susceptible to the same hash tables. In the past (for better or worse), I've used a function of the user's last login time and/or last IP as the for their password's salt.
e.g. (pseudocode) $password = hash(hash($_POST['password']) . hash($row['last_login']));
4) I'll defer the "Why is bcrypt better?" question to someone more knowledgeable about such things. This answer may help: How do you use bcrypt for hashing passwords in PHP?

Securely hash passwords - so much conflicting advice!

I'm reading so much conflicting advice as to how to store passwords securely. All I know for sure is not to use MD5! I've seen people advocate using PHP's bcrypt function, which seems like it'd hog the server's processor. I've seen advocates for salts, and advocates for not using salts.
It's all just so unclear. Is there real and credible advice as to how to store passwords securely?
Edit: After a fair amount of research, I found an article from ;login: that deals with the topic in quite some depth: http://www.usenix.org/publications/login/2004-06/pdfs/alexander.pdf
Well, there is several parts to this.
You need to try to make it difficult to get to your db and passwords in the first place, keep them secure. This includes not making your passwords cleartext and not using a symmetric encryption algorithm.
You need to use a salt. Doing this prevents people from using a precomputed lookup table (i.e. rainbow table) or something like http://md5.rednoize.com/. Pick some data for your salt that is both unique and unpredictable. I usually use a random 32 bit value, but I wouldn't go much less.
Some algorithms are stronger than others. This is defined in a couple ways
How fast it can be computed. Longer is better. The faster the attacker can calculate hashes, the better the odds are for a bruteforce attack.
If the algorithm has no known weakness which reduce the search space. For example, the number of bits in an md5 hash is misleading because there are known attacks that reduce the actual search space
As of today I think SHA1 or SHA2 with a salt is reasonably secure for the near future. There is a utility called bcrypt which uses an asymmetric variant of blowfish and has the concepts of salt and computational expense built-in, it might be worth checking out.
Edit: I wanted to clarify what a salt is, as there is a lot of misconception about it on SO and online.
What a Salt is not
A secret, pre-agreed upon string that you hash with the password. This is a secret key, not a salt.
What a Salt is
You include the salt (unique and unpredictable per hash) along with your password when hashing, but you also include a unencrypted copy of it outside of your hash, so that when verifying the hash later you are able to include the same salt when given a test password before hashing it so you can properly compare the hash.
The point of bycrpt is to hog the processor! (Relatively speaking.) It is for this reason that it is "better" for password hashing than SHA1/2. (This "better" assumes that the password hashes are already in the hands of the attacker or otherwise exposed; while it would nice if it were not the case, even big corporations have had security compromises.)
This requirement was explicitly considered for bcrypt -- if you can only process 1k hashes a second (still, that's a good bit of log-in attempts), how long will that take an attacker to brute-force? A good bit longer than if they could process 10 million hashes a second! The target attack space of a brute-force that is only of the allowed password input, which is often much smaller -- esp. in practice with "simple passwords" -- than the space of the hash!
And a salt is very much required to avoid rainbow tables which trade time for space :) A rainbow table would effectively need to be created for each unique salt value. (Thus, the more unique salt values, the more space is required and with enough values this becomes impractical for an attacker.)
Happy coding.
First of all you need to use a good hash function, I suggest SHA-256. You can create a SHA-256 hash like this:
$hash = hash('sha256', $password);
In addition you could also use salting like this:
$salt = 'salt here';
$hash = hash('sha256', $salt . $password);
Moreover, you can use HMACs, like this:
$secret = 'your secret';
$hmac = hash_hmac('sha256', $password, $secret);
The best way to create solid hashes is through salting and iteration.
You should loop the above functions until hashing takes 200ms.
You could also go ahead and use encryption, but that would be a bit overkill for most situations.
This is similar to this question: Methods for storing login information in database
Credible advice: Never store your passwords in clear text!
Beyond that you have some choices to make. As I mentioned in the response to the linked question, there are two camps: let some else store your authentication data or do it your self. If you decide to do it your self, then you need to come up with a hashing routine. This should probably include a salting your passwords.
You can use sha256. A good thing to do is to add extra information to the password such as username, userid, or some other data to it. This way, if someone hack your database, it will be impossible to use an existant hash database to find the password. They will have to crack the password starting from zero.

How secure is this hash? (PHP)

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.

Is my authentication encryption any good?

So I've been reading a lot about encryption in PHP. So much that I am not sure exactly what's a really good method to securely store login information.
However, the following function is what I came up with:
function loginHash($username, $password){
$salt = str_split($password,(strlen($password)/2)+1);
$hash = hash('whirlpool', $username.$salt[0].'centerSalt'.$salt[1]);
return $hash;
}
Am I doing it the right way? It's used for authenticating a password combined with a username, and the ability to compare the generated hash with the one stored in a database to verify a login.
Encrypting != Hashing. They both are generally accepted to be in the category of Cryptography, but when something can be encrypted, it can be decrypted, which is not the case in Hashing. Hashing is just hashing, and that's it.
The salt is indeed not properly constructed. It should be x-bytes read from /dev/urandom with a fopen() call. For example, 16 bytes of salt is what I personally use. This prevents rainbow table attacks effectively.
To make things more secure, use a secret key, too. For example:
$hashedPassword = hash_hmac('whirlpool',$password.$salt,$key);
The $key is simply random data. You could generate a 64 kB file, for instance, that is called "key.bin" in a hidden folder above the document root and use file_get_contents() before the hash process.
Why to use secret keys? If you store the hashes and salts in a database and the key in the filesystem, then this prevents anyone from cracking your hash if they get their hands on your stored hashes and salts. So, an attacker would need to crack into both the database and the filesystem to crack your hashes, but notice that it's pointless for anyone to crack your hashes anymore if they have already cracked your whole application, which implies that your hashing scheme is good.
My advise is to never, never, never write your own encryption and hash functions. Even experts do it wrong all the time, so dont try it yourself.
Ive heared that phpass (Openwall) is a nice hashing framework, i'd suggest you use that.
They use salts in their hashes and have quite some parameters to tweak the hash.
You're not actually using a salt.
Salt is a randomly generated string that is included in the input for your hash function. As such, it will be different every time.
The idea is that you generate a salt when a user stores a password, and that this salt is included in your data storage. When authenticating, you retrieve the salt and the stored hash, you prefix the given password with the stored salt, and hash the two together. Then compare the result with the stored hash.
I think the above code checks the two boxes.
Avoiding rainbow table attacks (via Salts)
Secure Login
using salt solves two problems:
rainbow tables: rainbow tables are just precalculated hashes, stored with the source value. by comparing the hashes, you get the unhashed value (password). by adding salt you got another layer of complexity - the attacker must know the salt for generating a custom hashing table.
difference of hashed values: without salt, the same 2 passwords generate the same 2 hashes. now it's easy to see if two users use the same password (the weak point here is about the same as with the rainbow tables, but still). that may not amount to much, but is still a point of concern.
additionally, you shouldn't use fast algorithms for password hashing. md5 is fast, sha is fast. the slower, the better.
the matsano chargen blog is a good (and funny) resource for hints and pointers regarding security.

Categories