Class: Argon2::Password

Inherits:
Object
  • Object
show all
Defined in:
lib/argon2/password.rb

Overview

Front-end API for the Argon2 module.

Constant Summary collapse

DEFAULT_T_COST =

Used as the default time cost if one isn’t provided when calling Argon2::Password.create

2
MIN_T_COST =

Used to validate the minimum acceptable time cost

1
MAX_T_COST =

Used to validate the maximum acceptable time cost

750
DEFAULT_M_COST =

Used as the default memory cost if one isn’t provided when calling Argon2::Password.create

16
MIN_M_COST =

Used to validate the minimum acceptable memory cost

3
MAX_M_COST =

Used to validate the maximum acceptable memory cost

31
DEFAULT_P_COST =

Used as the default parallelism cost if one isn’t provided when calling Argon2::Password.create

1
MIN_P_COST =

Used to validate the minimum acceptable parallelism cost

1
MAX_P_COST =

Used to validate the maximum acceptable parallelism cost

8

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(digest) ⇒ Password

Initialize an Argon2::Password instance using any valid Argon2 digest.



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/argon2/password.rb', line 143

def initialize(digest)
  digest = digest.to_s

  raise Argon2::Errors::InvalidHash unless valid_hash?(digest)

  # Split the digest into its component pieces
  split_digest = split_hash(digest)
  # Assign each piece to the Argon2::Password instance
  @digest   = digest
  @variant  = split_digest[:variant]
  @version  = split_digest[:version]
  @t_cost   = split_digest[:t_cost]
  @m_cost   = split_digest[:m_cost]
  @p_cost   = split_digest[:p_cost]
  @salt     = split_digest[:salt]
  @checksum = split_digest[:checksum]
end

Instance Attribute Details

#checksumObject (readonly)

The hash portion of the stored password hash. This is Base64 encoded by default.



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

def checksum
  @checksum
end

#digestObject (readonly)

The complete Argon2 digest string (not to be confused with the checksum).

For a detailed description of the digest format, please see: github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md



33
34
35
# File 'lib/argon2/password.rb', line 33

def digest
  @digest
end

#m_costObject (readonly)

The memory cost factor used to create the hash.



57
58
59
# File 'lib/argon2/password.rb', line 57

def m_cost
  @m_cost
end

#p_costObject (readonly)

The parallelism cost factor used to create the hash.



59
60
61
# File 'lib/argon2/password.rb', line 59

def p_cost
  @p_cost
end

#saltObject (readonly)

The salt of the stored password hash. This is Base64 encoded by default.

To retrieve the original salt:

require 'base64'

argon2 = Argon2::Password.new(digest)

argon2.salt
=> Base64 encoded salt
Base64.decode64(argon2.salt)
=> original salt


49
50
51
# File 'lib/argon2/password.rb', line 49

def salt
  @salt
end

#t_costObject (readonly)

The time cost factor used to create the hash.



55
56
57
# File 'lib/argon2/password.rb', line 55

def t_cost
  @t_cost
end

#variantObject (readonly)

Variant used (argon2i / argon2d / argon2id)



51
52
53
# File 'lib/argon2/password.rb', line 51

def variant
  @variant
end

#versionObject (readonly)

The version of the argon2 algorithm used to create the hash.



53
54
55
# File 'lib/argon2/password.rb', line 53

def version
  @version
end

Class Method Details

.create(password, options = {}) ⇒ Object

Takes a user provided password and returns an Argon2::Password instance with the resulting Argon2 hash.

Usage:

Argon2::Password.create(password)
Argon2::Password.create(password, t_cost: 4, m_cost: 20)
Argon2::Password.create(password, secret: pepper)
Argon2::Password.create(password, m_cost: 17, secret: pepper)

Currently available options:

  • :t_cost

  • :m_cost

  • :p_cost

  • :secret



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/argon2/password.rb', line 83

def create(password, options = {})
  raise Argon2::Errors::InvalidPassword unless password.is_a?(String)

  t_cost = options[:t_cost] || DEFAULT_T_COST
  m_cost = options[:m_cost] || DEFAULT_M_COST
  p_cost = options[:p_cost] || DEFAULT_P_COST

  raise Argon2::Errors::InvalidTCost if t_cost < MIN_T_COST || t_cost > MAX_T_COST
  raise Argon2::Errors::InvalidMCost if m_cost < MIN_M_COST || m_cost > MAX_M_COST
  raise Argon2::Errors::InvalidPCost if p_cost < MIN_P_COST || p_cost > MAX_P_COST

  salt = Engine.saltgen
  secret = options[:secret]

  Argon2::Password.new(
    Argon2::Engine.hash_argon2id_encode(
      password, salt, t_cost, m_cost, p_cost, secret
    )
  )
end

.valid_hash?(digest) ⇒ Boolean

Regex to validate if the provided String is a valid Argon2 hash output.

Supports 1 and argon2id formats.

Returns:

  • (Boolean)


109
110
111
# File 'lib/argon2/password.rb', line 109

def valid_hash?(digest)
  /^\$argon2(id?|d).{,113}/ =~ digest
end

.verify_password(password, digest, secret = nil) ⇒ Object

Takes a password, Argon2 hash, and optionally a secret, then uses the Argon2 C Library to verify if they match.

Also accepts passing another Argon2::Password instance as the password, in which case it will compare the final Argon2 hash for each against each other.

Usage:

Argon2::Password.verify_password(password, argon2_hash)
Argon2::Password.verify_password(password, argon2_hash, secret)


126
127
128
129
130
131
132
133
# File 'lib/argon2/password.rb', line 126

def verify_password(password, digest, secret = nil)
  digest = digest.to_s
  if password.is_a?(Argon2::Password)
    password == Argon2::Password.new(digest)
  else
    Argon2::Engine.argon2_verify(password, digest, secret)
  end
end

Instance Method Details

#==(other) ⇒ Object

Compares two Argon2::Password instances to see if they come from the same digest/hash.



173
174
175
176
177
178
179
180
181
# File 'lib/argon2/password.rb', line 173

def ==(other)
  # TODO: Should this return false instead of raising an error?
  unless other.is_a?(Argon2::Password)
    raise ArgumentError,
          'Can only compare an Argon2::Password against another Argon2::Password'
  end

  digest == other.digest
end

#matches?(password, secret = nil) ⇒ Boolean

Helper function to allow easily comparing an Argon2::Password against the provided password and secret.

Returns:

  • (Boolean)


165
166
167
# File 'lib/argon2/password.rb', line 165

def matches?(password, secret = nil)
  self.class.verify_password(password, digest, secret)
end

#to_sObject

Converts an Argon2::Password instance into a String.



186
187
188
# File 'lib/argon2/password.rb', line 186

def to_s
  digest.to_s
end

#to_strObject

Converts an Argon2::Password instance into a String.



193
194
195
# File 'lib/argon2/password.rb', line 193

def to_str
  digest.to_str
end