vendredi 5 juin 2015

Storing Hashed Passwords in MSSQL and Comparing the recalled password and salt

I have an Employee Class:

public class Employee
{
    [Key]
    public int EmployeeId { get; set; }

    [Required]
    public string UserId { get; private set; }

    [Required]
    public byte[] Password { get; private set; }

    [Required]
    public byte[] Salt { get; private set; }

    public void SetPassword(string password)
    {
        byte[] salt = Hash.GenerateSalt();

        byte[] hashedPassword = Hash.HashPasswordWithSalt(Encoding.UTF8.GetBytes(password), salt);

        Password = hashedPassword;
        Salt = salt;
    }

    public virtual bool Authenticate(string passedPassword)
    {
        byte[] hashedPassword = Hash.HashPasswordWithSalt(Encoding.UTF8.GetBytes(passedPassword), Salt);

        return Hash.CompareByteArrays(Password, hashedPassword);
    }

}

The SQL Server stores Password and Salt as varbinary(MAX)

Here is the Hash Class:

public class Hash
{
    public static byte[] GenerateSalt()
    {
        const int saltLength = 32;

        using (RNGCryptoServiceProvider randomNumberGenerator = new RNGCryptoServiceProvider())
        {
            byte[] randomNumber = new byte[saltLength];
            randomNumberGenerator.GetBytes(randomNumber);

            return randomNumber;
        }
    }

    private static byte[] Combine(byte[] first, byte[] second)
    {
        byte[] ret = new byte[first.Length + second.Length];

        Buffer.BlockCopy(first, 0, ret, 0, first.Length);
        Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);

        return ret;
    }

    public static byte[] HashPasswordWithSalt(byte[] toBeHased, byte[] salt)
    {
        using (var sha256 = SHA256.Create())
        {
            return sha256.ComputeHash(Combine(toBeHased, salt));
        }
    }

    public static bool CompareByteArrays(byte[] array1, byte[] array2)
    {
        if (array1.Length != array2.Length)
        {
            return false;
        }

        for (int i = 0; i < array1.Length; i++)
        {
            if (array1[i] != array2[i])
            {
                return false;
            }
        }

        return true;
    }
}

I am running a simple Unit Test but it always returns false on the second Assert.

    public void AuthenticateEmployee()
    {
        const string password = "password";

        Employee employee = _context.Object.Employees.First();

        Assert.IsNotNull(employee);

        bool flag = employee.Authenticate(password);

        Assert.IsTrue(flag);
    }

Do I need to modify the Database Column Storage Type? I can't figure out what I am missing.

Thanks in Advance.

Aucun commentaire:

Enregistrer un commentaire