class Authlogic::CryptoProviders::BCrypt

The family of adaptive hash functions (BCrypt, SCrypt, PBKDF2) is the best choice for password storage today. They have the three properties of password hashing that are desirable. They are one-way, unique, and slow. While a salted SHA or MD5 hash is one-way and unique, preventing rainbow table attacks, they are still lightning fast and attacks on the stored passwords are much more effective. This benchmark demonstrates the effective slowdown that BCrypt provides:

require "bcrypt"
require "digest"
require "benchmark"

Benchmark.bm(18) do |x|
  x.report("BCrypt (cost = 10:") { 100.times { BCrypt::Password.create("mypass", :cost => 10) } }
  x.report("BCrypt (cost = 4:") { 100.times { BCrypt::Password.create("mypass", :cost => 4) } }
  x.report("Sha512:") { 100.times { Digest::SHA512.hexdigest("mypass") } }
  x.report("Sha1:") { 100.times { Digest::SHA1.hexdigest("mypass") } }
end

                         user     system      total        real
BCrypt (cost = 10):  37.360000   0.020000  37.380000 ( 37.558943)
BCrypt (cost = 4):    0.680000   0.000000   0.680000 (  0.677460)
Sha512:               0.000000   0.000000   0.000000 (  0.000672)
Sha1:                 0.000000   0.000000   0.000000 (  0.000454)

You can play around with the cost to get that perfect balance between performance and security. A default cost of 10 is the best place to start.

Decided BCrypt is for you? Just install the bcrypt gem:

gem install bcrypt-ruby

Tell acts_as_authentic to use it:

acts_as_authentic do |c|
  c.crypto_provider = Authlogic::CryptoProviders::BCrypt
end

You are good to go!

Public Instance Methods

cost() click to toggle source

This is the :cost option for the BCrpyt library. The higher the cost the more secure it is and the longer is take the generate a hash. By default this is 10. Set this to any value >= the engine's minimum (currently 4), play around with it to get that perfect balance between security and performance.

# File lib/authlogic/crypto_providers/bcrypt.rb, line 50
def cost
  @cost ||= 10
end
cost=(val) click to toggle source
# File lib/authlogic/crypto_providers/bcrypt.rb, line 54
def cost=(val)
  if val < ::BCrypt::Engine::MIN_COST
    raise ArgumentError.new("Authlogic's bcrypt cost cannot be set below the engine's min cost (#{::BCrypt::Engine::MIN_COST})")
  end
  @cost = val
end
cost_matches?(hash) click to toggle source

This method is used as a flag to tell Authlogic to “resave” the password upon a successful login, using the new cost

# File lib/authlogic/crypto_providers/bcrypt.rb, line 74
def cost_matches?(hash)
  hash = new_from_hash(hash)
  if hash.blank?
    false
  else
    hash.cost == cost
  end
end
encrypt(*tokens) click to toggle source

Creates a BCrypt hash for the password passed.

# File lib/authlogic/crypto_providers/bcrypt.rb, line 62
def encrypt(*tokens)
  ::BCrypt::Password.create(join_tokens(tokens), :cost => cost)
end
matches?(hash, *tokens) click to toggle source

Does the hash match the tokens? Uses the same tokens that were used to encrypt.

# File lib/authlogic/crypto_providers/bcrypt.rb, line 67
def matches?(hash, *tokens)
  hash = new_from_hash(hash)
  return false if hash.blank?
  hash == join_tokens(tokens)
end

Private Instance Methods

join_tokens(tokens) click to toggle source
# File lib/authlogic/crypto_providers/bcrypt.rb, line 84
def join_tokens(tokens)
  tokens.flatten.join
end
new_from_hash(hash) click to toggle source
# File lib/authlogic/crypto_providers/bcrypt.rb, line 88
def new_from_hash(hash)
  begin
    ::BCrypt::Password.new(hash)
  rescue ::BCrypt::Errors::InvalidHash
    return nil
  end
end