From 4e0109888c11b15cfb19383fc24310999e506d04 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Mon, 14 Feb 2022 22:34:40 +0100 Subject: Add documentation and make sure the password is always erased MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- libar2simplified.h | 127 ++++++++++++++++++++++++++++++++++++++++++++++++ libar2simplified_hash.c | 6 ++- 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/libar2simplified.h b/libar2simplified.h index 55eb123..567097a 100644 --- a/libar2simplified.h +++ b/libar2simplified.h @@ -8,21 +8,148 @@ * hash separately, when the application uses a pepper, or * when composing multiple hash functions: */ +/** + * Encode hashing parameters, with or without hashing result + * + * This function extends the standard format for Argon2 by + * letting the exact salt or tag (hash) be unspecified, but + * the length specified using an asterisk-prefixed, decimal + * integer + * + * `params->key` and `params->ad` will not be included in + * the returned string + * + * @param params The hashing parameters, if `params->salt` + * is `NULL` the salt's length is encoded + * instead of an actual salt + * @param hash The tag, or `NULL` the tag's length is + * encoded instead of an actual tag + * @return The hashing parameter string, + * or `NULL` on failure; shall be dellocated + * using free(3) when no longer needed + */ LIBAR2_PUBLIC__ LIBAR2_NONNULL__(1) char *libar2simplified_encode(const struct libar2_argon2_parameters *params, void *hash); +/** + * Encode tag (hashing result) without parameters + * + * @param params The hashing parameters (used to get the tag length) + * @param hash The binary tag (hashing result) + * @return `hash` encoded with base64, or `NULL` + * on failure; shall be dellocated using + * free(3) when no longer needed + */ LIBAR2_PUBLIC__ LIBAR2_NONNULL__(1, 2) char *libar2simplified_encode_hash(const struct libar2_argon2_parameters *params, void *hash); +/** + * Decode hashing parameters + * + * If the salt's lengths is encoded, but not an + * actual salt, a random salt will be created + * + * The hashing string does not encode information + * about `params->key` or `params->ad`, therefore + * `params->key` and `params->ad` will be set to + * `NULL` and `params->keylen` and `params->adlen` + * will be set to 0 + * + * @param str The hashing parameter string to decode + * @param tagp Output parameter for the tag (hash + * result), or `NULL`. Unless `NULL`, + * `NULL` will be stored in `*tagp` if + * `str` includes a tag length instead + * of an actual tag, otherwise unless + * `NULL`, the beginning of the tag, in + * `str`, will be stored in `*tagp`. + * `*endp` will (unless `endp` or `*tagp` + * is `NULL`) mark the end of the tag. + * @param endp Output parameter for the end of the + * hashing parameter string, or `NULL`. + * Unless `NULL`, one position beyond + * the last byte in `str` determined to + * be part of the hashing parameter + * string will be stored in `*endp`. + * The application shall make sure that + * `**endp` is a valid termination of + * the hashing parameter string; typically + * this would be a ':' or a NUL byte. + * @param random_byte_generator Random number generator function, used + * to generate salt if `str` does not + * contain one. The function shall output + * `n` random bytes (only the lower 6 bits + * in each byte need to be random) to + * `out` and return 0. On failure, the + * function shall return -1. If `NULL`, + * the function will use a random number + * generator provided by the C standard + * library or the operating system. + * @return Decoded hashing parameters. Shall be + * deallocated using free(3) when no longer + * needed. Be aware than the allocation + * size of the returned object will exceed + * the size of the return type. + */ LIBAR2_PUBLIC__ LIBAR2_NONNULL__(1) struct libar2_argon2_parameters * libar2simplified_decode(const char *str, char **tagp, char **endp, int (*random_byte_generator)(char *out, size_t n)); +/** + * Calculate a password hashing + * + * @param hash Output parameter for the tag (hash result). + * This must be a buffer than is at least + * `libar2_hash_buf_size(params)` bytes large. + * @param msg The message (password) to hash. Will be + * erased (not deallocated) some time before + * the function returns. + * @param msglen The number of bytes in `msg` + * @param params Hashing parameters + * @return 0 on success, -1 on failure + */ LIBAR2_PUBLIC__ LIBAR2_NONNULL__(1, 4) int libar2simplified_hash(void *hash, void *msg, size_t msglen, struct libar2_argon2_parameters *params); /* This one is useful you just want to do it crypt(3)-style: */ +/** + * Calculate a password hashing + * + * This function works like crypt(3), except that it only supports + * Argon2, it will erase the input password, the return buffer is + * provided in the third parameter or (if `NULL`) is dynamically + * allocated, and it will generate a salt if one is not provided + * + * Assumming `params` contains a salt and a tag (hash), `msg` + * is (in all likelyhood) the password it was created with if + * the returned string is identical to `params`. It is + * recommended, to hinder timing attack, that this check is done + * by comparing all characters in the strings, even if a mismatch + * is found early. + * + * This function is generally not recommend. It should only be + * used for /etc/shadow and similar files. Other applications should + * use `libar2simplified_hash` and provide an application-specific, + * random, pepper. Applications are also recommended to use + * `libar2simplified_hash` so that they can compose password hashing + * functions and automatically harden passwords, without knowing + * their plain-text, when the hashing configuration is determined + * to be too weak. + * + * @param msg The password to hash. NB! Will be erased (not + * deallocated) some time before the function returns. + * @param params Hashing parameter string + * @param rv Output parameter for the hasing, or `NULL`. + * Unless `NULL`, this must be a buffer than is at least + * `libar2_hash_buf_size(libar2simplified_decode(params, + * NULL, NULL, NULL))` bytes large. + * @return The hashing result, including hashing parameters. + * `NULL` on failure. On success, `rv` is returned + * unless `rv` is `NULL`. If `rv` is `NULL`, the + * returned shall be deallocated using free(3) when + * it is no longer needed + */ LIBAR2_PUBLIC__ LIBAR2_NONNULL__(1, 2) char *libar2simplified_crypt(char *msg, const char *params, char *rv); diff --git a/libar2simplified_hash.c b/libar2simplified_hash.c index 4583dfb..8e4bd85 100644 --- a/libar2simplified_hash.c +++ b/libar2simplified_hash.c @@ -391,6 +391,7 @@ int libar2simplified_hash(void *hash, void *msg, size_t msglen, struct libar2_argon2_parameters *params) { struct libar2_context ctx; + int ret; memset(&ctx, 0, sizeof(ctx)); ctx.autoerase_message = 1; @@ -402,5 +403,8 @@ libar2simplified_hash(void *hash, void *msg, size_t msglen, struct libar2_argon2 ctx.join_thread_pool = join_thread_pool; ctx.destroy_thread_pool = destroy_thread_pool; - return libar2_hash(hash, msg, msglen, params, &ctx); + ret = libar2_hash(hash, msg, msglen, params, &ctx); + if (ret) + libar2_erase(msg, msglen); + return ret; } -- cgit v1.2.3-70-g09d2