diff options
| author | Mattias Andrée <m@maandree.se> | 2026-04-26 22:36:47 +0200 |
|---|---|---|
| committer | Mattias Andrée <m@maandree.se> | 2026-04-26 22:36:47 +0200 |
| commit | d77ab463184d113ca6119403887c9f4ed0dfdf0b (patch) | |
| tree | ca8a1de443f90a4b7def56ea5b61c96aaa949f45 /common.h | |
| download | librecrypt-d77ab463184d113ca6119403887c9f4ed0dfdf0b.tar.gz librecrypt-d77ab463184d113ca6119403887c9f4ed0dfdf0b.tar.bz2 librecrypt-d77ab463184d113ca6119403887c9f4ed0dfdf0b.tar.xz | |
First commit
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to 'common.h')
| -rw-r--r-- | common.h | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/common.h b/common.h new file mode 100644 index 0000000..389244f --- /dev/null +++ b/common.h @@ -0,0 +1,426 @@ +/* See LICENSE file for copyright and license details. */ +#include "librecrypt.h" +#if defined(__linux__) +# include <sys/auxv.h> +# include <sys/random.h> +#endif +#include <fcntl.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +#include "algorithms.h" + + +#if defined(__GNUC__) +# define HIDDEN __attribute__((__visibility__("hidden"))) +# define CONST __attribute__((__const__)) +#else +# define HIDDEN +# define CONST +#endif + +#define NONSTRING +#if defined(__GNUC__) && !defined(__clang__) +# if __GNUC__ >= 8 +# undef NONSTRING +# define NONSTRING __attribute__((__nonstring__)) +# endif +#endif + + +/** + * Used for literal commas in macro calls + */ +#define COMMA , + +/** + * Get the number of elements in an array + * + * @param ARRAY:nondecayed-array The array + * @return :size_t The number of elements in `ARRAY` + */ +#define ELEMSOF(ARRAY) (sizeof(ARRAY) / sizeof(*(ARRAY))) + + +/** + * Which function `librecrypt_hash_` shall behave as + */ +enum action { + /** + * Used for `librecrypt_hash_binary` + * + * Output is binary and hash result-only + */ + BINARY_HASH, + + /** + * Used for `librecrypt_hash` + * + * Output is ASCII and hash result-only + */ + ASCII_HASH, + + /** + * Used for `librecrypt_hash` + * + * Output is ASCII and contains algorithm configurations + */ + ASCII_CRYPT +}; + + +/** + * Hash algorithm information and implementation + */ +struct algorithm { + /** + * Get the number of bytes that constitute + * the algorithm specification and configuration + * + * @param settings The password hash string, containing a single algorithm + * @param len The number of bytes in `settings` + * @return `len` if the string does not contain any hash result, + * otherwise the offset of `settings` where the hash + * result begins + * + * This function shall be MT-Safe and AS-Safe + */ + size_t (*get_prefix)(const char *settings, size_t len); + + /** + * Determine if a password hash string + * selects the algorithm + * + * @param settings The password hash string, containing a single algorithm + * @param len The number of bytes in `settings` + * @return A positive value if the string matches the algorithm, + * 0 otherwise + * + * If non-zero is returned for multiple algorithm, + * the first with the highest value wins + * + * This function shall be MT-Safe and AS-Safe + */ + unsigned (*is_algorithm)(const char *settings, size_t len); + + /** + * Implements `librecrypt_hash_binary` for a single hash algorithm; + * see `librecrypt_hash_binary` for more information + * + * @param out_buffer See `librecrypt_hash_binary` + * @param size See `librecrypt_hash_binary` + * @param phrase See `librecrypt_hash_binary`; may be `NULL` + * even if `len` is positive, this happens when + * `size` is too small and the hash result will + * not be included, so there is no need to actually + * calculate the hash, however `len` and `settings` + * should still be checked + * @param len See `librecrypt_hash_binary` + * @param settings See `librecrypt_hash_binary`, + * will not contains asterisk-encoding + * @param prefix The length of `settings`, in bytes + * @param reserved See `librecrypt_hash_binary` + * @return 0 on success, -1 on failure + * @throws See `librecrypt_hash_binary` + * + * This function shall be MT-Safe but may be AS-Unsafe + */ + int (*hash)(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, size_t prefix, void *reserved); + + /** + * Check whether the hash algorithm is supported for given + * configuration and input + * + * @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 and correctly + * configured, 0 otherwise + * + * This function shall be MT-Safe and AS-Safe + */ + int (*test_supported)(const char *phrase, size_t len, int text, const char *settings, size_t prefix); + + /** + * See `librecrypt_make_settings` + * + * @param out_buffer See `librecrypt_make_settings` + * @param size See `librecrypt_make_settings` + * @param algorithm See `librecrypt_make_settings`, + * will match the algorithm or be `NULL` + * @param memcost See `librecrypt_make_settings` + * @param timecost See `librecrypt_make_settings` + * @param gensalt See `librecrypt_make_settings` + * @param rng See `librecrypt_make_settings` + * @param user See `librecrypt_make_settings` + * @return See `librecrypt_make_settings` + * @throws See `librecrypt_make_settings` + * + * This function shall be MT-Safe but may be AS-Safe + */ + ssize_t (*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); + + /** + * Expected argument for the `lut` parameter + * of the `librecrypt_encode` function + */ + const char *encoding_lut; + + /** + * Expected argument for the `lut` parameter + * of the `librecrypt_decode` function + */ + const unsigned char *decoding_lut; + + /** + * The algoritm's hash result size, in number + * of bytes when using binary encoding + */ + size_t hash_size; + + /** + * Expected argument for the `strict_pad` parameter + * of the `librecrypt_decode` function + */ + int strict_pad; + + /** + * Expected argument for the `pad` parameter + * of the `librecrypt_decode` function + */ + char pad; +}; + +/** + * Check if an `struct algorithm *` is the `END_OF_ALGORITHMS` + * at the end of `librecrypt_algorithms_` + */ +#define IS_END_OF_ALGORITHMS(A) (!(A)->get_prefix) + +/** + * Used at the end of `librecrypt_algorithms_` + */ +#define END_OF_ALGORITHMS {NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, '\0'} + +/** + * Create a concatenation of `ALPHABET` repeated + * for times; used to convert a base-64 alphabet + * to an encoding lookup table + * + * @param ALPHABET:string-literal A 64-character string + * @return :string-literal A 256-character string + * + * @seealso NONSTRING + */ +#define MAKE_ENCODING_LUT(ALPHABET) ALPHABET ALPHABET ALPHABET ALPHABET + +/** + * Use in algorithms's base-64 decoding lookup tables + * in entries matching the pad character and invalid + * characters + */ +#define XX 0xFFu + + +/** + * The list of all supported algorithms (those not disabled + * at compile-time) + * + * They are ordered by how preferable they are as the + * default algorithm, with the most preferable first + * + * The list is terminated by `END_OF_ALGORITHMS`, + * which can be checked using `IS_END_OF_ALGORITHMS` + */ +extern struct algorithm librecrypt_algorithms_[]; + +/** + * This just points to memset(3), but the pointer is volalite + * so that the compiler cannot assume that, and therefore the + * call cannot be optimised away + */ +extern void *(*volatile librecrypt_explicit_memset_____)(void *, int, size_t); /* librecrypt_wipe.c */ + +/** + * The is a pointer to a function that doesn't do anything, + * however the pointer is volatile so that the function + * cannot assume that and cannot optimise away the calculating + * of the input value + */ +extern void (*volatile librecrypt_explicit_____)(unsigned char); /* librecrypt_equal_binary.c */ + + +/** + * This function implements `librecrypt_hash_binary`, `librecrypt_hash`, + * and `librecrypt_test_supported`, depending on the value of `action`, + * see documentation of those functions for more default information + * + * @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` + * @param action The function this function shall implement + * @return The number of bytes that would have been written to `out_buffer` + * if `size` was sufficiently large, excluding a terminating + * NUL byte (not present if `action == BINARY_HASH`); + * -1 on failure + * + * This function is MT-Safe but AS-Unsafe + */ +LIBRECRYPT_WRITE_MEM__(1, 2) LIBRECRYPT_READ_MEM__(3, 4) +LIBRECRYPT_READ_STR__(6) LIBRECRYPT_NONNULL_I__(5) LIBRECRYPT_WUR__ HIDDEN +ssize_t librecrypt_hash_(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, void *reserved, enum action action); + + +/** + * Default random number generator, used if no other + * is specified + * + * Generates up to `n`, or {SSIZE_MAX} if `n` is + * greater than {SSIZE_MAX}, random bytes + * + * @param out Output buffer for the random bytes + * @param n The maximum number of bytes to generate + * @param user Not used + * @return The number of generated bytes; + * will always be positive + * + * This function cannot fail, however it will ignore + * any `EINTR`; if `EINTR` is encountered `errno` will + * be set to `EINTR` upon return, otherwise `errno` + * will remain unmodifed + * + * This function is MT-Safe but AS-Unsafe + */ +LIBRECRYPT_WRITE_MEM__(1, 2) LIBRECRYPT_WUR__ HIDDEN +ssize_t librecrypt_rng_(void *out, size_t n, void *user); + + +/** + * Generate a specific number of random bytes + * + * @param out Output buffer for the random bytes + * @param n The number of bytes to generate + * @param rng The random number generator to use, + * `librecrypt_rng_` will be used if `NULL`, + * see `librecrypt_rng_` details, but not + * that it may return -1 on failure and has + * no restrictions on modifying `errno` + * @param user Passed as is to `*rng` as its third argument, + * so that it can be used for user-defined + * purposes + * @return 0 on success, -1 on failure + * + * 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_WUR__ HIDDEN +int librecrypt_fill_with_random_(void *out, size_t n, ssize_t (*rng)(void *out, size_t n, void *user), void *user); + + +/** + * Find the first algorithm specified by a password has string + * + * @param settings The password has string + * @param len The number of bytes in `settings` + * @return Pointer to the algorithm information, + * `NULL` if not found + * + * This function does not modify `errno`, but the + * caller should usually set `errno` to `ENOSYS` + * if this function returns `NULL` + * + * This function is MT-Safe And AS-Safe + */ +LIBRECRYPT_READ_MEM__(1, 2) LIBRECRYPT_NONNULL__ LIBRECRYPT_WUR__ HIDDEN +const struct algorithm *librecrypt_find_first_algorithm_(const char *settings, size_t len); + + + +#ifdef TEST +# ifdef __linux__ +# include <sys/prctl.h> +# endif +# include <sys/resource.h> +# include <sys/types.h> +# include <sys/wait.h> +# include <assert.h> +# include <signal.h> +# include <stdio.h> +# include <string.h> +# include <unistd.h> + +# define SET_UP_ALARM()\ + do {\ + unsigned int alarm_time__ = alarm(10u);\ + if (alarm_time__ > 10u)\ + alarm(alarm_time__);\ + } while (0) + +# if defined(PR_SET_DUMPABLE) +# define INIT_TEST_ABORT()\ + do {\ + struct rlimit rl__;\ + rl__.rlim_cur = 0;\ + rl__.rlim_max = 0;\ + (void) setrlimit(RLIMIT_CORE, &rl__);\ + (void) prctl(PR_SET_DUMPABLE, 0);\ + EXPECT_ABORT(abort());\ + } while (0) +# else +# define INIT_TEST_ABORT()\ + do {\ + struct rlimit rl__;\ + rl__.rlim_cur = 0;\ + rl__.rlim_max = 0;\ + (void) setrlimit(RLIMIT_CORE, &rl__);\ + EXPECT_ABORT(abort());\ + } while (0) +# endif + +# define EXPECT__(EXPR, HOW, RETEXTRACT, RETEXPECT)\ + do {\ + pid_t pid__;\ + int status__;\ + pid__ = fork();\ + EXPECT(pid__ != -1);\ + if (pid__ == 0) {\ + (EXPR);\ + _exit(0);\ + }\ + EXPECT(waitpid(pid__, &status__, 0) == pid__);\ + EXPECT(HOW(status__));\ + EXPECT(RETEXTRACT(status__) == RETEXPECT);\ + } while (0) + +# define EXPECT_ABORT(EXPR)\ + do {\ + EXPECT__(EXPR, WIFSIGNALED, WTERMSIG, SIGABRT);\ + } while (0) + +# define EXPECT(EXPR)\ + do {\ + if (!(EXPR)) {\ + fprintf(stderr, "Failure at %s:%i: %s\n", __FILE__, __LINE__, #EXPR);\ + exit(1);\ + }\ + } while (0) +#endif |
