CRYPTO_ARGON2(3MONOCYPHER)
β¨ CRYPTO_ARGON2 β¨
okay so bestie, welcome to the 3MONOCYPHER manual, and buckle up because we're talking about password-based key derivation and it's literally so important π
πΈ NAME πΈ
crypto_argon2 β password-based key derivation (yes, the fancy expensive one, no cap)
π¦ SYNOPSIS π¦
#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;
π DESCRIPTION π
so Argon2 is this resource intensive password-based key derivation scheme, and it's optimised for your typical x86-like processor, iykyk. the iconic thing about it? it runs in constant time with respect to the contents of the password β so no sneaky timing leaks, periodt β¨
typical applications are password checking (think online services, the whole login vibe) and key derivation (for encryption). derived keys can be used to encrypt stuff like, for example, private keys or password databases. main character energy fr.
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 β lowkey chill about it π§
the arguments to crypto_argon2() are:
hashβ the output hash. and listen, if all parameters tocrypto_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. every single one. π―hash_sizeβ length ofhash, in bytes. this argument should be set to32or64for compatibility with thecrypto_verify32(3monocypher)orcrypto_verify64(3monocypher)constant time comparison functions.work_areaβ temporary buffer for the algorithm, allocated by you, the caller. it must beconfig.nb_blocksΓ1024bytes big and suitably aligned for 64-bit integers. if you're not sure how to allocate that buffer, just usemalloc(3)bestie, it's giving simplicity.
the work area is automatically wiped by crypto_argon2() β¨
configβ a struct of typecrypto_argon2_configthat determines the base parameters of this particular instance of Argon2. these are domain parameters and remain constant between multiple invocations ofcrypto_argon2().inputsβ a struct of typecrypto_argon2_inputsthat contains the actual input parameters.extrasβ a struct of typecrypto_argon2_extrasthat contains optional extra input parameters, which are not commonly used (the side characters of this function, honestly).
π the crypto_argon2_config struct π
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:
algorithmβ this value determines which variant of Argon2 should be used.CRYPTO_ARGON2_Dindicates Argon2d,CRYPTO_ARGON2_Iindicates Argon2i,CRYPTO_ARGON2_IDindicates Argon2id. choose your fighter πnb_blocksβ the number of blocks for the work area. must be at least8 Γ nb_lanes. a value of100000(one hundred megabytes) is a good starting point. if the computation takes too long, reduce this number. if it's too fast, increase it. if it's still too fast with all available memory, increasenb_passes.nb_passesβ the number of passes. must be at least1. a value of3is strongly recommended when using Argon2i; any value lower than3enables significantly more efficient attacks. so like, don't skimp on this one, seriously πnb_lanesβ the level of parallelism. must be at least1. since Monocypher does not support threads, this does not actually increase the number of threads. it is only provided for completeness to match the Argon2 specification. otherwise, leaving it to1is strongly recommended.
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. that's the move π
π¦ the crypto_argon2_inputs struct π¦
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:
passβ the password to hash. it should be wiped withcrypto_wipe(3monocypher)after being hashed. protect the secrets bestie π«Άpass_sizeβ length ofpass, in bytes.saltβ a password salt. this should be filled with random bytes, generated separately for each password to be hashed. seeintro(3monocypher)for advice about generating random bytes (use the operating system's random number generator). no made-up randomness, okay? use the real stuff π₯salt_sizeβ length ofsalt, in bytes. must be at least8.16is recommended.
π the crypto_argon2_extras struct π
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:
keyβ a key to use in the hash. may beNULLifkey_sizeis 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. sneaky and secure, we love that πkey_sizeβ length ofkey, in bytes. must be zero if there is no key.adβ additional data. may beNULLifad_sizeis zero. this is additional data that goes into the hash, similar to the authenticated encryption construction incrypto_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 withcrypto_blake2b(3monocypher). iconic teamwork tbh βad_sizeβ length ofad, in bytes. must be zero if there is no additional data.
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. seriously, do it, don't be that person π
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. tune it till it's just right, like a playlist π΅
β¨ RETURN VALUES β¨
crypto_argon2() returns nothing. that's it, that's the whole vibe π
π EXAMPLES π
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 */
};
uint8_t password[] = "Okay Password!";
crypto_argon2_inputs inputs = {
.pass = password, /* User password */
.salt = salt, /* Salt for the password */
.pass_size = sizeof(password) - 1, /* Password length */
.salt_size = 16
};
crypto_argon2_extras extras = {0}; /* Extra parameters unused */
/* Allocate work area.
* Note the conversion to size_t.
* Without it we cannot allocate more than 4GiB.
*/
void *work_area = malloc((size_t)config.nb_blocks * 1024);
if (work_area == NULL) {
/* Handle malloc() failure */
/* Wipe secrets if they are no longer needed */
crypto_wipe(password, sizeof(password));
} else {
arc4random_buf(salt, 16);
crypto_argon2(hash, 32, work_area,
config, inputs, extras);
/* Wipe secrets if they are no longer needed */
crypto_wipe(password, sizeof(password));
free(work_area);
}
π SEE ALSO π
crypto_aead_lock(3monocypher), crypto_verify16(3monocypher), crypto_wipe(3monocypher), intro(3monocypher)
π STANDARDS π
crypto_argon2() implements Argon2 as described in RFC 9106, but does not support actual parallelism. (still valid, still iconic, just single-threaded π
)
π HISTORY π
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. glow-up after glow-up, we love evolution β¨
πΈ CAVEATS πΈ
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. no cap, this one matters β double-check your stuff bestie π
and that's the whole page! brought to you by the Debian crew, dated February 25, 2023, under the CRYPTO_ARGON2(3MONOCYPHER) banner. stay secure, stay slay ππ«Άβ¨
π¦ where this page comes from
- nixpkgs unstable: monocypher 4.0.3
- π the page's license: BSD-2-Clause OR CC0-1.0
- Copyright (c) 2017-2019, 2023 Loup Vaillant
- Copyright (c) 2018 Michael Savage
- Copyright (c) 2017, 2019-2021, 2023 Fabio Scotoni
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms