Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP password_verify() vs Python bcrypt.hashpw()

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.

like image 880
kdougan Avatar asked Nov 16 '16 22:11

kdougan


1 Answers

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.

like image 84
Walt Sorensen Avatar answered Oct 22 '22 03:10

Walt Sorensen