crypto_argon2i —
password key derivation
#include
<monocypher.h>
void
crypto_argon2i(
uint8_t
*hash,
uint32_t hash_size,
void *work_area,
uint32_t nb_blocks,
uint32_t nb_iterations,
const uint8_t *password,
uint32_t password_size,
const uint8_t *salt,
uint32_t salt_size);
void
crypto_argon2i_general(
uint8_t
*hash,
uint32_t hash_size,
void *work_area,
uint32_t nb_blocks,
uint32_t nb_iterations,
const uint8_t *password,
uint32_t password_size,
const uint8_t *salt,
uint32_t salt_size,
const uint8_t *key,
uint32_t key_size,
const uint8_t *ad,
uint32_t ad_size);
Argon2i is a resource intensive password 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_argon2i() are:
-
-
- hash
- The output hash.
-
-
- hash_size
- Length of hash, in bytes.
This argument should be set to 32 or 64 for compatibility with the
crypto_verify*() constant time comparison
functions.
-
-
- work_area
- Temporary buffer for the algorithm, allocated by the
caller. It must be nb_blocks ×
1024 bytes big, and suitably aligned for 64-bit integers. If you are not
sure how to allocate that buffer, just use
malloc().
The work area is automatically wiped by
crypto_argon2i().
-
-
- nb_blocks
- The number of blocks for the work area. Must be at least 8.
A value of 100000 (one hundred megabytes) is a good starting point. If the
computation takes too long, reduce this number. If it is too fast,
increase this number. If it is still too fast with all available memory,
increase nb_iterations.
-
-
- nb_iterations
- The number of iterations. It must be at least 1. A value of
3 is strongly recommended; any value lower
than 3 enables significantly more efficient attacks.
-
-
- password
- The password to hash. It should be wiped with
crypto_wipe(3monocypher)
after being hashed.
-
-
- password_size
- Length of password, in
bytes.
-
-
- salt
- A password salt. This should be filled with random bytes,
generated separately for each password to be hashed. See
intro(3monocypher) for
advice about generating random bytes (use the operating system's random
number generator).
-
-
- salt_size
- Length of salt, in bytes.
Must be at least 8. 16 is recommended.
The output hash must not overlap with the work area, or it will be wiped along
with it. Any other overlap is permitted.
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_iterations 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. Three iterations and 100000
blocks (that is, one hundred megabytes of memory) is a good starting point.
Adjust
nb_blocks first. If using all
available memory is not slow enough, increase
nb_iterations.
crypto_argon2i_general() is a variant of
crypto_argon2i() that supports keyed hashing and
hashing of additional data. The additional arguments are:
-
-
- key
- A key to use in the hash. Can be
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 is
only possible upon user login.
-
-
- key_size
- Length of key, in bytes.
Must be zero if there is no key.
-
-
- ad
- Additional data. This is additional data that goes into the
hash, similar to the authenticated encryption with authenticated data
(AEAD) construction in
crypto_lock_aead(3monocypher).
This most likely has no practical application but is exposed for the sake
of completeness. This parameter may be
NULL
if
ad_size is zero.
-
-
- ad_size
- Length of ad, in bytes.
Must be zero if there is no additional data.
These functions return 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 */
char *password = "Okay Password!"; /* User's password */
uint32_t password_size = 14; /* Password length */
uint8_t salt[16]; /* Random salt */
const uint32_t nb_blocks = 100000; /* 100 megabytes */
const uint32_t nb_iterations = 3; /* 3 iterations */
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, nb_blocks, nb_iterations,
(uint8_t *)password, password_size,
salt, 16);
/* Wipe secrets if they are no longer needed */
crypto_wipe(password, password_size);
free(work_area);
}
crypto_lock(3monocypher),
crypto_verify16(3monocypher),
crypto_wipe(3monocypher),
intro(3monocypher)
These functions implement Argon2i. An RFC draft is being maintained.
The
crypto_argon2i_general() function first
appeared in Monocypher 0.1 but was called
crypto_argon2i(); it was renamed to its current
name in Monocypher 1.1.0. The current
crypto_argon2i() first appeared in Monocypher
1.1.0.
Any deviation from the specified input and output length ranges results in
undefined behaviour. Make sure your inputs are
correct.