So I have this PHP code,it is meant to encrypt a users password... Three problems/questions:

  1. My 'salt' CHANGES ITS NAME
  2. I get the same result
  3. Is this actually how the result is meant to be?



echo "Blowfish: " . crypt("$password", '$2a$09$anexamplestringforsalt$'); 


Blowfish: $2a$09$anexamplestringforsaleU79j3Xck4QHAVNZ.exkIn8ZZrZnIrHq

As you can see, my salt goes from $anexamplestringforsalt$ to $anexamplestringforsaleU. (Or is that supposed to happen?) Also, that is the same result I get even after changing the password.

Please help.

  • $\begingroup$ that does not look right at all $\endgroup$ – Richie Frame Sep 13 '18 at 20:10

The algorithm called "bcrypt" (which is not the same as blowfish) accepts a salt up to 128 bits long. The bits are encoded similar to Base64, just using a different map from bits to characters. Thus the maximum length your encoded salt can be is 22 characters.

Your salt looks like anexamplestringforsalt. That's 22 characters long. Note that 128 bits divided by 6 (or $\log_2 64$) bits per character is actually 21 characters with 2 bits remaining.

Try replacing the final 't' with different characters. You will see that the result will always replace the 22nd character with one of . O e or u. The 23rd character and onward of the (actual 128-bit) salt are truncated, having no impact on the result.

The PHP crypt function, atleast for bcrypt version 2a, uses only the first 128 bits. Additional bits are silently ignored. When I look at the relevant PHP source code it seems like this is deliberate. (Whether this was originally intended or if this was added to keep backwards compatibility, I don't know.)

The "U" in anexamplestringforsaleU is actually part of the hash, not the salt.

The reason why the final character only may take on one of four values is because that is the number of values the final 2 salt bits can take on. The reason why it's limited to . O e or u specifically is because the final character of the radix-64 string encodes those last two salt bits as the most significant two bits of the radix-64-digit. The low four bits are all forced to zero. . O e and u correspond to radix-64-digit numbers 0, 16, 32, and 48 respectively.

The alphabet is reproduced below based on this source. (I split into four segments for sake of clarity.)

./ABCDEFGHIJKLMN OPQRSTUVWXYZabcd efghijklmnopqrst uvwxyz0123456789


Use the Password Hashing API instead of crypt. It's already installed by default, it has reasonable defaults, supports bcrypt and argon2, and can generate salts automatically. The crypt function is much more difficult to use correctly.

Look into using Argon2. It uses relatively large amounts of RAM as a means of making password cracking more difficult.

The correct verb to use to describe password stretching/verification algorithms is usually "hash" not "encrypt". Password hashing is a one-way process (only brute force can "reverse" it). Encryption uses a secret key and is reversible. crypt was deceptively named.

Blowfish and bcrypt are not the same algorithm. Bcrypt is merely based on Blowfish.


Not the answer you're looking for? Browse other questions tagged or ask your own question.