如何使用Node.js验证Python的Passlib创建的加密哈希?

时间:2021-12-19 06:42:02

I have a backend application written in Python used by the content managers of my site. Users' passwords are hashed using passlib's pbkdf2_sha512 function. I began to develop the frontend application for which I decided to use nodejs with React for UX reasons.

我有一个用Python编写的后端应用程序,由我网站的内容管理员使用。使用passlib的pbkdf2_sha512函数对用户密码进行哈希处理。我开始开发前端应用程序,为了UX的原因,我决定使用带有React的nodejs。

Now my problem is I can't figure out how can I verify the passwords hashed by passlib using nodejs for authenticating my users. Passlib's implementation seems too specific to me and I'm not really into crypto stuff to figure it out.

现在我的问题是我无法弄清楚如何使用nodejs验证我的用户身份验证passlib密码的哈希值。 Passlib的实现对我来说似乎太具体了,我并没有真正进入加密的东西来解决它。

I have the MCF so I know the algorithm and digest type, the salt, the number of iterations and the key length. How can I verify this output from passlib in node? Should I rather choose another algorithm better supported by both platforms?

我有MCF所以我知道算法和摘要类型,盐,迭代次数和密钥长度。如何从节点中的passlib验证此输出?我是否应该选择两种平台更好地支持的另一种算法?

2 个解决方案

#1


1  

Ok, I turned to sha512_crypt instead and found a nice library for node called sha512crypt-node. The README itself contains an example for both Python and Node, exactly what I needed. Here's a little example for ppl. using these platforms:

好的,我转而使用sha512_crypt,并为名为sha512crypt-node的节点找到了一个很好的库。 README本身包含Python和Node的示例,正​​是我所需要的。这是ppl的一个小例子。使用这些平台:

Python:

from passlib.hash import sha512_crypt

orig = "password"
h = sha512_crypt.encrypt(orig)
print("hash", h)
# h for eg. is $6$rounds=100000$5YnTXatKh4b1pLjp$3QQjVIfjrbiTakj.wkaw1woAcFiPRAjJP2U/b3BiGW4m8OvI8x0tgw1bb63dNQWMUl1uYNDBcTO3tWgrJ6eHh1

okay = sha512_crypt.verify(orig, h)
print("verified", okay)

Node:

var sha512crypt = require("sha512crypt-node").sha512crypt;

// origHash is the hash generated by passlib    
var origHash = "$6$rounds=100000$5YnTXatKh4b1pLjp$3QQjVIfjrbiTakj.wkaw1woAcFiPRAjJP2U/b3BiGW4m8OvI8x0tgw1bb63dNQWMUl1uYNDBcTO3tWgrJ6eHh1",
    parts = origHash.split('$'),
    rounds = parts[2],
    salt = '$' + parts[1] + '$' + rounds + '$' + parts[3],
    password = "password";

var hash = sha512crypt(password, salt);
console.log("verified", hash === origHash);

#2


1  

We had exactly the same Problem but switching to sha512crypt was not an option. In our case the passwords were generated with flask-security. The examples below cover regular passlib and flask-security hashes, which first generate a HMAC with a secret salt and use it as the pbkdf2-sha512 password. See code below.

我们有完全相同的问题,但切换到sha512crypt不是一个选项。在我们的例子中,密码是使用flask-security生成的。下面的示例包括常规passlib和flask-security哈希,它首先生成带有秘密盐的HMAC并将其用作pbkdf2-sha512密码。见下面的代码。

Source is on GitHub: https://github.com/badzong/node-verify-flask-security-passwords

来源于GitHub:https://github.com/badzong/node-verify-flask-security-passwords

var crypto = require('crypto');
var pbkdf2_sha512 = require('pbkdf2-sha512');

function b64trimmed(buf) {
        return buf.toString('base64').replace(/=*$/, '').replace('+', '.');
}

function b64decode(str) {
        // . in Base64?
        str = str.replace('.', '+');
        if (str.length % 4) {
                str += '='.repeat(4 - str.length % 4);
        }
        return new Buffer(str, 'base64');
}

function get_hmac(secret, password) {
        var hmac = crypto.createHmac('sha512', secret).update(password).digest('base64');

        return hmac;
}

function get_hash(password, salt, rounds) {

        // FIXME: KeyLenBytes is hardcoded
        var h = b64trimmed(pbkdf2_sha512(password, salt, rounds, 64));
        var joined_hash = ['', 'pbkdf2-sha512', rounds, b64trimmed(salt), h].join('$');

        return joined_hash;
}

function verify_hash(password, stored_hash) {
        var scheme = stored_hash.split('$')[1];
        var rounds = stored_hash.split('$')[2];
        var salt = stored_hash.split('$')[3];

        // FIXME: Maybe throw an exception
        if (scheme !== 'pbkdf2-sha512') {
                return false;
        }

        var h = get_hash(password, b64decode(salt), rounds);

        return h === stored_hash;
}

function new_hash(password, rounds) {

        // FIXME: Salt size is hardcoded
        var salt = crypto.randomBytes(16);

        return get_hash(password, salt, rounds);
}

var password = 'Example Password';

// Usage:
var h = new_hash(password, 20000);
console.log('HASH ' + h);
console.log('VERIFY ' + verify_hash(password, h));

// Usage for passwords generated with flask_security:

// SECURITY_PASSWORD_SALT is set in config.py and used by flask-security
var SECURITY_PASSWORD_SALT = 'Many random bytes...';

var password_hmac = get_hmac(SECURITY_PASSWORD_SALT, password);
var h = new_hash(password_hmac, 20000);
console.log('HASH ' + h);
console.log('VERIFY ' + verify_hash(password_hmac, h));
        

#1


1  

Ok, I turned to sha512_crypt instead and found a nice library for node called sha512crypt-node. The README itself contains an example for both Python and Node, exactly what I needed. Here's a little example for ppl. using these platforms:

好的,我转而使用sha512_crypt,并为名为sha512crypt-node的节点找到了一个很好的库。 README本身包含Python和Node的示例,正​​是我所需要的。这是ppl的一个小例子。使用这些平台:

Python:

from passlib.hash import sha512_crypt

orig = "password"
h = sha512_crypt.encrypt(orig)
print("hash", h)
# h for eg. is $6$rounds=100000$5YnTXatKh4b1pLjp$3QQjVIfjrbiTakj.wkaw1woAcFiPRAjJP2U/b3BiGW4m8OvI8x0tgw1bb63dNQWMUl1uYNDBcTO3tWgrJ6eHh1

okay = sha512_crypt.verify(orig, h)
print("verified", okay)

Node:

var sha512crypt = require("sha512crypt-node").sha512crypt;

// origHash is the hash generated by passlib    
var origHash = "$6$rounds=100000$5YnTXatKh4b1pLjp$3QQjVIfjrbiTakj.wkaw1woAcFiPRAjJP2U/b3BiGW4m8OvI8x0tgw1bb63dNQWMUl1uYNDBcTO3tWgrJ6eHh1",
    parts = origHash.split('$'),
    rounds = parts[2],
    salt = '$' + parts[1] + '$' + rounds + '$' + parts[3],
    password = "password";

var hash = sha512crypt(password, salt);
console.log("verified", hash === origHash);

#2


1  

We had exactly the same Problem but switching to sha512crypt was not an option. In our case the passwords were generated with flask-security. The examples below cover regular passlib and flask-security hashes, which first generate a HMAC with a secret salt and use it as the pbkdf2-sha512 password. See code below.

我们有完全相同的问题,但切换到sha512crypt不是一个选项。在我们的例子中,密码是使用flask-security生成的。下面的示例包括常规passlib和flask-security哈希,它首先生成带有秘密盐的HMAC并将其用作pbkdf2-sha512密码。见下面的代码。

Source is on GitHub: https://github.com/badzong/node-verify-flask-security-passwords

来源于GitHub:https://github.com/badzong/node-verify-flask-security-passwords

var crypto = require('crypto');
var pbkdf2_sha512 = require('pbkdf2-sha512');

function b64trimmed(buf) {
        return buf.toString('base64').replace(/=*$/, '').replace('+', '.');
}

function b64decode(str) {
        // . in Base64?
        str = str.replace('.', '+');
        if (str.length % 4) {
                str += '='.repeat(4 - str.length % 4);
        }
        return new Buffer(str, 'base64');
}

function get_hmac(secret, password) {
        var hmac = crypto.createHmac('sha512', secret).update(password).digest('base64');

        return hmac;
}

function get_hash(password, salt, rounds) {

        // FIXME: KeyLenBytes is hardcoded
        var h = b64trimmed(pbkdf2_sha512(password, salt, rounds, 64));
        var joined_hash = ['', 'pbkdf2-sha512', rounds, b64trimmed(salt), h].join('$');

        return joined_hash;
}

function verify_hash(password, stored_hash) {
        var scheme = stored_hash.split('$')[1];
        var rounds = stored_hash.split('$')[2];
        var salt = stored_hash.split('$')[3];

        // FIXME: Maybe throw an exception
        if (scheme !== 'pbkdf2-sha512') {
                return false;
        }

        var h = get_hash(password, b64decode(salt), rounds);

        return h === stored_hash;
}

function new_hash(password, rounds) {

        // FIXME: Salt size is hardcoded
        var salt = crypto.randomBytes(16);

        return get_hash(password, salt, rounds);
}

var password = 'Example Password';

// Usage:
var h = new_hash(password, 20000);
console.log('HASH ' + h);
console.log('VERIFY ' + verify_hash(password, h));

// Usage for passwords generated with flask_security:

// SECURITY_PASSWORD_SALT is set in config.py and used by flask-security
var SECURITY_PASSWORD_SALT = 'Many random bytes...';

var password_hmac = get_hmac(SECURITY_PASSWORD_SALT, password);
var h = new_hash(password_hmac, 20000);
console.log('HASH ' + h);
console.log('VERIFY ' + verify_hash(password_hmac, h));