Boring crypto that simply works

cryptographic hashing

#include <monocypher.h>

crypto_blake2b(uint8_t hash[64], const uint8_t *message, size_t message_size);

crypto_blake2b_general(uint8_t *hash, size_t hash_size, const uint8_t *key, size_t key_size, const uint8_t *message, size_t message_size);

crypto_blake2b_init(crypto_blake2b_ctx *ctx);

crypto_blake2b_general_init(crypto_blake2b_ctx *ctx, size_t hash_size, const uint8_t *key, size_t key_size);

crypto_blake2b_update(crypto_blake2b_ctx *ctx, const uint8_t *message, size_t message_size);

crypto_blake2b_final(crypto_blake2b_ctx *ctx, uint8_t *hash);

BLAKE2b is a fast cryptographically secure hash based on the ideas of ChaCha20. It is faster than MD5, yet just as secure as SHA-3.

Note that BLAKE2b itself is not suitable for hashing passwords and deriving keys from them; use the crypto_argon2i() family of functions for that purpose instead.

BLAKE2b is immune to length extension attacks, and as such, does not require specific precautions such as using the HMAC algorithm.

The arguments are:

The output hash.
Length of hash, in bytes. Must be between 1 and 64. Anything below 32 is discouraged when using BLAKE2b as a general-purpose hash function; anything below 16 is discouraged when using BLAKE2b as a message authentication code.
Some secret key. One cannot predict the final hash without it. May be NULL if key_size is 0, in which case no key is used. Keys can be used to create a message authentication code (MAC). Use crypto_verify16(), crypto_verify32(), or crypto_verify64() to compare MACs created this way. Choose the size of the hash accordingly. Users may want to wipe the key with crypto_wipe() once they are done with it.
Length of key, in bytes. Must be between 0 and 64. 32 is a good default.
The message to hash. May overlap with hash. May be NULL if message_size is 0.
Length of message, in bytes.

The direct interface has two functions, () and crypto_blake2b_general(). crypto_blake2b() is provided for convenience and is equivalent to calling crypto_blake2b_general() with no key and a 64-byte hash.

() users can specify the size of the hash and use a secret key to make the hash unpredictable, – which is useful for message authentication codes. Even when using a key, you do not have to wipe the context struct with crypto_wipe().

The incremental interface is useful for handling streams of data or large files without using too much memory. This interface uses three steps:

  • Initialisation with () or crypto_blake2b_init(), which sets up a context with the hashing parameters;
  • Update with (), which hashes the message chunk by chunk and keeps the intermediary result in the context;
  • and Finalisation with (), which produces the final hash. The crypto_blake2b_ctx is automatically wiped upon finalisation.

The invariants of the parameters are the same as for (). () is a convenience initialisation function that specifies a 64-byte hash and no key. This is considered a good default.

These functions return nothing.

The following examples assume 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() for advice about how to generate cryptographically secure random bytes.

Hashing a message all at once:

uint8_t hash   [64]; /* Output hash (64 bytes)          */
uint8_t message[12] = "Lorem ipsum"; /* Message to hash */
crypto_blake2b(hash, message, 12);

Computing a message authentication code all at once:

uint8_t hash   [16];
uint8_t key    [32];
uint8_t message[11] = "Lorem ipsu"; /* Message to authenticate */
arc4random_buf(key, 32);
crypto_blake2b_general(hash, 16, key, 32, message, 11);
/* Wipe secrets if they are no longer needed */
crypto_wipe(message, 11);
crypto_wipe(key, 32);

Hashing a message incrementally (without a key):

uint8_t hash   [ 64]; /* Output hash (64 bytes) */
uint8_t message[500] = {1}; /* Message to hash  */
crypto_blake2b_ctx ctx;
for (size_t i = 0; i < 500; i += 100) {
    crypto_blake2b_update(&ctx, message + i, 100);
crypto_blake2b_final(&ctx, hash);

Computing a message authentication code incrementally:

uint8_t hash   [ 16];
uint8_t key    [ 32];
uint8_t message[500] = {1}; /* Message to authenticate         */
crypto_blake2b_ctx ctx;
arc4random_buf(key, 32);
crypto_blake2b_general_init(&ctx, 16, key, 32);
/* Wipe the key */
crypto_wipe(key, 32);
for (size_t i = 0; i < 500; i += 100) {
    crypto_blake2b_update(&ctx, message + i, 100);
    /* Wipe secrets if they are no longer needed */
    crypto_wipe(message + i, 100);
crypto_blake2b_final(&ctx, hash);

crypto_x25519(), crypto_lock(), intro()

These functions implement BLAKE2b, described in RFC 7693.

The crypto_blake2b(), crypto_blake2b_general(), crypto_blake2b_general_init(), crypto_blake2b_init(), crypto_blake2b_update(), and crypto_blake2b_final() functions first appeared in Monocypher 0.1.

Monocypher does not perform any input validation. Any deviation from the specified input and output length ranges results in . Make sure your inputs are correct.

BLAKE2b is a general-purpose cryptographic hash function; this means that it is not suited for hashing passwords and deriving cryptographic keys from passwords. While cryptographic keys usually have hundreds of bits of entropy, passwords are often much less complex. When storing passwords as hashes or when deriving keys from them, the goal is normally to prevent attackers from quickly iterating all possible passwords. Because passwords tend to be simple, it is important to artificially slow down attackers by using computationally difficult hashing algorithms. Monocypher therefore provides crypto_argon2i() for password hashing and deriving keys from passwords.

The core loop is unrolled by default. This speeds up BLAKE2b by about 20% on modern processors. On the other hand, this inflates the binary size by several kilobytes, and is slower on some embedded platforms. To roll the loop and generate a smaller binary, compile Monocypher with the -DBLAKE2_NO_UNROLLING option.

September 1, 2022 Debian