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:
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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With