Ruby BCrypt hash comparison not working
When you use ==
you are actually calling the ==
method defined on the object on the left hand side, passing the right hand side as argument:
a == b
is equivalent to
a.==(b)
Depending on the object you call the ==
method you might receive a different result. In other words:
a == b
might or might not return a different result than
b == a
While personally I think this is nonsense and equality operators should be transitive
, symetric
and reflexive
the BCrypt people have decided to implement it in another way:
def ==(secret)
super(BCrypt::Engine.hash_secret(secret, @salt))
end
(taken from http://bcrypt-ruby.rubyforge.org/classes/BCrypt/Password.html#M000009)
This means that you have to write:
stored_password = BCrypt::Password.new(user_arr[2])
if stored_password == user_input_password_attempt
...
end
in order to call the ==
method on the Password
instance.
How can i compare decrypted password and encrypted password by 'Bcrypt' Gem
ency_pass = BCrypt::Password.create("testing")
new_pass = "testing"
Let’s look at how we compare two bcrypt hashes, one coming from the database & one from user input (like a form or something like that).
BCrypt::Password.new(ency_pass) == new_pass
# true
BCrypt::Password.new(ency_pass) == "testing2"
#false
The part on the left (BCrypt::Password.new)
is a BCrypt object, which takes the hash stored in the database as a parameter.
The part on the right (new_pass) is just the plain-text password that the user is trying to log in with.
Let's understand this things:
BCrypt uses something called a “salt”, which is a random value used to increase security against pre-computed hashes. The salt is stored in the hash itself.
BCrypt defines its own == method, which knows how to extract that “salt” value so that it can take that into account when comparing the passwords.
BCrypt#== takes the “salt” value from the stored hash, then it hashes the plain-text password (the user input) using this salt so that both hashes will be identical if the password is valid.
If you were to look at the source code it would look something like this:
def ==(secret)
super(
BCrypt::Engine.hash_secret(secret, @salt)
)
end
Remember that super will call the same method (in this case ==) on the parent class. The parent class of BCrypt::Password is String.
Comparing bcrypt hashes
The lines returned by File#each
include the newline at the end of the line, so your passwordCheck
variable has a trailing newline but the bcrypt generated hash doesn't.
You can remove the newline with chomp
Ruby and Sinatra, unable to compare hashed password with BCrypt
Your use of bcrypt works, but the program flow is wrong. Most importantly, the call to status 201
does not exit from the controller at that point, it continues on, so you have set things up so that whether or not the bcrypt works is irrelevant.
Do something like this instead:
get "/test" do
password_hash = BCrypt::Password.create("wazz")
password = "wazz"
unless BCrypt::Password.new(password_hash).is_password? password
halt(500, {error: password_hash}.to_json)
end
status 201
{message: 'Session created'}.to_json
end
Related Topics
Best Way to Cache a Response in Sinatra
What's the Best Way to Parse a Tab-Delimited File in Ruby
How to Set a Blank Value for an F.Select Form Field
How to Check If a Gem Is Installed
Listing the Names of Associated Models
Rails Activeadmin - Custom Association Select Box
Checking If a Method Is Defined on the Class
Anybody Tried the Crystal Programming Language (Machine-Code Compiled Ruby)
Sidekiq List All Jobs [Queued + Running]
Ruby Method with Maximum Number of Parameters
Framework for Non-Web Ruby Project
Mongodb and Mongoid in Production
Ruby - Adding a Directory to $Load_Path - What Does It Do
Getting Memory Usage of My Process from Osx Using Ruby
Rails - How to Create a Model Linked to Two of Another Model