Class: Devise::Hashable::Strategy::Pbkdf2

Inherits:
Base
  • Object
show all
Defined in:
lib/devise/hashable/strategy/pbkdf2.rb

Overview

Pbkdf2 hashing

Class Method Summary collapse

Class Method Details

.compare(_klass, encrypted_password, password) ⇒ Boolean

Verifies a plain-text password against a PBKDF2 hash.

Parameters:

  • _klass (Class)

    the Devise model class (unused; the iteration count and digest are read from the hash itself)

  • encrypted_password (String)

    the stored PBKDF2 hash

  • password (String)

    the plain-text password to verify

Returns:

  • (Boolean)

    true when the password matches



16
17
18
19
20
21
# File 'lib/devise/hashable/strategy/pbkdf2.rb', line 16

def compare(_klass, encrypted_password, password)
  split_digest = split_password_hash(encrypted_password)
  value_to_test = digest_checksum(password, split_digest[:hash_iterations], split_digest[:salt], split_digest[:digest_algorithm])

  Devise.secure_compare(split_digest[:checksum], value_to_test)
end

.digest(klass, password) ⇒ String

Hashes a plain-text password with PBKDF2.

Parameters:

  • klass (Class)

    the Devise model class, read for hash_iterations and digest_algorithm

  • password (String)

    the plain-text password to hash

Returns:

  • (String)

    the encoded PBKDF2 hash, in passlib format



29
30
31
32
33
34
35
# File 'lib/devise/hashable/strategy/pbkdf2.rb', line 29

def digest(klass, password)
  configs = base_configs(klass)
  salt = Devise.friendly_token(16)
  checksum = digest_checksum(password, configs[:hash_iterations], salt, configs[:digest_algorithm])

  format_hash("pbkdf2-#{configs[:digest_algorithm]}", configs[:hash_iterations], salt, checksum)
end

.password_configurations_match?(klass, encrypted_password) ⇒ Boolean

Returns:

  • (Boolean)


37
38
39
40
41
42
43
44
45
# File 'lib/devise/hashable/strategy/pbkdf2.rb', line 37

def password_configurations_match?(klass, encrypted_password)
  current_password_configs = split_password_hash(encrypted_password)
  required_password_configs = base_configs(klass)

  return false if current_password_configs[:hash_iterations] != required_password_configs[:hash_iterations]
  return false if current_password_configs[:digest_algorithm] != required_password_configs[:digest_algorithm]

  true
end

.split_password_hash(encrypted_password) ⇒ Object

rubocop:disable Metrics/MethodLength



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/devise/hashable/strategy/pbkdf2.rb', line 47

def split_password_hash(encrypted_password) # rubocop:disable Metrics/MethodLength
  split_digest = encrypted_password.split("$")

  raise InvalidPasswordHash, "Invalid password hash for PBKDF2" unless split_digest.length == 5

  _, strategy, hash_iterations, salt, checksum = split_digest

  raise InvalidPasswordHash, "Invalid password hash strategy for PBKDF2" unless strategy.start_with?("pbkdf2-")

  split_strategy = strategy.split("-")
  base_strategy, digest_algorithm = split_strategy

  {
    strategy: strategy,
    base_strategy: base_strategy,
    digest_algorithm: digest_algorithm,
    hash_iterations: hash_iterations.to_i,
    salt: passlib_decode64(salt),
    checksum: passlib_decode64(checksum)
  }
end