Js 如何在不使用 salt 的情况下比较散列密码和明文密码?

来自 Github:

散列密码:

var bcrypt = require('bcrypt');
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash("B4c0/\/", salt, function(err, hash) {
// Store hash in your password DB.
});
});

检查密码:

// Load hash from your password DB.
bcrypt.compare("B4c0/\/", hash, function(err, res) {
// res == true
});
bcrypt.compare("not_bacon", hash, function(err, res) {
// res = false
});

从上面来看,为什么在比较中没有涉及到盐值? 我在这里遗漏了什么?

36936 次浏览

Salt 被合并到 hash 中(作为明文)。比较函数只是从散列中提取 salt,然后使用它散列密码并执行比较。

I had the same question too as the original poster and it took a look bit of looking around and trying different things to understand the mechanism. As has already been pointed out by others, the salt is concatenated to the final hash. So this means a couple of things:

  1. 算法必须知道盐的长度
  2. 还必须知道最后一个字符串中的 salt 的位置。例如,如果从左或右偏移一个特定的数字。

These two things are usually hard coded in the implementation e.g. the bcrypt implementation source for Bcryptjs defines the salt length as 16

/**
* @type {number}
* @const
* @private
*/


var BCRYPT_SALT_LEN = 16;

因此,为了说明这个想法背后的基本概念,如果一个人想手动完成它,它将看起来类似于下面。我不建议您在有库可以使用的情况下自己实现这样的东西。

var salt_length = 16;
var salt_offset = 0;


var genSalt = function(callback)
{
var alphaNum = '0123456789abcdefghijklmnopqurstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ';
var salt = '';
for (var i = 0; i < salt_length; i++) {
var j = Math.floor(Math.random() * alphaNum.length);
salt += alphaNum[j];
}
callback(salt);
}


// cryptographic hash function of your choice e.g. shar2
// preferably included from an External Library (dont reinvent the wheel)
var shar2 = function(str) {
// shar2 logic here
// return hashed string;
}


var hash = function(passwordText, callback)
{
var passwordHash = null;
genSalt(function(salt){
passwordHash = salt + shar2(passwordText + salt);
});


callback(null, passwordHash);
}


var compare = function(passwordText, passwordHash, callback)
{
var salt = passwordHash.substr(salt_offset, salt_length);
validatedHash = salt + shar2(passwordText + salt);


callback(passwordHash === validatedHash);
}


// sample usage
var encryptPassword = function(user)
{
// user is an object with fields like username, pass, email
hash(user.pass, function(err, passwordHash){
// use the hashed password here
user.pass = passwordHash;
});


return user;
}


var checkPassword = function(passwordText, user)
{
// user has been returned from database with a hashed password
compare(passwordText, user.pass, function(result){
// result will be true if the two are equal
if (result){
// succeeded
console.log('Correct Password');
}
else {
// failed
console.log('Incorrect Password');
}
});
}

因为我自己也有同样的问题,我完全知道你在想什么。

Cryptographic算法中使用的 “密钥”和用来减慢加密过程并使黑客更难使用暴力的“ Salt”之间存在误解。

当您使用 普通密码和 salt 生成散列时,这个散列 uses as secret key the password itself!因此,下次您将尝试将其与普通密码进行比较时,这个普通密码必须与您用来生成散列的密码完全相同!因此,这就是为什么您不必将它存储在其他地方,因为它总是由用户在注册和登录步骤中提供的!

The salt is incorporated into the hash. The compare function simply pulls the salt out of the hash and then uses it to hash the password and perform the comparison.

When a user will log into our system, we should check the password entered is correct or not. Unlike other systems that would decrypt the password in the database (if it is encrypted), and compare it with the one entered by the user, what I do with bcrypt ( given it implements one-way hashing) is encrypt the one entered by the user. To do this, I will pass the password to bcrypt to calculate the hash, but also the password stored in the database associated with the user (hash). This is because, as mentioned before, the bcrypt algorithm used a random segment (salt) to generate the hash associated with the pasword. This was stored along with the password, and you need it to recalculate the hash of the password entered by the user and finally compare with the one entered when registering and see if they match.

Bcrypt 比较不使用 salt 字符串的散列密码和明文密码,因为散列密码包含我们在散列时创建的 salt 字符串。

例如:

以这个简单的密码为例:

546456546456456456456546111

Hashed Password of above plain text using Bcrypt :

$2b $10 $uIKmW3Pvme9tH8qOn/H7uZqlv9ENS7zlIbkMvCSDIv7aup3WNH9W

所以在上面的散列密码中,有三个字段由 $符号分隔。

i) First Part $2b $ identifies the bcrypt algorithm version used.

Ii)第二部分 $10 $10是成本因素(在我们创建咸字符串时,只有盐轮。如果我们做15轮,那么值将是 $15 $

Iii)第三部分是第一个 22字符(除了}字符串之外什么都没有) 在这种情况下,它是

UuIKmW3Pvme9tH8qOn/H7u

剩下的字符串是散列密码。 因此,基本上,saltedHash = salt string + hashedPassword 可以保护您免受彩虹表的攻击。

It is just a fixed length string.

console.log("");
var salt = bcrypt.genSaltSync(10);
console.log(salt);
hash = bcrypt.hashSync("foobar", salt);
console.log(hash);


console.log("");
var salt = bcrypt.genSaltSync(10);
console.log(salt);
hash = bcrypt.hashSync("foobar", salt);
console.log(hash);


console.log("");
var salt = bcrypt.genSaltSync(10);
console.log(salt);
hash = bcrypt.hashSync("foobar", salt);
console.log(hash);
$2a$10$onmcKV.USxnoQAsQwBFB3e
$2a$10$onmcKV.USxnoQAsQwBFB3eytL3UZvZ5v/SudaWyaB9Vuq9buUqGO2


$2a$10$mwQfdyVS9dsO4SuxoR5Ime
$2a$10$mwQfdyVS9dsO4SuxoR5ImeG7atz7RXGRXb.c0VHp5zSn1N2VOA.Vq


$2a$10$uVUuJr6LryjchhKEg6PH7u
$2a$10$uVUuJr6LryjchhKEg6PH7unTw8aJGK0i3266c5kqDBLJkf80RHEpq


$2a$10$Y.upG5/54zvJyZacRxP17O
$2a$10$Y.upG5/54zvJyZacRxP17OH60BC0hQRMNfQjJxSWE77fyBrbzalmS