Iterations and salt
OWASP's Password Storage Cheat Sheet recommends at least 600,000 iterations with HMAC-SHA256, 220,000 with HMAC-SHA512, and 1,400,000 with HMAC-SHA1 (legacy systems only). Use a new random salt of at least 16 bytes for every password (RandomNumberGenerator.GetBytes(16)) and store it next to the hash, along with the iteration count and algorithm so you can raise them later.
Use Rfc2898DeriveBytes.Pbkdf2
The static Rfc2898DeriveBytes.Pbkdf2 method takes every setting explicitly. The old new Rfc2898DeriveBytes(password, salt) constructor silently uses HMAC-SHA1 and 1,000 iterations; on .NET 10 it is marked obsolete (warning SYSLIB0060). Compare derived hashes with CryptographicOperations.FixedTimeEquals.
ASP.NET Core Identity uses PBKDF2
Identity's password hasher is PBKDF2: HMAC-SHA512 with 100,000 iterations since .NET 7 (HMAC-SHA256 with 10,000 before). The Identity password hash decoder shows the salt, iterations and subkey inside a stored hash.
FAQ
What is PBKDF2?
Password-Based Key Derivation Function 2: it runs HMAC over the password and salt many times, so each guess costs an attacker the same work. It is used to store passwords and to turn passwords into encryption keys.
How many PBKDF2 iterations should I use?
OWASP recommends at least 600,000 with HMAC-SHA256 or 220,000 with HMAC-SHA512. Measure on your servers; raise the count over time and rehash at sign-in.
How do I use PBKDF2 in C#?
Rfc2898DeriveBytes.Pbkdf2(password, salt, iterations, HashAlgorithmName.SHA256, 32). Store the salt, iterations and algorithm with the result.
PBKDF2, bcrypt or Argon2?
OWASP prefers Argon2id, then scrypt; bcrypt for legacy systems; PBKDF2 when FIPS-140 compliance is required. .NET has PBKDF2 built in; bcrypt and Argon2 need a package.