
Rename Sodium::Pwhash#key_derive to #derive_key. Rename Sodium::Pwhash#kdf_derive to #derive_kdf. Rename Sodium::CryptoBox#encrypt_easy to #encrypt. Rename Sodium::CryptoBox#decrypt_easy to #decrypt. Rename Sodium::SecretBox#encrypt_easy to #encrypt. Rename Sodium::SecretBox#decrypt_easy to #decrypt. Remove redundant Sodium::SecretBox#encrypt methods.
111 lines
3.8 KiB
Crystal
111 lines
3.8 KiB
Crystal
require "./lib_sodium"
|
|
require "./secure_buffer"
|
|
|
|
module Sodium
|
|
# [Argon2 Password Hashing](https://libsodium.gitbook.io/doc/password_hashing/the_argon2i_function)
|
|
# * #store #verify #needs_rehash? are used together for password verification.
|
|
# * #derive_key is used on it's own to generate password based keys.
|
|
#
|
|
# **See `examples/pwhash_selector.cr` for help on selecting parameters.**
|
|
class Pwhash
|
|
class PasswordVerifyError < Sodium::Error
|
|
end
|
|
|
|
OPSLIMIT_MIN = LibSodium.crypto_pwhash_opslimit_min
|
|
OPSLIMIT_INTERACTIVE = LibSodium.crypto_pwhash_opslimit_interactive
|
|
OPSLIMIT_MODERATE = LibSodium.crypto_pwhash_opslimit_moderate
|
|
OPSLIMIT_SENSITIVE = LibSodium.crypto_pwhash_opslimit_sensitive
|
|
OPSLIMIT_MAX = LibSodium.crypto_pwhash_opslimit_max
|
|
|
|
MEMLIMIT_MIN = LibSodium.crypto_pwhash_memlimit_min
|
|
MEMLIMIT_INTERACTIVE = LibSodium.crypto_pwhash_memlimit_interactive
|
|
# Don't use this. Maximum of the library which is more ram than any computer.
|
|
MEMLIMIT_MAX = LibSodium.crypto_pwhash_memlimit_max
|
|
|
|
SALT_SIZE = LibSodium.crypto_pwhash_saltbytes
|
|
STR_SIZE = LibSodium.crypto_pwhash_strbytes
|
|
|
|
# Use the most recent algorithm Argon2id13 for new applications.
|
|
enum Mode
|
|
Argon2i13 = 1
|
|
Argon2id13 = 2
|
|
end
|
|
|
|
property opslimit = OPSLIMIT_INTERACTIVE
|
|
# Specified in bytes.
|
|
property memlimit = MEMLIMIT_INTERACTIVE
|
|
|
|
# Used by and must be set before calling #derive_key
|
|
property mode : Mode?
|
|
|
|
# Apply the most recent password hashing algorithm agains a password.
|
|
# Returns a opaque String which includes:
|
|
# * the result of a memory-hard, CPU-intensive hash function applied to the password
|
|
# * the automatically generated salt used for the previous computation
|
|
# * the other parameters required to verify the password, including the algorithm identifier, its version, opslimit and memlimit.
|
|
def create(pass)
|
|
outstr = Bytes.new STR_SIZE
|
|
if LibSodium.crypto_pwhash_str(outstr, pass, pass.bytesize, @opslimit, @memlimit) != 0
|
|
raise Sodium::Error.new("crypto_pwhash_str")
|
|
end
|
|
outstr
|
|
end
|
|
|
|
# Verify a password against a stored String.
|
|
# raises PasswordVerifyError on failure.
|
|
def verify(str, pass)
|
|
# BUG: verify str length
|
|
case LibSodium.crypto_pwhash_str_verify(str, pass, pass.bytesize)
|
|
when 0
|
|
# Passed
|
|
else
|
|
raise PasswordVerifyError.new
|
|
end
|
|
self
|
|
end
|
|
|
|
def needs_rehash?(str) : Bool
|
|
# BUG: verify str length
|
|
case LibSodium.crypto_pwhash_str_needs_rehash(str, @opslimit, @memlimit)
|
|
when 0
|
|
false
|
|
when 1
|
|
true
|
|
else
|
|
raise Sodium::Error.new("crypto_pwhash_str_needs_rehash")
|
|
end
|
|
end
|
|
|
|
# Returns a consistent key based on [salt, pass, key_bytes, mode, ops_limit, mem_limit] in a SecureBuffer
|
|
#
|
|
# Must set a mode before calling.
|
|
def derive_key(salt, pass, key_bytes)
|
|
derive_key salt.to_slice, pass.to_slice, key_bytes
|
|
end
|
|
|
|
def derive_key(salt : Bytes, pass : Bytes, key_bytes) : SecureBuffer
|
|
raise "salt expected #{SALT_SIZE} bytes, got #{salt.bytesize} " if salt.bytesize != SALT_SIZE
|
|
|
|
if m = mode
|
|
key = SecureBuffer.new key_bytes
|
|
if LibSodium.crypto_pwhash(key.to_slice, key.bytesize, pass, pass.bytesize, salt, @opslimit, @memlimit, m) != 0
|
|
raise Sodium::Error.new("crypto_pwhash_str")
|
|
end
|
|
key
|
|
else
|
|
raise ArgumentError.new("mode not set")
|
|
end
|
|
end
|
|
|
|
# Derives a key using derive_key and returns KDF.new(key)
|
|
def derive_kdf(salt, pass, key_bytes) : Kdf
|
|
key = derive_key salt, pass, key_bytes
|
|
Kdf.new key
|
|
end
|
|
|
|
# Returns a random salt for use with #derive_key
|
|
def random_salt
|
|
Random::Secure.random_bytes SALT_SIZE
|
|
end
|
|
end
|
|
end
|