From 4e6f25806e3c9fa4753ce959ef990167796acd32 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Thu, 14 May 2026 15:55:33 +0200 Subject: Tests and fixes 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 | 161 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 137 insertions(+), 24 deletions(-) (limited to 'librecrypt_add_algorithm.c') diff --git a/librecrypt_add_algorithm.c b/librecrypt_add_algorithm.c index 10a2174..4fa5b94 100644 --- a/librecrypt_add_algorithm.c +++ b/librecrypt_add_algorithm.c @@ -9,7 +9,7 @@ ssize_t -librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char *restrict augment, void *reserved) +librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend, const char *restrict augment, void *reserved) { size_t prefix1, prefix2, min, ret, len, phraselen; size_t hashsize1, hashsize2; @@ -18,15 +18,6 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char const unsigned char *lut; ssize_t r; -#define COPY_PREFIX()\ - do {\ - min = prefix1 < size ? prefix1 : size;\ - if (out_buffer != augend)\ - memmove(out_buffer, augend, min);\ - out_buffer = &out_buffer[min];\ - size -= min;\ - } while (0) - /* Reserve space for NUL-termination */ if (size) { nul_term = 1; @@ -39,7 +30,7 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char prefix1 = librecrypt_settings_prefix(augend, &hashsize1); prefix2 = librecrypt_settings_prefix(augment, &hashsize2); - /* If `augend` specifies as hash size rather than a hash, include it as the prefix */ + /* If `augend` specifies a hash size rather than a hash, include it as the prefix */ if (augend[prefix1] == '*') { prefix1 += strlen(&augend[prefix1]); hashsize1 = 0u; @@ -54,7 +45,11 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char } ret = prefix1 + 1u + prefix2; if (size) { - COPY_PREFIX(); + min = prefix1 < size ? prefix1 : size; + if (out_buffer != augend) + memmove(out_buffer, augend, min); + out_buffer = &out_buffer[min]; + size -= min; if (size) { *out_buffer++ = LIBRECRYPT_ALGORITHM_LINK_DELIMITER; size -= 1u; @@ -64,25 +59,30 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char if (hashsize2) { r_int = snprintf(&out_buffer[min], size + 1u, "*%zu", hashsize2); if (r_int < 2) - abort(); + abort(); /* $covered$ (impossible reliably) */ ret += (size_t)r_int; } else { out_buffer[min] = '\0'; } } else { - r_int = snprintf(NULL, 0, "*%zu", hashsize2); + if (!hashsize2) + goto out; + r_int = snprintf(NULL, 0u, "*%zu", hashsize2); if (r_int < 2) - abort(); + abort(); /* $covered$ (impossible reliably) */ ret += (size_t)r_int; + out: + if (nul_term) + out_buffer[0u] = '\0'; } return (ssize_t)ret; } /* Measure size of hash size specification for `augend` */ if (hashsize1) { - r_int = snprintf(NULL, 0, "*%zu", hashsize1); + r_int = snprintf(NULL, 0u, "*%zu", hashsize1); if (r_int < 2) - abort(); + abort(); /* $covered$ (impossible reliably) */ } else { r_int = 0; } @@ -91,7 +91,7 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char ret = prefix1 + (size_t)r_int + 1u; /* Decode the hash from base-64 to binary */ - if (size <= ret + prefix2 + 1u) { + if (size <= ret + prefix2) { /* If the new hash doesn't fit, don't bother; * hash sizes are independent of password size */ phrase = NULL; @@ -106,7 +106,7 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char return -1; /* Measure old binary hash */ - r = librecrypt_decode(NULL, 0, &augend[prefix1], len, lut, pad, strict_pad); + r = librecrypt_decode(NULL, 0u, &augend[prefix1], len, lut, pad, strict_pad); if (r <= 0) { if (!r) abort(); @@ -123,10 +123,18 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char } /* Chain the hash algorithms: write `augent` */ - COPY_PREFIX(); - if (hashsize1 && size) + min = prefix1 < size ? prefix1 : size; + if (out_buffer != augend) + memmove(out_buffer, augend, min); + out_buffer = &out_buffer[min]; + size -= min; + if (hashsize1 && size) { if (snprintf(out_buffer, size + 1u, "*%zu", hashsize1) != r_int) - abort(); + abort(); /* $covered$ (impossible reliably) */ + min = (size_t)r_int < size ? (size_t)r_int : size; + out_buffer = &out_buffer[min]; + size -= min; + } /* Chain the hash algorithms: write '>' */ if (size) { @@ -135,7 +143,7 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char } /* Chain the hash algorithms: write `augment` and hash */ - r = librecrypt_crypt(out_buffer, size + (nul_term ? 1u : 0u), phrase, phraselen, augment, reserved); + r = librecrypt_crypt(out_buffer, nul_term ? size + 1u : 0u, phrase, phraselen, augment, reserved); if (r <= 0) { librecrypt_wipe(phrase, phraselen); free(phrase); @@ -157,13 +165,118 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char int main(void) { +#define SALT1 "ABCDabcdABCDabcdABCDabcdABCDabcdABCDabcdABCDabcdABCDabcdABCDabcd" +#define SALT2 "0123abcd0123ABCD0123abcd0123ABCD0123abcd0123ABCD0123abcd0123ABCD" +#define HASH1 "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTYVWXYZ/+" +#define ASTRA "*48" + + char buf[1024], phrase[sizeof(buf)], expected[sizeof(buf)], pad; + size_t i, min, phraselen; + int strict_pad; + const void *lut; + ssize_t r; + SET_UP_ALARM(); INIT_RESOURCE_TEST(); +#define CHECK(AUGEND, AUGMENT, RESULT)\ + do {\ + r = librecrypt_add_algorithm(buf, sizeof(buf), (AUGEND), (AUGMENT), NULL);\ + EXPECT(r > 0);\ + EXPECT((size_t)r == strlen(RESULT));\ + assert((size_t)r < sizeof(buf) + 1u);\ + EXPECT(!buf[r]);\ + EXPECT(!memcmp(buf, (RESULT), (size_t)r));\ + \ + for (i = (size_t)r + 2u;; i--) {\ + memset(buf, 99, sizeof(buf));\ + EXPECT(librecrypt_add_algorithm(buf, i, (AUGEND), (AUGMENT), NULL) == r);\ + if (!i)\ + break;\ + min = i - 1u < (size_t)r ? i - 1u : (size_t)r;\ + EXPECT(!buf[min]);\ + EXPECT(!memcmp(buf, (RESULT), min));\ + }\ + \ + EXPECT(librecrypt_add_algorithm(NULL, 0u, (AUGEND), (AUGMENT), NULL) == r);\ + \ + assert(sizeof(buf) > strlen(AUGEND));\ + stpcpy(buf, (AUGEND));\ + \ + EXPECT(librecrypt_add_algorithm(buf, sizeof(buf), buf, (AUGMENT), NULL) == r);\ + EXPECT(!buf[r]);\ + EXPECT(!memcmp(buf, (RESULT), (size_t)r));\ + \ + for (i = (size_t)r + 2u;; i--) {\ + stpcpy(buf, (AUGEND));\ + EXPECT(librecrypt_add_algorithm(buf, i, buf, (AUGMENT), NULL) == r);\ + if (!i)\ + break;\ + min = i - 1u < (size_t)r ? i - 1u : (size_t)r;\ + EXPECT(!buf[min]);\ + EXPECT(!memcmp(buf, (RESULT), min));\ + }\ + } while (0) + +#if defined(SUPPORT_ARGON2I) && defined(SUPPORT_ARGON2D) + + CHECK("$argon2d$v=16$m=8,t=1,p=1$*16$*40", "$argon2i$v=19$m=16,t=4,p=2$*18$*50", + "$argon2d$v=16$m=8,t=1,p=1$*16$*40>" "$argon2i$v=19$m=16,t=4,p=2$*18$*50"); + + CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$*40", "$argon2i$m=8,t=4,p=2$"SALT2"$*50", + "$argon2d$m=8,t=1,p=1$"SALT1"$*40>" "$argon2i$m=8,t=4,p=2$"SALT2"$*50"); + + CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$", "$argon2i$m=8,t=4,p=2$"SALT2"$", + "$argon2d$m=8,t=1,p=1$"SALT1"$>" "$argon2i$m=8,t=4,p=2$"SALT2"$"); + + CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$*40", "$argon2i$m=8,t=4,p=2$"SALT2"$", + "$argon2d$m=8,t=1,p=1$"SALT1"$*40>" "$argon2i$m=8,t=4,p=2$"SALT2"$"); + + CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$", "$argon2i$m=8,t=4,p=2$"SALT2"$*50", + "$argon2d$m=8,t=1,p=1$"SALT1"$>" "$argon2i$m=8,t=4,p=2$"SALT2"$*50"); + + CHECK("$argon2d$m=8,t=1,p=1$*16$", "$argon2i$m=8,t=4,p=2$"SALT2"$", + "$argon2d$m=8,t=1,p=1$*16$>" "$argon2i$m=8,t=4,p=2$"SALT2"$"); + + CHECK("$argon2d$m=8,t=1,p=1$*16$*50", "$argon2i$m=8,t=4,p=2$"SALT2"$", + "$argon2d$m=8,t=1,p=1$*16$*50>" "$argon2i$m=8,t=4,p=2$"SALT2"$"); + + CHECK("$argon2d$m=8,t=1,p=1$*16$", "$argon2i$m=8,t=4,p=2$"SALT2"$*60", + "$argon2d$m=8,t=1,p=1$*16$>" "$argon2i$m=8,t=4,p=2$"SALT2"$*60"); + + CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$", "$argon2i$m=8,t=4,p=2$*20$", + "$argon2d$m=8,t=1,p=1$"SALT1"$>" "$argon2i$m=8,t=4,p=2$*20$"); + + CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$*32", "$argon2i$m=8,t=4,p=2$*20$", + "$argon2d$m=8,t=1,p=1$"SALT1"$*32>" "$argon2i$m=8,t=4,p=2$*20$"); + + CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$", "$argon2i$m=8,t=4,p=2$*20$*32", + "$argon2d$m=8,t=1,p=1$"SALT1"$>" "$argon2i$m=8,t=4,p=2$*20$*32"); + + lut = librecrypt_get_encoding("$argon2d$", sizeof("$argon2d$") - 1u, &pad, &strict_pad, 1); + assert(lut); + r = librecrypt_decode(phrase, sizeof(phrase), HASH1, strlen(HASH1), lut, pad, strict_pad); + assert(r > 0 && (size_t)r <= sizeof(phrase)); + phraselen = (size_t)r; + stpcpy(expected, "$argon2d$m=8,t=1,p=1$"SALT1"$"ASTRA">$argon2i$m=8,t=4,p=1$"SALT2"$"); + r = librecrypt_hash(&expected[strlen(expected)], sizeof(expected) - strlen(expected), + phrase, phraselen, "$argon2i$m=8,t=4,p=1$"SALT2"$*32", NULL); + assert(r > 0 && (size_t)r < sizeof(expected) - strlen(expected)); + assert(!expected[strlen(expected) + (size_t)r]); + CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$"HASH1, "$argon2i$m=8,t=4,p=1$"SALT2"$*32", expected); + CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$"HASH1, + "$argon2i$m=8,t=4,p=1$"SALT2"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", expected); + +#endif + STOP_RESOURCE_TEST(); return 0; } #endif -/* TODO test */ +/* TODO test with hash but asterisk-salt on augend */ +/* TODO test with asterisk-salt on augment */ +/* TODO test with empty salt */ +/* TODO test with salts that are not multiple of 4 base64 characters */ +/* TODO test with hashes that are not multiple of 4 base64 characters */ -- cgit v1.2.3-70-g09d2