rails使用Bcrypt解密码token(Comeonin.Bcrypt in an Elixir app)
https://github.com/codahale/bcrypt-ruby/issues/120
https://github.com/codahale/bcrypt-ruby/pull/91
I'm using Comeonin.Bcrypt in an Elixir app. I can compare hashes with salts generated by the bcrypt-ruby but bcrypt-ruby cant compare with those that was generated by Comeonin.Bcrypt.
Example:
"abcabc12345" => "$2b$10$li1IT3V0dEi4czS74rGL/.rObZhj6k5wAMtzWZVKZxgxVyKeXAMGC"
Only works with the Elixir lib.
If I use a salt generated by bcrypt-ruby everything works. What lib is wrong?
@dissolve From the sounds of this answer on stack overflow: https://stackoverflow.com/a/20981781it sounds like you can just replace $2y
with $2a
and it will validate accordingly.
I gave it a quick test as I've just come across the same issue (migrating to ruby from a php app which stored the hash with a $2y
prefix) and it seems to work. Code isn't pretty, but maybe this will tide people over for another 4 years...
def password_correct?(password, current_passsword_hash)
current_passsword_hash = current_passsword_hash.sub(/^.../, '$2a')
BCrypt::Password.new(current_passsword_hash).is_password?(password)
end
总结: 这个问题主要是 bcrypt-ruby 的一个bug。 使用 elixir的Comeonin.Bcrypt 加密的secret 前缀伟 $2b, 而 bcrypt-ruby 加密密码为 $2a 所以转换一下就可以解密了。
require 'bcrypt' require 'pp' secret = 'my password' BCrypt::Engine.cost = 4 # default is 10 password = BCrypt::Password.create(secret) puts '********** create **********' puts ['version:', password.version].join(' ') puts ['cost:', password.cost].join(' ') puts ['salt:', password.salt].join(' ') puts ['checksum:', password.checksum].join(' ') # this is actually comparing the password hash, and not the password string itself. # alias_method: BCrypt::Password#is_password?(secret) pp password == secret puts '********** read **********' # with the password and the salt, this .hash_secret return the password hash # same as BCrypt::Password#to_s hash_secret = BCrypt::Engine.hash_secret(secret, password.salt) puts ['Hash Secret:', hash_secret].join(' ') password = BCrypt::Password.new(hash_secret) pp password == secret