From d77ab463184d113ca6119403887c9f4ed0dfdf0b Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 26 Apr 2026 22:36:47 +0200 Subject: First commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- librecrypt.h | 776 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 776 insertions(+) create mode 100644 librecrypt.h (limited to 'librecrypt.h') diff --git a/librecrypt.h b/librecrypt.h new file mode 100644 index 0000000..9cf966b --- /dev/null +++ b/librecrypt.h @@ -0,0 +1,776 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBRECRYPT_H +#define LIBRECRYPT_H + +#include +#include +#include +#include + + +#if defined(__GNUC__) +# define LIBRECRYPT_PURE__ __attribute__((__pure__)) +# define LIBRECRYPT_NONNULL__ __attribute__((__nonnull__)) +# define LIBRECRYPT_NONNULL_I__(I) __attribute__((__nonnull__(I))) +# define LIBRECRYPT_WUR__ __attribute__((__warn_unused_result__)) +# define LIBRECRYPT_READ_STR__(S) __attribute__((__access__(read_only, S))) +# define LIBRECRYPT_READ_MEM__(B, N) __attribute__((__access__(read_only, B, N))) +# define LIBRECRYPT_WRITE_MEM__(B, N) __attribute__((__access__(write_only, B, N))) +# define LIBRECRYPT_READ_WRITE_STR__(S) __attribute__((__access__(read_write, S))) +#else +# define LIBRECRYPT_PURE__ +# define LIBRECRYPT_NONNULL__ +# define LIBRECRYPT_NONNULL_I__(I) +# define LIBRECRYPT_WUR__ +# define LIBRECRYPT_READ_STR__(S) +# define LIBRECRYPT_READ_MEM__(B, N) +# define LIBRECRYPT_WRITE_MEM__(B, N) +# define LIBRECRYPT_READ_WRITE_STR__(S) +#endif +#define LIBRECRYPT_NONNULL_1__ LIBRECRYPT_NONNULL_I__(1) + + +/** + * Symbol used as a general delimiter + */ +#define LIBRECRYPT_HASH_COMPOSITION_DELIMITER '$' + +/** + * Symbol used to delimit algorithms in a chain + */ +#define LIBRECRYPT_ALGORITHM_LINK_DELIMITER '>' + + + +/** + * Get number of bytes in a password hash string + * that make up the algorithm configuration + * + * @param hash The password hash string; must not be `NULL` + * @return The number of bytes, from the front of `hash`, + * that make up the algorithm configuration; may be 0 + * + * For the return value `r`, `&hash[r]` points to the + * hash result proper + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_READ_STR__(1) LIBRECRYPT_NONNULL__ LIBRECRYPT_WUR__ LIBRECRYPT_PURE__ +inline size_t +librecrypt_settings_prefix(const char *hash) +{ + size_t i, ret = 0u; + + for (i = 0u; hash[i]; i++) + if (hash[i] == LIBRECRYPT_HASH_COMPOSITION_DELIMITER || hash[i] == LIBRECRYPT_ALGORITHM_LINK_DELIMITER) + ret = i + 1u; + + return ret; +} + + +/** + * Get the number of chained hash algorithms specified in + * a password hash string + * + * @param hash The password hash string; must not be `NULL` + * @return The number of chained hash algorithms; always non-zero + * + * @seealso librecrypt_decompose_chain + * @seealso librecrypt_decompose_chain1 + * @seealso librecrypt_next_algorithm + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_READ_STR__(1) LIBRECRYPT_NONNULL__ LIBRECRYPT_WUR__ LIBRECRYPT_PURE__ +inline size_t +librecrypt_chain_length(const char *hash) +{ + size_t n = 1u; + + for (; *hash; hash++) + if (*hash == LIBRECRYPT_ALGORITHM_LINK_DELIMITER) + n += 1u; + + return n; +} + + +/** + * Decompose the chain of hash algorithms specified in + * a password hash string + * + * @param hash The password hash string to decompose; may be modified; must not be `NULL` + * @param chain_out_array Output array for the hash algorithms; each element will be an offset of `hash` + * @param size The number of elements `chain_out_buffer` fit + * @return The number of chained hashes (same as `librecrypt_chain_length(hash)`) + * + * Algorithms are delimited using `LIBRECRYPT_ALGORITHM_LINK_DELIMITER` + * (which is `'>'`). The first `size - 1u` occurences will be set to `NULL`. + * `hash` can be restored by setting the terminating NUL byte in each but + * the last string, that is stored to `chain_out_array`, to + * `LIBRECRYPT_ALGORITHM_LINK_DELIMITER` + * + * If positive `size` is smaller than the returned value, + * `chain_out_array[size - 1u]` will contain all algorithms + * (still delimited by `LIBRECRYPT_ALGORITHM_LINK_DELIMITER`) + * that where not placed in earlier slots + * + * Unless already stripped out before input, + * `chain_out_array[size - 1u]` (provided that `size` is + * positive) will end with the resulting hash + * + * @seealso librecrypt_chain_length + * @seealso librecrypt_decompose_chain1 + * @seealso librecrypt_next_algorithm + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_READ_WRITE_STR__(1) LIBRECRYPT_NONNULL_1__ LIBRECRYPT_WUR__ +inline size_t +librecrypt_decompose_chain(char *hash, char **chain_out_array, size_t size) +{ + size_t n = 1u; + + if (size) + chain_out_array[0u] = hash; + + for (; *hash; hash++) { + if (*hash == LIBRECRYPT_ALGORITHM_LINK_DELIMITER) { + if (n < size) { + *hash = '\0'; + chain_out_array[n] = &hash[1u]; + } + n += 1u; + } + } + + return n; +} + + +/** + * Replace each `LIBRECRYPT_ALGORITHM_LINK_DELIMITER` + * (which is `'>'`) in a password hash string with NUL + * bytes, effectively decomposing it to one string per + * hash algorithm, with the hashing result still attached + * to the last one if it as in the string + * + * @param hash The password hash string to decompose; may be modified; must not be `NULL` + * @return The number of chained hashes (same as `librecrypt_chain_length(hash)`) + * + * @seealso librecrypt_decompose_chain + * @seealso librecrypt_next_algorithm + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_READ_WRITE_STR__(1) LIBRECRYPT_NONNULL__ LIBRECRYPT_WUR__ +inline size_t +librecrypt_decompose_chain1(char *hash) +{ + size_t n = 1u; + + for (; *hash; hash++) { + if (*hash == LIBRECRYPT_ALGORITHM_LINK_DELIMITER) { + *hash = '\0'; + n += 1u; + } + } + + return n; +} + + +/** + * This function is called repeatedly to get each + * hash algorithm (with parameters) that shall + * be chained together according to a provided + * hash string + * + * @param hash On the initial call, this argument shall point + * to the password hash string; on each call the + * function will update it to the current parsing + * state, meaning it will set `*hash` to point to + * an offset of `*hash` or point to `NULL`; + * additionally at each call, except on the final + * call, the string will be modified + * @return On the first call, this will be the first hash + * algorithm to use, and the second call it will + * be the second algorithm to use (if there is a + * second one), and so on. Once all algorithms have + * been extracted and returned, `NULL` is returned. + * + * Except once the function has returned `NULL`, overwriting + * the terminating NUL byte in the previous returned string + * with `LIBRECRYPT_ALGORITHM_LINK_DELIMITER` (which is `'>'`) + * will restore the password hash string to its original content + * + * Unless already stripped out before input, the last returned + * string will end with the resulting hash + * + * @seealso librecrypt_decompose_chain + * @seealso librecrypt_decompose_chain1 + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_NONNULL__ LIBRECRYPT_WUR__ +inline char * +librecrypt_next_algorithm(char **hash) +{ + char *ret; + + if (!*hash) + return NULL; + + ret = *hash; + *hash = strchr(*hash, LIBRECRYPT_ALGORITHM_LINK_DELIMITER); + if (*hash) + *(*hash)++ = '\0'; + return ret; +} + + +/** + * Encode a hash result or salt in ASCII, from binary + * + * This is the inverse of `librecrypt_decode` + * + * @param out_buffer Output buffer for the ASCII representation + * @param size The number bytes the function may write to `out_buffer` + * @param binary The raw binary data to encode + * @param len The number of bytes in `binary` + * @param lut The encoding alphabet, consisting of 64 characters, + * repeated 4 times + * @param pad The padding character to use at the end; the NUL byte if none + * @return The number of bytes that would have been written to `out_buffer`, + * excluding the terminating NUL byte, if `size` was sufficiently large + * + * On successful completion, the N bytes is written to + * `out_buffer` where N is the lesser of `size` and 1 in + * excess of the return value (this count includes the + * terminating NUL byte) + * + * On successful completion, if `size` is positive, + * the output to `out_buffer` is NUL terminated even + * if this truncates the string + * + * @seealso librecrypt_get_encoding + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_WRITE_MEM__(1, 2) LIBRECRYPT_READ_MEM__(3, 4) LIBRECRYPT_NONNULL_I__(5) LIBRECRYPT_WUR__ +size_t librecrypt_encode(char *out_buffer, size_t size, const void *binary, size_t len, + const char lut[restrict static 256], char pad); + + +/** + * Encode a hash result or salt in ASCII, from binary + * + * This is the inverse of `librecrypt_decode` + * + * @param out_buffer Output buffer for the raw binary data + * @param size The number bytes the function may write to `out_buffer` + * @param ascii The ASCII encoding of the data, the text to decode + * @param len The number of bytes in `ascii` + * @param lut Alphabet reverse lookup table, shall map any valid + * character (except the padding character) to the value + * of that character in the encoding alphabet, and map + * any other character to the value `0xFF` + * @param pad The padding character to used at the end; the NUL byte if none + * @param strict_pad Zero if the padding at the end is optional, non-zero otherwise + * @return The number of bytes that would have been written to `out_buffer`, + * if `size` was sufficiently large, -1 on failure + * @throws EINVAL `ascii` uses an invalid encoding + * + * On successful completion, the N bytes is written to + * `out_buffer` where N is the lesser of `size` and the + * return value + * + * @seealso librecrypt_get_encoding + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_WRITE_MEM__(1, 2) LIBRECRYPT_READ_MEM__(3, 4) LIBRECRYPT_NONNULL_I__(5) LIBRECRYPT_WUR__ +ssize_t librecrypt_decode(void *out_buffer, size_t size, const char *ascii, size_t len, + const unsigned char lut[restrict static 256], char pad, int strict_pad); + + +/** + * Get the ASCII (base-64) encoding used for the + * last algorithm in a chain + * + * @param settings The algorithm chain + * @param len The number of bytes in `settings` + * @param pad_out Output parameter for the padding character, + * will be set to the NUL byte if there is none + * @param strict_pad_out Set to 1 if encodings must be padded to a + * multiple of 4 bytes using `*pad_out` at the end, + * 0 otherwise; set arbitrarily if `*pad_out` is + * set to the NUL byte + * @param decoding 0 if the returned pointer should be useful for, + * `librecrypt_encode`, otherwise it will be useful + * for `librecrypt_decode` + * @return If `decoding` is 0: + * the encoding alphabet, consisting of 64 characters, + * repeated 4 times; + * otherwise: + * alphabet reverse lookup table, mapping any valid + * character (except the padding character) to the + * value of that character in the encoding alphabet, + * and any other character to the value `0xFF`; + * but `NULL` on failure + * @throws ENOSYS The last algorithm in `settings` is not recognised + * or was disabled at compile-time + * + * The return type is `const char *` if `decoding` is 0, + * and `const unsigned char *` otherwise + * + * `*pad_out` shall be used for the `pad` parameter of the `librecrypt_encode` + * and `librecrypt_decode` functions, however the NUL byte may also be used + * for the `librecrypt_encode` function if `*strict_pad_out` is set to 0 + * + * `*strict_pad_out` shall be used for the `strict_pad` parameter of the + * `librecrypt_decode` function + * + * The returned pointer (unless `NULL`) shall be used for the `lut` parameter + * of the `librecrypt_encode` function if `decoding` is 0, and for the `lut` + * parameter of the `librecrypt_decode` function otherwise + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_READ_STR__(1) LIBRECRYPT_NONNULL__ LIBRECRYPT_WUR__ +const void *librecrypt_get_encoding(const char *settings, size_t len, char *pad_out, + int *strict_pad_out, int decoding); + + +/** + * Securely erase a memory buffer + * + * @param buffer The memory to erase + * @param size The number of bytes in `buffer` to erase + * + * @seealso librecrypt_wipe_str + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_WRITE_MEM__(1, 2) +void librecrypt_wipe(void *buffer, size_t size); + + +/** + * Securely erase a string + * + * @param string The string to erase + * + * @seealso librecrypt_wipe + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_READ_WRITE_STR__(1) +inline void +librecrypt_wipe_str(char *string) +{ + if (string) + librecrypt_wipe(string, strlen(string)); +} + + +/** + * Compare two memory segments in constant-time + * + * @param a One of the segments to compare + * @param b The other segments to compare + * @param len The number of bytes to compare + * @return 1 if the `a` and `b` are equal in their + * first `len` bytes, 0 otherwise + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_READ_MEM__(1, 3) LIBRECRYPT_READ_MEM__(2, 3) LIBRECRYPT_WUR__ +int librecrypt_equal_binary(const void *a, const void *b, size_t len); + + +/** + * Compare two strings in constant-time + * + * If the strings are of different length, + * it will stop immediately after measurement; + * this should not happen in the real world as + * this function is used to compare password + * hashes, whose length depends strictly on the + * configuration, not the input password + * + * @param a One of the strings to compare + * @param b The other string to compare + * @return 1 if the `a` and `b` are equal, 0 otherwise + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_READ_STR__(1) LIBRECRYPT_READ_STR__(2) LIBRECRYPT_WUR__ LIBRECRYPT_NONNULL__ +inline int +librecrypt_equal(const char *a, const char *b) +{ + size_t n = strlen(a); + size_t m = strlen(b); + return n == m && librecrypt_equal_binary(a, b, n); +} + + +/** + * Locate all asteriskes followed by a non-negative + * decimal number and replace each with ASCII-encded + * random bytes (as many bytes as the number specifies) + * + * @param out_buffer Output buffer for the ASCII representation + * @param size The number bytes the function may write to `out_buffer` + * @param settings The string to replace the asterisk-encoding in + * (the asterisk-free version is written to `out_buffer`) + * @param rng Random number generating function, `NULL` can be used + * for a default cryptographic random number generator; + * the function shall generate between 1 and `n` (inclusively) + * bytes and write them to the front of `out`, and return + * the number of generated bytes, or -1 on failure + * @param user Passed as the third argument to `*rng` for user-defined + * purposes, ignored if `rng` is `NULL` + * @return The number of bytes that would have been written to `out_buffer`, + * if `size` was sufficiently large, -1 on failure + * @throws ERANGE The expected return value is greater than {SSIZE_MAX} + * @throws EINVAL Asterisk-encoding was used in an invalid context + * @throws ENOSYS `settings` contain an algorithm that is not recognised + * or was disabled at compile-time + * + * If `rng` is `NULL`, any encountered `EINTR` is ignored, + * however, if it is encountered `errno` will be set to `EINTR`, + * but `errno` will remain unmodified otherwise, except if + * the function fails due to one of the above listed reasons + * + * Failure can only happen through `*rng`, it is + * responsible for setting `errno` if desired, or + * because of the conditions listed above` + * + * On successful completion, the N bytes is written to + * `out_buffer` where N is the lesser of `size` and 1 in + * excess of the return value (this count includes the + * terminating NUL byte) + * + * On successful completion, if `size` is positive, + * the output to `out_buffer` is NUL terminated even + * if this truncates the string + * + * On failure, `out_buffer` may be partially written + * + * The encoding depend on the algorithm, which is why + * it can fail with `EINVAL` or `ENOSYS` + * + * When `rng` is non-`NULL`, this function inherits any + * MT-Unsafe and AS-Unsafe properties from `*rng`, being + * is MT-Safe and AS-Safe as a baseline; however when + * `rng` is `NULL`, this function is MT-Safe but AS-Unsafe + */ +LIBRECRYPT_WRITE_MEM__(1, 2) LIBRECRYPT_READ_STR__(3) LIBRECRYPT_WUR__ +ssize_t librecrypt_realise_salts(char *restrict out_buffer, size_t size, const char *settings, + ssize_t (*rng)(void *out, size_t n, void *user), void *user); + + +/** + * Generate a password hash setting string + * + * @param out_buffer Output buffer for the ASCII representation + * @param size The number bytes the function may write to `out_buffer` + * @param algorithm Hash algorithm string; it need not specify any parameters + * however any unspecified parameter that cannot be determined + * by `memcost` or `timecost` will be set to an arbitrary, + * valid value. If `NULL`, a default, strong algorithm is + * selected. Note that the empty string represents the + * deprecated DES algorithm. Algorithm chains are disallowed. + * @param memcost Approximate memory cost in bytes, ignored if not supported; + * a default value is selected if 0 is specified + * @param timecost Total time cost, in an arbitrary, algorithm-dependent, + * implementation-dependent, monotonic (may have flat sections) + * unit and scale that is approximately linear; a default value + * is selected if 0 is specified + * @param gensalt Zero if salts shall specified to be randomly generated + * (reusable password hash setting string), + * non-zero if random salts shall be included in the generated + * output (non-reusable password hash setting string) + * @param rng Random number generating function, `NULL` can be used + * for a default cryptographic random number generator; + * the function shall generate between 1 and `n` (inclusively) + * bytes and write them to the front of `out`, and return + * the number of generated bytes, or -1 on failure; + * ignored if `gensalt` is zero + * @param user Passed as the third argument to `*rng` for user-defined + * purposes, ignored if `rng` is `NULL` or if `gensalt` is zero + * @return The number of bytes that would have been written to + * `out_buffer`, if `size` was sufficiently large, -1 on failure + * @throws EINVAL `algorithm` represents a chain of algorithms + * @throws ENOSYS `algorithm` represents an algorithm that is not + * recognised or was disabled at compile-time + * @throws ENOSYS `algorithm` is `NULL` but all algorithms were disabled at + * compile-time + * + * If `rng` is `NULL`, any encountered `EINTR` is ignored, + * however, if it is encountered `errno` will be set to `EINTR`, + * but `errno` will remain unmodified otherwise, except if + * the function fails due to `EINVAL` or `ENOSYS` + * + * Failure can only happen through `*rng`, it is + * responsible for setting `errno` if desired, or + * because of the conditions for `EINVAL` or `ENOSYS` + * + * On successful completion, the N bytes is written to + * `out_buffer` where N is the lesser of `size` and 1 in + * excess of the return value (this count includes the + * terminating NUL byte) + * + * On successful completion, if `size` is positive, + * the output to `out_buffer` is NUL terminated even + * if this truncates the string + * + * On failure, `out_buffer` may be partially written + * + * This function is MT-Safe but AS-Unsafe + */ +LIBRECRYPT_WRITE_MEM__(1, 2) LIBRECRYPT_READ_STR__(3) LIBRECRYPT_WUR__ +ssize_t librecrypt_make_settings(char *out_buffer, size_t size, const char *algorithm, + size_t memcost, uintmax_t timecost, int gensalt, + ssize_t (*rng)(void *out, size_t n, void *user), void *user); + + +/** + * Compute the hash of a password + * + * The hash will be stored in raw binary format without any settings + * + * @param out_buffer Output buffer for the hash result + * @param size The number bytes the function may write to `out_buffer` + * @param phrase The password to hash, may contain NUL bytes + * @param len The number of bytes in `phrase` + * @param settings The password hash configuration string, + * may contain resulting hash, which will be ignored + * @param reserved Reserved for future use, should be `NULL` + * @return The number of bytes that would have been written to `out_buffer` + * if `size` was sufficiently large; -1 on failure + * + * @throws EINVAL `reserved` is non-`NULL` (this case will be removed + * once `reserved` as being used by the library) + * @throws EINVAL `settings` is invalid (invalid algorithm configuration, + * invalid configuration syntax, or the output from one + * chained hash algorithm cannot be input the next algorithm + * in the chain (either because of format or length issues)) + * @throws EINVAL `settings` uses asterisk-encoding to specify random salts + * @throws ERANGE `len` is too large or too small for the the selected + * initial algorithm in the algorithm chain + * @throws ENOMEM Failed to allocate internal scratch memory + * @throws ENOSYS A selected hash algorithm is either not recognised + * disabled at compile-time + * + * Any encountered `EINTR` is ignored + * + * On successful completion, the N bytes is written to + * `out_buffer` where N is the lesser of `size` and the + * return value + * + * On failure, `out_buffer` will remain unmodified + * + * @seealso librecrypt_hash + * @seealso librecrypt_crypt + * @seealso librecrypt_test_supported + * + * This function is MT-Safe but AS-Unsafe + */ +LIBRECRYPT_WRITE_MEM__(1, 2) LIBRECRYPT_READ_MEM__(3, 4) LIBRECRYPT_READ_STR__(5) +LIBRECRYPT_NONNULL_I__(5) LIBRECRYPT_WUR__ +ssize_t librecrypt_hash_binary(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, void *reserved); + + +/** + * Compute the hash of a password + * + * The hash will be encoded with `librecrypt_encode` + * but stored without any settings + * + * @param out_buffer Output buffer for the hash result + * @param size The number bytes the function may write to `out_buffer` + * @param phrase The password to hash, may contain NUL bytes + * @param len The number of bytes in `phrase` + * @param settings The password hash configuration string, + * may contain resulting hash, which will be ignored + * @param reserved Reserved for future use, should be `NULL` + * @return The number of bytes that would have been written to `out_buffer` + * if `size` was sufficiently large, excluding a terminating + * NUL byte; -1 on failure + * + * @throws EINVAL `reserved` is non-`NULL` (this case will be removed + * once `reserved` as being used by the library) + * @throws EINVAL `settings` is invalid (invalid algorithm configuration, + * invalid configuration syntax, or the output from one + * chained hash algorithm cannot be input the next algorithm + * in the chain (either because of format or length issues)) + * @throws EINVAL `settings` uses asterisk-encoding to specify random salts + * @throws ERANGE `len` is too large or too small for the the selected + * initial algorithm in the algorithm chain + * @throws ENOMEM Failed to allocate internal scratch memory + * @throws ENOSYS A selected hash algorithm is either not recognised + * disabled at compile-time + * + * Any encountered `EINTR` is ignored + * + * On successful completion, the N bytes is written to + * `out_buffer` where N is the lesser of `size` and 1 in + * excess of the return value (this count includes the + * terminating NUL byte) + * + * On successful completion, if `size` is positive, + * the output to `out_buffer` is NUL terminated even + * if this truncates the string + * + * On failure, `out_buffer` will remain unmodified + * + * @seealso librecrypt_hash_binary + * @seealso librecrypt_crypt + * @seealso librecrypt_test_supported + * + * This function is MT-Safe but AS-Unsafe + */ +LIBRECRYPT_WRITE_MEM__(1, 2) LIBRECRYPT_READ_MEM__(3, 4) LIBRECRYPT_READ_STR__(5) +LIBRECRYPT_NONNULL_I__(5) LIBRECRYPT_WUR__ +ssize_t librecrypt_hash(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, void *reserved); + + +/** + * Compute the hash of a password + * + * The hash will be encoded with `librecrypt_encode`; + * and the settings will be included in the front + * + * @param out_buffer Output buffer for the hash result + * @param size The number bytes the function may write to `out_buffer` + * @param phrase The password to hash, may contain NUL bytes + * @param len The number of bytes in `phrase` + * @param settings The password hash configuration string, + * may contain resulting hash, which will be ignored + * @param reserved Reserved for future use, should be `NULL` + * @return The number of bytes that would have been written to `out_buffer` + * if `size` was sufficiently large, excluding a terminating + * NUL byte; -1 on failure + * + * @throws EINVAL `reserved` is non-`NULL` (this case will be removed + * once `reserved` as being used by the library) + * @throws EINVAL `settings` is invalid (invalid algorithm configuration, + * invalid configuration syntax, or the output from one + * chained hash algorithm cannot be input the next algorithm + * in the chain (either because of format or length issues)) + * @throws ERANGE `len` is too large or too small for the the selected + * initial algorithm in the algorithm chain + * @throws ENOMEM Failed to allocate internal scratch memory + * @throws ENOSYS A selected hash algorithm is either not recognised + * disabled at compile-time + * + * Any encountered `EINTR` is ignored + * + * On successful completion, the N bytes is written to + * `out_buffer` where N is the lesser of `size` and 1 in + * excess of the return value (this count includes the + * terminating NUL byte) + * + * On successful completion, if `size` is positive, + * the output to `out_buffer` is NUL terminated even + * if this truncates the string + * + * On failure, `out_buffer` may be partially written + * + * @seealso librecrypt_hash_binary + * @seealso librecrypt_hash + * @seealso librecrypt_test_supported + * + * This function is MT-Safe but AS-Unsafe + */ +LIBRECRYPT_WRITE_MEM__(1, 2) LIBRECRYPT_READ_MEM__(3, 4) LIBRECRYPT_READ_STR__(5) +LIBRECRYPT_NONNULL_I__(5) LIBRECRYPT_WUR__ +ssize_t librecrypt_crypt(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, void *reserved); + + +/** + * Check whether a hash algorithm chain is supported, + * for the given input, and that each algorithm + * configuration is valid + * + * @param phrase The password to hash, may contain NUL bytes; + * may be `NULL` even if `len` is non-zero + * @param len The number of bytes in `phrase`, if `phrase` is `NULL`, + * the function will check that the specified number of + * bytes is supported as well as any byte sequence unless + * `text` is non-zero + * @param text Assume the password is valid UTF-8 text (without NUL bytes) + * iff non-zero; ignored if `phrase` is non-`NULL` + * @param settings The password hash string; it is allowed for algorithm + * tuning parameters, and the hash result, to be omitted + * @return 1 if the configuration is supported, 0 otherwise, which + * means part of the string is invalid: the algorithm does + * not exist, supported was disabled at compile-time, or an + * algorithm it does not support the output of the previous + * algorithm in the chain as input; additionally a small + * number of legacy algorithms require the passphrase to + * be within a specific length range or be valid text, + * if the selected word does not match such constraints + * for the first algorithm in the chain, 0 is returned + * + * This function is MT-Safe and AS-Safe + */ +LIBRECRYPT_READ_STR__(4) LIBRECRYPT_NONNULL_I__(4) LIBRECRYPT_WUR__ +int librecrypt_test_supported(const char *phrase, size_t len, int text, const char *settings); + + +/** + * Chain togather another set of hash algorithms + * + * @param out_buffer Output buffer for the new password hash string + * @param size The number bytes the function may write to `out_buffer` + * @param augend THe existing password hash string; if it contains a + * hash result, a new hash result will be computed and + * any random number generation specification in `augment` + * will be realised + * @param augment Password hash setting string describing the additional + * hashing to perform; if it contains a hash result, that + * part will be ignored + * @param reserved Reserved for future use, should be `NULL` + * @return The number of bytes that would have been written to `out_buffer` + * if `size` was sufficiently large, excluding a terminating + * NUL byte; -1 on failure + * + * @throws EINVAL `reserved` is non-`NULL` (this case will be removed + * once `reserved` as being used by the library) + * @throws EINVAL `settings` is invalid (invalid algorithm configuration, + * invalid configuration syntax, or the output from one + * chained hash algorithm cannot be input the next algorithm + * in the chain (either because of format or length issues)) + * @throws ERANGE `len` is too large or too small for the the selected + * initial algorithm in the algorithm chain + * @throws ENOMEM Failed to allocate internal scratch memory + * @throws ENOSYS A selected hash algorithm is either not recognised + * disabled at compile-time + * + * On successful completion, the N bytes is written to + * `out_buffer` where N is the lesser of `size` and 1 in + * excess of the return value (this count includes the + * terminating NUL byte) + * + * On successful completion, if `size` is positive, + * the output to `out_buffer` is NUL terminated even + * if this truncates the string + * + * On failure, `out_buffer` will remain unmodified + * + * This function is MT-Safe but AS-Unsafe + */ +LIBRECRYPT_WRITE_MEM__(1, 2) LIBRECRYPT_READ_WRITE_STR__(3) LIBRECRYPT_READ_STR__(4) +LIBRECRYPT_NONNULL_I__(3) LIBRECRYPT_NONNULL_I__(4) LIBRECRYPT_WUR__ +ssize_t librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, + const char *restrict augment, void *reserved); + + +#endif -- cgit v1.2.3-70-g09d2