113

来自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
});

从上面看,比较中怎么可能没有盐值?我在这里想念什么?

4

6 回答 6

111

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

于 2012-10-23T06:00:12.363 回答
30

我也有与原始海报相同的问题,我环顾四周并尝试不同的事情来理解机制。正如其他人已经指出的那样,盐被连接到最终的哈希值。所以这意味着几件事:

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

这两件事通常在实现中被硬编码,例如bcryptjs的 bcrypt 实现源将盐长度定义为 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');
        }
    });
}
于 2014-05-24T05:23:27.130 回答
15

Bcrypt 比较没有盐字符串的散列密码和明文密码,因为散列密码包含我们在散列时创建的盐字符串。

例如 :

取这个普通密码:

546456546456546456456546111

使用 Bcrypt 的上述纯文本的哈希密码:

$2b$10$uuIKmW3Pvme9tH8qOn/H7uZqlv9ENS7zlIbkMvCSDIv7aup3WNH9W

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

i) 第一部分$2b$标识使用的 bcrypt 算法版本。

ii) 第二部分$10$ 10 是成本因素(在我们创建盐串时只有盐轮。如果我们进行 15 轮,那么价值将是$15$

iii)第三部分是前22 个字符(只不过是盐字符串)在这种情况下,它是

uuIKmW3Pvme9tH8qOn/H7u

剩下的字符串是散列密码。所以基本上,saltedHash = salt string + hashedPassword 可以防止彩虹表攻击。

于 2020-10-21T05:44:50.033 回答
4

因为我自己也有同样的问题,所以我很清楚你在想什么。

您对密码算法中使用的“密钥”和用于减慢加密过程并使黑客更难使用暴力的“盐”有误解。

当您使用普通密码和盐生成散列时,此散列将密码本身用作密钥!因此,下次您将尝试将其与纯密码进行比较时,此纯密码必须与您用于生成哈希的密码完全相同!这就是为什么您不必将其存储在其他地方的原因,因为它始终由用户在注册和登录步骤中提供!

于 2020-04-11T19:58:24.057 回答
2

它只是一个固定长度的字符串。

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
于 2020-10-27T19:38:12.880 回答
1

盐被合并到哈希中。比较函数只是简单地从散列中提取盐,然后使用它来散列密码并执行比较。

当用户登录我们的系统时,我们应该检查输入的密码是否正确。与其他系统会解密数据库中的密码(如果它是加密的)并将其与用户输入的密码进行比较,我对 bcrypt 所做的(假设它实现单向散列)是对输入的密码进行加密用户。为此,我将密码传递给 bcrypt 以计算哈希,同时还将密码存储在与用户关联的数据库中(哈希)。这是因为,如前所述,bcrypt 算法使用随机段(盐)来生成与密码关联的散列。这与密码一起存储,您需要它来重新计算用户输入的密码的哈希值,最后与注册时输入的密码进行比较,看看它们是否匹配。

于 2020-10-15T18:08:24.803 回答