1

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 
            }
Community
  • 1
  • 1
  • So it is a matter of whether this line in your loop is going to match up with your verfication - which from what you are saying it is not. result = sha256.ComputeHash(Encoding.UTF8.GetBytes(salt + Convert.ToBase64String(result))); – Tom Stickel May 20 '16 at 19:14
  • 1
    You should just use bcrypt or PBKDFv2, which does everything right. – SLaks May 20 '16 at 19:17
  • @SLaks From the other related question it's a requirement from his job to use their own method. NIH syndrome I guess. – Nasreddine May 20 '16 at 19:18
  • 2
    @Nasreddine Even still, this is a great example of picking your battles. This is not a battle to give up on. Ask any security professional if rolling your own hashing algorithm is a good idea... – Lews Therin May 20 '16 at 19:20
  • 2
    For example, you're using too much base64, and you have timing issues. **Don't do this!** – SLaks May 20 '16 at 19:20
  • Your `resultHash` is generated completely differently from the original hash. Why do you expect that to work? – SLaks May 20 '16 at 19:24
  • 1. yes, i'm a contractor and its a fortune 50 company of which is well known company... they are not budging it is my 2nd week on the job 2. I didn't write that loop with the base64, but i agree with you... The biggest issue is that I can't seem to get the hashes to validate . Not sure if I put this in a .NET fiddle that it would help make it easier for you guys to figure out the problem. .. thx in advance let me know –  May 20 '16 at 19:27
  • @SLaks "Cause i'm stupid" - in all seriousness and being humble ... I realize it is different , but I'm not quite sure how to go about fixing it .. any pointers or help is greatly appreciated. –  May 20 '16 at 19:29
  • If you want the second hash to match, you need to construct it using exactly the same code as you constructed the first hash (you should pull that code into a separate function for reuse). – SLaks May 20 '16 at 19:30
  • @SLaks The problem I'm having is that when I'm trying to code the 2nd hash the same way I'm running into the problem of which I do not already have the new hash , thus --> (salt+password) + hash ( where do i get that hash as the whole point is that I'm trying to get the hash... –  May 20 '16 at 19:38
  • No; you're trying to build the hash in the same way and see if it matches. – SLaks May 20 '16 at 19:39
  • byte[] buff = sha2.ComputeHash(Encoding.Unicode.GetBytes(SaltAndPwd + hash)); ? the hash is not known ... need help –  May 20 '16 at 19:42
  • [Salted Password Hashing - Doing it Right](https://crackstation.net/hashing-security.htm) I am not sure what `This should be stored in your DB for example along with the hash result` means but it is the hashed PW *and* the salt used that needs to be saved – Ňɏssa Pøngjǣrdenlarp May 20 '16 at 20:06

1 Answers1

2

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"

Nasreddine
  • 36,610
  • 17
  • 75
  • 94
  • I still am not able to validate/verify the hash created. I will post the code above in the question at the bottom - thx –  May 20 '16 at 19:57
  • 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 } –  May 20 '16 at 20:00
  • I'm not sure what you're trying to "verify". The method you're using to generate your `buff` variable doesn't match the one used in the `Hash` method. There's no reason for them to match. – Nasreddine May 20 '16 at 20:01
  • Look at my usage example. first time a user registers you store the generated salt and the result of `Hash`ing his password. The next time he's trying to authenticate you read back the stored `salt` then pass the password he provides during authentication to the `Hash` method with the read back salt then compare the result you're getting WITH the stored hash value from when he registered. – Nasreddine May 20 '16 at 20:04
  • 1
    @Nasreddine He is probably just attempting to mock up something on the fly so if a computehash is used again as if a user was trying to login to a website, that the password and salt would generate the exact same hash, obviously what he is doing will not work , but he does not understand that he MUST use the same method to verify. – Tom Stickel May 20 '16 at 20:54
  • 1
    @MillRunner - basically you just want to verify so you would then do `var verifyResult = Convert.ToBase64String(SOPasswordHasher.Hash("hovercraft", newsalt));` Then check if it is the same `if (result.Equals(verifyResult)) { ... }` – Tom Stickel May 20 '16 at 20:56
  • 1
    @TomStickel - thanks that works, and of course a big thanks to Nasredddine ! –  May 20 '16 at 21:00