Class: Argon2id::Password

Inherits:
Object
  • Object
show all
Defined in:
lib/argon2id/password.rb,
lib/argon2id/extension.rb,
ext/argon2id/argon2id.c

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.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
  \$
  argon2id
  (?:\$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

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)


115
116
117
118
119
120
121
122
123
124
125
# File 'lib/argon2id/password.rb', line 115

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

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

Instance Attribute Details

#encodedObject (readonly) Also known as: to_s

The encoded password hash.



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

def encoded
  @encoded
end

#m_costObject (readonly)

The “memory cost” of the hashing function.



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

def m_cost
  @m_cost
end

#outputObject (readonly)

The hash output.



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

def output
  @output
end

#parallelismObject (readonly)

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



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

def parallelism
  @parallelism
end

#saltObject (readonly)

The salt.



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

def salt
  @salt
end

#t_costObject (readonly)

The “time cost” of the hashing function.



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

def t_cost
  @t_cost
end

#versionObject (readonly)

The version number of the hashing function.



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

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"


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

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(
    hash_encoded(
      Integer(t_cost),
      Integer(m_cost),
      Integer(parallelism),
      String(pwd),
      OpenSSL::Random.random_bytes(Integer(salt_len)),
      Integer(output_len)
    )
  )
end

.valid_hash?(encoded) ⇒ Boolean

Check an encoded hash is a valid Argon2id hash.

Returns true if so and false if not.

Returns:

  • (Boolean)


106
107
108
# File 'lib/argon2id/password.rb', line 106

def self.valid_hash?(encoded)
  PATTERN.match?(String(encoded))
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


136
137
138
# File 'lib/argon2id/password.rb', line 136

def ==(other)
  verify(String(other))
end