I've finally had a chance to make an answer to this, but I want it noted that Bruno Costa had a great answer, and this is only an improvement on his.
First and foremost:
The only question I have is am I ok to store the iterations in the database record or is this a bad practice? I was planning on creating a column to store salt, another for the hashed password, and possibly one for the amount of iterations.
This is 100% acceptable, and encouraged. It's necessary, especially to change the iteration count (which you should be doing annually), as you'll want to increase it a little regularly. (There's other guidance out there for how often and how much to increase it, but basically do what is necessary to keep the user cost low-ish, and keep attackers having to work for it.)
My thought with the iterations was that I read that it should increase every so often so when creating new users or they update their passwords it would pull the value to pass in from the database.
You should increase the iteration count when necessary, and do the rehashing on user-login. Forget about making them change their password, you can change their iteration and salt each time they login (as at that moment you absolutely must know the password anyway). I even go out-of-the-way to change the salt each time users login to my websites.
Now some notes on the other answer:
Rfc2898DeriveBytes only gives you 20 bytes of entropy (as indicated), I always use one of the constructors that takes a
HashAlgorithmName, and I always provide
HashAlgorithmName.SHA512. This gives you entropy up to 64 bytes, so you can use your
32, or go all the way up to the
64. (That's up to you.)
Answering your additional question about the iteration count, there is nothing wrong with that. You can even use that as a
pepper, different users can have slightly different iteration counts. Which makes the job of a hacker harder. In some scenarios people also store the actually algorithm that was used to hash the password. That might allow you to switch between algorithms in a easier fashion.
There are some good and bad points here (alright, I shouldn't say "bad", just less optimal):
- DO store the
- DO store the
HASH_ALGORITHM_NAME at your discretion (probably worth doing so);
- DO NOT intentionally vary
ITERATION_COUNT per user, this offers no advantage to securing the user, especially if the attacker gets a copy of the database, and only complicates your code and introduces potential vulnerabilities;
- DO consider adding an efficient random delay to prevent side-channel analysis and timing attacks;