NodeJS 中的 RabbitMQ 密码散列

RabbitMQ password hashing in NodeJS

我在 Docker 中使用 RabbitMQ。我想直接在 definitions.json 文件中更新配置。用户应该使用 rabbit_password_hashing_sha256 哈希算法将密码存储在那里。我找到了一个有用的 Python 脚本来散列密码,但我无法在 NodeJS 中使用 Crypto 库重现它的逻辑。

Python 脚本:

#!/usr/bin/env python3

# RabbitMQ password hashing algorith as laid out in:
# http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2011-May/012765.html

from __future__ import print_function
import base64
import os
import hashlib
import struct
import sys

# The plain password to encode
password = sys.argv[1]

# Generate a random 32 bit salt
salt = os.urandom(4)

# Concatenate with the UTF-8 representation of plaintext password
tmp0 = salt + password.encode('utf-8')

# Take the SHA256 hash and get the bytes back
tmp1 = hashlib.sha256(tmp0).digest()

# Concatenate the salt again
salted_hash = salt + tmp1

# Convert to base64 encoding
pass_hash = base64.b64encode(salted_hash)

# Print to the console (stdout)
print(pass_hash.decode("utf-8"))

输出: python hash-password.py test >> t7+JG/ovWbTd9lfrYrPXdFhNZLcO+y56x4z0d8S2OutE6XTE

第一次执行失败:

const crypto = require('crypto');

this.password = process.argv[2];

this.salt = crypto.randomBytes(16).toString('hex');

this.password_hash = crypto.pbkdf2Sync(this.password.trim(), this.salt, 1000, 24, `sha256`).toString(`hex`);

console.log(this.password_hash);

输出: 节点password.js测试>>7611058fb147f5e7a0faab8a806f56f047c1a091d8355544

我在NodeJS中无法重现,所以收集了子进程执行的stdout结果,不太优雅。

第二次执行失败:

const crypto = require('crypto');
const utf8 = require('utf8');

this.password = process.argv[2];

this.salt = crypto.randomBytes(4);

this.tmp0 = this.salt + utf8.encode(this.password);

this.tmp1 = crypto.createHash(`sha256`).digest();

this.salted_hash = this.salt + this.tmp1;

this.pass_hash = Buffer.from(this.salted_hash).toString('base64');

console.log(utf8.decode(this.pass_hash));

输出: 节点password.js测试>>Mu+/ve+/vWnvv73vv71C77+977+9HBTvv73vv73vv73ImW/vv70kJ++/vUHvv71k77+977+9TO+/ve+/ve+/vRt4Uu+/vVU=

任何人都可以帮助正确实施吗?

你可以或多或少地移植到 NodeJS 1:1:

var crypto = require('crypto') 

// The plain password to encode
var password = Buffer.from('my passphrase', 'utf8') // sample password

//  Generate a random 32 bit salt
var salt = crypto.randomBytes(4);
//var salt = Buffer.from('1234', 'utf8'); // for testing, gives pass_hash = MTIzNNcAIpZVAOz2It9VMePU/k4wequLpsQVl+aYDdJa6y9r  

// Concatenate with the UTF-8 representation of plaintext password
var tmp0 = Buffer.concat([salt, password])

// Take the SHA256 hash and get the bytes back
var tmp1 = crypto.createHash('sha256').update(tmp0).digest()

// Concatenate the salt again
var salted_hash = Buffer.concat([salt, tmp1])

// Convert to base64 encoding
pass_hash = salted_hash.toString('base64')

// Print to the console (stdout)
console.log(pass_hash)

上面的代码使用示例密码 my passphrase。您需要用您的密码替换密码。

请注意,即使密码相同,您也无法直接比较 Python 和 NodeJS 代码的结果,因为 random 盐。
因此,带有UTF-8编码盐1234的注释掉的行可用于产生与Python代码进行比较的结果:MTIzNNcAIpZVAOz2It9VMePU/k4wequLpsQVl+aYDdJa6y9r


您的第一个实施中的问题是,除其他外,Python 代码中未应用 PBKDF2 的使用。

第二个实现更接近实际解决方案。一个问题是散列没有考虑要散列的数据。
另一个缺陷是字符串的使用,其中一些操作隐式应用 UTF-8 编码,这会破坏(任意二进制)数据。为防止这种情况,必须使用 binary 作为编码而不是 UTF-8。仅仅因为可能的编码问题,这里使用字符串的实现不如使用缓冲区那么健壮。