Safe Comparison of Password Hashes in C#

For the first blog post in 2025, let’s check a topic many people might not be aware of: how to correctly compare two hashed passwords. Let’s assume they are hashed and not plain text, which would be just another very big WTF 😉

Timing measurements can be attack vectors for online applications. In order to avoid this attack vector the class System.Security.Cryptography.CryptographicOperations offers supports. The method FixedTimeEquals can be used instead of the standard Linq SequenceEquals or a custom Equals method, as it determines the equality of two byte sequences in an amount of time that depends only on the length of the sequences, but not their respective values.

Let me illustrate the usage with a simple piece of code to compare two passwords:

using System.Security.Cryptography;

namespace PasswordVerification;

public class Program
{
    public static void Main()
    {
        string password = "secret_password";
        string userPasswordInput = "secret_password";
        
        // for example simplicity only
        byte[] salt = new byte[8];
        using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) { rng.GetBytes(salt); }
        int iterationCount = 10000;

        // create hashes for passwords
        byte[] hashedPassword = HashPassword(password, salt, iterationCount);
        byte[] hashedUserInput = HashPassword(userPasswordInput, salt, iterationCount);

        // correct way: safe comparison of hashed passwords
        bool isPasswordCorrect = CryptographicOperations.FixedTimeEquals(hashedPassword, hashedUserInput);
        Console.WriteLine(isPasswordCorrect ? "Correct password" : "Wrong password");
    }

    private static byte[] HashPassword(string password, byte[] salt, int iterationCount)
    {
        return new Rfc2898DeriveBytes(password, salt, iterationCount, HashAlgorithmName.SHA256).GetBytes(32);
    }
}

The code first hashes a password stored in the system (example variable password) and compares it with the hash of a password the user entered (example variable userPasswordInput). The comparison operation of the two hashes uses FixedTimeEquals, and therefore the comparison operation will not be aborted after the first different value in byte array. Have fun and Happy coding 🚀!