NAME

Crypt::Sodium::XS::pwhash - Password hashing and verification

SYNOPSIS

use Crypt::Sodium::XS::pwhash ":default";

my $passphrase = "this is a passphrase.";

# key derivation
my $salt = sodium_random_bytes($pwhash->SALTBYTES);
my $key_size = 32;
my $key = pwhash($passphrase, $salt, $key_size);

# password storage
my $pwhash_str = pwhash_str($passphrase);
die "bad password" unless pwhash_verify($pwhash_str, $passphrase);
if (pwhash_str_needs_rehash($pwhash_str)) {
  my $new_pwhash_str = pwhash_str($passphrase);
}

DESCRIPTION

Secret keys used to encrypt or sign confidential data have to be chosen from a very large keyspace. However, passwords are usually short, human-generated strings, making dictionary attacks practical.

Crypt::Sodium::XS::pwhash functions derive a secret key of any size from a password and a salt.

    The generated key has the size defined by the application, no matter what the password length is.

    The same password hashed with same parameters will always produce the same output.

    The same password hashed with different salts will produce different outputs.

    The function deriving a key from a password and a salt is CPU intensive and intentionally requires a fair amount of memory. Therefore, it mitigates brute-force attacks by requiring a significant effort to verify each password.

Common use cases:

  • Password storage

    Or rather: storing what it takes to verify a password without having to store the actual password.

  • Deriving a secret key from a password

    For example, for disk encryption. Crypt::Sodium::XS::pwhash's high-level pwhash_* API currently leverages the Argon2id function on all platforms (when not using primitive-specific functions). This can change at any point in time, but it is guaranteed that a given version of libsodium can verify all hashes produced by all previous versions, from any platform. Applications don't have to worry about backward compatibility.

The scryptsalsa208sha256 primitive uses the more conservative and widely deployed Scrypt function.

FUNCTIONS

Nothing is exported by default. A :default tag imports the functions and constants documented below. A separate :<primitive> import tag is provided for each of the primitives listed in "PRIMITIVES". These tags import the pwhash_<primitive>_* functions and constants for that primitive. A :all tag imports everything.

pwhash

pwhash_<primitive>

my $hash = pwhash($password, $salt, $hash_size, $opslimit, $memlimit);

$password is an arbitrary-length input password. It may be a Crypt::Sodium::XS::MemVault.

$salt is an arbitrary string which must be "pwhash_SALTBYTES" bytes. It may be random and does not need to be kept secret.

$hash_size is optional. It specifies the desired output hash size, in bytes. It must be in the range of "pwhash_BYTES_MIN" to "pwhash_BYTES_MAX", inclusive. If it is omitted or numifies to zero (undef, 0, ""), the default of "pwhash_STRBYTES" will be used.

$opslimit is optional. It specifies the cpu-hardness of generating the hash. It must be in the range of "pwhash_OPSLIMIT_MIN" to "pwhash_OPSLIMIT_MAX", inclusive. If it is omitted or numifies to zero (undef, 0, ""), the default of "pwhash_OPSLIMIT_INTERACTIVE" will be used.

$memlimit is optional. It specifies the memory-hardness of generating the hash. It must be in the range of "pwhash_MEMLIMIT_MIN" to "pwhash_MEMLIMIT_MAX", inclusive. If it is omitted or numifies to zero (undef, 0, ""), the default of "pwhash_MEMLIMIT_INTERACTIVE" will be used.

Returns a Crypt::Sodium::XS::MemVault: the output hash of $hash_size bytes.

pwhash_salt

my $salt = pwhash_salt();

Returns a random salt of "pwhash_SALTBYTES" bytes.

pwhash_str

my $hash_string = pwhash_str($password, $opslimit, $memlimit);

$password is an arbitrary-length input password. It may be a Crypt::Sodium::XS::MemVault.

$opslimit is optional. It specifies the cpu-hardness of generating the hash. It must be in the range of "pwhash_OPSLIMIT_MIN" to "pwhash_OPSLIMIT_MAX", inclusive. If it is omitted or numifies to zero (undef, 0, ""), the default of "pwhash_OPSLIMIT_INTERACTIVE" will be used.

$memlimit is optional. It specifies the memory-hardness of generating the hash. It must be in the range of "pwhash_MEMLIMIT_MIN" to "pwhash_MEMLIMIT_MAX", inclusive. If it is omitted or numifies to zero (undef, 0, ""), the default of "pwhash_MEMLIMIT_INTERACTIVE" will be used.

Returns an ASCII encoded string into out, 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.

pwhash_str_needs_rehash

my $needs_rehash = pwhash_str_needs_rehash($string);
my $needs_rehash = pwhash_str_needs_rehash($string, $opslimit);
my $needs_rehash = pwhash_str_needs_rehash($string, $opslimit, $memlimit);

$hash_string is a string returned by a previous call to "str".

$opslimit is optional. It specifies the required cpu-hardness of generating the hash. It must be in the range of "pwhash_OPSLIMIT_MIN" to "pwhash_OPSLIMIT_MAX", inclusive. If it is omitted or numifies to zero (undef, 0, ""), the default of "pwhash_OPSLIMIT_INTERACTIVE" will be used.

$memlimit is optional. It specifies the required memory-hardness of generating the hash. It must be in the range of "pwhash_MEMLIMIT_MIN" to "pwhash_MEMLIMIT_MAX", inclusive. If it is omitted or numifies to zero (undef, 0, ""), the default of "pwhash_MEMLIMIT_INTERACTIVE" will be used.

Returns false if $hash_str is a valid password verification string (as generated by "pwhash_str") and matches the parameters $opslimit, $memlimit, and the current primitive, true otherwise.

pwhash_verify

my $is_valid = pwhash_verify($hash_string, $password);

$hash_string is a string returned by a previous call to "str".

$password is an arbitrary-length input password. It may be a Crypt::Sodium::XS::MemVault.

Returns true if $hash_string is a valid password verification string (as generated by "str") for $password, false otherwise.

CONSTANTS

pwhash_PRIMITIVE

my $default_primitive = pwhash_PRIMITIVE();

Returns the name of the default primitive.

pwhash_BYTES_MAX

my $hash_max_size = pwhash_BYTES_MAX();

Returns the maximum size, in bytes, of hash output.

pwhash_BYTES_MIN

my $hash_min_size = pwhash_BYTES_MAX();

Returns the minimum size, in bytes, of hash output.

pwhash_MEMLIMIT_INTERACTIVE

pwhash_OPSLIMIT_INTERACTIVE

my $memlimit = pwhash_MEMLIMIT_INTERACTIVE();
my $opslimit = pwhash_OPSLIMIT_INTERACTIVE();

Returns baseline values for interactive online applications. This currently requires 64 MiB of dedicated RAM.

pwhash_MEMLIMIT_MODERATE

pwhash_OPSLIMIT_MODERATE

my $memlimit = pwhash_MEMLIMIT_MODERATE();
my $opslimit = pwhash_OPSLIMIT_MODERATE();

Returns baseline settings slightly higher than interactive. This requires 256 MiB of dedicated RAM and takes about 0.7 seconds on a 2.8 GHz Core i7 CPU.

pwhash_MEMLIMIT_SENSITIVE

pwhash_OPSLIMIT_SENSITIVE

my $memlimit = pwhash_MEMLIMIT_SENSITIVE();
my $opslimit = pwhash_OPSLIMIT_SENSITIVE();

Returns baseline settings for highly-sensitive and non-interactive sessions. With these parameters, deriving a key takes about 3.5 seconds on a 2.8 GHz Core i7 CPU and requires 1024 MiB of dedicated RAM.

pwhash_MEMLIMIT_MAX

my $memlimit = pwhash_MEMLIMIT_MAX();

Returns the maximum memlimit.

pwhash_MEMLIMIT_MIN

my $memlimit = pwhash_MEMLIMIT_MIN();

Returns the minimum memlimit.

pwhash_OPSLIMIT_MAX

my $memlimit = pwhash_OPSLIMIT_MAX();

Returns the maximum opslimit.

pwhash_OPSLIMIT_MIN

my $memlimit = pwhash_OPSLIMIT_MIN();

Returns the minimum opslimit.

pwhash_PASSWD_MAX

my $hash_max_size = pwhash_PASSWD_MAX();

Returns the maximum size, in bytes, of password input.

pwhash_PASSWD_MIN

my $hash_min_size = pwhash_PASSWD_MIN();

Returns the minimum size, in bytes, of password input.

pwhash_SALTBYTES

my $salt_size = pwhash_SALTBYTES();

Returns the size, in bytes, of a salt.

pwhash_STRBYTES

my $hash_string_size = pwhash_STRBYTES();

Returns the size, in bytes, of a string returned by "pwhash_str".

pwhash_STRPREFIX

my $hash_string_prefix = pwhash_STRPREFIX();

Returns the primitive-specific prefix of a string returned by "str".

PRIMITIVES

All constants (except _PRIMITIVE) and functions have pwhash_<primitive>-prefixed couterparts (e.g., pwhash_argon2id, pwhash_argon2i_STRBYTES).

argon2i and argon2id are version 1.3 of the primitive.

  • argon2i

  • argon2id (default)

  • scryptsalsa208sha256

GUIDELINES FOR CHOOSING OPSLIMIT AND MEMLIMIT

Start by determining how much memory the function can use. What will be the highest number of processes evaluating the function simultaneously (ideally, no more than 1 per CPU core)? How much physical memory is guaranteed to be available?

Set memlimit to the amount of memory you want to reserve for password hashing.

Then set opslimit to 3 and measure the time it takes to hash a password.

If this is way too long for your application, reduce memlimit, but keep opslimit set to 3.

If the function is so fast that you can afford it to be more computationally intensive without any usability issues, then increase opslimit.

For online use (e.g. logging in on a website), a 1 second computation is likely to be the acceptable maximum.

For interactive use (e.g. a desktop application), a 5 second pause after having entered a password is acceptable if the password doesn’t need to be entered more than once per session.

For non-interactive and infrequent use (e.g. restoring an encrypted backup), an even slower computation can be an option.

However, the best defense against brute-force password cracking is to use strong passwords.

SEE ALSO

Crypt::Sodium::XS
Crypt::Sodium::XS::OO::pwhash
https://doc.libsodium.org/password_hashing

FEEDBACK

For reporting bugs, giving feedback, submitting patches, etc. please use the following:

AUTHOR

Brad Barden <perlmodules@5c30.org>

COPYRIGHT & LICENSE

Copyright (c) 2022 Brad Barden. All rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.