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.
Related
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 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.
I'm starting a website and I'm trying to decide how to encrypt user passwords to store them in a SQL database.
I realize that using a simple md5(password) is very unsecured. I'm considering using a sha512(password.salt), and I have been researching the best way to generate a useful salt.
I read numerous articles stating that a salt should be as random as possible to add entropy to the hash and it looks like a great idea. But:
you need to store the random salt along with your hash
given that an attacker somehow got access to your hashed passwords (and is trying to reverse the hash to plain text), it means he probably dumped your database, then got access to your random salts also
Isn't it obvious that the weird looking value next to the hash in the database is a salt? If the attacker can access the salt along with the hash value, how is that more secure?
Anyone has any expertise in that area? Thanks!
An attacker is "allowed" to know the salt - your security must be designed in a way that even with the knowledge of the salt it is still secure.
What does the salt do ?
Salt aids in defending against brute-force attacks using pre-computed "rainbow-tables".
Salt makes brute-force much more expensive (in time/memory terms) for the attacker.
Calculating such a table is expensive and usually only done when it can be used for more than one attack/password.
IF you use the same salt for all password an attacker could pre-compute such a table and then brute-force your passwords into cleartext...
As long as you generate a new (best cryptogrpahically strong) random salt for every password you want to store the hash of there is no problem.
IF you want to strengthen the security further
You could calculate the hash several times over (hash the hash etc.) - this doesn't cost you much but it makes a brute-force attack / calculating "rainbow-tables" even more expensive... please don't invent yourself - there are proven standard methods to do so, see for example http://en.wikipedia.org/wiki/PBKDF2 and http://www.itnewb.com/tutorial/Encrypting-Passwords-with-PHP-for-Storage-Using-the-RSA-PBKDF2-Standard
NOTE:
Using such a mechanism is these days mandatrory since "CPU time" (usable for attacks like rainbow tables/brute force etc.) is getting more and more widely available (see for example the fact that Amazon's Cloud service is among the top 50 of fastest supercomuters worldwide and can be used by anyone for a comparatively small amount)!
given that an attacker somehow got access to your hashed passwords
(and is trying to reverse the hash to plain text), it means he
probably dumped your database, then got access to your random salts
also
The whole point of salting is to defeat "rainbow tables":
http://en.wikipedia.org/wiki/Rainbow_table
See why a sufficiently long salt defeats any rainbow table under the section "Defense against rainbow tables".
how is that more secure?
It used to be more secure because it forced the attacker to try a, back then, very costly brute-force approach instead of an instant looked in precomputed rainbow tables. If you had a 64 bit salt, the attacker needed to have 2^64 precomputed rainbow tables instead of one... In other words: it made rainbow tables useless.
Note however that modern GPUs can crack billions of passwords per second making it mostly pointless for an attacker to store huge rainbow tables (instead of storing billions of hashes, simply compute them in a few seconds).
Nowadays you want to store your "passwords" using something like PBKDF2 or scrypt.
The strength of your hashed, salted passwords rely on all of the following factors:
The strength of the hashing algorithm
The randomness of the salt
The randomness of the password
Your system is as strong as the weakest of the above.
The questions below are from the sister site Security StackExchange. They discuss hashing, salts, PBKDF2, bcrypt, scrypt, and a few other things.
How to securely hash passwords?
Do any security experts recommend bcrypt for password storage?
There's also some previous discussion from here on StackOverflow as well:
Is BCrypt a good hashing algorithm to use in C#? Where can I find it?
In short answer to you question, a salt is a safeguard that makes it take a long time to recover a password in the event of compromise just as a hash is. If attacking one password, the salt won't make a difference. If trying to use a pre-computed dictionary or test many passwords at the same time, having a different salt for each entry will greatly increase the amount of work needed and generally make generating a suitable rainbow table infeasible.
Here's a good article on cryptography: http://www.javacodegeeks.com/2012/02/introduction-to-strong-cryptography-p1.html
See the section Real World Usage of Hash Algorithms, Scenario 1 for discussion of the salt.
I highly recommend using http://docs.oracle.com/javase/6/docs/api/java/security/SecureRandom.html to generate your salt
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.
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 .