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

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:

Yes, this is how it should be done. And that $salt should be randomly generated each time you set the password.
–
cafJun 29 '10 at 3:58

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.qvistJun 29 '10 at 10:40

1

@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 en.wikipedia.org/wiki/Salt_%28cryptography%29.
–
Michael MadsenJun 29 '10 at 21:10

@Michael Madsen, thanks for the response, would you recommend a randomly generated salt for each password entry in the db?
–
soren.qvistJun 29 '10 at 21:20

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.qvistJun 28 '10 at 19:48

3

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 BakerJun 28 '10 at 19:58

BCrypt uses 128 bits for salt, so 22 bytes Base64, with only two bits of the last byte being used.

The hash is computed using the salt and the password. When you pass the crypted password, the algorithm reads the strength, the salt (ignoring everything beyond it), and the password you gave, and computes the hash, appending it. If you have PostgreSQL and pg_crypto handy, SELECT gen_salt('bf'); will show you what of $salt is being read.

There is no reason to use the same salt for all of your passwords. The salt is part of the output anyway so you gain nothing in convenience... though I grant PHP ought to have a built-in gen_salt function.

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.

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.qvistJun 28 '10 at 20:00

1

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.
–
GregJun 28 '10 at 20:41

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:

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).
–
GregJun 29 '10 at 21:05

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.qvistJun 29 '10 at 21:14