1

I found the following code on the Web and would like to know why the autor does replace all + signs after base64-encoding the return value of mcrypt_create_iv().

    $salt = mcrypt_create_iv(22, MCRYPT_DEV_URANDOM);
    $salt = base64_encode($salt);
    $salt = str_replace('+', '.', $salt); 

The salt is later passed to crypt() for generating a password hash. So my assumption is, the replacement of all + with . has to do with crypt().

  • Probably because using characters as such `+` or `<` could have adverse effects on how PHP parses them; I've seen that happen before. – Funk Forty Niner Aug 11 '14 at 17:39
  • Fred, Can you please elaborate on this, give an example? Thanks. –  Aug 11 '14 at 17:41
  • This `$salt=sprintf('$2y$%02d$',$cost);` for example is taken from one of my scripts which is invalid and would generate a proper salt. However, is using `$salt=sprintf('$2y$%02d$+',$cost);` would generate `*0`; that's not good. The script in question is borrowed from this answer http://stackoverflow.com/a/13153865/ that I use myself. I'm sure I have another script to use as an example, but that would take me a bit more time to find/test. – Funk Forty Niner Aug 11 '14 at 17:48
  • In the example, was the salt transmitted over http/s as part of a query string? (This should never be done, btw, but...) If so, some http clients and servers will interpret a `+` as a space. This is non-standard behavior, specifically against the RFC for Url's, but it does happen (e.g. in Chrome). – Patrick M Aug 11 '14 at 17:49
  • The author of that looks confused, since they want to generate 22 Base64 characters, but specify 22 bytes instead of 16. – CodesInChaos Aug 13 '14 at 10:34

2 Answers2

1

Without more context, I can only guess, but I can give you a very likely reason:

In many setups, the password hash is stored in a format like method+iterations+salt+hash. If stored this way, rather than putting the salt in a separate column in the database, you need a way to separate the salt (and other details) back out from the hash. If it is splitting on +, then extra pluses in the salt would break the method.

This can be avoided by storing the hash, salt, and method in their own columns, or by splitting based on position rather than by a specific character. However, the method you appear to be using is just fine anyway. Substituting one specific character will have no meaningful impact on the success of a good salt/hash.

1

So my assumption is, the replacement of all + with . has to do with crypt().

Yes, it does.

From the crypt docs:

CRYPT_STD_DES - Standard DES-based hash with a two character salt from the alphabet "./0-9A-Za-z". Using invalid characters in the salt will cause crypt() to fail.

CRYPT_EXT_DES - Extended DES-based hash. The "salt" is a 9-character string consisting of an underscore followed by 4 bytes of iteration count and 4 bytes of salt. These are encoded as printable characters, 6 bits per character, least significant character first. The values 0 to 63 are encoded as "./0-9A-Za-z". Using invalid characters in the salt will cause crypt() to fail.

So the salt must be in the alphabet ./0-9A-Za-z

Community
  • 1
  • 1
hlscalon
  • 7,304
  • 4
  • 33
  • 40
  • Thanks. Then the salt-generating function must be insufficient, since it does not replace = signs. –  Aug 11 '14 at 18:03