Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome and IE return different SHA hashes

I have written a website that utilizes a SHA-256 hash to validate a user's password. This is a relatively unsecure setup to start with, as most users will have the same username/password. To try and protect it at least a little bit, I do the following:

  1. The client requests a new salt from the server
  2. The client hashes the password with this salt
  3. The client sends the hashed password with the salt back to the server
  4. The server hashes the actual password and compares the two

Here is my code:

C#

//Just for testing!
private static Dictionary<string, string> users = new Dictionary<string, string>() { { "User", "Password" } };

[HttpGet]
public HttpResponseMessage GetSalt()
{
   RNGCryptoServiceProvider secureRNG = new RNGCryptoServiceProvider();
   byte[] saltData = new byte[64];

   secureRNG.GetBytes(saltData);

   HttpResponseMessage response = new HttpResponseMessage();
   response.Content = new StringContent(System.Text.Encoding.Unicode.GetString(saltData), System.Text.Encoding.Unicode);
   return response;
}

[HttpGet]
public bool ValidateUser(string userName, string hashedPassword, string salt)
{
   SHA256Managed hash = new SHA256Managed();         
   if (users.ContainsKey(userName))
   {
       string fullPassword = salt + users[userName];
       byte[] correctHash = hash.ComputeHash(System.Text.Encoding.UTF8.GetBytes(fullPassword));

       if (hashedPassword.ToUpper() == BitConverter.ToString(correctHash).Replace("-",""))
       {
           return true;
       }
   }
   return false;
}

Javascript

$scope.login = function () {
    $http.get('api/Login').success(function (salt) {
        //Hash the password with the salt and validate
        var hashedPassword = sjcl.hash.sha256.hash(salt.toString().concat($scope.password));
        var hashString = sjcl.codec.hex.fromBits(hashedPassword);

        $http.get('api/Login?userName=' + $scope.userName + '&hashedPassword=' + hashString + '&salt=' + salt).success(function (validated) {
            $scope.loggedIn = validated;
        });
    });

This code works fine on Google Chrome, but not on Internet Explorer 11. The problem (as seen in the debugger) is that the hash generated by the javascript is different than that generated by C#.

I suspect this has something to do with character encoding, but haven't found much on the web to prove/disprove this theory (or help with the problem in general). If there is a better way to accomplish this problem, I'm happy to hear about it but would like understanding as to the cause of the original error as well.

Why are the hashes different, and what can I do to fix it?

like image 492
BradleyDotNET Avatar asked Jun 11 '14 04:06

BradleyDotNET


1 Answers

IE does not like Unicode characters in the query string. It also doesn't like some "special" characters that are ASCII. Even though it accepts them correctly, and performs the hash correctly, when you run this code, the salt is "???????" when coming from IE, and the correct string when coming from Chrome.

The simple fix is to just limit the character set of the salt to upper-case, lower-case, and numbers. Using this method, both browsers give the correct hash.

like image 100
BradleyDotNET Avatar answered Sep 21 '22 19:09

BradleyDotNET