1

I'm trying to use BCrypt in my rails app to save user's passwords securely. I'm able to save the encrypted password just fine and even compare it against the original plain text string to successfully verify it. The problem seems to be that every time I encrypt the password I get a different output (I'm assuming due to some salt or something) and the verification doesn't hold up after being saved to the database (I'm saving in an sqlite3 database if it makes a difference).

For example (in a Rails console):

2.1.2 :001 > u = User.new
 => #<User id: nil, created_at: nil, updated_at: nil, username: nil, password: nil> 
2.1.2 :002 > u.username = "jdoe"
 => "jdoe"
2.1.2 :002 > u.password = BCrypt::Password.create("snoopy")
 => "$2a$10$jJpHrgUmAh.YULY9CJUDjOSb9audpeD3Hx.66uVhix.WEDDB0HO.y" 
2.1.2 :003 > u.password == "snoopy"
 => true
2.1.2 :004 > u.save
 => true
u2 = User.find_by_username("jdoe")
 => [user "jdoe" is found here]
2.1.2 :006 > u2.password == "snoopy"
 => false

I know there are ready made solutions like has_secure_password, but I'd like to implement this manually to really understand what's going on.

Jason Burgett
  • 117
  • 1
  • 10
  • Is there a reason you aren't using Rails' built in `has_secure_password` which uses bcrypt? http://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password – infused Jul 23 '14 at 23:30
  • I generally like to write my own methods (within reason) so I have a firm understanding of what's happening in the code. Especially if it's something new to me. Once I feel like I have a full understanding of the tech, then I allow myself to use shortcuts or pre-written code. – Jason Burgett Jul 24 '14 at 12:05

1 Answers1

1

When you set the password, you are setting it to a BCrypt::Password object. I guess that when you load it from the database it is loaded as a simple string, so == will not encrypt the given string with the original salt.

Try the following:

(...)
u.save
u2 = User.find_by_username("jdoe")
BCrypt::Password.new(u2.password) == "snoopy"

Edit

It seems Rails provides a after_find callback so if you define something like this

class User < ActiveRecord::Base
  after_find do |user|
    user.password = BCrypt::Password.new(user.password)
  end
end

it should work as you intended.

Salem
  • 12,808
  • 4
  • 34
  • 54