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}/.freeze
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, #to_64

Methods included from DescendantTracker

#children, #find_child, #inherited

Constructor Details

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

Returns a new instance of Argon2.



59
60
61
62
63
64
65
66
# File 'lib/htauth/argon2.rb', line 59

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

Instance Attribute Details

#optionsObject

Returns the value of attribute options.



36
37
38
# File 'lib/htauth/argon2.rb', line 36

def options
  @options
end

Class Method Details

.ensure_available!Object

Raises:



31
32
33
34
# File 'lib/htauth/argon2.rb', line 31

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

.extract_options_from_existing_password_field(existing) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/htauth/argon2.rb', line 45

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)


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

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

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

.supported?Boolean

Returns:

  • (Boolean)


27
28
29
# File 'lib/htauth/argon2.rb', line 27

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

Instance Method Details

#encode(password) ⇒ Object



68
69
70
71
# File 'lib/htauth/argon2.rb', line 68

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

#verify_password?(password, digest) ⇒ Boolean

Returns:

  • (Boolean)


73
74
75
# File 'lib/htauth/argon2.rb', line 73

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