views:

86

answers:

4

I need to get the basics of this function. The php.net documentation states, for the blowfish algorithm, that:

Blowfish hashing with a salt as follows: "$2a$", a two digit cost parameter, "$", and 22 base 64 digits from the alphabet "./0-9A-Za-z". Using characters outside of this range in the salt will cause crypt() to return a zero-length string

So this, by definition, should not work:

echo crypt('rasmuslerdorf', '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringforsalt$');

However, it spits out:

$2a$07$usesomadasdsadsadsadaeMTUHlZEItvtV00u0.kb7qhDlC0Kou9e

Where it seems that crypt() has cut the salt itself to a length of 22. Could somebody please explain this?

Another aspect of this function I can't get my head around is when they use crypt() to compare passwords. http://php.net/manual/en/function.crypt.php (look at ex. #1). Does this mean that if I use the same salt for all encrypting all my passwords, I have to crypt it first? ie:

$salt = "usesomadasdsadsadsadae";
$salt_crypt = crypt($salt);

if (crypt($user_input, $salt) == $password) {
   // FAIL WONT WORK
}

if (crypt($user_input, $salt_crypt) == $password) {
   // I HAVE TO DO THIS?
}    

Thanks for your time

+2  A: 

Quoting from the manual

CRYPT_BLOWFISH - Blowfish hashing with a salt as follows: "$2a$", a two digit cost parameter, "$", and 22 base 64 digits from the alphabet

Note: 22 base 64 digits

Mark Baker
English isn't my first language, so maybe I've totally misunderstood this :) I'm not using 22 characters in my example, but that's totally fine with PHP anyway?
soren.qvist
PHP doesn't mind >22 chars in the salt; it objects to <22. However, only the first 22 are used: crypt('rasmuslerdorf', '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringforsalt$') and crypt('rasmuslerdorf', '$2a$07$usesomadasdsadsadsadasxxxxxxxxxxxxxxxxxxxxxxxxxxxxx$') will return identical values because the first 22 characters are identical
Mark Baker
Thanks for the answer
soren.qvist
+2  A: 

First question:

So this, by definition, should not work:

echo crypt('rasmuslerdorf', '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringforsalt$');

Where it seems that crypt() has cut the salt itself to a length of 22. Could somebody please explain this?

There isn't a problem with having too many characters... the phrase Using characters outside of this range in the salt will cause crypt() to return a zero-length string referse to outside the range of base 64 not the range of 22 characters. Try putting an illegal character in the salt string, and you should find that you get an empty output (or if you put < 22 characters in, resulting in illegal empty bytes).

Second question:

You pass in the encrypted stored password as salt because the salt string always appears (by design) in the encrypted string, and this way you ensure that you have the same salt for both encryption of stored and user-entered password.

Greg Harman
So I store my encrypted password in the db, something like 'MTUHlZEItvtV00u0.kb7qhDlC0Kou9e' and then use that as salt? But I've used another salt to create that encryption haven't I?
soren.qvist
Right, you've used another salt (or the default generated salt) to create the first encryption. It turns out that due to some (carefully design, I imagine) peculiarities of the encryption algorithms that you can then use that encrypted string as the salt for another encryption and you get the effect of using the same salt.
Greg Harman
+2  A: 

Following code example may answer your questions.

To generate hashed password using Blowfish, you first need to generate a salt, which starts with $2a$ followed by iteration count and 22 characters of Base64 string.

$salt = '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringfors';
$digest = crypt('rasmuslerdorf', $salt);

Store the whole $digest in database, it has both the salt and digest.

When comparing password, just do this,

  if (crypt($user_input, $digest) == $digest)

You are reusing the digest as salt. crypt knows how long is the salt from the algorithm identifier.

ZZ Coder
Yes, this is how it should be done. And that `$salt` should be randomly generated each time you set the password.
caf
Ahh I see, I thought I was supposed to store only the hash in the db. But storing the salt along with the hash in the db kind of removes the purpose of a salt doesn't it?
soren.qvist
@soren.qvist: Not completely, no. Even if an attacker knows the salt, he still has to recalculate the hash for each possible password with that salt attached; it's not enough to compute it once and then just lookup the hash in the results. It is even better if the salt is unknown, because then he has to try all passwords for each possible salt, but even if the per-user salt is stored alongside each password, it will still require re-computation for that user's salt. See also http://en.wikipedia.org/wiki/Salt_%28cryptography%29.
Michael Madsen
@Michael Madsen, thanks for the response, would you recommend a randomly generated salt for each password entry in the db?
soren.qvist
@soren.qvist: You should definitely use a different salt for each *record*. Whether it's random or not - I'm not sure there's much difference. Even if the salt is predictable, you'd still need to run the hash for each salt. It's the same for creating a new salt when the password is changed; you still need to calculate everything for that salt. It prevents someone from targeting that specific user by pre-computing the hashes and then re-using it, but that's about it. However, having said that, it certainly wouldn't *hurt* to have a random salt on every change - so you might as well do that.
Michael Madsen
Excellent, thanks for your time!
soren.qvist
Check out gensalt_blowfish() from Wordpress: http://cvsweb.openwall.com/cgi/cvsweb.cgi/projects/phpass/PasswordHash.php?rev=1.7
ZZ Coder
A: 

This question is in relation to my response to ZZ Coder's answer. Basically my question is regarding storing the crypt() result in the database. Am I supposed to store the entire output in the database, so that my database looks like this:

--------------------------------------------------------------------------------
| ID | Username |                          Password                            |
--------------------------------------------------------------------------------
| 32 | testuser | $2a$07$usesomadasdsadsadsadaeMTUHlZEItvtV00u0.kb7qhDlC0Kou9e |
--------------------------------------------------------------------------------

If yes, then doesn't this kind of defy the purpose of using a salt in the first place? If someone gains access to the db, they can clearly see the salt used for the encryption?

Bonus question: Is it secure to use the same salt for every password?

soren.qvist
First - You are hashing, not encrypting. Second - By using a different salt for every user, you protect yourself from rainbow tables. The fact that the salts are stored in the database doesn't significantly aid an attacker - you can't guess the password from the salt (for good hashing algorithms).
Greg
So, yes, I am supposed to store the password this way? I thought the hash was the result of the encryption, but maybe I've got the terminology all wrong
soren.qvist