Parameters for PBKDF2 for password hashing

Your starting point

PBKDF2-HMAC-SHA-256

number of iterations desired = 1024

length of the salt in bytes = 16

length of the derived key in bytes = 4096


Algorithm

Ok - PBKDF2-HMAC-SHA-256 is a solid choice, though if you're running on any modern 64-bit CPU, I would strongly recommend PBKDF2-HMAC-SHA-512 instead, because SHA-512 requires 64-bit operations that reduce the margin of a GPU based attacker's advantage, since modern GPU's don't do 64-bit as well.


Salt

16 bytes of salt is fine, as long as it is cryptographically random and is unique per password. Normal recommendations are in the 12-24 byte range, with 16 considered quite solid.


Output and Iterations

4096 bytes of output is ACTIVELY BAD! SHA-256 has a native output size of 32 bytes. PBKDF2/RFC2898 states that in this case, you'll first run 1024 iterations to get the first (leftmost) 32 bytes, then another 1024 iterations for the next 32 bytes, and so on for 128 times in total to get the full 4096 bytes of output you requested.

So, you did 131072 iterations total, and got 4096 bytes of output. The attacker is going to do 1024 iterations total, and compare their 32 bytes of output to the first (leftmost) 32 bytes of your output - if those are the same, they guessed correctly! You just gave every attacker a 128:1 advantage!

Instead, if you're happy with the speed, you should do 131072 iterations with 32 bytes of output - you will spend the SAME amount of time you are now (so it's free!), and your attackers will need to spend 128 times more time than they do now!

  • NOTE: If you move to PBKDF2-HMAC-SHA-512, you can use up to 64 bytes of output, and each iteration will take slightly longer.

Never get more output for password hashing than the native output of your hash function, i.e. 20 bytes for SHA-1, 32 for SHA-256, 64 for SHA-512. You can optionally store less, but it doesn't save you any computations. I would recommend storing at least 28 bytes of output (224 bits, which is twice 112 bits, the nominal security of 3DES).

Note that output length values are pure binary output - BEFORE you BASE64 or hexify them, if you do (personally, I'd store the raw binary - it uses less space, and requires one less conversion).


  1. 8 bytes salt is fine, because that is globally unique when randomly generated, and that's the purpose of a salt: uniqueness. Too big is not an issue so estimating on the high side is fine, except you waste a little bit of storage.

  2. 32 bytes would be good for a derived key length (most hashing algorithms will output between 16 and 64 bytes, where 64 is just overkill). Your value of 4096 is definitely overkill -- I actually hope you mistook bytes for bits there!

  3. Iterations is very simple: as many as possible on your hardware. If a login may take up to half a second, then benchmark how many iterations you can do before it passes half a second. In 2020, 400 000 is a reasonable value for a low-end server (average server CPUs can handle more iterations).

  4. SHA-256 is a good algorithm if you have to choose one. Avoid MD5, SHA-1, and anything else with known attacks. They may be secure for this purpose (even MD5), but attacks only ever get better and you might as well not use something that's already partially broken.

If you're running on an underpowered system (e.g. Raspberry Pi), you might want to consider different hardware depending on how secure things should be, or make the login take a longer time. A login is typically done only once a day or so anyway, so waiting 10 seconds might be reasonable depending on your application.


My first suggestion is to use the default password storage mechanism of your platform. Functions like PHP's password_hash take all the worry and fuss out of password storage.

Assuming that you can't do that, I recommend using bcrypt, or maybe even the newer scrypt functions. bcrypt is more difficult to crack when using parallel operations on a GPU. scrypt taxes memory as well as the CPU. This answer explains all this is great detail.

Assuming that you're stuck with pbkdf2 for whatever reason...

Salt: According to this 2013 answer by Thomas Pornin, 128 bits or 16 bytes is sufficient. The recommendations of the Crackstation is 192 bits or 24 bytes. I think anywhere in that range is safe. Personally, I would go with the 24 bytes as the salt length (assuming that you don't hang on generating random data) doesn't really contribute to the hash performance. Be sure to use a CSPRNG for generating the salt.

Password Length: Thomas Pornin's answer recommends 12 bytes, Crackstation 24. Again, I would tend to go with the larger size but think anything in that range is safe.

Iterations: The number of iterations should be as many as you can tolerate. So start testing the performance of the hashing. I've seen recommendations for 0.05-0.10 seconds but think those are just estimates. If you have computational resources to spare, perhaps you can go a bit higher (too much higher will slow authentication too much). If you're scarce on computational resources, go smaller.

Summary:

number of iterations desired        = max you can tolerate
length of the salt in bytes         = 16-24
length of the derived key in bytes  = 12-24