How to implement iterations when hashing passwords?

All we need is an easy explanation of the problem, so here it is.

To securely hash passwords, algorithms such as PBKDF2 do many iterations of a common hash such as SHA1. Are there certain ways that these iterations need to be done to be safe?

In particular, from password-hash.js:

function generateHash(algorithm, salt, password, iterations) {
  iterations = iterations || 1;
  try {
    var hash = password;
    for(var i=0; i<iterations; ++i) {
      hash = crypto.createHmac(algorithm, salt).update(hash).digest('hex');
    }

    return algorithm + '$' + salt + '$' + iterations + '$' + hash;
  } catch (e) {
    throw new Error('Invalid message digest algorithm');
  }
}

Is this a safe way to hash the password? I can imagine that if you have an algorithm such as this that does:

HMAC(HMAC(HMAC(password)))

then there exists some faster function

HMAC3(password)

that gives the same output. Is this the case?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Yes, there are several requirements for an iterative hash function:

  • It should not be possible to do any precomputation, such as using rainbow tables.
  • The implementation should avoid running into cycles or fixed points in the hash function.
  • The implementation should be as fast as possible, because that is what the attacker would use.

Especially on the final point the example code is lacking. The crypto.createHmac(algorithm, salt) should really be outside of the loop. Because the attacker hashes many passwords with the same salt, he can even place the createHmac call outside of the password loop, e.g:

hmac = crypto.createHmac(algorithm, salt)
for (password in allpasswords) {
    var hash = password;
    for(var i=0; i<iterations; ++i) {
        hash = hmac.update(hash).digest('hex');
    }
    ...
}

This gives the attacker an advantage when cracking passwords, which would be avoided if the HMAC used the password instead of the salt as the key, as PBKDF2 does.

By implementing the given code in C and doing some optimizations, I managed to get it to be 10 times faster than the original NodeJS implementation. This means that an attacker can crack passwords 10 times faster than you intended, without even using a GPU or FPGA.

So there does exist a function that does a fast version of HMAC(HMAC(HMAC(password))), simply because HMAC does much the same work in every iteration.

I wrote a blog post about this.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply