我对密码散列有什么误解?

时间:2017-02-21 12:36:39

标签: node.js cryptography buffer libsodium

据我所知,当输入相同数据时,哈希函数将始终返回相同的结果。但我一直在使用libsodium(通过node-sodium),而这不是正在发生的事情。

我的架构中有这个:

UserSchema.pre('save', function(next) {
    // declare my variables       
    let user = this,
        buf = Buffer.alloc(sodium.crypto_pwhash_STRBYTES, 'ascii'),
        passwordBuf = Buffer.from(user.password, 'ascii'),
        saltedPassBuf,
        hash;
    // only hash the password if it has been modified (or is new)
    if (!user.isModified('password')) return next();
    // generate a salt
    sodium.randombytes_buf(buf, sodium.crypto_pwhash_STRBYTES, 'ascii');
    // add salt to the password
    saltedPassBuf = Buffer.concat([passwordBuf, buf], 128);
    // hash it separately multiple times
    // note, i'm not hashing the hash,
    // I'm hashing the original buffer to see what happens
    // this has no application in production
    hash = sodium.crypto_pwhash_str(saltedPassBuf, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE);
    hash2 = sodium.crypto_pwhash_str(saltedPassBuf, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE);
    hash3 = sodium.crypto_pwhash_str(saltedPassBuf, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE);
    // log it to see what I got -- not for production
    console.log(hash.toString());
    console.log(hash2.toString());
    console.log(hash3.toString());
    // save the salt and the buffer for authentication
    user.salt = buf;
    user.password = hash;
    next();
});

我使用该代码记录了三个不同的字符串。例如

$argon2i$v=19$m=32768,t=4,p=1$ayPVQ1X+xNhWmD9S5AUuaw$1mWusk59AebhzOHhl+j5JpvmRI27Pq57XG5zcAB5R4U
$argon2i$v=19$m=32768,t=4,p=1$PjTYKpfhh1bZh+MV84Y9kA$9+U33nf6efuugsrz15cEKDa5+rAHgYVA5Kqo4F1G3DE
$argon2i$v=19$m=32768,t=4,p=1$Ii8AErmAFc0na9Yi2OgCkw$ySU80Fv9OiOmeT9EV/BWon1Jjck2Lx23nOeCk0wkMPU

现在每个部分的第一部分是相同的,这使得我提交的密码部分是相同的(因为它是被哈希的缓冲区的第一部分)。也许这是我不理解的缓冲区。

但如果buf保持静态,为什么saltedPassBuff的其余部分会发生变化?

编辑:当我不小心提交时编辑完成,编辑完成编写问题

2 个答案:

答案 0 :(得分:1)

除了你的盐之外,pwhash函数(文档是最小的)最有可能还添加了自己的随机盐,它也包含在结果中,以便稍后使用crypto_pwhash_str_verify进行比较。

还有一个“CPU密集型”方面,可能是迭代。仅使用带有salt的哈希函数几乎不能提高安全性。需要添加CPU密集型组件,例如迭代。

重点是让攻击者花费大量时间通过暴力破解密码。

答案 1 :(得分:0)

顾名思义,输出是盐渍的。这意味着在散列之前将随机字符串添加到密码中,并且还单独包含在输出值中。

这样做的目的是打败dictionary attacks。通过在散列之前向每个密码添加随机字符串,可以确保相同的密码以不同方式散列,从而迫使攻击者单独破解每个密码。