So, right to it.
I have setup a [simple] PHP REST API where I am receiving a hashed password via the X-API-KEY header key. This works great when interfacing with another PHP script and the phrase is hashed via PHP's password_hash() method. However, when i try to interface with the API via Python and the Requests library, the key is rejected. Here are some samples:
PHP:
<?php
$usrid = '123456';
$dt = new DateTime();
$secret = "secret{$usrid}{$dt->format('Ymd')}";
$hashed = password_hash($secret, PASSWORD_BCRYPT);
echo $secret."\n";
echo $hashed."\n";
echo(phpversion());
?>
Python:
#!/usr/bin/python
import bcrypt, datetime, sys
usrid = '123456' # user id
t = datetime.datetime.now().strftime('%Y%m%d')
secret = "secret{usrid}{t}".format(usrid=usrid,t=t)
hashed = bcrypt.hashpw(secret, bcrypt.gensalt())
print secret
print hashed
print '%d.%d.%d' % (sys.version_info[:3])
The output of each of these is as follows:
PHP:
secret12345620161116
$2y$10$/WUBS2RkTlfcgPxvmqYRI.EkBD/CPgnpE9rYvOqweERgSwFeENUDO
5.6.24
Python:
secret12345620161116
$2b$11$9v/l6KglHiNgOybw1Y8jWeCFHiAfv.cguO1Qmc7Noe4azSluoBeHO
2.7.11
Now, obviously they are different, that is the point, but when you pass the Python output to the PHP password_verify() function, it returns False. The PHP output verifies just fine.
There has to be something I'm missing here but, for the life of me, I cant find it. I have tried using different salt options with no success. What am I missing? Are the two just not compatible? That seems silly, if it's true.
Thank you in advanced, you intelligent internet peoples.
UPDATE
[I have updated the scripts with the following 2 lines for the tests]
PHP: $hashed = password_hash($secret, PASSWORD_BCRYPT, ['cost'=>11]);
Python: hashed = bcrypt.hashpw(secret, bcrypt.gensalt(11))
And I have used this [PHP] to verify the above:
<?php
$secret = 'secret12345620161116';
$php = '$2y$11$rMqK7PhWtYd3E6yqqor0K.p2XEOJqbxJSrknLLWfhqZKsbYRa1YRa'; // output from php script
$python = '$2b$11$yWzCNB4dfIIVH2FLWWEQ/efSmN/KlVmLq.MGJ54plgedE1OSQgvPu'; // putput from python script
$php_needs_rehash = password_needs_rehash($php, PASSWORD_BCRYPT);
$python_needs_rehash = password_needs_rehash($python, PASSWORD_BCRYPT);
echo 'php_needs_rehash: '.$php_needs_rehash."\n";
echo 'python_needs_rehash: '.$python_needs_rehash."\n";
echo "\n";
echo "php_info:\n";
print_r(password_get_info($php));
echo "\n";
echo "python_info:\n";
print_r(password_get_info($python));
echo "\n";
echo "php_verified: ".password_verify($secret, $php)."\n";
echo "python_verified: ".password_verify($secret, $python)."\n";
echo "\n";
?>
With the following output:
php_needs_rehash: 1
python_needs_rehash: 1
php_info:
Array
(
[algo] => 1
[algoName] => bcrypt
[options] => Array
(
[cost] => 11
)
)
python_info:
Array
(
[algo] => 0
[algoName] => unknown
[options] => Array
(
)
)
php_verified: 1
python_verified: 1
So, now I'm really confused as the server still doesn't recognize my python hashed key, if I don't replace the "$2b" with "$2y" as suggested by richardhsu in the comments, that is.
Technically they are both different versions of bcrypt or crypt-blowfish
in php the prefix is $2y$10$ in python the prefix is $2b$11$
This means the cost factors are slightly different 10 vs 11 respectively in your update you have fixed the cost factors to both be 11
The other part of the prefix indicates php is using the CRYPT_BLOWFISH hashing where python is using bcrypt which is based on the Blowfish cipher.
Because of those differences the 2 passwords are not interchangeable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With