class RbNaCl::PasswordHash::Argon2
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.
Constants
- ALG_DEFAULT
- ARGON2_MAX_OUTLEN
- ARGON2_MIN_OUTLEN
- ARGON_ERROR_CODES
- MEMLIMIT_MAX
- MEMLIMIT_MIN
- OPSLIMIT_MAX
- OPSLIMIT_MIN
Public Class Methods
Clamps digest size between 16..4294967295
@raise [LengthError] if the value is out of range
@return [Integer] digest_size a valid value for digest size
# File lib/rbnacl/password_hash/argon2.rb, line 197 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
Compares a password with a digest string
@param [String] password to be hashed @param [String] digest_string to compare to
@return [boolean] true if password matches digest_string
# File lib/rbnacl/password_hash/argon2.rb, line 147 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
Clamps memlimit between 8192 bytes and 4 TB (eg. 2**32)
@param [Integer] memlimit, in bytes
@raise [ArgumentError] if the value is out of range
@return [Integer] memlimit a valid value for memlimit
# File lib/rbnacl/password_hash/argon2.rb, line 181 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
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
@param [Integer] opslimit the CPU cost (1..10) @param [Integer] memlimit the memory cost (e.g. 2**24) @param [Integer] digest_size the byte length of the resulting digest
@return [RbNaCl::PasswordHash::Argon2] An Argon2
password hasher object
# File lib/rbnacl/password_hash/argon2.rb, line 96 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
Clamps opslimit to an acceptable range (3..10)
@param [Integer] opslimit value to be checked
@raise [ArgumentError] if the value is out of range
@return [Integer] opslimit a valid value for opslimit
# File lib/rbnacl/password_hash/argon2.rb, line 163 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
Public Instance Methods
Calculate an Argon2
digest for a given password and salt
@param [String] password to be hashed @param [String] salt to make the digest unique
@return [String] scrypt digest of the string as raw bytes
# File lib/rbnacl/password_hash/argon2.rb, line 108 def digest(password, salt) raise ArgumentError, "digest_size is required" unless @digest_size digest = Util.zeros(@digest_size) salt = Util.check_string(salt, SALTBYTES, "salt") status = self.class.pwhash( digest, @digest_size, password, password.bytesize, salt, @opslimit, @memlimit, ALG_DEFAULT ) raise CryptoError, ARGON_ERROR_CODES[status] if status.nonzero? digest end
Calculate an Argon2
digest in the form of a crypt-style string. The resulting string encodes the parameters and salt.
@param [String] password to be hashed
@return [String] argon2 digest string
# File lib/rbnacl/password_hash/argon2.rb, line 128 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