30

When creating a hash with PBKDF2, it allows the developer to choose the size of the hash. Is longer always better? Also, what about the size of the random salt? Should that be the same size as the hash?

EDIT: Particularly in hashing passwords.

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
blesh
  • 485
  • 1
  • 4
  • 9

3 Answers3

26

For the hash function, you want to use a function for which the most efficient platform type (the one which will produce the more hash computations per second and per dollar) is the machine that you intend to use (i.e. a PC). That's because you are in a weapon race with the attacker, and the attacker can buy other kinds of hardware to get an edge over you (such as a GPU). GPU are very good at 32-bit arithmetics, but not at 64-bit arithmetics, whereas a PC (in 64-bit mode) will be quite fast at the latter.

Thus, use a hash function which runs on 64-bit arithmetic operations. This points at SHA-512.

PBKDF2 is a key derivation function: it produces an output of configurable size. For password hashing, you want the size to be large enough to deter generic preimage attacks (i.e. trying random passwords until a match is found), so this would need, say, at least 80 bits of output. If only for making the security more convincing for the unwary, and also for aesthetics, go for the next power of 2: a 128-bit output. It is not useful to go beyond that.

The salt must be unique -- as unique as possible. An easy way to achieve unique salt values is to generate salts with a cryptographically strong PRNG: probability of reusing a salt value will be sufficiently low to be neglected if these random salts are large enough, and "large enough" means "128 bits". So use random 128-bit salts.

Personally, I prefer bcrypt over PBKDF2 for password hashing.

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • Wha you mean that more than 128 bit output "is not useful"? As the entropy of password and salt will no exceed 128bit? Runtimecost? Will the use of HMAC-SHA1 instead of SHA512 change you given numbers of output and salt size? – aggsol Jun 05 '13 at 12:19
  • Given the low security cost of reusing an occasional PBKDF2 salt, the cost to the entropy pool of generating an extra 8 random bytes (and the memory and disk cost to store them), is 128 bits really worth it over 64 bits? Would adding a constant "purpose" string to the salt achieve the goal even better? (I know this is a bit nit-picky; it's just something I've been thinking through recently and was looking for other opinions.) – Rob Napier Jan 15 '14 at 21:05
  • 3
    All these questions about "the entropy pool" are misguided. Entropy does not exhaust like gasoline. If you are doing things properly, then whatever "real entropy" you got for hardware is used as a seed for a cryptographically strong PRNG which will give you gigabytes of pseudorandomness which is indistinguishable (in a strong sense) from random bytes -- and that's _good enough for crypto_. In particular salts, which don't even need to be indistinguishable from randomness; they just need not to repeat too often. – Thomas Pornin Jan 15 '14 at 21:11
  • 1
    Note that for PBKDF2 in password hashing, the output length must be strictly less than or equal to the native hash output size. I.e. for PBKDF2-HMAC-SHA-512, no more than 512 bits of hash output. The reason for this is that if you ask for more, then PBKDF2 specifies concatenating the result of the first bits with the results of , so an attacker will only need to match the first bits to see they've found the password. As the defender, you should simply increase number of iterations, which affects both you and the attacker linearly. – Anti-weakpasswords Feb 22 '14 at 21:10
  • @Anti-weakpasswords But if we hash the result - we should be OK with lengths over the native length. Correct? (I asked about it [here](https://crypto.stackexchange.com/q/54922/1131)) – ispiro Jan 22 '18 at 15:49
  • @ispiro First, there's no real point in hashing the ouput. Second, instead of I iterations at N times the native hash length, do N*I iterations at the native hash length or less. See [my answer here](https://security.stackexchange.com/a/51430/39623) for a more lengthy explanation. – Anti-weakpasswords Jan 23 '18 at 03:32
13

According to the PBKDF2 standard, the minimum recommended size for the salt is 64 bits, though I'd personally recommend 128 bits or higher for a decent safety margin. The size of the salt is independant to your choice of hash.

As far as security is concerned, I recommend choosing a derived key length of at least the same size of your salt's output, with a minimum of 256 bits. Any hash size less than 256-bit is below the security boundary of most modern hash functions anyway.

Choosing a derived key length that is less than the output length of the hash function makes little sense, unless you're using the key for a block cipher that can't handle a key of that size.

In terms of optimal security, I'd suggest SHA-512 as the PRF, with a 512-bit derived key, a 128-bit salt, and as many iterations as your situation can warrant.

Polynomial
  • 132,208
  • 43
  • 298
  • 379
6

In case your platform of choice is .NET, there is an OWASP article specifically dedicated to its Rfc2898DeriveBytes class. Specifically note (emphasis mine):

The built-in .NET implementation of Rfc2898DeriveBytes limits the user to one psudorandom function - HMAC with SHA-1. This is acceptable in most scenarios today, but in the future, a more complex hashing function may be required.

Using PBKDF2 for password storage, one should never output more bits than the base hash function's size. With PBKDF2-SHA1 this is 160 bits or 20 bytes. Output more bits doesn't make the hash more secure, but it costs the defender a lot more time while not costing the attacker. An attacker will just compare the first hash function sized output saving them the time to generate the reset of the PBKDF2 output.

They also have a code sample, which I adjusted per the other answers' guidance:

public static string Hash(string str)
{
    // Generate the hash, with an automatic 16 byte salt
    using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(str, 16))
    {
        rfc2898DeriveBytes .IterationCount = 10000 // or whatever you can afford
        byte[] hash = rfc2898DeriveBytes.GetBytes(20);
        byte[] salt = rfc2898DeriveBytes.Salt;
        return Convert.ToBase64String(salt) + "|" + Convert.ToBase64String(hash);
    }
}
Ohad Schneider
  • 169
  • 1
  • 6
  • .NET Core supports HMAC-SHA216 and HMAC-SHA512 just fine. That article, and this comment, are woefully outdated. – Ian Kemp Sep 13 '21 at 10:52