module RbNaCl::PasswordHash

Password hashing functions

These hash functions are designed specifically for the purposes of securely storing passwords in a way that they can be checked against a supplied password but an attacker who obtains a hash cannot easily reverse them back into the original password.

Unlike normal hash functions, which are intentionally designed to hash data as quickly as they can while remaining secure, password hashing functions are intentionally designed to be slow so they are hard for attackers to brute force.

All password hashing functions take a “salt” value which should be randomly generated on a per-password basis (using RbNaCl::Random, accept no substitutes)

All of them also take a CPU work factor, which increases the amount of computation needed to produce the digest.

Public Class Methods

argon2(password, salt, opslimit, memlimit, digest_size = 64) click to toggle source

argon2: state of the art in the design of memory-hard hashing functions.

@param [String] password to be hashed @param [String] salt to make the digest unique @param [Integer] opslimit the CPU cost (3..10) @param [Integer] memlimit the memory cost, in bytes @param [Integer] digest_size of the output

@raise [CryptoError] If calculating the digest fails for some reason.

@return [String] The argon2i digest as raw bytes

# File lib/rbnacl/password_hash.rb, line 50
def self.argon2(password, salt, opslimit, memlimit, digest_size = 64)
  argon2_supported? && Argon2.new(opslimit, memlimit, digest_size).digest(password, salt)
end
argon2_str(password, opslimit = :interactive, memlimit = :interactive) click to toggle source

argon2_str: crypt-style password digest

@param [String] password to be hashed @param [Integer] opslimit the CPU cost (3..10) @param [Integer] memlimit the memory cost, in bytes

@raise [CryptoError] If calculating the digest fails for some reason.

@return [String] The argon2i digest as crypt-style string

# File lib/rbnacl/password_hash.rb, line 63
def self.argon2_str(password, opslimit = :interactive, memlimit = :interactive)
  argon2_supported? && Argon2.new(opslimit, memlimit).digest_str(password)
end
argon2_valid?(password, str_digest) click to toggle source

argon2_valid?: verify crypt-style password digest

@param [String] password to verify @param [String] str_digest to verify

@return [Boolean] true if digest was created using password

# File lib/rbnacl/password_hash.rb, line 73
def self.argon2_valid?(password, str_digest)
  argon2_supported? && Argon2.digest_str_verify(password, str_digest)
end
scrypt(password, salt, opslimit, memlimit, digest_size = 64) click to toggle source

scrypt: the original sequential memory-hard password hashing function.

@param [String] password to be hashed @param [String] salt to make the digest unique @param [Integer] opslimit the CPU cost (e.g. 2**20) @param [Integer] memlimit the memory cost (e.g. 2**24) @param [Integer] digest_size of the output

@raise [CryptoError] If calculating the digest fails for some reason.

@return [String] The scrypt digest as raw bytes

# File lib/rbnacl/password_hash.rb, line 35
def self.scrypt(password, salt, opslimit, memlimit, digest_size = 64)
  SCrypt.new(opslimit, memlimit, digest_size).digest(password, salt)
end

Protected Class Methods

argon2_supported?() click to toggle source
# File lib/rbnacl/password_hash.rb, line 80
def argon2_supported?
  if RbNaCl::Sodium::Version::ARGON2_SUPPORTED
    true
  else
    raise NotImplementedError, "argon2 requires libsodium version >= 1.0.9" \
                               " (currently running #{RbNaCl::Sodium::Version::STRING})"
  end
end