Verifying Password Hashes Generated By Python Passlib
Solution 1:
I can offer this solution for php:
/*
* This function creates a passlib-compatible pbkdf2 hash result. Parameters are:
* $algo - one of the algorithms supported by the php `hash_pbkdf2()` function
* $password - the password to hash, `hash_pbkdf2()`format
* $salt - a random string in ascii format
* $iterations - the number of iterations to use
*/
function create_passlib_pbkdf2($algo, $password, $salt, $iterations)
{
$hash = hash_pbkdf2($algo, $password, base64_decode(str_replace(".", "+", $salt)), $iterations, 64, true);
returnsprintf("\$pbkdf2-%s\$%d\$%s\$%s", $algo, $iterations, $salt, str_replace("+", ".", rtrim(base64_encode($hash), '=')));
}
I you copy the salt, iterations, and algorithm out of an existing passlib-generated hash string, and supply them with the plaintext password to this function, it will generated the same result as passlib.
Here's a php function to just verify a passlib pbkdf2 password, based on the above:
/*
* This function verifies a python passlib-format pbkdf2 hash against a password, returning true if they match
* only ascii format password are supported.
*/functionverify_passlib_pbkdf2($password, $passlib_hash)
{
if (empty($password) || empty($passlib_hash)) returnfalse;
$parts = explode('$', $passlib_hash);
if (!array_key_exists(4, $parts)) returnfalse;
/*
* Results in:
* Array
* (
* [0] =>
* [1] => pbkdf2-sha512
* [2] => 20000
* [3] => AGzdiek7yUzJ9iorZD6dBPdy
* [4] => 0298be2be9f2a84d2fcc56d8c88419f0819c3501e5434175cad3d8c44087866e7a42a3bd170a035108e18b1e296bb44f0a188f7862b3c005c5971b7b49df22ce
* )
*/$t = explode('-', $parts[1]);
if (!array_key_exists(1, $t)) returnfalse;
$algo = $t[1];
$iterations = (int) $parts[2];
$salt = $parts[3];
$orghash = $parts[4];
$hash = create_passlib_pbkdf2($algo, $password, $salt, $iterations);
return$passlib_hash === $hash;
}
Solution 2:
Passlib's pbkdf2_sha256 hash format is custom to passlib, so there (probably?) won't be very many ports of it to other languages. But it's a very simple wrapper around the PBKDF2-HMAC-SHA256 algorithm + base64 encoding, both of which are standard and should have implementations for the other languages -- so it should be pretty easy to port.
However, if portability is a priority requirement, you might want to try using passlib's bcrypt or sha256_crypt hashes instead. Both of those are standard, and should have implementations across a number of languages.
Keep in mind, both bcrypt & sha256_crypt are pretty complex -- so if you can't find a port under one of the languages you need, porting pbkdf2_sha256 is going to be a LOT less effort than porting one of them.
Another option entirely is to invoke passlib under python via a subprocess. Calling the following python oneliner...
python3 -c 'import sys; from passlib.hash import pbkdf2_sha256 as ph; print(ph.verify(input(), input()))'
... will let you write password\nhash\n
to stdin, and have it write back True
or False
(or an error message if the hash is malformed).
Since the password is being written via stdin, this should be relatively secure (compared to passing it as an argument, or env var).
(The python2 equivalent is the same, just use raw_input()
instead of input()
)
Solution 3:
In java you can use jython, which allows to use python libraries and execute python code.
Here is sample java function to verify hash using passlib:
Booleanverify_pbkdf2_sha512(String pw, String hash) {
PythonInterpreter python = newPythonInterpreter();
python.exec("from passlib.hash import pbkdf2_sha512");
python.set("pw", newPyString(pw));
python.set("hash", newPyString(hash));
python.exec("valid = 1 if pbkdf2_sha512.identify(hash) and pbkdf2_sha512.verify(pw, hash) else 0");
Boolean valid = ((PyInteger)python.get("valid")).asInt()==1;
return (Boolean)valid;
}
You can find more information on my blog: http://codeinpython.blogspot.com/2015/11/using-python-passlib-in-java.html
Post a Comment for "Verifying Password Hashes Generated By Python Passlib"