user5299399
user5299399

Reputation:

Verification of Hashing password is not working

I have asked a question of which I did get a lot of great feedback, along with a good answer. I assume that I am doing something wrong with my verification check of the 2 hashes. Perhaps the code in the loop is fine, but my code with understanding of bytes and base64 etc. is the problem?

Here is the original question. Password Hashing - Why salt 60,000 times

Problem is these hashes do not match if (resultHash.Equals(hashPassword))

Code

public string BuildVerify()
{

    string password = "";
    string salt = "";
    byte[] result;


    using (var sha256 = SHA256.Create())
    {
        password = "hovercraft";

        // step 1: you can use RNGCryptoServiceProvider for something worth using
        var passwordHashing = new PasswordHashing();
        salt = passwordHashing.CreateRandomSalt();

        // step 2
        string hash =
           Convert.ToBase64String(sha256.ComputeHash(Encoding.UTF8.GetBytes(salt + password)));

        // step 3
        result = sha256.ComputeHash(Encoding.UTF8.GetBytes(salt + hash));

        // step 4
        for (int i = 0; i < 60000; i++)
        {
            result =
             sha256.ComputeHash(Encoding.UTF8.GetBytes(salt + Convert.ToBase64String(result)));
        }
    }


    // TESTING  VERIFY this works ..

    string SaltAndPwd = string.Concat(password, salt);
    SHA256 sha2 = SHA256Managed.Create();
    byte[] buff = sha2.ComputeHash(Encoding.Unicode.GetBytes(SaltAndPwd));
    string resultHash = Convert.ToBase64String(buff);
    string hashPassword = Convert.ToBase64String(result);

    if (resultHash.Equals(hashPassword))
    {
        // perfect 
    }





    return "";

}


public class PasswordHashing
{

     public string CreateRandomSalt()
     {
        string password = "";
        password = HashPassword.CreateSalt(8) + "=";
        password = password.Replace("/", "c");
        return password;
     }

  }

public static string CreateSalt(int size)
{
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

    byte[] buff = new byte[size];
    rng.GetBytes(buff);
    return Convert.ToBase64String(buff);
}

Update - issue

Ok, I'm using the code from the answer, but obviously my assumptions are not correct as I cannot use my code to verify

            // This should be stored in your DB for example along with the hash result
            var newsalt = SOPasswordHasher.GetSalt();

            // We calculate the hash then store the result. Next time you want to authenticate someone
            // You'll have to reuse the same salt and recalculate the hash then compare 
            // the stored hash with the new one
            var result = Convert.ToBase64String(SOPasswordHasher.Hash("hovercraft", newsalt));

            string SaltAndPwd = string.Concat("hovercraft", newsalt);
            SHA256 sha2 = SHA256Managed.Create();
            byte[] buff = sha2.ComputeHash(Encoding.Unicode.GetBytes(SaltAndPwd));
            string resultHash = Convert.ToBase64String(buff);

            if (result.Equals(resultHash))
            {
                // perfect 
            }

Upvotes: 1

Views: 968

Answers (1)

Nasreddine
Nasreddine

Reputation: 37788

Here's a reusable class that you can use (relying less on converting to base64):

class SOPasswordHasher
{
    /// <summary>
    /// Password Hasher
    /// </summary>
    /// <param name="password">The password you want to hash</param>
    /// <param name="salt">byte array of (crypto-secure) random values</param>
    /// <param name="iterations">Number of iterations. default is 60,000</param>
    /// <returns>Byte array containing the hashed password</returns>

    public static byte[] Hash(string password, byte[] salt, int iterations = 60000)
    {
        using (var sha256 = SHA256.Create())
        {
            byte[] passwordBytes = Encoding.UTF8.GetBytes(password);

            // step 2
            byte[] hash = sha256.ComputeHash(passwordBytes.Concat(salt).ToArray());

            // step 3
            byte[] result = sha256.ComputeHash(salt.Concat(hash).ToArray());

            // step 4
            for (int i = 0; i < iterations; i++)
            {
                result =
                    sha256.ComputeHash(salt.Concat(result).ToArray());
            }

            return result;
        }
    }

    public static byte[] GetSalt(int size = 32)
    {
        byte[] salt = new byte[size];
        using (var cryptoServiceProvider = new RNGCryptoServiceProvider())
        {
            cryptoServiceProvider.GetBytes(salt);
        }
        return salt;
    }
}

and here's a usage example:

// This should be stored in your DB for example along with the hash result
var salt = SOPasswordHasher.GetSalt();

// We calculate the hash then store the result. Next time you want to authenticate someone
// You'll have to reuse the same salt and recalculate the hash then compare 
// the stored hash with the new one
var result = Convert.ToBase64String(SOPasswordHasher.Hash("hovercraft", salt));

Important: I make no guarantee that this code is safe to use since I'm not a security expert. Bruce Schneier said it best: "Amateurs Produce Amateur Cryptography"

Upvotes: 2

Related Questions