jakeb jakeb - 3 months ago 12
PHP Question

Convert PHP's password_verify to Ruby on Rails

We're in the process of converting our site from an old PHP framework to Rails, and would really like for users to continue being able to login with their old password. On the old site, we're using password_hash and password_verify to hash and verify the passwords. However, on Rails I can't seem to get it to verify the old password.

Here is what we have in PHP:

Hash:

password_hash($user['salt'] . $password . $user['salt'], PASSWORD_DEFAULT);


Verify:

password_verify($user['salt'] . $password . $user['salt'], $user['password'])


On the new Rails framework we're using Devise and have built a custom migration script to move everything over and identify the correct password hashing method based on a password_version stored in the db, and this is what I'm using inside my User model:

def valid_password?(password)
if password_version == 'legacy'
hash = BCrypt::Password.new(encrypted_password)
hash_str = password_salt+password+password_salt

return hash.is_password? hash_str
end

super(password)
end


Any ideas would be greatly appreciated

Answer

The format of a PHP password_hash password looks roughly like this:

$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

The default Ruby Bcrypt method produces passwords of the form:

$2a$10$GtKs1Kbsig8ULHZzO1h2TetZfhO4Fmlxphp8bVKnUlZCBYYClPohG

For a clean solution here you can always differentiate between the two by the $2y or $2a prefix. There's no need for a format column when it's already baked into the format.

For example:

case (encrypted_password[0,3])
when '$2y'
  # Legacy PHP password
  BCrypt::Password.new(encrypted_password.sub(/\A\$2y/, '$2a')).is_password?(salt + password + salt)
when '$2a'
  # Ruby BCrypt password
  BCrypt::Password.new(encrypted_password).is_password?(password) 
else
  # Unexpected type?
end

What you'll want to do on a successful verification of password is re-write the password to the database using Ruby's method to gradually replace all the old PHP formatted ones.

Comments