views:

359

answers:

5

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.

+5  A: 

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.

Henri
Thank you. Wish there would be some documentation for that framework though.
Tom
Unfortunately they still use MD5.
molf
Oh, it might be better for me not to use it then.
Tom
Md5 is broken, but still you need 300 playstations to break it. So for simple webapplications its still enough.Moreover, you can change the code of the framework to use sha1/2 instead of md5
Henri
It only uses MD5 as a last-resort fallback. It will use Blowfish instead if it's available. Even with MD5, it still runs it through multiple rounds, so it's more difficult to break than straight MD5.
BlackAura
+1  A: 

I think the above code checks the two boxes.

  • Avoiding rainbow table attacks (via Salts)
  • Secure Login
Webber
+5  A: 

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.

molf
Interesting. However, if the salt is different all the time, how can you compare the hash to the one in a database? Won't it be different all the time?
Tom
Yes, which is why you store it in the database too. It is the best mechanism to make sure that the hash is not predictable, based on the username/password combination.
molf
I'm missing something then, because I'm not quite sure how can you see if string A is good, compared to string B even though both strings are different? Hope I make any sense.
Tom
Ah, sorry, you meant that you also store the salt in the database. Thanks.
Tom
You save the salt off in a separate location from the hashed $password.$salt. This provides consider resistance to rainbow tables.
Kevin Montrose
@Kevin, that's wrong. All you need to do is to have a sufficiently large salt to prevent rainbow table attacks. It does not matter where you store your salts and who knows them.
rFactor
@Kali, its considered good practice to store them separately. It is not required. My original comment is a little unclear as to what I meant is providing the rainbow table resistance (the salt, not the storage location), admittedly.
Kevin Montrose
@Kevin: Salts just and only prevent rainbow table attacks, in which case it is irrelevant where you store them.http://en.wikipedia.org/wiki/Salt_%28cryptography%29
rFactor
+6  A: 

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.

rFactor
Awesome, thank you!
Tom
+1  A: 

using salt solves two problems:

  1. 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.

  2. 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.

Schnalle