From 9579e103657288321166f88e7ea73209ac8fd580 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Wed, 23 Sep 2026 19:39:27 +0200 Subject: Fix bug that caused (custom) hash functions with fixed tag size to be unsupported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- librecrypt_add_algorithm.c | 232 ++++++++++++++++++++++++++++++++++++++++++-- librecrypt_crypt.c | 225 ++++++++++++++++++++++++++++++++++++++++-- librecrypt_get_encoding.c | 112 +++++++++++++++++++-- librecrypt_hash.c | 219 ++++++++++++++++++++++++++++++++++++++++- librecrypt_hash_.c | 20 ++-- librecrypt_hash_binary.c | 219 ++++++++++++++++++++++++++++++++++++++++- librecrypt_make_settings.c | 222 ++++++++++++++++++++++++++++++++++++++++++ librecrypt_test_supported.c | 173 ++++++++++++++++++++++++++++++++- librecrypt_verify.c | 206 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 1582 insertions(+), 46 deletions(-) diff --git a/librecrypt_add_algorithm.c b/librecrypt_add_algorithm.c index 877e410..d561983 100644 --- a/librecrypt_add_algorithm.c +++ b/librecrypt_add_algorithm.c @@ -15,7 +15,7 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend, size_t prefix1, prefix2, min, ret, len, phraselen; size_t hashsize1, hashsize2; char *phrase, pad; - int strict_pad, r_int, nul_term; + int strict_pad, r_int, nul_term, saved_errno; const unsigned char *lut; ssize_t r; @@ -167,10 +167,12 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend, /* Chain the hash algorithms: write `augment` and hash */ r = librecrypt_crypt(out_buffer, nul_term ? size + 1u : 0u, phrase, phraselen, augment, ctx); if (r <= 0) { + saved_errno = errno; librecrypt_wipe(phrase, phraselen); free(phrase); if (!r) abort(); /* $covered$ (impossible) */ + errno = saved_errno; return -1; } if (ret > (size_t)(SSIZE_MAX - r)) { @@ -192,6 +194,194 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend, #else +#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +#define ALT_ALPHABET "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" + +NONSTRING static const char encoding_lut[256u] = MAKE_ENCODING_LUT(ALPHABET); +NONSTRING static const char alt_encoding_lut[256u] = MAKE_ENCODING_LUT(ALT_ALPHABET); + +static const unsigned char decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, XX, + XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, XX, XX, XX, XX, XX, + XX, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static const unsigned char alt_decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, XX, XX, XX, XX, XX, XX, + XX, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, + XX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static unsigned +rot4_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$rot4$") - 1u) + if (!strncmp(settings, "$rot4$", sizeof("$rot4$") - 1u)) + return 1u; + return 0u; +} + +static unsigned +trunc_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$trunc$") - 1u) + if (!strncmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 1u; + return 0u; +} + +static int +trunc_supported(const char *phrase, size_t len, int text, const char *settings, + size_t prefix, size_t *len_out) +{ + size_t i, digit, n = 0u, q, r; + + (void) phrase; + (void) len; + (void) text; + + if (prefix < sizeof("$trunc$") - 1u || memcmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 0; + + if (prefix == sizeof("$trunc$") - 1u) { + *len_out = 4u; + return 1; + } + + if (settings[sizeof("$trunc$") - 1u] == '*') { + for (i = sizeof("$trunc$*") - 1u; i < prefix; i++) { + if ('0' > settings[i] || settings[i] > '9') + return 0; + digit = (size_t)(settings[i] - '0'); + if (n > (SIZE_MAX - digit) / 10u) + return 0; + n = n * 10u + digit; + } + } else { + for (i = sizeof("$trunc$") - 1u; i < prefix; i++) { + if (settings[i] == '@') + break; + if (alt_decoding_lut[(unsigned char)settings[i]] == XX) + return 0; + n += 1u; + } + q = n / 4u; + r = n % 4u; + if (r == 1u) + return 0; + n = q * 3u + r; + if (r) { + n -= 1u; + for (; r < 4u && i < prefix; r++, i++) + if (settings[i] != '@') + break; + if (r != 4u || i != prefix) + return 0; + } + } + if (!n) + return 0; + *len_out = n; + return 1; +} + +static int +rot4_hash(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, size_t prefix, LIBRECRYPT_CONTEXT *ctx) +{ + size_t i; + + (void) settings; + (void) prefix; + (void) ctx; + + for (i = 0u; i < 8u && i < size; i++) { + out_buffer[i] = '\0'; + if (i < len) + out_buffer[i] = (char)((((int)phrase[i] & 0x0F) << 4) | (((int)phrase[i] >> 4) & 0x0F)); + } + return 0; +} + +static int +trunc_hash(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, size_t prefix, LIBRECRYPT_CONTEXT *ctx) +{ + size_t hash_size, i; + + (void) ctx; + + if (!trunc_supported(NULL, 0u, 1, settings, prefix, &hash_size)) { + errno = EINVAL; + return -1; + } + + size = MIN(hash_size, size); + for (i = 0u; i < size; i++) + out_buffer[i] = i < len ? phrase[i] : '\0'; + + return 0; +} + +static const struct librecrypt_algorithm rot4_algo = { + .is_algorithm = &rot4_is_algorithm, + .hash = &rot4_hash, + .encoding_lut = encoding_lut, + .decoding_lut = decoding_lut, + .hash_size = 8u, + .flexible_hash_size = 0, + .strict_pad = 1, + .pad = '#' +}; + +static const struct librecrypt_algorithm trunc_algo = { + .is_algorithm = &trunc_is_algorithm, + .hash = &trunc_hash, + .encoding_lut = alt_encoding_lut, + .decoding_lut = alt_decoding_lut, + .hash_size = 4u, + .flexible_hash_size = 1, + .strict_pad = 1, + .pad = '@' +}; + +#define TEST_PHRASE64_ROT4 "EiM0RVZneIk#" +#define TEST_HASH_ROT4 "ITJDVGV2h5g#" +#define TEST_HASH_TRUNC "4ycQhg@@" +#define TEST_HASH_TRUNC6 "4ycQhlpD" +#define TEST_HASH_TRUNC_ROT4 "ITJDVAAAAAA#" +#define TEST_HASH_TRUNC6_ROT4 "ITJDVGV2AAA#" +#define TEST_HASH_ROT4_TRUNC "8j93l0@@" +#define TEST_HASH_ROT4_TRUNC6 "8j93l6lS" +#define TEST_HASH_TRUNC_TRUNC6 "4ycQhg00" + + int main(void) { @@ -200,6 +390,8 @@ main(void) #define HASH1 "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTYVWXYZ/+" #define ASTRA "*48" + const struct librecrypt_algorithm custom[] = {rot4_algo, trunc_algo}; + LIBRECRYPT_CONTEXT *ctx = NULL; char buf[1024], phrase[sizeof(buf)], expected[sizeof(buf)], pad; size_t i, min, phraselen; int strict_pad; @@ -213,7 +405,7 @@ main(void) #define CHECK(AUGEND, AUGMENT, RESULT)\ do {\ CANARY_FILL(buf);\ - r = librecrypt_add_algorithm(buf, sizeof(buf), (AUGEND), (AUGMENT), NULL);\ + r = librecrypt_add_algorithm(buf, sizeof(buf), (AUGEND), (AUGMENT), ctx);\ EXPECT(r > 0);\ EXPECT((size_t)r == strlen(RESULT));\ assert((size_t)r < sizeof(buf) + 1u);\ @@ -223,7 +415,7 @@ main(void) \ for (i = (size_t)r + 2u;; i--) {\ CANARY_FILL(buf);\ - EXPECT(librecrypt_add_algorithm(buf, i, (AUGEND), (AUGMENT), NULL) == r);\ + EXPECT(librecrypt_add_algorithm(buf, i, (AUGEND), (AUGMENT), ctx) == r);\ if (!i) {\ CANARY_CHECK(buf, 0u);\ break;\ @@ -234,13 +426,13 @@ main(void) CANARY_CHECK(buf, min + 1u);\ }\ \ - EXPECT(librecrypt_add_algorithm(NULL, 0u, (AUGEND), (AUGMENT), NULL) == r);\ + EXPECT(librecrypt_add_algorithm(NULL, 0u, (AUGEND), (AUGMENT), ctx) == r);\ \ assert(sizeof(buf) > strlen(AUGEND));\ \ CANARY_FILL(buf);\ stpcpy(buf, (AUGEND));\ - EXPECT(librecrypt_add_algorithm(buf, sizeof(buf), buf, (AUGMENT), NULL) == r);\ + EXPECT(librecrypt_add_algorithm(buf, sizeof(buf), buf, (AUGMENT), ctx) == r);\ EXPECT(!buf[r]);\ EXPECT(!memcmp(buf, (RESULT), (size_t)r));\ n = strlen(AUGEND) + 1u;\ @@ -251,7 +443,7 @@ main(void) CANARY_FILL(buf);\ stpcpy(buf, (AUGEND));\ n = strlen(AUGEND) + 1u;\ - EXPECT(librecrypt_add_algorithm(buf, i, buf, (AUGMENT), NULL) == r);\ + EXPECT(librecrypt_add_algorithm(buf, i, buf, (AUGMENT), ctx) == r);\ if (!i) {\ CANARY_CHECK(buf, n);\ break;\ @@ -374,6 +566,34 @@ main(void) EXPECT(errno == ENOSYS); CANARY_CHECK(buf, 0u); + ctx = librecrypt_create_context(); + assert(ctx != NULL); + + librecrypt_set_custom_algorithms(ctx, custom, ELEMSOF(custom)); + CHECK("$rot4$", "$rot4$", "$rot4$>$rot4$"); + CHECK("$rot4$", "$trunc$", "$rot4$>$trunc$"); + CHECK("$rot4$", "$trunc$*6", "$rot4$>$trunc$*6"); + CHECK("$trunc$", "$trunc$", "$trunc$>$trunc$"); + CHECK("$trunc$", "$trunc$*6", "$trunc$>$trunc$*6"); + CHECK("$trunc$", "$rot4$", "$trunc$>$rot4$"); + CHECK("$trunc$*4", "$trunc$", "$trunc$*4>$trunc$"); + CHECK("$trunc$*4", "$trunc$*6", "$trunc$*4>$trunc$*6"); + CHECK("$trunc$*4", "$rot4$", "$trunc$*4>$rot4$"); + CHECK("$trunc$*6", "$trunc$", "$trunc$*6>$trunc$"); + CHECK("$trunc$*6", "$trunc$*6", "$trunc$*6>$trunc$*6"); + CHECK("$trunc$*6", "$rot4$", "$trunc$*6>$rot4$"); + CHECK("$rot4$"TEST_HASH_ROT4, "$rot4$", "$rot4$>$rot4$"TEST_PHRASE64_ROT4); + CHECK("$rot4$"TEST_HASH_ROT4, "$trunc$", "$rot4$>$trunc$"TEST_HASH_ROT4_TRUNC); + CHECK("$rot4$"TEST_HASH_ROT4, "$trunc$*6", "$rot4$>$trunc$"TEST_HASH_ROT4_TRUNC6); + CHECK("$trunc$"TEST_HASH_TRUNC6, "$trunc$", "$trunc$*6>$trunc$"TEST_HASH_TRUNC); + CHECK("$trunc$"TEST_HASH_TRUNC6, "$trunc$*6", "$trunc$*6>$trunc$"TEST_HASH_TRUNC6); + CHECK("$trunc$"TEST_HASH_TRUNC6, "$rot4$", "$trunc$*6>$rot4$"TEST_HASH_TRUNC6_ROT4); + CHECK("$trunc$"TEST_HASH_TRUNC, "$trunc$", "$trunc$*4>$trunc$"TEST_HASH_TRUNC); + CHECK("$trunc$"TEST_HASH_TRUNC, "$trunc$*6", "$trunc$*4>$trunc$"TEST_HASH_TRUNC_TRUNC6); + CHECK("$trunc$"TEST_HASH_TRUNC, "$rot4$", "$trunc$*4>$rot4$"TEST_HASH_TRUNC_ROT4); + + librecrypt_free_context(ctx); + STOP_RESOURCE_TEST(); return 0; } diff --git a/librecrypt_crypt.c b/librecrypt_crypt.c index fb93cd2..d837724 100644 --- a/librecrypt_crypt.c +++ b/librecrypt_crypt.c @@ -14,6 +14,194 @@ librecrypt_crypt(char *restrict out_buffer, size_t size, const char *phrase, #else +#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +#define ALT_ALPHABET "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" + +NONSTRING static const char encoding_lut[256u] = MAKE_ENCODING_LUT(ALPHABET); +NONSTRING static const char alt_encoding_lut[256u] = MAKE_ENCODING_LUT(ALT_ALPHABET); + +static const unsigned char decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, XX, + XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, XX, XX, XX, XX, XX, + XX, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static const unsigned char alt_decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, XX, XX, XX, XX, XX, XX, + XX, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, + XX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static unsigned +rot4_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$rot4$") - 1u) + if (!strncmp(settings, "$rot4$", sizeof("$rot4$") - 1u)) + return 1u; + return 0u; +} + +static unsigned +trunc_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$trunc$") - 1u) + if (!strncmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 1u; + return 0u; +} + +static int +trunc_supported(const char *phrase, size_t len, int text, const char *settings, + size_t prefix, size_t *len_out) +{ + size_t i, digit, n = 0u, q, r; + + (void) phrase; + (void) len; + (void) text; + + if (prefix < sizeof("$trunc$") - 1u || memcmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 0; + + if (prefix == sizeof("$trunc$") - 1u) { + *len_out = 4u; + return 1; + } + + if (settings[sizeof("$trunc$") - 1u] == '*') { + for (i = sizeof("$trunc$*") - 1u; i < prefix; i++) { + if ('0' > settings[i] || settings[i] > '9') + return 0; + digit = (size_t)(settings[i] - '0'); + if (n > (SIZE_MAX - digit) / 10u) + return 0; + n = n * 10u + digit; + } + } else { + for (i = sizeof("$trunc$") - 1u; i < prefix; i++) { + if (settings[i] == '@') + break; + if (alt_decoding_lut[(unsigned char)settings[i]] == XX) + return 0; + n += 1u; + } + q = n / 4u; + r = n % 4u; + if (r == 1u) + return 0; + n = q * 3u + r; + if (r) { + n -= 1u; + for (; r < 4u && i < prefix; r++, i++) + if (settings[i] != '@') + break; + if (r != 4u || i != prefix) + return 0; + } + } + if (!n) + return 0; + *len_out = n; + return 1; +} + +static int +rot4_hash(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, size_t prefix, LIBRECRYPT_CONTEXT *ctx) +{ + size_t i; + + (void) settings; + (void) prefix; + (void) ctx; + + for (i = 0u; i < 8u && i < size; i++) { + out_buffer[i] = '\0'; + if (i < len) + out_buffer[i] = (char)((((int)phrase[i] & 0x0F) << 4) | (((int)phrase[i] >> 4) & 0x0F)); + } + return 0; +} + +static int +trunc_hash(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, size_t prefix, LIBRECRYPT_CONTEXT *ctx) +{ + size_t hash_size, i; + + (void) ctx; + + if (!trunc_supported(NULL, 0u, 1, settings, prefix, &hash_size)) { + errno = EINVAL; + return -1; + } + + size = MIN(hash_size, size); + for (i = 0u; i < size; i++) + out_buffer[i] = i < len ? phrase[i] : '\0'; + + return 0; +} + +static const struct librecrypt_algorithm rot4_algo = { + .is_algorithm = &rot4_is_algorithm, + .hash = &rot4_hash, + .encoding_lut = encoding_lut, + .decoding_lut = decoding_lut, + .hash_size = 8u, + .flexible_hash_size = 0, + .strict_pad = 1, + .pad = '#' +}; + +static const struct librecrypt_algorithm trunc_algo = { + .is_algorithm = &trunc_is_algorithm, + .hash = &trunc_hash, + .encoding_lut = alt_encoding_lut, + .decoding_lut = alt_decoding_lut, + .hash_size = 4u, + .flexible_hash_size = 1, + .strict_pad = 1, + .pad = '@' +}; + +#define TEST_PHRASE "\x12\x23\x34\x45\x56\x67\x78\x89" +#define TEST_PHRASE64_ROT4 "EiM0RVZneIk#" +#define TEST_HASH_ROT4 "ITJDVGV2h5g#" +#define TEST_HASH_TRUNC "4ycQhg@@" +#define TEST_HASH_TRUNC6 "4ycQhlpD" +#define TEST_HASH_TRUNC_ROT4 "ITJDVAAAAAA#" +#define TEST_HASH_TRUNC6_ROT4 "ITJDVGV2AAA#" +#define TEST_HASH_ROT4_TRUNC "8j93l0@@" +#define TEST_HASH_ROT4_TRUNC6 "8j93l6lS" +#define TEST_HASH_TRUNC_TRUNC6 "4ycQhg00" + #define SP4 " " #define SP20 SP4 SP4 SP4 SP4 SP4 #define SP80 SP20 SP20 SP20 SP20 @@ -77,23 +265,27 @@ check(const char *phrase, const char *settings, const char *chain, size_t chain_ EXPECT(librecrypt_crypt(buf2, sizeof(buf2), phrase, len, chain, ctx) == (ssize_t)(hashlen - hash_prefix + chain_prefix)); EXPECT(!memcmp(buf2, chain, chain_prefix)); EXPECT(!memcmp(&buf[hash_prefix], &buf2[chain_prefix], hashlen - hash_prefix + 1u)); - CANARY_X_CHECK(buf, hashlen, scratchsize); CANARY_X_CHECK(buf2, hashlen - hash_prefix + chain_prefix, scratchsize); + CANARY_X_CHECK(buf, hashlen, scratchsize); } -#define CHECK(PHRASE, CONF, HASHLEN, IS_DEFAULT_HASHLEN, HASH)\ +#define CHECK(PHRASE, CONF, HASHLEN, IS_DEFAULT_HASHLEN /* -1 if fixed */, HASH)\ do {\ size_t scratchsize = GET_SCRATCH_SIZE(HASHLEN);\ - check(PHRASE, CONF HASH, CONF "*" #HASHLEN ">" CONF HASH,\ - sizeof(CONF "*" #HASHLEN ">" CONF) - 1u, CONF HASH,\ - sizeof(CONF) - 1u, scratchsize, ctx);\ - check(PHRASE, CONF "*" #HASHLEN, CONF "*" #HASHLEN ">" CONF "*" #HASHLEN,\ - sizeof(CONF "*" #HASHLEN ">" CONF) - 1u, CONF HASH,\ - sizeof(CONF) - 1u, scratchsize, ctx);\ + if (IS_DEFAULT_HASHLEN >= 0) {\ + check(PHRASE, CONF HASH, CONF "*" #HASHLEN ">" CONF HASH,\ + sizeof(CONF "*" #HASHLEN ">" CONF) - 1u, CONF HASH,\ + sizeof(CONF) - 1u, scratchsize, ctx);\ + check(PHRASE, CONF "*" #HASHLEN, CONF "*" #HASHLEN ">" CONF "*" #HASHLEN,\ + sizeof(CONF "*" #HASHLEN ">" CONF) - 1u, CONF HASH,\ + sizeof(CONF) - 1u, scratchsize, ctx);\ + }\ if (IS_DEFAULT_HASHLEN) {\ check(PHRASE, CONF, CONF ">" CONF, sizeof(CONF ">" CONF) - 1u,\ CONF HASH, sizeof(CONF) - 1u, scratchsize, ctx);\ + check(PHRASE, CONF HASH, CONF ">" CONF HASH, sizeof(CONF ">" CONF) - 1u,\ + CONF HASH, sizeof(CONF) - 1u, scratchsize, ctx);\ }\ } while (0) @@ -109,6 +301,7 @@ check(const char *phrase, const char *settings, const char *chain, size_t chain_ int main(void) { + const struct librecrypt_algorithm custom[] = {rot4_algo, trunc_algo}; char buf[1024], buf2[1024], conf[256], nuls[256]; LIBRECRYPT_CONTEXT *ctx = NULL; ssize_t r; @@ -275,6 +468,22 @@ main(void) # undef GET_SCRATCH_SIZE #endif +#define GET_SCRATCH_SIZE(HASHLEN) (HASHLEN) + librecrypt_set_custom_algorithms(ctx, custom, ELEMSOF(custom)); + CHECK(TEST_PHRASE, "$trunc$", 4, 1, TEST_HASH_TRUNC); + CHECK(TEST_PHRASE, "$trunc$", 6, 0, TEST_HASH_TRUNC6); + CHECK(TEST_PHRASE, "$rot4$", 8, -1, TEST_HASH_ROT4); + CHECK(TEST_PHRASE, "$rot4$>$trunc$", 4, 1, TEST_HASH_ROT4_TRUNC); + CHECK(TEST_PHRASE, "$rot4$>$trunc$", 6, 0, TEST_HASH_ROT4_TRUNC6); + CHECK(TEST_PHRASE, "$trunc$>$rot4$", 8, -1, TEST_HASH_TRUNC_ROT4); + CHECK(TEST_PHRASE, "$trunc$*6>$rot4$", 8, -1, TEST_HASH_TRUNC6_ROT4); + CHECK(TEST_PHRASE, "$trunc$>$trunc$", 4, 1, TEST_HASH_TRUNC); + CHECK(TEST_PHRASE, "$trunc$>$trunc$", 6, 0, TEST_HASH_TRUNC_TRUNC6); + CHECK(TEST_PHRASE, "$trunc$*6>$trunc$", 4, 1, TEST_HASH_TRUNC); + CHECK(TEST_PHRASE, "$trunc$*6>$trunc$", 6, 0, TEST_HASH_TRUNC6); + CHECK(TEST_PHRASE, "$rot4$>$rot4$", 8, -1, TEST_PHRASE64_ROT4); +#undef GET_SCRATCH_SIZE + librecrypt_free_context(ctx); STOP_RESOURCE_TEST(); diff --git a/librecrypt_get_encoding.c b/librecrypt_get_encoding.c index 7d0e62c..6d02d07 100644 --- a/librecrypt_get_encoding.c +++ b/librecrypt_get_encoding.c @@ -38,6 +38,88 @@ librecrypt_get_encoding(const char *settings, size_t len, char *pad_out, int *st # ifndef FUZZ +#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +#define ALT_ALPHABET "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" + +NONSTRING static const char encoding_lut[256u] = MAKE_ENCODING_LUT(ALPHABET); +NONSTRING static const char alt_encoding_lut[256u] = MAKE_ENCODING_LUT(ALT_ALPHABET); + +static const unsigned char decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, XX, + XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, XX, XX, XX, XX, XX, + XX, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static const unsigned char alt_decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, XX, XX, XX, XX, XX, XX, + XX, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, + XX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static unsigned +rot4_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$rot4$") - 1u) + if (!strncmp(settings, "$rot4$", sizeof("$rot4$") - 1u)) + return 1u; + return 0u; +} + +static unsigned +trunc_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$trunc$") - 1u) + if (!strncmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 1u; + return 0u; +} + +static const struct librecrypt_algorithm rot4_algo = { + .is_algorithm = &rot4_is_algorithm, + .encoding_lut = encoding_lut, + .decoding_lut = decoding_lut, + .hash_size = 8u, + .flexible_hash_size = 0, + .strict_pad = 1, + .pad = '#' +}; + +static const struct librecrypt_algorithm trunc_algo = { + .is_algorithm = &trunc_is_algorithm, + .encoding_lut = alt_encoding_lut, + .decoding_lut = alt_decoding_lut, + .hash_size = 4u, + .flexible_hash_size = 1, + .strict_pad = 1, + .pad = '@' +}; + #define NSA "$~no~such~algorithm~$" @@ -73,7 +155,7 @@ check_decoding_lut(const unsigned char *lut, const char *alpha) do {\ pad = (char)~(PAD);\ strict_pad = -1;\ - elut = librecrypt_get_encoding(PREFIX, sizeof(PREFIX) - 1u, &pad, &strict_pad, 0, NULL);\ + elut = librecrypt_get_encoding(PREFIX, sizeof(PREFIX) - 1u, &pad, &strict_pad, 0, ctx);\ EXPECT(elut != NULL);\ EXPECT(pad == (PAD));\ EXPECT(strict_pad == (STRICT_PAD));\ @@ -81,7 +163,7 @@ check_decoding_lut(const unsigned char *lut, const char *alpha) \ pad = (char)~(PAD);\ strict_pad = -1;\ - dlut = librecrypt_get_encoding(PREFIX, sizeof(PREFIX) - 1u, &pad, &strict_pad, 1, NULL);\ + dlut = librecrypt_get_encoding(PREFIX, sizeof(PREFIX) - 1u, &pad, &strict_pad, 1, ctx);\ EXPECT(dlut != NULL);\ EXPECT(pad == (PAD));\ EXPECT(strict_pad == (STRICT_PAD));\ @@ -89,7 +171,7 @@ check_decoding_lut(const unsigned char *lut, const char *alpha) \ pad = (char)~(PAD);\ strict_pad = -1;\ - elut = librecrypt_get_encoding(NSA">"PREFIX, sizeof(NSA">"PREFIX) - 1u, &pad, &strict_pad, 0, NULL);\ + elut = librecrypt_get_encoding(NSA">"PREFIX, sizeof(NSA">"PREFIX) - 1u, &pad, &strict_pad, 0, ctx);\ EXPECT(elut != NULL);\ EXPECT(pad == (PAD));\ EXPECT(strict_pad == (STRICT_PAD));\ @@ -105,6 +187,8 @@ check_decoding_lut(const unsigned char *lut, const char *alpha) int main(void) { + const struct librecrypt_algorithm custom[] = {rot4_algo, trunc_algo}; + LIBRECRYPT_CONTEXT *ctx = NULL; const char *elut; const unsigned char *dlut; char pad; @@ -114,19 +198,19 @@ main(void) INIT_RESOURCE_TEST(); errno = 0; - EXPECT(librecrypt_get_encoding(NSA, sizeof(NSA) - 1u, &pad, &strict_pad, 0, NULL) == NULL); + EXPECT(librecrypt_get_encoding(NSA, sizeof(NSA) - 1u, &pad, &strict_pad, 0, ctx) == NULL); EXPECT(errno == ENOSYS); errno = 0; - EXPECT(librecrypt_get_encoding(NSA, sizeof(NSA) - 1u, &pad, &strict_pad, 1, NULL) == NULL); + EXPECT(librecrypt_get_encoding(NSA, sizeof(NSA) - 1u, &pad, &strict_pad, 1, ctx) == NULL); EXPECT(errno == ENOSYS); errno = 0; - EXPECT(librecrypt_get_encoding(">"NSA, sizeof(">"NSA) - 1u, &pad, &strict_pad, 0, NULL) == NULL); + EXPECT(librecrypt_get_encoding(">"NSA, sizeof(">"NSA) - 1u, &pad, &strict_pad, 0, ctx) == NULL); EXPECT(errno == ENOSYS); errno = 0; - EXPECT(librecrypt_get_encoding(">"NSA, sizeof(">"NSA) - 1u, &pad, &strict_pad, 1, NULL) == NULL); + EXPECT(librecrypt_get_encoding(">"NSA, sizeof(">"NSA) - 1u, &pad, &strict_pad, 1, ctx) == NULL); EXPECT(errno == ENOSYS); IF__argon2i_v1_0__SUPPORTED(CHECK("$argon2i$", UPPER LOWER DIGIT "+/", '=', 0);) @@ -139,6 +223,20 @@ main(void) IF__argon2id_v1_3__SUPPORTED(CHECK("$argon2id$v=19$", UPPER LOWER DIGIT "+/", '=', 0);) IF__argon2ds_v1_3__SUPPORTED(CHECK("$argon2ds$v=19$", UPPER LOWER DIGIT "+/", '=', 0);) + ctx = librecrypt_create_context(); + assert(ctx != NULL); + + librecrypt_set_custom_algorithms(ctx, custom, ELEMSOF(custom)); + CHECK("$rot4$", ALPHABET, '#', 1); + CHECK("$trunc$", ALT_ALPHABET, '@', 1); + CHECK("$trunc$*4", ALT_ALPHABET, '@', 1); + CHECK("$rot4$>$trunc$", ALT_ALPHABET, '@', 1); + CHECK("$rot4$>$trunc$*4", ALT_ALPHABET, '@', 1); + CHECK("$trunc$>$rot4$", ALPHABET, '#', 1); + CHECK("$trunc$*4>$rot4$", ALPHABET, '#', 1); + + librecrypt_free_context(ctx); + STOP_RESOURCE_TEST(); return 0; } diff --git a/librecrypt_hash.c b/librecrypt_hash.c index 3d37d03..18627d1 100644 --- a/librecrypt_hash.c +++ b/librecrypt_hash.c @@ -14,6 +14,194 @@ librecrypt_hash(char *restrict out_buffer, size_t size, const char *phrase, #else +#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +#define ALT_ALPHABET "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" + +NONSTRING static const char encoding_lut[256u] = MAKE_ENCODING_LUT(ALPHABET); +NONSTRING static const char alt_encoding_lut[256u] = MAKE_ENCODING_LUT(ALT_ALPHABET); + +static const unsigned char decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, XX, + XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, XX, XX, XX, XX, XX, + XX, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static const unsigned char alt_decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, XX, XX, XX, XX, XX, XX, + XX, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, + XX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static unsigned +rot4_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$rot4$") - 1u) + if (!strncmp(settings, "$rot4$", sizeof("$rot4$") - 1u)) + return 1u; + return 0u; +} + +static unsigned +trunc_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$trunc$") - 1u) + if (!strncmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 1u; + return 0u; +} + +static int +trunc_supported(const char *phrase, size_t len, int text, const char *settings, + size_t prefix, size_t *len_out) +{ + size_t i, digit, n = 0u, q, r; + + (void) phrase; + (void) len; + (void) text; + + if (prefix < sizeof("$trunc$") - 1u || memcmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 0; + + if (prefix == sizeof("$trunc$") - 1u) { + *len_out = 4u; + return 1; + } + + if (settings[sizeof("$trunc$") - 1u] == '*') { + for (i = sizeof("$trunc$*") - 1u; i < prefix; i++) { + if ('0' > settings[i] || settings[i] > '9') + return 0; + digit = (size_t)(settings[i] - '0'); + if (n > (SIZE_MAX - digit) / 10u) + return 0; + n = n * 10u + digit; + } + } else { + for (i = sizeof("$trunc$") - 1u; i < prefix; i++) { + if (settings[i] == '@') + break; + if (alt_decoding_lut[(unsigned char)settings[i]] == XX) + return 0; + n += 1u; + } + q = n / 4u; + r = n % 4u; + if (r == 1u) + return 0; + n = q * 3u + r; + if (r) { + n -= 1u; + for (; r < 4u && i < prefix; r++, i++) + if (settings[i] != '@') + break; + if (r != 4u || i != prefix) + return 0; + } + } + if (!n) + return 0; + *len_out = n; + return 1; +} + +static int +rot4_hash(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, size_t prefix, LIBRECRYPT_CONTEXT *ctx) +{ + size_t i; + + (void) settings; + (void) prefix; + (void) ctx; + + for (i = 0u; i < 8u && i < size; i++) { + out_buffer[i] = '\0'; + if (i < len) + out_buffer[i] = (char)((((int)phrase[i] & 0x0F) << 4) | (((int)phrase[i] >> 4) & 0x0F)); + } + return 0; +} + +static int +trunc_hash(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, size_t prefix, LIBRECRYPT_CONTEXT *ctx) +{ + size_t hash_size, i; + + (void) ctx; + + if (!trunc_supported(NULL, 0u, 1, settings, prefix, &hash_size)) { + errno = EINVAL; + return -1; + } + + size = MIN(hash_size, size); + for (i = 0u; i < size; i++) + out_buffer[i] = i < len ? phrase[i] : '\0'; + + return 0; +} + +static const struct librecrypt_algorithm rot4_algo = { + .is_algorithm = &rot4_is_algorithm, + .hash = &rot4_hash, + .encoding_lut = encoding_lut, + .decoding_lut = decoding_lut, + .hash_size = 8u, + .flexible_hash_size = 0, + .strict_pad = 1, + .pad = '#' +}; + +static const struct librecrypt_algorithm trunc_algo = { + .is_algorithm = &trunc_is_algorithm, + .hash = &trunc_hash, + .encoding_lut = alt_encoding_lut, + .decoding_lut = alt_decoding_lut, + .hash_size = 4u, + .flexible_hash_size = 1, + .strict_pad = 1, + .pad = '@' +}; + +#define TEST_PHRASE "\x12\x23\x34\x45\x56\x67\x78\x89" +#define TEST_PHRASE64_ROT4 "EiM0RVZneIk#" +#define TEST_HASH_ROT4 "ITJDVGV2h5g#" +#define TEST_HASH_TRUNC "4ycQhg@@" +#define TEST_HASH_TRUNC6 "4ycQhlpD" +#define TEST_HASH_TRUNC_ROT4 "ITJDVAAAAAA#" +#define TEST_HASH_TRUNC6_ROT4 "ITJDVGV2AAA#" +#define TEST_HASH_ROT4_TRUNC "8j93l0@@" +#define TEST_HASH_ROT4_TRUNC6 "8j93l6lS" +#define TEST_HASH_TRUNC_TRUNC6 "4ycQhg00" + #define SP4 " " #define SP20 SP4 SP4 SP4 SP4 SP4 #define SP80 SP20 SP20 SP20 SP20 @@ -79,18 +267,22 @@ check(const char *phrase, const char *settings, const char *chain, errno = 0; EXPECT(librecrypt_hash(buf2, sizeof(buf2), phrase, len, chain, ctx) == (ssize_t)hashlen); EXPECT(!memcmp(buf, buf2, hashlen + 1u)); - CANARY_X_CHECK(buf, hashlen + 2, scratchsize); CANARY_X_CHECK(buf2, hashlen + 2, scratchsize); + CANARY_X_CHECK(buf, hashlen + 2, scratchsize); } -#define CHECK(PHRASE, CONF, HASHLEN, IS_DEFAULT_HASHLEN, HASH)\ +#define CHECK(PHRASE, CONF, HASHLEN, IS_DEFAULT_HASHLEN /* -1 if fixed */, HASH)\ do {\ size_t scratchsize = GET_SCRATCH_SIZE(HASHLEN);\ - check(PHRASE, CONF HASH, CONF "*" #HASHLEN ">" CONF HASH, HASH, scratchsize, ctx);\ - check(PHRASE, CONF "*" #HASHLEN, CONF "*" #HASHLEN ">" CONF "*" #HASHLEN, HASH, scratchsize, ctx);\ - if (IS_DEFAULT_HASHLEN)\ + if (IS_DEFAULT_HASHLEN >= 0) {\ + check(PHRASE, CONF HASH, CONF "*" #HASHLEN ">" CONF HASH, HASH, scratchsize, ctx);\ + check(PHRASE, CONF "*" #HASHLEN, CONF "*" #HASHLEN ">" CONF "*" #HASHLEN, HASH, scratchsize, ctx);\ + }\ + if (IS_DEFAULT_HASHLEN) {\ check(PHRASE, CONF, CONF ">" CONF, HASH, scratchsize, ctx);\ + check(PHRASE, CONF HASH, CONF ">" CONF HASH, HASH, scratchsize, ctx);\ + }\ } while (0) @@ -129,6 +321,7 @@ check(const char *phrase, const char *settings, const char *chain, int main(void) { + const struct librecrypt_algorithm custom[] = {rot4_algo, trunc_algo}; char conf[256], nuls[256]; LIBRECRYPT_CONTEXT *ctx = NULL; int r; @@ -216,6 +409,22 @@ main(void) # undef GET_SCRATCH_SIZE #endif +#define GET_SCRATCH_SIZE(HASHLEN) (HASHLEN) + librecrypt_set_custom_algorithms(ctx, custom, ELEMSOF(custom)); + CHECK(TEST_PHRASE, "$trunc$", 4, 1, TEST_HASH_TRUNC); + CHECK(TEST_PHRASE, "$trunc$", 6, 0, TEST_HASH_TRUNC6); + CHECK(TEST_PHRASE, "$rot4$", 8, -1, TEST_HASH_ROT4); + CHECK(TEST_PHRASE, "$rot4$>$trunc$", 4, 1, TEST_HASH_ROT4_TRUNC); + CHECK(TEST_PHRASE, "$rot4$>$trunc$", 6, 0, TEST_HASH_ROT4_TRUNC6); + CHECK(TEST_PHRASE, "$trunc$>$rot4$", 8, -1, TEST_HASH_TRUNC_ROT4); + CHECK(TEST_PHRASE, "$trunc$*6>$rot4$", 8, -1, TEST_HASH_TRUNC6_ROT4); + CHECK(TEST_PHRASE, "$trunc$>$trunc$", 4, 1, TEST_HASH_TRUNC); + CHECK(TEST_PHRASE, "$trunc$>$trunc$", 6, 0, TEST_HASH_TRUNC_TRUNC6); + CHECK(TEST_PHRASE, "$trunc$*6>$trunc$", 4, 1, TEST_HASH_TRUNC); + CHECK(TEST_PHRASE, "$trunc$*6>$trunc$", 6, 0, TEST_HASH_TRUNC6); + CHECK(TEST_PHRASE, "$rot4$>$rot4$", 8, -1, TEST_PHRASE64_ROT4); +#undef GET_SCRATCH_SIZE + librecrypt_free_context(ctx); STOP_RESOURCE_TEST(); diff --git a/librecrypt_hash_.c b/librecrypt_hash_.c index 71ec98d..164a47b 100644 --- a/librecrypt_hash_.c +++ b/librecrypt_hash_.c @@ -118,18 +118,15 @@ next: /* Special case for bsdicrypt */ prefix = 1u; /* $covered$ (TODO we currently don't have an algorithm to trigger this) */ } - if (!algo->flexible_hash_size && prefix != n) - goto einval; /* Get hash size */ - if (!algo->flexible_hash_size) { - /* fixed */ - hash_size = algo->hash_size; - } else if (prefix == n) { + if (prefix == n) { /* default */ hash_size = algo->hash_size; } else if (settings[prefix] == '*') { - /* hash length encoded */ + /* hash length encoded, not allowed when fixed */ + if (!algo->flexible_hash_size) + goto einval; i = prefix + 1u; hash_size = 0u; for (; i < n; i++) { @@ -169,6 +166,9 @@ next: hash_size = quotient * 3u; if (remainder) hash_size += remainder - 1u; + /* Must align with fixed hash size when hash size is fixed */ + if (!algo->flexible_hash_size && hash_size != algo->hash_size) + goto einval; } /* For `librecrypt_crypt`: copy hash configurations to output */ @@ -436,7 +436,7 @@ add1_hash(char *restrict out_buffer, size_t size, const char *phrase, size_t len return 0; } -static const struct librecrypt_algorithm rot4 = { +static const struct librecrypt_algorithm rot4_algo = { .is_algorithm = &rot4_is_algorithm, .hash = &rot4_hash, .encoding_lut = elut, @@ -447,7 +447,7 @@ static const struct librecrypt_algorithm rot4 = { .pad = '#' }; -static const struct librecrypt_algorithm add1 = { +static const struct librecrypt_algorithm add1_algo = { .is_algorithm = &add1_is_algorithm, .hash = &add1_hash, .encoding_lut = elut, @@ -476,7 +476,7 @@ main(void) size_t i, n; ssize_t r, r1, r1b, r1c, r2, r3; LIBRECRYPT_CONTEXT *ctx = NULL; - struct librecrypt_algorithm custom[] = {rot4, add1}; + struct librecrypt_algorithm custom[] = {rot4_algo, add1_algo}; SET_UP_ALARM(); INIT_RESOURCE_TEST(); diff --git a/librecrypt_hash_binary.c b/librecrypt_hash_binary.c index 8596160..398f7e3 100644 --- a/librecrypt_hash_binary.c +++ b/librecrypt_hash_binary.c @@ -14,6 +14,194 @@ librecrypt_hash_binary(void *restrict out_buffer, size_t size, const char *phras #else +#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +#define ALT_ALPHABET "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" + +NONSTRING static const char encoding_lut[256u] = MAKE_ENCODING_LUT(ALPHABET); +NONSTRING static const char alt_encoding_lut[256u] = MAKE_ENCODING_LUT(ALT_ALPHABET); + +static const unsigned char decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, XX, + XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, XX, XX, XX, XX, XX, + XX, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static const unsigned char alt_decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, XX, XX, XX, XX, XX, XX, + XX, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, + XX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static unsigned +rot4_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$rot4$") - 1u) + if (!strncmp(settings, "$rot4$", sizeof("$rot4$") - 1u)) + return 1u; + return 0u; +} + +static unsigned +trunc_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$trunc$") - 1u) + if (!strncmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 1u; + return 0u; +} + +static int +trunc_supported(const char *phrase, size_t len, int text, const char *settings, + size_t prefix, size_t *len_out) +{ + size_t i, digit, n = 0u, q, r; + + (void) phrase; + (void) len; + (void) text; + + if (prefix < sizeof("$trunc$") - 1u || memcmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 0; + + if (prefix == sizeof("$trunc$") - 1u) { + *len_out = 4u; + return 1; + } + + if (settings[sizeof("$trunc$") - 1u] == '*') { + for (i = sizeof("$trunc$*") - 1u; i < prefix; i++) { + if ('0' > settings[i] || settings[i] > '9') + return 0; + digit = (size_t)(settings[i] - '0'); + if (n > (SIZE_MAX - digit) / 10u) + return 0; + n = n * 10u + digit; + } + } else { + for (i = sizeof("$trunc$") - 1u; i < prefix; i++) { + if (settings[i] == '@') + break; + if (alt_decoding_lut[(unsigned char)settings[i]] == XX) + return 0; + n += 1u; + } + q = n / 4u; + r = n % 4u; + if (r == 1u) + return 0; + n = q * 3u + r; + if (r) { + n -= 1u; + for (; r < 4u && i < prefix; r++, i++) + if (settings[i] != '@') + break; + if (r != 4u || i != prefix) + return 0; + } + } + if (!n) + return 0; + *len_out = n; + return 1; +} + +static int +rot4_hash(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, size_t prefix, LIBRECRYPT_CONTEXT *ctx) +{ + size_t i; + + (void) settings; + (void) prefix; + (void) ctx; + + for (i = 0u; i < 8u && i < size; i++) { + out_buffer[i] = '\0'; + if (i < len) + out_buffer[i] = (char)((((int)phrase[i] & 0x0F) << 4) | (((int)phrase[i] >> 4) & 0x0F)); + } + return 0; +} + +static int +trunc_hash(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, size_t prefix, LIBRECRYPT_CONTEXT *ctx) +{ + size_t hash_size, i; + + (void) ctx; + + if (!trunc_supported(NULL, 0u, 1, settings, prefix, &hash_size)) { + errno = EINVAL; + return -1; + } + + size = MIN(hash_size, size); + for (i = 0u; i < size; i++) + out_buffer[i] = i < len ? phrase[i] : '\0'; + + return 0; +} + +static const struct librecrypt_algorithm rot4_algo = { + .is_algorithm = &rot4_is_algorithm, + .hash = &rot4_hash, + .encoding_lut = encoding_lut, + .decoding_lut = decoding_lut, + .hash_size = 8u, + .flexible_hash_size = 0, + .strict_pad = 1, + .pad = '#' +}; + +static const struct librecrypt_algorithm trunc_algo = { + .is_algorithm = &trunc_is_algorithm, + .hash = &trunc_hash, + .encoding_lut = alt_encoding_lut, + .decoding_lut = alt_decoding_lut, + .hash_size = 4u, + .flexible_hash_size = 1, + .strict_pad = 1, + .pad = '@' +}; + +#define TEST_PHRASE "\x12\x23\x34\x45\x56\x67\x78\x89" +#define TEST_PHRASE64_ROT4 "EiM0RVZneIk#" +#define TEST_HASH_ROT4 "ITJDVGV2h5g#" +#define TEST_HASH_TRUNC "4ycQhg@@" +#define TEST_HASH_TRUNC6 "4ycQhlpD" +#define TEST_HASH_TRUNC_ROT4 "ITJDVAAAAAA#" +#define TEST_HASH_TRUNC6_ROT4 "ITJDVGV2AAA#" +#define TEST_HASH_ROT4_TRUNC "8j93l0@@" +#define TEST_HASH_ROT4_TRUNC6 "8j93l6lS" +#define TEST_HASH_TRUNC_TRUNC6 "4ycQhg00" + #define SP4 " " #define SP20 SP4 SP4 SP4 SP4 SP4 #define SP80 SP20 SP20 SP20 SP20 @@ -67,18 +255,22 @@ check(const char *phrase, const char *settings, const char *chain, const char *h errno = 0; EXPECT(librecrypt_hash_binary(buf2, sizeof(buf2), phrase, len, chain, ctx) == (ssize_t)hashlen); EXPECT(!memcmp(buf, buf2, hashlen)); - CANARY_X_CHECK(buf, hashlen, scratchsize); CANARY_X_CHECK(buf2, hashlen, scratchsize); + CANARY_X_CHECK(buf, hashlen, scratchsize); } -#define CHECK(PHRASE, CONF, HASHLEN, IS_DEFAULT_HASHLEN, HASH)\ +#define CHECK(PHRASE, CONF, HASHLEN, IS_DEFAULT_HASHLEN /* -1 if fixed */, HASH)\ do {\ size_t scratchsize = GET_SCRATCH_SIZE(HASHLEN);\ - check(PHRASE, CONF HASH, CONF "*" #HASHLEN ">" CONF HASH, HASH, (size_t)HASHLEN, scratchsize, ctx);\ - check(PHRASE, CONF "*" #HASHLEN, CONF "*" #HASHLEN ">" CONF "*" #HASHLEN, HASH, (size_t)HASHLEN, scratchsize, ctx);\ - if (IS_DEFAULT_HASHLEN)\ + if (IS_DEFAULT_HASHLEN >= 0) {\ + check(PHRASE, CONF HASH, CONF "*" #HASHLEN ">" CONF HASH, HASH, (size_t)HASHLEN, scratchsize, ctx);\ + check(PHRASE, CONF "*" #HASHLEN, CONF "*" #HASHLEN ">" CONF "*" #HASHLEN, HASH, (size_t)HASHLEN, scratchsize, ctx);\ + }\ + if (IS_DEFAULT_HASHLEN) {\ check(PHRASE, CONF, CONF ">" CONF, HASH, (size_t)HASHLEN, scratchsize, ctx);\ + check(PHRASE, CONF HASH, CONF ">" CONF HASH, HASH, (size_t)HASHLEN, scratchsize, ctx);\ + }\ } while (0) @@ -96,6 +288,7 @@ check(const char *phrase, const char *settings, const char *chain, const char *h int main(void) { + const struct librecrypt_algorithm custom[] = {rot4_algo, trunc_algo}; LIBRECRYPT_CONTEXT *ctx = NULL; char nuls[256]; @@ -164,6 +357,22 @@ main(void) # undef GET_SCRATCH_SIZE #endif +#define GET_SCRATCH_SIZE(HASHLEN) (HASHLEN) + librecrypt_set_custom_algorithms(ctx, custom, ELEMSOF(custom)); + CHECK(TEST_PHRASE, "$trunc$", 4, 1, TEST_HASH_TRUNC); + CHECK(TEST_PHRASE, "$trunc$", 6, 0, TEST_HASH_TRUNC6); + CHECK(TEST_PHRASE, "$rot4$", 8, -1, TEST_HASH_ROT4); + CHECK(TEST_PHRASE, "$rot4$>$trunc$", 4, 1, TEST_HASH_ROT4_TRUNC); + CHECK(TEST_PHRASE, "$rot4$>$trunc$", 6, 0, TEST_HASH_ROT4_TRUNC6); + CHECK(TEST_PHRASE, "$trunc$>$rot4$", 8, -1, TEST_HASH_TRUNC_ROT4); + CHECK(TEST_PHRASE, "$trunc$*6>$rot4$", 8, -1, TEST_HASH_TRUNC6_ROT4); + CHECK(TEST_PHRASE, "$trunc$>$trunc$", 4, 1, TEST_HASH_TRUNC); + CHECK(TEST_PHRASE, "$trunc$>$trunc$", 6, 0, TEST_HASH_TRUNC_TRUNC6); + CHECK(TEST_PHRASE, "$trunc$*6>$trunc$", 4, 1, TEST_HASH_TRUNC); + CHECK(TEST_PHRASE, "$trunc$*6>$trunc$", 6, 0, TEST_HASH_TRUNC6); + CHECK(TEST_PHRASE, "$rot4$>$rot4$", 8, -1, TEST_PHRASE64_ROT4); +#undef GET_SCRATCH_SIZE + librecrypt_free_context(ctx); STOP_RESOURCE_TEST(); diff --git a/librecrypt_make_settings.c b/librecrypt_make_settings.c index 84270d1..89a73fb 100644 --- a/librecrypt_make_settings.c +++ b/librecrypt_make_settings.c @@ -45,6 +45,201 @@ enosys: #else +#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +NONSTRING static const char encoding_lut[256u] = MAKE_ENCODING_LUT(ALPHABET); + +static const unsigned char decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, XX, + XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, XX, XX, XX, XX, XX, + XX, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static unsigned +rot4_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$rot4$") - 1u) + if (!strncmp(settings, "$rot4$", sizeof("$rot4$") - 1u)) + return 1u; + return 0u; +} + +static unsigned +trunc_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$trunc$") - 1u) + if (!strncmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 1u; + return 0u; +} + +static int +rot4_supported(const char *phrase, size_t len, int text, const char *settings, + size_t prefix, size_t *len_out) +{ + size_t i, j, n; + + (void) phrase; + (void) len; + (void) text; + + i = sizeof("$rot4$") - 1u; + if (prefix < i || memcmp(settings, "$rot4$", prefix)) + return 0; + n = i - prefix; + if (n && n != 12u) + return 0; + if (n == 12u) { + for (j = 0u; j < 11u; j++, i++) + if (decoding_lut[(unsigned char)settings[i]] == XX) + return 0; + if (decoding_lut[(unsigned char)settings[i]] != '#') + return 0; + } + + *len_out = 8u; + return 1; +} + +static int +trunc_supported(const char *phrase, size_t len, int text, const char *settings, + size_t prefix, size_t *len_out) +{ + size_t i, digit, n = 0u, q, r; + + (void) phrase; + (void) len; + (void) text; + + if (prefix < sizeof("$trunc$") - 1u || memcmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 0; + + if (prefix == sizeof("$trunc$") - 1u) { + *len_out = 4u; + return 1; + } + + if (settings[sizeof("$trunc$") - 1u] == '*') { + for (i = sizeof("$trunc$*") - 1u; i < prefix; i++) { + if ('0' > settings[i] || settings[i] > '9') + return 0; + digit = (size_t)(settings[i] - '0'); + if (n > (SIZE_MAX - digit) / 10u) + return 0; + n = n * 10u + digit; + } + } else { + for (i = sizeof("$trunc$") - 1u; i < prefix; i++) { + if (settings[i] == '@') + break; + if (decoding_lut[(unsigned char)settings[i]] == XX) + return 0; + n += 1u; + } + q = n / 4u; + r = n % 4u; + if (r == 1u) + return 0; + n = q * 3u + r; + if (r) { + n -= 1u; + for (; r < 4u && i < prefix; r++, i++) + if (settings[i] != '@') + break; + if (r != 4u || i != prefix) + return 0; + } + } + if (!n) + return 0; + *len_out = n; + return 1; +} + +static ssize_t +rot4_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) +{ + size_t ret = sizeof("$rot4$") - 1u; + + (void) algorithm; + (void) memcost; + (void) timecost; + (void) gensalt; + (void) rng; + (void) user; + + if (size) { + size = MIN(ret, size - 1u); + memcpy(out_buffer, "$rot4$", size); + out_buffer[size] = '\0'; + } + + return (ssize_t) ret; +} + +static ssize_t +trunc_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) +{ + size_t ret = sizeof("$trunc$*4") - 1u; + + (void) algorithm; + (void) memcost; + (void) timecost; + (void) gensalt; + (void) rng; + (void) user; + + if (size) { + size = MIN(ret, size - 1u); + memcpy(out_buffer, "$trunc$*4", size); + out_buffer[size] = '\0'; + } + + return (ssize_t)ret; +} + +static const struct librecrypt_algorithm rot4_algo = { + .is_algorithm = &rot4_is_algorithm, + .test_supported = &rot4_supported, + .make_settings = &rot4_make_settings, + .encoding_lut = encoding_lut, + .decoding_lut = decoding_lut, + .hash_size = 8u, + .flexible_hash_size = 0, + .strict_pad = 1, + .pad = '#' +}; + +static const struct librecrypt_algorithm trunc_algo = { + .is_algorithm = &trunc_is_algorithm, + .test_supported = &trunc_supported, + .make_settings = &trunc_make_settings, + .encoding_lut = encoding_lut, + .decoding_lut = decoding_lut, + .hash_size = 4u, + .flexible_hash_size = 1, + .strict_pad = 1, + .pad = '@' +}; + + static unsigned char saltbyte = 0u; @@ -72,6 +267,8 @@ saltfail(void *out, size_t n, void *user) int main(void) { + const struct librecrypt_algorithm custom[] = {rot4_algo, trunc_algo}; + LIBRECRYPT_CONTEXT *ctx = librecrypt_create_context(); char buf[1024]; char buf2[sizeof(buf)]; int any_supported = 0; @@ -195,6 +392,31 @@ main(void) EXPECT(errno == ENOSYS); } + ctx = librecrypt_create_context(); + assert(ctx != NULL); + + librecrypt_set_custom_algorithms(ctx, custom, ELEMSOF(custom)); + + CANARY_FILL(buf); + r = librecrypt_make_settings(buf, sizeof(buf), "$rot4$", 0u, 0u, 0, NULL, NULL, ctx); + EXPECT(r == (ssize_t)(sizeof("$rot4$") - 1u)); + EXPECT(!strcmp(buf, "$rot4$")); + CANARY_CHECK(buf, (size_t)r + 1u); + + CANARY_FILL(buf); + r = librecrypt_make_settings(buf, sizeof(buf), "$trunc$", 0u, 0u, 0, NULL, NULL, ctx); + EXPECT(r == (ssize_t)(sizeof("$trunc$*4") - 1u)); + EXPECT(!strcmp(buf, "$trunc$*4")); + CANARY_CHECK(buf, (size_t)r + 1u); + + CANARY_FILL(buf); + r = librecrypt_make_settings(buf, sizeof(buf), "$trunc$*6", 0u, 0u, 0, NULL, NULL, ctx); + EXPECT(r == (ssize_t)(sizeof("$trunc$*4") - 1u)); + EXPECT(!strcmp(buf, "$trunc$*4")); + CANARY_CHECK(buf, (size_t)r + 1u); + + librecrypt_free_context(ctx); + STOP_RESOURCE_TEST(); return 0; } diff --git a/librecrypt_test_supported.c b/librecrypt_test_supported.c index f069d44..3e416c0 100644 --- a/librecrypt_test_supported.c +++ b/librecrypt_test_supported.c @@ -44,22 +44,171 @@ librecrypt_test_supported(const char *phrase, size_t len, int text, const char * # ifndef FUZZ +#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +NONSTRING static const char encoding_lut[256u] = MAKE_ENCODING_LUT(ALPHABET); + +static const unsigned char decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, XX, + XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, XX, XX, XX, XX, XX, + XX, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static unsigned +rot4_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$rot4$") - 1u) + if (!strncmp(settings, "$rot4$", sizeof("$rot4$") - 1u)) + return 1u; + return 0u; +} + +static unsigned +trunc_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$trunc$") - 1u) + if (!strncmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 1u; + return 0u; +} + +static int +rot4_supported(const char *phrase, size_t len, int text, const char *settings, + size_t prefix, size_t *len_out) +{ + size_t i, j, n; + + (void) phrase; + (void) len; + (void) text; + + i = sizeof("$rot4$") - 1u; + if (prefix < i || memcmp(settings, "$rot4$", prefix)) + return 0; + n = i - prefix; + if (n && n != 12u) + return 0; + if (n == 12u) { + for (j = 0u; j < 11u; j++, i++) + if (decoding_lut[(unsigned char)settings[i]] == XX) + return 0; + if (decoding_lut[(unsigned char)settings[i]] != '#') + return 0; + } + + *len_out = 8u; + return 1; +} + +static int +trunc_supported(const char *phrase, size_t len, int text, const char *settings, + size_t prefix, size_t *len_out) +{ + size_t i, digit, n = 0u, q, r; + + (void) phrase; + (void) len; + (void) text; + + if (prefix < sizeof("$trunc$") - 1u || memcmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 0; + + if (prefix == sizeof("$trunc$") - 1u) { + *len_out = 4u; + return 1; + } + + if (settings[sizeof("$trunc$") - 1u] == '*') { + for (i = sizeof("$trunc$*") - 1u; i < prefix; i++) { + if ('0' > settings[i] || settings[i] > '9') + return 0; + digit = (size_t)(settings[i] - '0'); + if (n > (SIZE_MAX - digit) / 10u) + return 0; + n = n * 10u + digit; + } + } else { + for (i = sizeof("$trunc$") - 1u; i < prefix; i++) { + if (settings[i] == '@') + break; + if (decoding_lut[(unsigned char)settings[i]] == XX) + return 0; + n += 1u; + } + q = n / 4u; + r = n % 4u; + if (r == 1u) + return 0; + n = q * 3u + r; + if (r) { + n -= 1u; + for (; r < 4u && i < prefix; r++, i++) + if (settings[i] != '@') + break; + if (r != 4u || i != prefix) + return 0; + } + } + if (!n) + return 0; + *len_out = n; + return 1; +} + +static const struct librecrypt_algorithm rot4_algo = { + .is_algorithm = &rot4_is_algorithm, + .test_supported = &rot4_supported, + .encoding_lut = encoding_lut, + .decoding_lut = decoding_lut, + .hash_size = 8u, + .flexible_hash_size = 0, + .strict_pad = 1, + .pad = '#' +}; + +static const struct librecrypt_algorithm trunc_algo = { + .is_algorithm = &trunc_is_algorithm, + .test_supported = &trunc_supported, + .encoding_lut = encoding_lut, + .decoding_lut = decoding_lut, + .hash_size = 4u, + .flexible_hash_size = 1, + .strict_pad = 1, + .pad = '@' +}; + #define NSA "$~no~such~algorithm~$" #define CHECK(ALGO, VALID, INVALID)\ do {\ - EXPECT(librecrypt_test_supported(NULL, 4096u, 0, ALGO VALID, NULL) == 1);\ - EXPECT(librecrypt_test_supported(NULL, 4096u, 0, ALGO VALID">"NSA, NULL) == 0);\ - EXPECT(librecrypt_test_supported(NULL, 4096u, 0, NSA">"ALGO VALID, NULL) == 0);\ - EXPECT(librecrypt_test_supported(NULL, 4096u, 0, ALGO VALID">"ALGO VALID, NULL) == 1);\ - EXPECT(librecrypt_test_supported(NULL, 4096u, 0, ALGO INVALID, NULL) == 0);\ + EXPECT(librecrypt_test_supported(NULL, 4096u, 0, ALGO VALID, ctx) == 1);\ + EXPECT(librecrypt_test_supported(NULL, 4096u, 0, ALGO VALID">"NSA, ctx) == 0);\ + EXPECT(librecrypt_test_supported(NULL, 4096u, 0, NSA">"ALGO VALID, ctx) == 0);\ + EXPECT(librecrypt_test_supported(NULL, 4096u, 0, ALGO VALID">"ALGO VALID, ctx) == 1);\ + EXPECT(librecrypt_test_supported(NULL, 4096u, 0, ALGO INVALID, ctx) == 0);\ } while (0) int main(void) { + const struct librecrypt_algorithm custom[] = {rot4_algo, trunc_algo}; + LIBRECRYPT_CONTEXT *ctx = NULL; + SET_UP_ALARM(); INIT_RESOURCE_TEST(); @@ -83,6 +232,20 @@ main(void) IF__argon2id_v1_0__SUPPORTED(CHECK("$argon2id$", "m=8,t=1,p=1$*16$*40", "m=0,t=0,p=0$*1$*1")); IF__argon2ds_v1_0__SUPPORTED(CHECK("$argon2ds$", "m=8,t=1,p=1$*16$*40", "m=0,t=0,p=0$*1$*1")); + ctx = librecrypt_create_context(); + assert(ctx != NULL); + + librecrypt_set_custom_algorithms(ctx, custom, ELEMSOF(custom)); + CHECK("$rot4$", "", "x"); + CHECK("$trunc$", "", "*0"); + CHECK("$trunc$", "*6", "*0"); + EXPECT(librecrypt_test_supported(NULL, 4096u, 0, "$rot4$>$trunc$", ctx) == 1); + EXPECT(librecrypt_test_supported(NULL, 4096u, 0, "$rot4$>$trunc$*8", ctx) == 1); + EXPECT(librecrypt_test_supported(NULL, 4096u, 0, "$trunc$*6>$rot4$", ctx) == 1); + EXPECT(librecrypt_test_supported(NULL, 4096u, 0, "$trunc$>$rot4$", ctx) == 1); + + librecrypt_free_context(ctx); + STOP_RESOURCE_TEST(); return 0; } diff --git a/librecrypt_verify.c b/librecrypt_verify.c index fa51efd..aa304ca 100644 --- a/librecrypt_verify.c +++ b/librecrypt_verify.c @@ -64,9 +64,199 @@ librecrypt_verify(const char *phrase, size_t len, const char *settings, LIBRECRY #else +#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +#define ALT_ALPHABET "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" + +NONSTRING static const char encoding_lut[256u] = MAKE_ENCODING_LUT(ALPHABET); +NONSTRING static const char alt_encoding_lut[256u] = MAKE_ENCODING_LUT(ALT_ALPHABET); + +static const unsigned char decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, XX, + XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, XX, XX, XX, XX, XX, + XX, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static const unsigned char alt_decoding_lut[256u] = { + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, XX, XX, XX, XX, XX, XX, + XX, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, + XX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX +}; + +static unsigned +rot4_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$rot4$") - 1u) + if (!strncmp(settings, "$rot4$", sizeof("$rot4$") - 1u)) + return 1u; + return 0u; +} + +static unsigned +trunc_is_algorithm(const char *settings, size_t len) +{ + if (len >= sizeof("$trunc$") - 1u) + if (!strncmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 1u; + return 0u; +} + +static int +trunc_supported(const char *phrase, size_t len, int text, const char *settings, + size_t prefix, size_t *len_out) +{ + size_t i, digit, n = 0u, q, r; + + (void) phrase; + (void) len; + (void) text; + + if (prefix < sizeof("$trunc$") - 1u || memcmp(settings, "$trunc$", sizeof("$trunc$") - 1u)) + return 0; + + if (prefix == sizeof("$trunc$") - 1u) { + *len_out = 4u; + return 1; + } + + if (settings[sizeof("$trunc$") - 1u] == '*') { + for (i = sizeof("$trunc$*") - 1u; i < prefix; i++) { + if ('0' > settings[i] || settings[i] > '9') + return 0; + digit = (size_t)(settings[i] - '0'); + if (n > (SIZE_MAX - digit) / 10u) + return 0; + n = n * 10u + digit; + } + } else { + for (i = sizeof("$trunc$") - 1u; i < prefix; i++) { + if (settings[i] == '@') + break; + if (alt_decoding_lut[(unsigned char)settings[i]] == XX) + return 0; + n += 1u; + } + q = n / 4u; + r = n % 4u; + if (r == 1u) + return 0; + n = q * 3u + r; + if (r) { + n -= 1u; + for (; r < 4u && i < prefix; r++, i++) + if (settings[i] != '@') + break; + if (r != 4u || i != prefix) + return 0; + } + } + if (!n) + return 0; + *len_out = n; + return 1; +} + +static int +rot4_hash(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, size_t prefix, LIBRECRYPT_CONTEXT *ctx) +{ + size_t i; + + (void) settings; + (void) prefix; + (void) ctx; + + for (i = 0u; i < 8u && i < size; i++) { + out_buffer[i] = '\0'; + if (i < len) + out_buffer[i] = (char)((((int)phrase[i] & 0x0F) << 4) | (((int)phrase[i] >> 4) & 0x0F)); + } + return 0; +} + +static int +trunc_hash(char *restrict out_buffer, size_t size, const char *phrase, size_t len, + const char *settings, size_t prefix, LIBRECRYPT_CONTEXT *ctx) +{ + size_t hash_size, i; + + (void) ctx; + + if (!trunc_supported(NULL, 0u, 1, settings, prefix, &hash_size)) { + errno = EINVAL; + return -1; + } + + size = MIN(hash_size, size); + for (i = 0u; i < size; i++) + out_buffer[i] = i < len ? phrase[i] : '\0'; + + return 0; +} + +static const struct librecrypt_algorithm rot4_algo = { + .is_algorithm = &rot4_is_algorithm, + .hash = &rot4_hash, + .encoding_lut = encoding_lut, + .decoding_lut = decoding_lut, + .hash_size = 8u, + .flexible_hash_size = 0, + .strict_pad = 1, + .pad = '#' +}; + +static const struct librecrypt_algorithm trunc_algo = { + .is_algorithm = &trunc_is_algorithm, + .hash = &trunc_hash, + .encoding_lut = alt_encoding_lut, + .decoding_lut = alt_decoding_lut, + .hash_size = 4u, + .flexible_hash_size = 1, + .strict_pad = 1, + .pad = '@' +}; + +#define TEST_PHRASE "\x12\x23\x34\x45\x56\x67\x78\x89" +#define TEST_PHRASE64_ROT4 "EiM0RVZneIk#" +#define TEST_HASH_ROT4 "ITJDVGV2h5g#" +#define TEST_HASH_TRUNC "4ycQhg@@" +#define TEST_HASH_TRUNC6 "4ycQhlpD" +#define TEST_HASH_TRUNC_ROT4 "ITJDVAAAAAA#" +#define TEST_HASH_TRUNC6_ROT4 "ITJDVGV2AAA#" +#define TEST_HASH_ROT4_TRUNC "8j93l0@@" +#define TEST_HASH_ROT4_TRUNC6 "8j93l6lS" +#define TEST_HASH_TRUNC_TRUNC6 "4ycQhg00" + + int main(void) { + const struct librecrypt_algorithm custom[] = {rot4_algo, trunc_algo}; LIBRECRYPT_CONTEXT *ctx = NULL; char conf[256], nuls[256], spaces[256]; int r; @@ -153,6 +343,22 @@ main(void) EXPECT(librecrypt_verify(spaces, 80u, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$mzPlVOVjVos", ctx) == 1); #endif +#define CHECK(CRYPT) EXPECT(librecrypt_verify(TEST_PHRASE, sizeof(TEST_PHRASE) - 1u, CRYPT, ctx) == 1); + librecrypt_set_custom_algorithms(ctx, custom, ELEMSOF(custom)); + CHECK("$trunc$"TEST_HASH_TRUNC); + CHECK("$trunc$"TEST_HASH_TRUNC6); + CHECK("$rot4$"TEST_HASH_ROT4); + CHECK("$rot4$>$trunc$"TEST_HASH_ROT4_TRUNC); + CHECK("$rot4$>$trunc$"TEST_HASH_ROT4_TRUNC6); + CHECK("$trunc$>$rot4$"TEST_HASH_TRUNC_ROT4); + CHECK("$trunc$*6>$rot4$"TEST_HASH_TRUNC6_ROT4); + CHECK("$trunc$>$trunc$"TEST_HASH_TRUNC); + CHECK("$trunc$>$trunc$"TEST_HASH_TRUNC_TRUNC6); + CHECK("$trunc$*6>$trunc$"TEST_HASH_TRUNC); + CHECK("$trunc$*6>$trunc$"TEST_HASH_TRUNC6); + CHECK("$rot4$>$rot4$"TEST_PHRASE64_ROT4); +#undef CHECK + librecrypt_free_context(ctx); STOP_RESOURCE_TEST(); -- cgit v1.3.1