Class: CryptCheckpass::Argon2
- Inherits:
-
CryptCheckpass
- Object
- CryptCheckpass
- CryptCheckpass::Argon2
- Defined in:
- lib/crypt_checkpass/argon2.rb
Overview
Argon2 the Password Hashing Competition winner.
Newhash:
You can use crypto_newhash
to create a new password hash using argon2:
crypt_newhash(password, id: 'argon2i', m_cost: 12, t_cost: 3)
where:
password
is the raw binary password that you want to digest.id
is "argon2i" when you want an argon2 hash. Due to underlying ruby-argons gem's restriction we do not support other argon2 variants.m_cost
andt_cost
are both integer parameter to the algorighm.
The generated password hash has following format.
Format:
Argon2 specifies its hash structure in detail named "PHC String Format", then ignored the format by itself. See also 1. Empirical findings show that the algorithm now has the following output format:
%r{
(?<digits> 0|[1-9]\d* ){0}
(?<b64> [a-zA-Z0-9+/] ){0}
(?<id> argon2 (i|d|id) ){0}
(?<v> v=19 ){0}
(?<m> m=\g<digits> ){0}
(?<t> t=\g<digits> ){0}
(?<p> p=\g<digits> ){0}
(?<salt> \g<b64>+ ){0}
(?<csum> \g<b64>+ ){0}
\A [$] \g<id>
(?: [$] \g<v> )?
[$] \g<m>
[,] \g<t>
[,] \g<p>
[$] \g<salt>
[$] \g<csum>
\z
}x
id
is "argon2" + something that denotes the variant of the hash. Variant "argon2i" seems most widely adopted.v
is, when available, a number 19. That doesn't mean anything. What is important is the absense of that parameter, which means the hash was genrated using old argon2 1.0 and shall be out of date.m
is the amount of memory filled by the algorithm (2**m KiB). Memory consumption depends on this parameter.t
is the mumber of passes over the memory. The running time depends linearly on this parameter.p
is the degree of parallelism, called "lanes" in the C implementation.salt
andcsum
are the salt and checksum strings. Both are encoded in base64-like strings that do not strictly follow RFC4648. They both can be arbitrary length. In case there are "unused" bits at the end of those fields, they shall be zero-filled.
Implementation limitations:
Ruby binding of argon2 library (ruby-argon2) is pretty well designed and can be recommended for daily uses. You really should use it whenever possible. The big problem is however, that it only supports argon2i. That is definitely OK for hash generation. However in verifying, it is desirable to support other variants.
In order to reroute this problem we load the ruby-argon2 gem, then ignore its ruby part and directly call the canonical C implementation via FFI.
Class Method Summary collapse
-
.checkpass?(pass, hash) ⇒ true, false
Checks if the given password matches the hash.
-
.newhash(pass, id: 'argon2i', m_cost: 12, t_cost: 3) ⇒ String
Generate a new password hash string.
-
.provide?(id) ⇒ true, false
Checks if the given ID can be handled by this class.
-
.understand?(str) ⇒ true, false
Checks if the given hash string can be handled by this class.
Methods inherited from CryptCheckpass
crypt_checkpass?, crypt_newhash
Class Method Details
.checkpass?(pass, hash) ⇒ true, false
Checks if the given password matches the hash.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/crypt_checkpass/argon2.rb', line 144 def self.checkpass? pass, hash h = hash p = pass n = pass.bytesize __load_argon2_dll case hash when /\A\$argon2i\$/ then ret = @dll.argon2i_verify h, p, n when /\A\$argon2d\$/ then ret = @dll.argon2d_verify h, p, n when /\A\$argon2id\$/ then ret = @dll.argon2id_verify h, p, n else raise ArgumentError, "unknown hash format %p", hash end case ret when 0 then return true when -35 then return false # ARGON2_VERIFY_MISMATCH else errstr = ::Argon2::ERRORS[ret.abs] || ret.to_s raise ::Argon2::ArgonHashFail, "got %s", errstr end end |
.newhash(pass, id: 'argon2i', m_cost: 12, t_cost: 3) ⇒ String
There is no way to specify salt. That's a bad idea.
Generate a new password hash string.
179 180 181 182 183 184 |
# File 'lib/crypt_checkpass/argon2.rb', line 179 def self.newhash pass, id: 'argon2i', m_cost: 12, t_cost: 3 require 'argon2' argon2 = ::Argon2::Password.new m_cost: m_cost, t_cost: t_cost return argon2.create pass end |
.provide?(id) ⇒ true, false
we don't support generating argon2d hashs.
Checks if the given ID can be handled by this class. A class is free to handle several IDs, like 'argon2i', 'argon2d', ...
169 170 171 |
# File 'lib/crypt_checkpass/argon2.rb', line 169 def self.provide? id return id == 'argon2i' end |
.understand?(str) ⇒ true, false
Checks if the given hash string can be handled by this class.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/crypt_checkpass/argon2.rb', line 120 def self.understand? str return match? str, %r{ (?<id> argon2 (i|d|id) ){0} (?<digits> 0|[1-9]\d* ){0} (?<b64> [a-zA-Z0-9+/] ){0} (?<v> v=19 ){0} (?<m> m=\g<digits> ){0} (?<t> t=\g<digits> ){0} (?<p> p=\g<digits> ){0} (?<salt> \g<b64>+ ){0} (?<csum> \g<b64>+ ){0} \A [$] \g<id> (?: [$] \g<v> )? [$] \g<m> [,] \g<t> [,] \g<p> [$] \g<salt> [$] \g<csum> \z }x end |