Hash & salt & HMAC

When you have to save an user password into a database, you usually did


hash('md5', $password);

smart guys also add a salt


hash('md5', $salt.$password);

but salt could be readable (hardcoded or saved into the db).

then I’ve found HMAC http://en.wikipedia.org/wiki/HMAC

The problem? HMAC is useful only if the secret key is “secret”. So if I also save the key (like I can save the salt) it’s not that useful.

And where can I find a secret key? Maybe the user password itself??

So I thought




$key = $password;

hash_hmac('sha256', $password, $key);



What do you think about this? Does it make any sense? Is there a problem if the secret key is the hashed string itself? Thank you.

Well I guess a salt should be something not related to the actual data being hashed. I’m not sure how exactly hmac works, but I guess when you use the data being hashed as secret key, it could be exploitable if an attacker knows indeed that you’re doing so.

So if the password is “12345” and the secret key is also “12345”, you can imagine it doesn’t fit to the bolded part of the text below I’ve copied from Wikipedia.

So I guess if you’re indeed doing this, you could also do sha1(sha1($data)). The final result is probably the same strength.

Well, if the salt is the hashed data, maybe it’s not very secure, but if you save the salt somewhere (because you need it later) then it’s not very secure too.

I believe "the size and quality of the key" is simply related to the usual concept of "secure key" as you could bruteforce it.

This is a PHP hmac implementation I’ve found here: http://php.net/manual/en/function.hash-hmac.php




function custom_hmac($algo, $data, $key, $raw_output = false)

{

    $algo = strtolower($algo);

    $pack = 'H'.strlen($algo('test'));

    $size = 64;

    $opad = str_repeat(chr(0x5C), $size);

    $ipad = str_repeat(chr(0x36), $size);


    if (strlen($key) > $size) {

        $key = str_pad(pack($pack, $algo($key)), $size, chr(0x00));

    } else {

        $key = str_pad($key, $size, chr(0x00));

    }


    for ($i = 0; $i < strlen($key) - 1; $i++) {

        $opad[$i] = $opad[$i] ^ $key[$i];

        $ipad[$i] = $ipad[$i] ^ $key[$i];

    }


    $output = $algo($opad.pack($pack, $algo($ipad.$data)));


    return ($raw_output) ? pack($pack, $output) : $output;

}



Where with salt+password the security margin is very low, hmac seems like a much more sophisticated solution.

Mmm… :lol:

Maybe it does make sense if the attacker doesn’t know $key = $password

but if he knows that then bruteforcing


hash_hmac('sha256', $password, $password)

or


hash('sha256', $password)

is not so different (the only difference… maybe hmac is computationally more intensive so it takes more time).

From a real security point of view, the idea of using the data as secret key is insecure. It’s like doing hash($data + $publicSalt). The key should be secret. It ain’t secret anymore when the attacker already knows that the hashed data is the key. He could just do custom_hmac(‘sha1’, $generatedKey, $generatedKey) in a brute-force script. Let’s think about this:




$password = '1';

$key = $password;


$hmac = custom_hmac('sha1', $password, $key);



How long does it take for an attacker with knowledge to crack it instead of… ?




$password = '1';

$key = 'daF93mF1plAyokF73mFQyi12FpaY0pR3';


$hmac = custom_hmac('sha1', $password, $key);



I guess the real benefit of HMAC against hashed data or hashed data + salt is that the key is indeed secret. If you just change the security concept, security will suffer.

Also an attacker that got root-access to read your static key from the server, could also take a look into your php-scripts and check out how you generate the hashes and then create a custom brute-force script. So that argument doesn’t really convince me.

But to be honest, if you don’t write a banking-script or something your may use your idea. Still I have the feeling every crypto-expert would hit you in the face for that :lol:

However


hash_hmac('sha256', $password, $salt);

still is probably more secure than


hash('sha256', $password.$salt);

Yeah, I already underlined this in the message above yours.

A comment from http://php.net/manual/en/function.md5.php

So it seems like (also with a known salt), hash_hmac() could be more secure than hash() with salt.

However the bolded text sounds to me more like


md5($salt).md5($password);

than




md5($salt.$password);

???

Just store a randomly generated salt value in the db per password. Append the salt value to user’s password when calculating the hash value. Store the hash value in the db. Do not store plain text password anywhere. Regenerate the salt value when the password needs to be changed. Do not roll your own hashing and/or encryption functions.

Wei.

Larry Ullman’s Yii book talks about setting the secret in the config file.




	// application-level parameters that can be accessed

	// using Yii::app()->params['paramName']

	'params'=>array(

		// this is used in contact page

		'adminEmail'=>'someone@example.com.au',


    	'encryptionKey'=>'lvkj23mn5j25KJE5r'

	),



Not sure if this helps. I also realise this is an old thread.

Cheers!