Class: HTAuth::Argon2

Inherits:
Algorithm show all
Defined in:
lib/htauth/argon2.rb

Overview

Internal: Support of the argon2id algorithm and password format.

Defined Under Namespace

Classes: NotInstalledError, NotSupportedError

Constant Summary collapse

PREFIX =

from upstream, used to help make a nice error message if its not installed github.com/technion/ruby-argon2/blob/3388d7e05e8b486ea4ba8bd2aeb1e9988f025f13/lib/argon2/hash_format.rb#L45

/^\$argon2(id?|d).{,113}/
ARGON2_GEM_INSTALLED =
defined?(::Argon2)

Constants inherited from Algorithm

HTAuth::Algorithm::ARGON2, HTAuth::Algorithm::BCRYPT, HTAuth::Algorithm::CRYPT, HTAuth::Algorithm::DEFAULT, HTAuth::Algorithm::EXISTING, HTAuth::Algorithm::MD5, HTAuth::Algorithm::PLAINTEXT, HTAuth::Algorithm::SALT_CHARS, HTAuth::Algorithm::SALT_LENGTH, HTAuth::Algorithm::SHA1

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Algorithm

algorithm_from_field, algorithm_from_name, algorithm_name, #gen_salt, secure_compare, #to64

Methods included from DescendantTracker

#children, #find_child, #inherited

Constructor Details

#initialize(params = { profile: :rfc_9106_low_memory }) ⇒ Argon2

Returns a new instance of Argon2.



67
68
69
70
71
72
73
74
75
# File 'lib/htauth/argon2.rb', line 67

def initialize(params = { profile: :rfc_9106_low_memory })
  super()
  self.class.ensure_available!
  @options = if (existing = params["existing"] || params[:existing])
               self.class.extract_options_from_existing_password_field(existing)
             else
               params
             end
end

Instance Attribute Details

#optionsObject

Returns the value of attribute options.



43
44
45
# File 'lib/htauth/argon2.rb', line 43

def options
  @options
end

Class Method Details

.ensure_available!Object

Raises:



38
39
40
41
# File 'lib/htauth/argon2.rb', line 38

def self.ensure_available!
  raise NotSupportedError unless supported?
  raise NotInstalledError unless ARGON2_GEM_INSTALLED
end

.extract_options_from_existing_password_field(existing) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/htauth/argon2.rb', line 53

def self.extract_options_from_existing_password_field(existing)
  hash_format = ::Argon2::HashFormat.new(existing)

  # m_cost on the input is the 2**m_cost, but in the hash its the number of
  # bytes, so need to convert it back to a power of 2, which is the
  # log2(m_cost)

  {
    t_cost: hash_format.t_cost,
    m_cost: ::Math.log2(hash_format.m_cost).floor,
    p_cost: hash_format.p_cost,
  }
end

.handles?(password_entry) ⇒ Boolean

Returns:

  • (Boolean)


45
46
47
48
49
50
51
# File 'lib/htauth/argon2.rb', line 45

def self.handles?(password_entry)
  return false unless PREFIX.match?(password_entry)

  ensure_available!

  ::Argon2::Password.valid_hash?(password_entry)
end

.supported?Boolean

Returns:

  • (Boolean)


34
35
36
# File 'lib/htauth/argon2.rb', line 34

def self.supported?
  !::Gem.win_platform?
end

Instance Method Details

#encode(password) ⇒ Object



77
78
79
80
# File 'lib/htauth/argon2.rb', line 77

def encode(password)
  argon2 = ::Argon2::Password.new(options)
  argon2.create(password)
end

#verify_password?(password, digest) ⇒ Boolean

Returns:

  • (Boolean)


82
83
84
# File 'lib/htauth/argon2.rb', line 82

def verify_password?(password, digest)
  ::Argon2::Password.verify_password(password, digest)
end