How to fix BCrypt-3.1.11 hashed passwords appended stream of "\x00" characters

Viewed 226

I recently started getting BCrypt "invalid hash" errors when I tried to save a record with a password, so I looked into the BCrypt code, and found the following method for validating passwords:

  def valid_hash?(h)
    h =~ /^\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$/
  end

which is called by the initialize method:

def initialize(raw_hash)
  if valid_hash?(raw_hash)
    self.replace(raw_hash)
    @version, @cost, @salt, @checksum = split_hash(self)
  else
    raise Errors::InvalidHash.new("invalid hash")
  end
end

The following passwords:

"PassiveForbearenceFox"
"VindictivePurpleAlligator12345"
"LostBlueLizard!@#$1234" 

all return "Invalid Hash" errors.

I dug deeper, and found that the regex is checking the hashed password, but the hash that is getting passed has a stream of /x00s after it.

For example, if I use the password "LostBlueLizard!@#1234", the hash that is passed to challenge the regex is:

"$2a$11$NcmldbbyCDfumGYALgYhfuIQt2FZ8gpbVCQfuiVlwjhCtkD2ndDFy\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\...

and so on, for farther than I could scroll.

If I remove the \x00s and pass in $2a$11$NcmldbbyCDfumGYALgYhfuIQt2FZ8gpbVCQfuiVlwjhCtkD2ndDFy, it passes the regex.

Why does the hash have those characters? I can't prove they weren't there before, but my passwords were always accepted until recently.


Also, it's actually the raw_hash that's getting input into the initialize method that's the hash with all the \x00s. So somewhere there's code that generates the faulty hash and passes it to initialize, but I searched the entire gem's codebase for the term "initialize" and there were no results like that, so I can't find where the hash is actually generated.


I tracked the issue further, to the BCrypt::Engine.create method, which calls __bc_crypt, which is what returns the faulty hash. __bc_crypt is actually from the C source file ext/mri/bcrypt_ext.c, which is beyond my ability to investigate.

I updated BCrypt from 3.1.11 to 3.1.13, and now it works fine. I'm not sure whether it was a bug or not, but the point is it works now.

1 Answers

It does not mean the Bcrypt's valid_hash? method is wrong, it means that the password stored, that one is invalid or nil which does not match the valid hash system

you may have to add

has_secure_password

if that one is not there and check the password_digest field after that.

Related