Cryptographically safe password hashing and check methods

Provided methods allow to get a rainbow tables-proof password hash and to check a password against that hash.
Usage example:

static void Main(string[] args)
{
	var pwd = "11122334455";
	Console.WriteLine("Password: " + pwd);
	var hash = GetPasswordHash(pwd, null);
	Console.WriteLine(hash);

	Console.WriteLine(CheckPassword(hash, "11122334455"));
	Console.WriteLine(CheckPassword(hash, "1112233445"));

	Console.ReadKey();
}

Methods themselves:

private static string GetPasswordHash(string password, byte[] salt)
{
	Rfc2898DeriveBytes generator = new Rfc2898DeriveBytes(password, 32);
	generator.IterationCount = 16384;
	if (salt != null)
	{
		generator.Salt = salt;
	}

	byte[] hashBytes = generator.GetBytes(32);
	byte[] saltBytes = generator.Salt;

	return Convert.ToBase64String(saltBytes) + "|" + Convert.ToBase64String(hashBytes);
}

private static bool CheckPassword(string hash, string password)
{
	// Get salt value from the provided password hash
	string[] hashParts = hash.Split(new string[] { "|" }, StringSplitOptions.None);
	byte[] hashBytes = Convert.FromBase64String(hashParts[0]);

	// Get hash of the provided password with the salt previuously used to hash the correct password
	string passwordHash = GetPasswordHash(password, hashBytes);

	// Compare (in cryptographically safe way) the storead and calculated password hashes
	return Equals(System.Text.Encoding.ASCII.GetBytes(hash), System.Text.Encoding.ASCII.GetBytes(passwordHash));
}

private static bool Equals(byte[] value1, byte[] value2)
{
	uint diff = (uint)value1.Length ^ (uint)value2.Length;

	for (int i = 0; i < value1.Length && i < value2.Length; i++)
	{
		diff |= (uint)(value1[i] ^ value2[i]);
	}

	return diff == 0;
}
1 Like