aboutsummaryrefslogtreecommitdiffstats
path: root/librecrypt.h
diff options
context:
space:
mode:
Diffstat (limited to 'librecrypt.h')
-rw-r--r--librecrypt.h776
1 files changed, 776 insertions, 0 deletions
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 <sys/types.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+
+#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