class DjangoHash

Attributes

hsh[R]

Public Class Methods

new(params) click to toggle source
# File lib/pbkdf2_password_hasher/django_hash.rb, line 7
def initialize(params)
  @password  = params[:password]
  @dklen     = params[:dklen]    || 32
  @c         = params[:c].to_i   || 12_000
  @hsh       = params[:hash]
  @salt      = params[:salt]

  @hash_f = OpenSSL::Digest.new('sha256')
end
parse(str) click to toggle source

Instanciate class using hash string

# File lib/pbkdf2_password_hasher/django_hash.rb, line 18
def self.parse(str)
  algo, c, salt, hsh = str.split('$')
  fail "sorry, don't know what to do with #{algo}" unless algo == 'pbkdf2_sha256'
  DjangoHash.new(
    :dklen => Base64.decode64(hsh).size,
    :c     => c,
    :salt  => salt,
    :hash  => hsh
  )
end

Public Instance Methods

check_password(password) click to toggle source

Check password against computed hash

# File lib/pbkdf2_password_hasher/django_hash.rb, line 35
def check_password(password)
  @password = password
  @hsh == get_hash
end
get_hash() click to toggle source

Compute hash

# File lib/pbkdf2_password_hasher/django_hash.rb, line 30
def get_hash
  (1..number_of_blocks).map(&block).reduce('', &:<<)
end

Private Instance Methods

block() click to toggle source
# File lib/pbkdf2_password_hasher/django_hash.rb, line 57
def block
  -> i do
    u = prf(@salt + [i].pack('N'))
    f = u
    2.upto(@c) do |_i|
      u = prf(u)
      f = xor(f, u)
    end
    Base64.encode64(f[0..@dklen - 1]).chomp
  end
end
number_of_blocks() click to toggle source
# File lib/pbkdf2_password_hasher/django_hash.rb, line 42
def number_of_blocks
  (@dklen.to_f / @hash_f.size).ceil
end
prf(data) click to toggle source

Pseudo Random Function, as described in wikipedia

# File lib/pbkdf2_password_hasher/django_hash.rb, line 52
def prf(data)
  @hash_func ||= OpenSSL::Digest.new('sha256')
  OpenSSL::HMAC.digest(@hash_func, @password, data)
end
xor(s1, s2) click to toggle source

“string xor”

# File lib/pbkdf2_password_hasher/django_hash.rb, line 47
def xor(s1, s2)
  s1.bytes.zip((s2).bytes).map { |a, b| a ^ b }.pack('C*')
end