What Is the Correct Format for a Blowfish Salt Using PHP's Crypt

What is the correct format for a blowfish salt using PHP's crypt?

The number following the 2a specifies the log2 of the number of rounds to perform. For example, 10 means do 1024 rounds. Usually, 10 is normal. Don't use numbers that are too big, or your password will take forever to verify.

See Why does BCrypt.net GenerateSalt(31) return straight away? for something related. :-)

Length of salt in CRYPT_BLOWFISH

This is due to how the salt is encoded. The actual salt is 128 bit but the encoded salt in the crypt format is 22 character · 8 bit/character · 3/4 = 132 bit. So 4 bits of the encoded salt are not actually used.

This also means that there are 16 encoded salts that result in the same hash as the first four bits of their least significant character are identical:

$hashes = array();
$chars = array_merge(array('.','/'), range('A','Z'), range('a','z'), range('0','9'));
foreach ($chars as $char) {
$salt = 'QAZXSWEDCVFRTGBNHYUJM'.$char;
$hashes[$salt] = crypt('pass','$2a$08$'.$salt);
}
var_dump($hashes);

Here are the encoded salts that result in the same hash:

QAZXSWEDCVFRTGBNHYUJM.
QAZXSWEDCVFRTGBNHYUJM/
QAZXSWEDCVFRTGBNHYUJMA
QAZXSWEDCVFRTGBNHYUJMB
QAZXSWEDCVFRTGBNHYUJMC
QAZXSWEDCVFRTGBNHYUJMD
QAZXSWEDCVFRTGBNHYUJME
QAZXSWEDCVFRTGBNHYUJMF
QAZXSWEDCVFRTGBNHYUJMG
QAZXSWEDCVFRTGBNHYUJMH
QAZXSWEDCVFRTGBNHYUJMI
QAZXSWEDCVFRTGBNHYUJMJ
QAZXSWEDCVFRTGBNHYUJMK
QAZXSWEDCVFRTGBNHYUJML
QAZXSWEDCVFRTGBNHYUJMM
QAZXSWEDCVFRTGBNHYUJMN

crypt probably simply uses the first that encodes the internally used 128 bit salt, which is QAZXSWEDCVFRTGBNHYUJM..

Blowfish salt length for the Crypt() function?

Blowfish salts should be 22 chars long (including the trailing $, so 21) - you can double check with var_dump(CRYPT_SALT_LENGTH), I can't verify this now but my guess is that less chars will return an error and more chars will be truncated.

Regarding your third question: yes, you should read and check the hash using the embedded salt (and cost) parameters from the hash itself.

different encryptions with crypt. what format should the salt be etc

The official documentation of the crypt function has quite some information about the various modes, and what should be passed as their salt parameter:

  • CRYPT_STD_DES: two character salt from the alphabet ./0-9A-Za-z, i.e. an 12 bit salt.
  • CRYPT_EXT_DES: a _ character, then a 4 character iteration count, then a 4 character salt (each using the same alphabet).
  • CRYPT_MD5: a marker $1$, then 9 more salt characters (using the same alphabet as above, I suppose).
  • CRYPT_BLOWFISH: a marker $2a$, then a two digit cost parameter in the range 04 to 31 (meaning 24 to 231 iterations), then $ and a 22-digit salt (again, using the same alphabet as above).
  • CRYPT_SHA256: a marker $5$, an optional round parameter indication of rounds=number$ (with a decimal number between 1000 and 999999999), and a 16-character salt (using the same alphabet as above).
  • CRYPT_SHA512: a marker $6$, an optional round parameter indication of rounds=number$ (with a decimal number between 1000 and 999999999), and a 16-character salt (using the same alphabet as above).

The start of the salt parameter uniquely identifies which kind of password hash algorithm is to be used here - so yes, if you use a salt in the bcrypt format (starting with $2a$), it will automatically use bcrypt.

How to automatically generate salt for crypt method with blowfish

A salt should be unique (for each password) and unpredictable. These two criterias are a bit difficult to fulfill with a deterministic computer, so the best thing you can do is, to use the random source of the operating system, to generate the salt.

Time stamps, as well as the mt_rand() function, are not ideal, because one can argue that they are predictable. At least an attacker can narrow down (and therefore precalculate) the possible combinations for a certain period. While this may not have a big impact in practice, why not do the best you can?

Since PHP 5.3 you can safely use the mcrypt_create_iv() function to read from the random source, then you will have to encode the binary string to the allowed alphabet. This is a possible implementation.

PHP 5.5 will have it's own functions password_hash() and password_verify() ready, to simplify this task. There is also a compatibility pack for PHP 5.3/5.4 available, downloadable at password_compat.

Am I using PHP's crypt() function correctly?

You really should have a look at PHPASS: http://www.openwall.com/phpass/ It's a password hashing framework using crypt() which is used in projects like Wordpress and phpBB.

There is also an excellent article on this website about password hashing, salting and stretching using crypt(): http://www.openwall.com/articles/PHP-Users-Passwords

UPDATE:
Currently there's an alternative for the PHPASS library. In the next version of PHP there are special functions for hashing and verifying passwords (using bcrypt): http://www.php.net/manual/en/ref.password.php. There is a compatibility library that implements these functions for PHP 5.3.7+: https://github.com/ircmaxell/password_compat



Related Topics



Leave a reply



Submit