Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are Rails passwords generated with bcrypt portable?

I have an existing web application with a few thousand users which I'm porting over to Rails. As I rewrite and refactor this app I may need to run it on any number of different servers for development, testing, and production purposes.

I'm using Rails' built-in has_secure_password method in my user model but I'm concerned about the portability of password data. I will need to move the contents of my database from machine to machine to test in different environments and its very important that I can test the user authentication functionality using the same set of users and passwords in each environment.

So far its easy to find answers about how bcrypt-ruby works along with Rails has_secure_password but after weeks of searching I haven't found a clear answer.

If has_secure_password results in a WorkFactor + Salt + HashedPassword concatenated and saved to the password_digest database column then can that hash be regenerated and compared reliably if moved to any other machine (assuming any other machine is running Rails on a Unix-like OS)?

OR To put it another way - are bcrypt-ruby passwords generated with Rails' has_secure_password portable?

Follow up question: If the salt is always generated randomly (I've seen the same password use different hashes so I don't think the salt is created from the text of the password itself) then how would a Rails app be able to reliably rehash the password on a login form submit and compare it to what's in the database. Obviously it would have to know what the salt is first in order to compare it. How does it do that?

like image 390
wgp Avatar asked Sep 29 '13 15:09

wgp


1 Answers

Yes the passwords are portable. The format used is a standard "crypt encoding" format, also used as part of RFC 2307 (in RFC 2307, the string would be prefixed "{CRYPT}"). I have worked with a Perl library Authen::Passphrase that would happily authenticate passwords against the bcrypt-hashed versions from an RoR database.

For the follow-up question: The salt is embedded in the stored value (along with the type of hashing, the number of bcrypt cycles to use and of course the hash itself), and to authenticate the server needs to read the stored value, then it simply re-uses the same salt to generate the hash part - if the input password is correct, then the hash will be identical. The authentication process does not create a new random salt. A random salt is only created when generating a brand new hash for storing.

The bcrypt password is easily split into components for a server to read (I have chosen non-realistic characters to make it easier to see boundaries, in fact salt and hash are base 64 encoded binary data):

 $2a$10$AaBbCcDdEeFfGgHhIiJjKk0987654321098765432109876543210
  • This part means "use bcrypt, 2**10 == 1024 iterations": $2a$10$

  • This part is the salt: AaBbCcDdEeFfGgHhIiJjKk, always 22 characters

  • This part is the hash: 0987654321098765432109876543210, always 31 characters

like image 112
Neil Slater Avatar answered Sep 20 '22 23:09

Neil Slater