欢迎来到cool的博客
7

Music box

Click to Start

点击头像播放音乐
新博客链接

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

https://stackoverflow.com/questions/20980859/using-bcrypt-ruby-to-validate-hashed-passwords-using-version-2y/20981781#20981781

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

返回列表