CRYPTO_ARGON2(3MONOCYPHER) | 3MONOCYPHER | CRYPTO_ARGON2(3MONOCYPHER) |
crypto_argon2
—
password-based key derivation
#include
<monocypher.h>
void
crypto_argon2
(uint8_t *hash,
uint32_t hash_size, void
*work_area, crypto_argon2_config config,
crypto_argon2_inputs inputs,
crypto_argon2_extras extras);
extern const crypto_argon2_extras crypto_argon2_no_extras;
Argon2 is a resource intensive password-based key derivation scheme optimised for the typical x86-like processor. It runs in constant time with respect to the contents of the password.
Typical applications are password checking (for online services) and key derivation (for encryption). Derived keys can be used to encrypt, for example, private keys or password databases.
The version provided by Monocypher has no threading support, so the degree of parallelism is limited to 1. This is considered good enough for most purposes.
The arguments to
crypto_argon2
()
are:
crypto_argon2
() are identical between two calls,
then the output hash is also identical. In other
words, all input parameters passed to the function influence the output
value.The work area is automatically wiped by
crypto_argon2
().
crypto_argon2
().The crypto_argon2_config struct is defined as follows:
typedef struct { uint32_t algorithm; uint32_t nb_blocks; uint32_t nb_passes; uint32_t nb_lanes; } crypto_argon2_config;
Its members are:
CRYPTO_ARGON2_D
indicates Argon2d,
CRYPTO_ARGON2_I
indicates Argon2i,
CRYPTO_ARGON2_ID
indicates Argon2id.Users who want to take actual advantage of parallelism should instead call several instances of Argon2 in parallel. The extras parameter may be used to differentiate the inputs and produce independent digests that can be hashed together.
The crypto_argon2_inputs struct is defined as follows:
typedef struct { const uint8_t *pass; const uint8_t *salt; uint32_t pass_size; uint32_t salt_size; } crypto_argon2_inputs;
Its members are:
The crypto_argon2_extras struct is defined as follows:
typedef struct { const uint8_t *key; const uint8_t *ad; uint32_t key_size; uint32_t ad_size; } crypto_argon2_extras;
Its members are:
NULL
if
key_size is zero. The key is generally not needed,
but it does have some uses. In the context of password derivation, it
would be stored separately from the password database and would remain
secret even if an attacker were to steal the database. Note that changing
the key requires rehashing the user's password, which can only be done
when the user logs in.NULL
if
ad_size is zero. This is additional data that goes
into the hash, similar to the authenticated encryption construction in
crypto_aead_lock(3monocypher).
Can be used to differentiate inputs when invoking several Argon2 instances
in parallel: each instance gets a different thread number as additional
data, generating as many independent digests as we need. We can then hash
those digests with
crypto_blake2b(3monocypher).The arguments in the config and extras structs may overlap or point at the same buffer.
Use crypto_verify16(3monocypher), crypto_verify32(3monocypher), or crypto_verify64(3monocypher) to compare password hashes to prevent timing attacks.
To select the nb_blocks and nb_passes parameters, it should first be decided how long the computation should take. For user authentication, values somewhere between half a second (convenient) and several seconds (paranoid) are recommended. The computation should use as much memory as can be spared.
Since parameter selection depends on your hardware, some trial and error will be required in order to determine the ideal settings. Argon2i with three iterations and 100000 blocks (one hundred megabytes of memory) is a good starting point. So is Argon2id with one iteration and 300000 blocks. Adjust nb_blocks first. If using all available memory is not slow enough, increase nb_passes.
crypto_argon2
() returns nothing.
The following example assumes the existence of
arc4random_buf
(), which fills the given buffer with
cryptographically secure random bytes. If
arc4random_buf
() does not exist on your system, see
intro(3monocypher) for advice about how
to generate cryptographically secure random bytes.
This example shows how to hash a password with the recommended baseline parameters:
uint8_t hash[32]; /* Output hash */ uint8_t salt[16]; /* Random salt */ crypto_argon2_config config = { .algorithm = CRYPTO_ARGON2_I, /* Argon2i */ .nb_blocks = 100000, /* 100 megabytes */ .nb_passes = 3, /* 3 iterations */ .nb_lanes = 1 /* Single-threaded */ }; crypto_argon2_inputs inputs = { .pass = (const uint8_t *)"Okay Password!", /* User password */ .pass_size = 14, /* Password length */ .salt = salt, /* Salt for the password */ .salt_size = 16 }; crypto_argon2_extras extras = {0}; /* Extra parameters unused */ void *work_area = malloc(nb_blocks * 1024); /* Work area */ if (work_area == NULL) { /* Handle malloc() failure */ /* Wipe secrets if they are no longer needed */ crypto_wipe(password, password_size); } else { arc4random_buf(salt, 16); crypto_argon2i(hash, 32, work_area, config, inputs, extras); /* Wipe secrets if they are no longer needed */ crypto_wipe(password, password_size); free(work_area); }
crypto_aead_lock(3monocypher), crypto_verify16(3monocypher), crypto_wipe(3monocypher), intro(3monocypher)
crypto_argon2
() implements Argon2 as
described in RFC 9106, but does not support actual parallelism.
In Monocypher 0.1, crypto_argon2i
()
implemented Argon2i and had all extra parameters as input. It was then split
into a crypto_argon2i_general
() and a simplified
crypto_argon2i
() function in Monocypher 1.1.0. Both
were replaced by crypto_argon2
() in Monocypher
4.0.0.
Monocypher does not perform any input validation. Any deviation from the algorithm constants, specified input and output length ranges results in undefined behaviour. Make sure your inputs are correct.
February 25, 2023 | Debian |