node.bcrypt.js如何在没有盐的情况下比较散列密码和明文密码?

时间:2012-10-23 03:57:10

标签: node.js bcrypt

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

从上面来看,如何在比较中不涉及盐值?我在这里缺少什么?

6 个答案:

答案 0 :(得分:73)

盐被合并到散列中(作为明文)。 compare函数简单地将salt从哈希中拉出,然后使用它来哈希密码并执行比较。

答案 1 :(得分:22)

我也和原版海报一样有同样的问题,看了一下,尝试了不同的东西来理解机制。正如其他人已经指出的那样,盐被连接到最终的哈希值。所以这意味着一些事情:

  1. 算法必须知道盐的长度
  2. 还必须知道最终字符串中盐的位置。例如如果从左或右偏移特定数字。
  3. 这两件事通常在实施例中被硬编码,例如bcryptjs的bcrypt实现源将salt长度定义为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');
            }
        });
    }
    

答案 2 :(得分:1)

因为我本人也有同样的问题,所以我确切地知道您在想什么。

"Secret Key"算法中使用的Cryptographic与用于减慢加密过程并使黑客更难使用蛮力的“ Salt”之间存在误解。

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

答案 3 :(得分:1)

Bcrypt比较不带盐字符串的哈希密码和纯文本密码,因为哈希密码包含我们在哈希时创建的盐字符串。

例如:

输入此普通密码:

546456546456546456456546111

使用Bcrypt加密上述纯文本密码:

$ 2b $ 10 $ uuIKmW3Pvme9tH8qOn / H7uZqlv9ENS7zlIbkMvCSDIv7aup3WNH9W

因此,在上面的哈希密码中,存在三个用 $ 符号分隔的字段。

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

ii)第二部分 $ 10 $ (是成本因素)(创建盐串时只进行盐舍入。如果进行15次舍入,则值将为 $ 15 $ < / strong>

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

uuIKmW3Pvme9tH8qOn / H7u

其余字符串为哈希密码。 因此,基本上来说,saltedHash = salt string + hashedPassword可以防止彩虹表攻击。

答案 4 :(得分:1)

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

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

答案 5 :(得分:0)

将盐合并到哈希中。比较功能只是将盐从哈希表中提取出来,然后用它来哈希密码并执行比较。

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