问题
I have a need to verify password hashes generated using python passlib. My objective is to use passlib's pbkdf2_sha512
scheme for hashing all user passwords. However, due to the nature of our backend, I need to verify this password from php scripts, js and java. I haven't found libraries in either of them that can take a passlib hash and verify the password. I was wondering if there exist one before I set out to implement passlib's hashing algorithm in php, js and java.
回答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);
return sprintf("\$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.
*/
function verify_passlib_pbkdf2($password, $passlib_hash)
{
if (empty($password) || empty($passlib_hash)) return false;
$parts = explode('$', $passlib_hash);
if (!array_key_exists(4, $parts)) return false;
/*
* Results in:
* Array
* (
* [0] =>
* [1] => pbkdf2-sha512
* [2] => 20000
* [3] => AGzdiek7yUzJ9iorZD6dBPdy
* [4] => 0298be2be9f2a84d2fcc56d8c88419f0819c3501e5434175cad3d8c44087866e7a42a3bd170a035108e18b1e296bb44f0a188f7862b3c005c5971b7b49df22ce
* )
*/
$t = explode('-', $parts[1]);
if (!array_key_exists(1, $t)) return false;
$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;
}
回答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()
)
回答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:
Boolean verify_pbkdf2_sha512(String pw, String hash) {
PythonInterpreter python = new PythonInterpreter();
python.exec("from passlib.hash import pbkdf2_sha512");
python.set("pw", new PyString(pw));
python.set("hash", new PyString(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
来源:https://stackoverflow.com/questions/32391262/verifying-password-hashes-generated-by-python-passlib