Hash Password Before Sending it to Server in ASP.NET

Hashing is a process in which a password (from human understand form) is converted into a non-understandable form of string. That string is not directly, nor indirectly understandable by the humans.

Salting is another technique used to make the hashing process faster. Salt is just a bunch of more characters that you add to the input before the hashing process takes place. This would create a much more strong hashing result and the string returned would be even stronger than before. But salting requires you to save the salt for each user.


Lets see that with the example : 

Step 1:  Create one js file and put the below code (Example: Hashing.js)
The below function is used to Hash password at client side. It will accept one paramer "s" which will be your plain text and returns Hashed text.


function SHA256(s) {
    var chrsz = 8;
    var hexcase = 0;
    function safe_add(x, y) {
        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        return (msw << 16) | (lsw & 0xFFFF);
    }

    function S(X, n) { return (X >>> n) | (X << (32 - n)); }
    function R(X, n) { return (X >>> n); }
    function Ch(x, y, z) { return ((x & y) ^ ((~x) & z)); }
    function Maj(x, y, z) { return ((x & y) ^ (x & z) ^ (y & z)); }
    function Sigma0256(x) { return (S(x, 2) ^ S(x, 13) ^ S(x, 22)); }
    function Sigma1256(x) { return (S(x, 6) ^ S(x, 11) ^ S(x, 25)); }
    function Gamma0256(x) { return (S(x, 7) ^ S(x, 18) ^ R(x, 3)); }
    function Gamma1256(x) { return (S(x, 17) ^ S(x, 19) ^ R(x, 10)); }
    function core_sha256(m, l) {
        var K = new Array(0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0xFC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x6CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2);
        var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19);
        var W = new Array(64);
        var a, b, c, d, e, f, g, h, i, j;
        var T1, T2;
        m[l >> 5] |= 0x80 << (24 - l % 32);
        m[((l + 64 >> 9) << 4) + 15] = l;
        for (var i = 0; i < m.length; i += 16) {
            a = HASH[0];
            b = HASH[1];
            c = HASH[2];
            d = HASH[3];
            e = HASH[4];
            f = HASH[5];
            g = HASH[6];
            h = HASH[7];
            for (var j = 0; j < 64; j++) {
                if (j < 16) W[j] = m[j + i];
                else W[j] = safe_add(safe_add(safe_add(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
                T1 = safe_add(safe_add(safe_add(safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
                T2 = safe_add(Sigma0256(a), Maj(a, b, c));
                h = g;
                g = f;
                f = e;
                e = safe_add(d, T1);
                d = c;
                c = b;
                b = a;
                a = safe_add(T1, T2);
            }
            HASH[0] = safe_add(a, HASH[0]);
            HASH[1] = safe_add(b, HASH[1]);
            HASH[2] = safe_add(c, HASH[2]);
            HASH[3] = safe_add(d, HASH[3]);
            HASH[4] = safe_add(e, HASH[4]);
            HASH[5] = safe_add(f, HASH[5]);
            HASH[6] = safe_add(g, HASH[6]);
            HASH[7] = safe_add(h, HASH[7]);
        }
        return HASH;
    }

    function str2binb(str) {
        var bin = Array();
        var mask = (1 << chrsz) - 1;
        for (var i = 0; i < str.length * chrsz; i += chrsz) {
            bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i % 32);
        }
        return bin;
    }

    function Utf8Encode(string) {
        string = string.replace(/\r\n/g, "\n");
        var utftext = "";
        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);
            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if ((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }
        }
        return utftext;
    }

    function binb2hex(binarray) {
        var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
        var str = "";
        for (var i = 0; i < binarray.length * 4; i++) {
            str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 0xF) +
                hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8)) & 0xF);
        }
        return str;
    }

    s = Utf8Encode(s);
    return binb2hex(core_sha256(str2binb(s), s.length * chrsz));

}

Step 2: Create a class and put the below code (Example: Security.cs)
This class is used to generate salt bits and to Hash password at server side.

       //This function is used to get Hashed password
        public static dynamic getHashSha256(string text)
        {
            SHA256 sha256 = SHA256Managed.Create();
            byte[] bytes = Encoding.UTF8.GetBytes(text);
            byte[] hash = sha256.ComputeHash(bytes);
            var Hashda = GetStringFromHash(hash);
            return Hashda;
        }

        //This function will return the Hashed string 
        private static string GetStringFromHash(byte[] hash)
        {
            StringBuilder result = new StringBuilder();
            for (int i = 0; i < hash.Length; i++)
            {
                result.Append(hash[i].ToString("X2"));
            }
            return result.ToString();

        }

        public static class SaltGenerator
        {
            private static RNGCryptoServiceProvider m_cryptoServiceProvider = null;
            private const int SALT_SIZE = 24;

            static SaltGenerator()
            {
                m_cryptoServiceProvider = new RNGCryptoServiceProvider();
            }

            public static string GetSaltString()
            {
                // Lets create a byte array to store the salt bytes
                byte[] saltBytes = new byte[SALT_SIZE];

                // lets generate the salt in the byte array
                m_cryptoServiceProvider.GetNonZeroBytes(saltBytes);

                // Let us get some string representation for this salt
                string saltString = ASCIIEncoding.ASCII.GetString(saltBytes);

                // Now we have our salt string ready lets return it to the caller
                return saltString;
            }

        }

Now we have the code to hash password at Clientside as well as ServerSide.

Step 3: Let's register a user and create login credentials to him and save the hashed password as well as the Salt bits to the database.

        //user name
        string Username="admin"; 

        //Generate  Salt bits
        string salt=Security.SaltGenerator.GetSaltString();
     
      //Generate Hash for the plaintext "admin"
      string Hashedpassword=Security.getHashSha256("admin");

      //Append the salt bits to the hashed password
      Hashedpassword =Hashedpassword.Trim().ToUpper() + salt;

     //Hash again to make it more difficult to hack
    string FinalHashedData=Security.getHashSha256(Hashedpassword );

     //Now save the  credentials and salt bits to the database 
      Example: 
           username="admin"
           password="CA2F76291B9CF2F93D50565361F90DEDF11734260B8792E69DFC81D6BEC68AE9";
           salt="?(Inm$??.??? ?????lN?t??";

Now the database is having login credentials and salt bits to the user "admin".


Step 4: Let's create a login page where we can enter our credential to login to our application.
(Example: Login.aspx)


Remember we have created a Hashing.js file to hash the password at client side. So give the reference to that file in Login.aspx page.   

 <script src="/js/Hashing.js"></script>

 //I have the following fields in my login page i.e Login.aspx
 <input type="text" id="txtusername"  runat="server" clientidmode="static" />

 <input type="password" id="txtpassword" runat="server" clientidmode="static" />

  <asp:Button ID="btnLogin" runat="server" Text="Login" OnClick="btnLogin_Click"         OnClientClick="return getHash();" />

                                          

                                      

<script type="text/javascript">

         function getHash()
         {
             //Hash the plain text
             var HashedPassword=SHA256($("#txtpassword").val());
            
             //put the hashed text to password feild
             $("#txtpassword").val(HashedPassword);
             return true;
         }

</script>


Now we have hashed the password at client side using SHA256() function. Let's pass this hashed text to server, add salt bits to it, then hash again and compare the password with database value.


Step 5: Let's see btnLogin_Click() function in Login.aspx.cs page.

protected void btnLogin_Click(object sender, EventArgs e)
{
        //Check username exists and get the salt by using the username
         string salt = db.DummyLogin.Where(x => x.user_name == txtusername.Value)
                             .Select(x=>  x.salt).FirstOrDefault();
      
       //Append salt to the already hashed password (i.e. Hashed at client side)
       string Password =(txtpassword.Value.Trim()).ToUpper() + salt_bits.Trim();

       //Hash again then compare the password
        var FinalHash= Security.getHashSha256(Password);

      //Now you have completely hashed password , go ahead and compare with the database and                  return the result                      
}

That's it. you are all done :)

Note: To make even more secure, if the credentials are correct then generate new salt and hash the password again and store the result in DB. 



Comments