Class: RbNaCl::PasswordHash::Argon2
- Inherits:
-
Object
- Object
- RbNaCl::PasswordHash::Argon2
- Extended by:
- Sodium
- Defined in:
- lib/rbnacl/password_hash/argon2.rb
Overview
Since version 1.0.9, Sodium provides a password hashing scheme called Argon2. Argon2 summarizes the state of the art in the design of memory- hard functions. It aims at the highest memory filling rate and effective use of multiple computing units, while still providing defense against tradeoff attacks. It prevents ASICs from having a significant advantage over software implementations.
Constant Summary collapse
- ARGON2_MIN_OUTLEN =
16
- ARGON2_MAX_OUTLEN =
0xFFFFFFFF
- ARGON_ERROR_CODES =
{ -1 => "ARGON2_OUTPUT_PTR_NULL", -2 => "ARGON2_OUTPUT_TOO_SHORT", -3 => "ARGON2_OUTPUT_TOO_LONG", -4 => "ARGON2_PWD_TOO_SHORT", -5 => "ARGON2_PWD_TOO_LONG", -6 => "ARGON2_SALT_TOO_SHORT", -7 => "ARGON2_SALT_TOO_LONG", -8 => "ARGON2_AD_TOO_SHORT", -9 => "ARGON2_AD_TOO_LONG", -10 => "ARGON2_SECRET_TOO_SHORT", -11 => "ARGON2_SECRET_TOO_LONG", -12 => "ARGON2_TIME_TOO_SMALL", -13 => "ARGON2_TIME_TOO_LARGE", -14 => "ARGON2_MEMORY_TOO_LITTLE", -15 => "ARGON2_MEMORY_TOO_MUCH", -16 => "ARGON2_LANES_TOO_FEW", -17 => "ARGON2_LANES_TOO_MANY", -18 => "ARGON2_PWD_PTR_MISMATCH", -19 => "ARGON2_SALT_PTR_MISMATCH", -20 => "ARGON2_SECRET_PTR_MISMATCH", -21 => "ARGON2_AD_PTR_MISMATCH", -22 => "ARGON2_MEMORY_ALLOCATION_ERROR", -23 => "ARGON2_FREE_MEMORY_CBK_NULL", -24 => "ARGON2_ALLOCATE_MEMORY_CBK_NULL", -25 => "ARGON2_INCORRECT_PARAMETER", -26 => "ARGON2_INCORRECT_TYPE", -27 => "ARGON2_OUT_PTR_MISMATCH", -28 => "ARGON2_THREADS_TOO_FEW", -29 => "ARGON2_THREADS_TOO_MANY", -30 => "ARGON2_MISSING_ARGS", -31 => "ARGON2_ENCODING_FAIL", -32 => "ARGON2_DECODING_FAIL", -33 => "ARGON2_THREAD_FAIL", -34 => "ARGON2_DECODING_LENGTH_FAIL", -35 => "ARGON2_VERIFY_MISMATCH" }.freeze
Class Method Summary collapse
-
.digest_size_value(digest_size) ⇒ Integer
Clamps digest size between 16..4294967295.
-
.digest_str_verify(password, digest_string) ⇒ boolean
Compares a password with a digest string.
-
.memlimit_value(memlimit) ⇒ Integer
Clamps memlimit between 8192 bytes and 4 TB (eg. 2**32).
-
.opslimit_value(opslimit) ⇒ Integer
Clamps opslimit to an acceptable range (3..10).
Instance Method Summary collapse
-
#digest(password, salt, algo = nil) ⇒ String
Calculate an Argon2 digest for a given password and salt.
-
#digest_str(password) ⇒ String
Calculate an Argon2 digest in the form of a crypt-style string.
-
#initialize(opslimit, memlimit, digest_size = nil) ⇒ RbNaCl::PasswordHash::Argon2
constructor
Create a new Argon2 password hash object.
Methods included from Sodium
primitive, sodium_constant, sodium_function, sodium_function_with_return_code, sodium_primitive, sodium_type
Constructor Details
#initialize(opslimit, memlimit, digest_size = nil) ⇒ RbNaCl::PasswordHash::Argon2
Create a new Argon2 password hash object
opslimit and memlimit may be an integer, or one of the following symbols:
[:interactive] Suitable for interactive online operations. This requires 32 Mb of dedicated RAM. [:moderate] A compromise between interactive and sensitive. This requires 128 Mb of dedicated RAM, and takes about 0.7 seconds on a 2.8 Ghz Core i7 CPU. [:sensitive] For highly sensitive and non-interactive operations. This requires 128 Mb of dedicated RAM, and takes about 0.7 seconds on a 2.8 Ghz Core i7 CPU
95 96 97 98 99 |
# File 'lib/rbnacl/password_hash/argon2.rb', line 95 def initialize(opslimit, memlimit, digest_size = nil) @opslimit = self.class.opslimit_value(opslimit) @memlimit = self.class.memlimit_value(memlimit) @digest_size = self.class.digest_size_value(digest_size) if digest_size end |
Class Method Details
.digest_size_value(digest_size) ⇒ Integer
Clamps digest size between 16..4294967295
215 216 217 218 219 220 221 |
# File 'lib/rbnacl/password_hash/argon2.rb', line 215 def self.digest_size_value(digest_size) digest_size = digest_size.to_i raise LengthError, "digest size too short" if digest_size < ARGON2_MIN_OUTLEN raise LengthError, "digest size too long" if digest_size > ARGON2_MAX_OUTLEN digest_size end |
.digest_str_verify(password, digest_string) ⇒ boolean
Compares a password with a digest string
164 165 166 167 168 169 170 171 172 |
# File 'lib/rbnacl/password_hash/argon2.rb', line 164 def self.digest_str_verify(password, digest_string) raise ArgumentError, "password must be a String" unless password.is_a?(String) raise ArgumentError, "digest_string must be a String" unless digest_string.is_a?(String) pwhash_str_verify( digest_string, password, password.bytesize ) end |
.memlimit_value(memlimit) ⇒ Integer
Clamps memlimit between 8192 bytes and 4 TB (eg. 2**32)
199 200 201 202 203 204 205 206 207 208 |
# File 'lib/rbnacl/password_hash/argon2.rb', line 199 def self.memlimit_value(memlimit) case memlimit when :interactive then MEMLIMIT_INTERACTIVE when :moderate then MEMLIMIT_MODERATE when :sensitive then MEMLIMIT_SENSITIVE when MEMLIMIT_MIN..MEMLIMIT_MAX then memlimit.to_i else raise ArgumentError, "memlimit must be within the range 2**(13..32)" end end |
.opslimit_value(opslimit) ⇒ Integer
Clamps opslimit to an acceptable range (3..10)
181 182 183 184 185 186 187 188 189 190 |
# File 'lib/rbnacl/password_hash/argon2.rb', line 181 def self.opslimit_value(opslimit) case opslimit when :interactive then OPSLIMIT_INTERACTIVE when :moderate then OPSLIMIT_MODERATE when :sensitive then OPSLIMIT_SENSITIVE when OPSLIMIT_MIN..OPSLIMIT_MAX then opslimit.to_i else raise ArgumentError, "opslimit must be within the range 3..10" end end |
Instance Method Details
#digest(password, salt, algo = nil) ⇒ String
Calculate an Argon2 digest for a given password and salt
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/rbnacl/password_hash/argon2.rb', line 111 def digest(password, salt, algo = nil) raise ArgumentError, "digest_size is required" unless @digest_size digest = Util.zeros(@digest_size) salt = Util.check_string(salt, SALTBYTES, "salt") if algo.nil? algorithm = ALG_DEFAULT elsif algo == :argon2i algorithm = ALG_ARGON2I13 elsif algo == :argon2id && Sodium::Version::ARGON2ID_SUPPORTED algorithm = ALG_ARGON2ID13 else raise ArgumentError, "digest algorithm is not supported" end status = self.class.pwhash( digest, @digest_size, password, password.bytesize, salt, @opslimit, @memlimit, algorithm ) raise CryptoError, ARGON_ERROR_CODES[status] if status.nonzero? digest end |
#digest_str(password) ⇒ String
Calculate an Argon2 digest in the form of a crypt-style string. The resulting string encodes the parameters and salt.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/rbnacl/password_hash/argon2.rb', line 143 def digest_str(password) raise ArgumentError, "password must be a String" unless password.is_a?(String) result = Util.zeros(STRBYTES) ok = self.class.pwhash_str( result, password, password.bytesize, @opslimit, @memlimit ) raise CryptoError, "unknown error in Argon2#digest_str" unless ok result.delete("\x00") end |