ASP.NET MVC 3 application, BCrypt.CheckPassword failed

I am working on implementing security in an ASP.NET MVC 3 application, and am using the BCrypt implementation found here to handle encryption and password verification. The user registration screen encrypts the password that the user provides just fine, and the hashed password is stored in the database. I have a problem with password verification on the login page, although I can’t understand why.

My registration controller action contains the following:

[HttpPost] [RequireHttps] public ActionResult Register(Registration registration) { // Validation logic... try { var user = new User { Username = registration.Username, Password = Password.Hash(HttpUtility.HtmlDecode(registration.Password)), EmailAddress = registration.EmailAddress, FirstName = registration.FirstName, MiddleInitial = registration.MiddleInitial, LastName = registration.LastName, DateCreated = DateTime.Now, DateModified = DateTime.Now, LastLogin = DateTime.Now }; var userId = _repository.CreateUser(user); } catch (Exception ex) { ModelState.AddModelError("User", "Error creating user, please try again."); return View(registration); } // Do some other stuff... } 

This is the password. Hash:

 public static string Hash(string password) { return BCrypt.HashPassword(password, BCrypt.GenerateSalt(12)); } 

This is how I handle the login:

 [HttpPost] [RequireHttps] public ActionResult Login(Credentials login) { // Validation logic... var authorized = _repository.CredentialsAreValid(HttpUtility.HtmlDecode(login.username), login.password); if (authorized) { // log the user in... } else { ModelState.AddModelError("AuthFail", "Authentication failed, please try again"); return View(login); } } 

CredentialsAreValid terminates the BCrypt.CheckPassword call:

 public bool CredentialsAreValid(string username, string password) { var user = GetUser(username); if (user == null) return false; return Password.Compare(password, user.Password); } 

Password.Compare:

 public static bool Compare(string password, string hash) { return BCrypt.CheckPassword(password, hash); } 

And finally, this is what BCrypt.CheckPassword does:

 public static bool CheckPassword(string plaintext, string hashed) { return StringComparer.Ordinal.Compare(hashed, HashPassword(plaintext, hashed)) == 0; } 

So yes ... I don’t know what is happening, but what I know is that my boolean authorized in my login controller action always returns false for some reason.

I have used this same BCrypt class in at least several other projects in the past and have never experienced any problems with it. Is ASP.NET MVC 3 some kind of weird, different encoding for published data that I am missing or need to handle differently or something else? Either this, or SQL CE 4 does this (what is the data store that I am currently using)? Everything seems to be okay with my code, what can I say, but for some reason the password check does not work every time. Does anyone have any ideas?

Thanks.

UPDATE: here are the code comments included in the BCrypt class, with examples of how it is used and works.

 /// <summary>BCrypt implements OpenBSD-style Blowfish password hashing /// using the scheme described in "A Future-Adaptable Password Scheme" /// by Niels Provos and David Mazieres.</summary> /// <remarks> /// <para>This password hashing system tries to thwart offline /// password cracking using a computationally-intensive hashing /// algorithm, based on Bruce Schneier Blowfish cipher. The work /// factor of the algorithm is parametized, so it can be increased as /// computers get faster.</para> /// <para>To hash a password for the first time, call the /// <c>HashPassword</c> method with a random salt, like this:</para> /// <code> /// string hashed = BCrypt.HashPassword(plainPassword, BCrypt.GenerateSalt()); /// </code> /// <para>To check whether a plaintext password matches one that has /// been hashed previously, use the <c>CheckPassword</c> method:</para> /// <code> /// if (BCrypt.CheckPassword(candidatePassword, storedHash)) { /// Console.WriteLine("It matches"); /// } else { /// Console.WriteLine("It does not match"); /// } /// </code> /// <para>The <c>GenerateSalt</c> method takes an optional parameter /// (logRounds) that determines the computational complexity of the /// hashing:</para> /// <code> /// string strongSalt = BCrypt.GenerateSalt(10); /// string strongerSalt = BCrypt.GenerateSalt(12); /// </code> /// <para> /// The amount of work increases exponentially (2**log_rounds), so /// each increment is twice as much work. The default log_rounds is /// 10, and the valid range is 4 to 31. /// </para> /// </remarks> 
+4
source share
3 answers

Forgive me if I missed something, but looking at your hash and your model, you did not seem to store the salt anywhere, instead, you use a new salt each time.

So, when the password is set, you must store both the hash and the salt; when you want to check the entered password, you will get the salt, calculate the hash using it, then compare with the saved one.

+1
source

I had the same problem. BCryptHelper.CheckPassword always returns false

I found that the hashed string was stored in db as nchar (). This made the check always fail. I changed this to char () and it works.

+1
source

HttpUtility.HtmlDecode () is used when the user is created before the password was originally hashed:

 Password = Password.Hash(HttpUtility.HtmlDecode(registration.Password)), 

However, HttpUtility.HtmlDecode () is not used when later when comparing a password with a hash, in

 var authorized = _repository.CredentialsAreValid(HttpUtility.HtmlDecode(login.username), login.password); 

Perhaps a slight change:

 var authorized = _repository.CredentialsAreValid(HttpUtility.HtmlDecode(login.username), HttpUtility.HtmlDecode(login.password)); 

I understand this is an old question, but I am considering using BCrypt, and this question raised a potential flag for me, so I am interested to know if this solves this problem. I apologize, I am not yet able to verify my answer, but I hope this helps.

0
source

All Articles