Boring crypto that simply works

Password Key Derivation

Password key derivation with Argon2i.


#include <monocypher.h>

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);

    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 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:

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() , crypto_verify32() or crypto_verify64() 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, we recommend somewhere between half a second (convenient) and several seconds (paranoid). 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:

Return values

These functions return nothing.


This example shows how to hash a password with the recommended baseline parameters:

uint8_t        hash[32];                    /* Output hash     */
const uint8_t *password;                    /* User's password */
uint8_t        password_size;               /* Password length */
const 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 */
crypto_argon2i(hash, 32,
               work_area, nb_blocks, nb_iterations,
               password, password_size,
               salt, 16);
/* Wipe secrets if they are no longer needed */
crypto_wipe(password, password_size);


These functions implement Argon2i. An RFC draft is being maintained.


Any deviation from the specified input and output length ranges results in undefined behaviour. Make sure your inputs are correct.