ircmaxell/password_compat — pull request #38 by Jacques1 (2013-12-09 21:24:08+00:00)
Title: Incorrect encoding of raw salt

The library encodes a raw salt by applying common Base64, removing the padding and replacing “+” with “.”. This is *not* how the Base64 variant of bcrypt works. In bcrypt, the Base64 digits have completely different values:

Common Base64 is

```
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
```

bcrypt Base64 is

```
./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
```

As a result, the library is incompatible with common bcrypt implementations when you pass a raw salt. This can easily be tested with PHPass which uses correct encoding. For example, a cost of 10 with the salt 0x00...00 (16 bytes) should result in

```
$2y$10$......................Y.ZR0C94dLJxYMB7aLoGRMNOqWmz51u
```

But password_compat instead returns

```
$2y$10$AAAAAAAAAAAAAAAAAAAAA.sY4I5nDHsL5ufSOH0P.gICQkhzJWhMS
```

Also note how the 22nd salt digit “inexplicibly” turns into “.” (see below).

The wrong encoding also leads to a nonsensical 22nd salt digit. For example, if the last two bits of the raw salt are 0b11, then the last digit should be “u” which represents 0b110000. Instead, the wrong encoding will yield the digit “w” which represents 0b1100[1]0 in bcrypt. Since the salt only covers the first two bits (the rest is padding), this digit makes no sense.

Fortunately, the current bcrypt implementation doesn’t choke on this. It automatically corrects the 22nd digit by nullifying all bits except the first two. However, this makes the library inconsistent in the sense that encoding the raw input salt yields a different result than what is in the calculated hash:

```php
$raw_salt = str_repeat("\x12", 22);

// encode salt using your method:
echo substr(str_replace('+', '.', base64_encode($raw_salt)), 0, 22), '
';
// the encoded salt is "EhISEhISEhISEhISEhISE[h]"

// calculate hash from raw salt:
echo password_hash('foo', PASSWORD_BCRYPT, array('salt' => $raw_salt));
// now we suddenly have "EhISEhISEhISEhISEhISE[e]"
```