My team and I have ended up creating this class, which is called directly from ASP.NET Identity as a custom password hasher. I'd like to know whether this would be overkill/use a lot of CPU, specially because the site is going to be hosted in Azure.To take into account:  HashPassword is called when a new user is being created by IdentityVerifyHashedPassword is called when a user logs inprivate const int SaltByteLength = 16;private const int DerivedKeyLength = 20;private const int minIterationCount = 44000;private const int maxIterationCount = 50000;public string HashPassword(string password){    return CreateSecurePasswordHash(password);}public PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword){    providedPassword = Convert.ToBase64String(ComputeHash(providedPassword));    bool result = ComparePasswordHashes(providedPassword, hashedPassword);    return result ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;}private static byte[] ComputeHash(string password){    using (MemoryStream ms = new MemoryStream())    using (StreamWriter sw = new StreamWriter(ms))    {        sw.Write(password);        sw.Flush();        ms.Position = 0;        using (SHA512CryptoServiceProvider provider = new SHA512CryptoServiceProvider())            return provider.ComputeHash(ms);    }}private static string CreateSecurePasswordHash(string password){    byte[] hashedPassword = ComputeHash(password);    byte[] salt = GenerateSecureSalt();    Random rand = new Random();    int iterationCount = rand.Next(minIterationCount, maxIterationCount);    byte[] hashValue = GenerateSecureHashValue(hashedPassword, salt, iterationCount);    byte[] iterationCountBtyeArr = BitConverter.GetBytes(iterationCount);    byte[] valueToSave = new byte[SaltByteLength + DerivedKeyLength + iterationCountBtyeArr.Length];    Buffer.BlockCopy(salt, 0, valueToSave, 0, SaltByteLength);    Buffer.BlockCopy(hashValue, 0, valueToSave, SaltByteLength, DerivedKeyLength);    Buffer.BlockCopy(iterationCountBtyeArr, 0, valueToSave, salt.Length + hashValue.Length, iterationCountBtyeArr.Length);    return Convert.ToBase64String(valueToSave);}private static byte[] GenerateSecureSalt(){    using (RNGCryptoServiceProvider rngCSP = new RNGCryptoServiceProvider())    {        byte[] salt = new byte[SaltByteLength];        rngCSP.GetBytes(salt);        return salt;    }}private static byte[] GenerateSecureHashValue(byte[] password, byte[] salt, int iterationCount){    using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterationCount))    {        return pbkdf2.GetBytes(DerivedKeyLength);    }}private static bool ComparePasswordHashes(string guess, string saved){    if (string.IsNullOrEmpty(guess) || string.IsNullOrEmpty(saved))        return false;    byte[] passwordGuess = Convert.FromBase64String(guess);    byte[] savedPassword = Convert.FromBase64String(saved);    byte[] salt = new byte[SaltByteLength];    byte[] actualPasswordByteArr = new byte[DerivedKeyLength];    int iterationCount = savedPassword.Length - (salt.Length + actualPasswordByteArr.Length);    byte[] iterationCountByteArr = new byte[iterationCount];    Buffer.BlockCopy(savedPassword, 0, salt, 0, SaltByteLength);    Buffer.BlockCopy(savedPassword, SaltByteLength, actualPasswordByteArr, 0, actualPasswordByteArr.Length);    Buffer.BlockCopy(savedPassword, (salt.Length + actualPasswordByteArr.Length), iterationCountByteArr, 0, iterationCount);    byte[] passwordGuessByteArr = GenerateSecureHashValue(passwordGuess, salt, BitConverter.ToInt32(iterationCountByteArr, 0));    return ConstantTimeComparison(passwordGuessByteArr, actualPasswordByteArr);}private static bool ConstantTimeComparison(byte[] passwordGuessHash, byte[] savedHash){    uint difference = (uint)passwordGuessHash.Length ^ (uint)savedHash.Length;    for (var i = 0; i < passwordGuessHash.Length && i < savedHash.Length; i++)    {        difference |= (uint)(passwordGuessHash[i] ^ savedHash[i]);    }    return difference == 0;}All connections to my website are done strictly through TLS 1.2. Also, in the application where this code is used, absolutely no information about the user is stored, other than username, password and email. All other information is temporary and is deleted upon the user logging out.
Secure custom password hashing
c#;authentication
At first glance, your code seems to do the right thing security wise and is reasonable performance wise. If performance becomes a problem, you can still reduce the iteration count of pbkdf2. But considering the original recommandation in RFC 2898 (at least 1000 iteration) in 2000 and the increase in processing power since then, 50000 iteration seems pretty conservative to me.It's also worth considering that your user will enter his password only once per session so the performance cost of checking a password will probably be negligible. But as always with performance question the best answer is to bench your code and decide wether its performance is acceptable or not.P.S. I'm not a security expert so don't make any critical decision based on my opinion