Class: Argon2id::Password

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

Overview

The Password class encapsulates an encoded Argon2id password hash.

To hash a plain text password, use Argon2id::Password.create:

password = Argon2id::Password.create("password")
password.to_s
#=> "$argon2id$v=19$m=19456,t=2,p=1$+Lrjry9Ifq0poLr15OGU1Q$utkDvejJB0ugwm4s9+a+vF6+1a/W+Y3CYa5Wte/85ig"

To wrap an encoded Argon2id password hash, use Argon2id::Password.new:

password = Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")

You can then verify it matches a given plain text:

password == "password"     #=> true
password == "not password" #=> false

password.is_password?("password")     #=> true
password.is_password?("not password") #=> false

You can read various parameters out of a password hash:

password.type        #=> "argon2id"
password.version     #=> 19
password.m_cost      #=> 19456
password.t_cost      #=> 2
password.parallelism #=> 1
password.salt        #=>  "somesalt"

Constant Summary collapse

PATTERN =

A regular expression to match valid hashes.

%r{
  \A
  \$
  (argon2(?:id|i|d))
  (?:\$v=(\d+))?
  \$m=(\d+)
  ,t=(\d+)
  ,p=(\d+)
  \$
  ([a-zA-Z0-9+/]+)
  \$
  [a-zA-Z0-9+/]+
  \z
}x.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(encoded) ⇒ Password

call-seq: Argon2id::Password.new(encoded)

Create a new Password with the given encoded password hash.

password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$FI8yp1gXbthJCskBlpKPoQ$nOfCCpS2r+I8GRN71cZND4cskn7YKBNzuHUEO3YpY2s")

Raises an ArgumentError if given an invalid hash.

Raises:

  • (ArgumentError)


111
112
113
114
115
116
117
118
119
120
121
# File 'lib/argon2id/password.rb', line 111

def initialize(encoded)
  raise ArgumentError, "invalid hash" unless PATTERN =~ String(encoded)

  @encoded = $&
  @type = $1
  @version = ($2 || 0x10).to_i
  @m_cost = $3.to_i
  @t_cost = $4.to_i
  @parallelism = $5.to_i
  @salt = $6.unpack1("m")
end

Instance Attribute Details

#encodedObject (readonly) Also known as: to_s

The encoded password hash.



52
53
54
# File 'lib/argon2id/password.rb', line 52

def encoded
  @encoded
end

#m_costObject (readonly)

The “memory cost” of the hashing function.



64
65
66
# File 'lib/argon2id/password.rb', line 64

def m_cost
  @m_cost
end

#parallelismObject (readonly)

The number of threads and compute lanes of the hashing function.



67
68
69
# File 'lib/argon2id/password.rb', line 67

def parallelism
  @parallelism
end

#saltObject (readonly)

The salt.



70
71
72
# File 'lib/argon2id/password.rb', line 70

def salt
  @salt
end

#t_costObject (readonly)

The “time cost” of the hashing function.



61
62
63
# File 'lib/argon2id/password.rb', line 61

def t_cost
  @t_cost
end

#typeObject (readonly)

The type of the hashing function.



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

def type
  @type
end

#versionObject (readonly)

The version number of the hashing function.



58
59
60
# File 'lib/argon2id/password.rb', line 58

def version
  @version
end

Class Method Details

.create(pwd, t_cost: Argon2id.t_cost, m_cost: Argon2id.m_cost, parallelism: Argon2id.parallelism, salt_len: Argon2id.salt_len, output_len: Argon2id.output_len) ⇒ Object

Create a new Password object that hashes a given plain text password pwd.

  • :t_cost: integer (default 2) the “time cost” given as a number of iterations

  • :m_cost: integer (default 19456) the “memory cost” given in kibibytes

  • :parallelism: integer (default 1) the number of threads and compute lanes to use

  • :salt_len: integer (default 16) the salt size in bytes

  • :output_len: integer (default 32) the desired length of the hash in bytes

For example, with the default configuration:

password = Argon2id::Password.create("password")
password.to_s
#=> "$argon2id$v=19$m=19456,t=2,p=1$FI8yp1gXbthJCskBlpKPoQ$nOfCCpS2r+I8GRN71cZND4cskn7YKBNzuHUEO3YpY2s"

When overriding the configuration:

password = Argon2id::Password.create("password", t_cost: 3, m_cost: 12288)
password.to_s
#=> "$argon2id$v=19$m=12288,t=3,p=1$JigW7fFn+N3NImt+aWpuzw$eM5F1cKeIBALNTU6LuWra75Zi2nymGvQLWzJzVFv0Nc"


91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/argon2id/password.rb', line 91

def self.create(pwd, t_cost: Argon2id.t_cost, m_cost: Argon2id.m_cost, parallelism: Argon2id.parallelism, salt_len: Argon2id.salt_len, output_len: Argon2id.output_len)
  new(
    Argon2id.hash_encoded(
      Integer(t_cost),
      Integer(m_cost),
      Integer(parallelism),
      String(pwd),
      OpenSSL::Random.random_bytes(Integer(salt_len)),
      Integer(output_len)
    )
  )
end

Instance Method Details

#==(other) ⇒ Object Also known as: is_password?

Compare the password with the given plain text, returning true if it verifies successfully.

password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$FI8yp1gXbthJCskBlpKPoQ$nOfCCpS2r+I8GRN71cZND4cskn7YKBNzuHUEO3YpY2s")
password == "password"    #=> true
password == "notpassword" #=> false


132
133
134
# File 'lib/argon2id/password.rb', line 132

def ==(other)
  Argon2id.verify(encoded, String(other))
end