Update: I've learned that bcrypt, PBKDF2, etc. should be used instead of SHAxxx. So replacing SHA512 by bcrypt in my question:
I want to upgrade password hashing from
Digest::SHA1.hexdigest(password + some_string + salt)
to bcrypt.
Is there a way to migrate existing SHA1 password hashes to the same security level as bcrypt? What about this:
hashed_pw_bcrypt = BCrypt::Password.create(hashed_pw_sha1)
And then authorize existing users as follows:
BCrypt::Password.create(Digest::SHA1.hexdigest(password + some_string + salt)) == hashed_pw_bcrypt
And as soon as users successfully login this way, then change hashing to
hashed_pw_bcrypt = BCrypt::Password.create(password)
and set the hashed_pw_sha1 attribute to nil in order to mark the user as migrated.
I think what I would do is add a new set of fields to the existing user record for the new password types, and a boolean column to switch between which one to use. Once all your users are migrated to the new version, you can close off the old method. Something like this pseudocode:
if the boolean is false, test given password against old hash
if it passes
re-hash the given password with the new algorithm
set the boolean
set the new hash column
save
redirect
if not
whatever you currently do
end
Yes, this is kind of a creeping migration, i.e. an user will be migrated as soon as he’s successfully being authenticated the first time.
What I think of is increasing the security level for all existing users before they login the first time: immediately migrating all passwords to bcrypt(old hash). The question is if this will really achieve the security level of bcrypt for existing user accounts.
bcrypt(oldhash(password)) cannot be easier to crack than oldhash(password), and will be harder except for degenerate cases where oldhash(password) is easier to guess than password. (Imagine for instance a "hash" function which just returned "password1" for all inputs...)