1

It is my understanding that a hash function will always return the same results when fed the same data. But I've been using libsodium (via node-sodium) and that is not what is happening.

I have this in my schema:

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();
});

I get three different strings logged with that code. e.g.

$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

Now the first part of each of those is the same, making me thing the submitted password part is the same (since it is the first part of the buffer that is being hashed). So maybe it's buffers I don't understand.

But if buf remains static, why would the rest of saltedPassBuff change?

edit: had not finished writing when I accidentally submitted, edited to finish writing the question

The E
  • 697
  • 1
  • 9
  • 23

2 Answers2

1

In addition to your salt the pwhash function (documentations is minimal) most likely also adds its own random salt which is also included in the result for later comparison using crypto_pwhash_str_verify.

There is also a "CPU intensive" aspect, probably an iteration. Just using a hash function with a salt does little to improve the security. A CPU intensive component needs to be added such as iteration.

The point is to make the attacker spend a lot of time finding passwords by brute force.

zaph
  • 111,848
  • 21
  • 189
  • 228
  • this turns out to be the case. Which also halves the amount of code in my .pre() function. I think I'm not going to go into how libsodium tracks what salt is added. – The E Feb 21 '17 at 13:34
0

As the name alludes, the output is salted. This means that a random string was added to the password before hashing, and also included in the output value separately.

The purpose of this is to defeat dictionary attacks. By adding a random string to each password before hashing, you ensure that the same password will hash differently, forcing the attacker to crack every password separately.

Nick Johnson
  • 100,655
  • 16
  • 128
  • 198
  • I don't think that answers what I'm asking. I am adding random data through the `randombytes_buf()` function but that happens once, and the hashing function is hashing the same set of data each time it runs. Unless you're saying that the `crypto_pwhash_str()` is ALSO adding random bytes before running the actual hash. Is that the case? if so, how do you authenticate? – The E Feb 21 '17 at 13:06
  • @Nick Johnson The salt also insurers that two passwords do not hash to the same value thus leaking that two users have the same password. – zaph Feb 21 '17 at 13:28
  • @TheE Yes, `crypto_pwhash_str` adds a salt, as per [the docs](https://download.libsodium.org/doc/password_hashing/the_argon2i_function.html). You don't need to add your own; it's intended as a complete password hashing solution. – Nick Johnson Feb 22 '17 at 11:36