diff options
| author | Mattias Andrée <m@maandree.se> | 2026-05-13 21:37:08 +0200 |
|---|---|---|
| committer | Mattias Andrée <m@maandree.se> | 2026-05-13 21:37:08 +0200 |
| commit | 5598f1d5da1940ca2f8597b464f331d4cea2cdc0 (patch) | |
| tree | 938814d2e119005b1a580add853708f9ecfb4b3f | |
| parent | Work on test code (diff) | |
| download | librecrypt-5598f1d5da1940ca2f8597b464f331d4cea2cdc0.tar.gz librecrypt-5598f1d5da1940ca2f8597b464f331d4cea2cdc0.tar.bz2 librecrypt-5598f1d5da1940ca2f8597b464f331d4cea2cdc0.tar.xz | |
Tests and fixes
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | argon2/hash.c | 82 | ||||
| -rw-r--r-- | common.h | 7 | ||||
| -rw-r--r-- | librecrypt_hash_.c | 197 | ||||
| -rw-r--r-- | librecrypt_realise_salts.c | 2 | ||||
| -rw-r--r-- | librecrypt_rng_.c | 28 | ||||
| -rw-r--r-- | librecrypt_settings_prefix.c | 56 | ||||
| -rw-r--r-- | libtest/alloc.c | 85 | ||||
| -rw-r--r-- | libtest/random.c | 5 |
9 files changed, 381 insertions, 83 deletions
@@ -91,7 +91,7 @@ $(TEST): $(HDR) librecrypt.a libtest/libtest.a libtest/libtest.h $(CC) -fPIC -c -o $@ $< $(ALL_CFLAGS) $(COV_CFLAGS) $(ALL_CPPFLAGS) $(COV_CPPFLAGS) .c.to: - $(CC) -DTEST -c -o $@ $< $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(COV_CPPFLAGS) + $(CC) -DTEST -c -o $@ $< $(G) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(COV_CPPFLAGS) .to.t: $(CC) -o $@ $< librecrypt.a libtest/libtest.a $(G) $(ALL_LDFLAGS) $(TEST_LDFLAGS) $(COV_LDFLAGS) diff --git a/argon2/hash.c b/argon2/hash.c index dbb7c53..6ca665f 100644 --- a/argon2/hash.c +++ b/argon2/hash.c @@ -27,17 +27,6 @@ librecrypt__argon2__hash(char *restrict out_buffer, size_t size, const char *phr /* Not yet used */ (void) reserved; - /* Gives us memory allocation and threading support; - * so we don't have to implement any of that ourselves */ - libar2simplified_init_context(&ctx); - /* Configure automatic erasure of input memory */ - ctx.autoerase_message = 0; /* allows `phrase` to be read-only */ - ctx.autoerase_secret = 0; /* alloes to params.key, which we are not using, but maybe in the future */ - ctx.autoerase_associated_data = 0; /* alloes to params.ad, which we are not using, but maybe in the future */ - ctx.autoerase_salt = 1; /* since we are decoding the salt, we do a memory allocation, - * and our testing always checks that allocated memory is earse; - * it doesn't really matter, but it's paranoid, and that's good */ - /* Parse `settings` */ r = librecrypt_check_settings_(settings, prefix, "$argon2%^s$%^sm=%^p,t=%^p,p=%^p$%&b$%^h", @@ -53,6 +42,35 @@ librecrypt__argon2__hash(char *restrict out_buffer, size_t size, const char *phr return -1; } + /* If not output, will just validate the input and return 0 */ + if (!size) { + /* Argon2 has a maximum passphrase length of 2³²-1 */ +#if SIZE_MAX > UINT32_MAX + if (len > (size_t)UINT32_MAX) { + errno = EINVAL; + return -1; + } +#endif + /* This is important because the caller may have skipped calculating + * an intermediate hash, and instead pass `NULL` (= assume non-text) + * to us as `phrase`, but leave `len` non-zero is it can be validated, + * because we are not provided any output buffer so the input passphrase + * does not affect us. So we must return so that libar2_hash(3) does + * not attempt to read the passphrase from `NULL`. */ + return 0; + } + + /* Gives us memory allocation and threading support; + * so we don't have to implement any of that ourselves */ + libar2simplified_init_context(&ctx); + /* Configure automatic erasure of input memory */ + ctx.autoerase_message = 0; /* allows `phrase` to be read-only */ + ctx.autoerase_secret = 0; /* alloes to params.key, which we are not using, but maybe in the future */ + ctx.autoerase_associated_data = 0; /* alloes to params.ad, which we are not using, but maybe in the future */ + ctx.autoerase_salt = 1; /* since we are decoding the salt, we do a memory allocation, + * and our testing always checks that allocated memory is earse; + * it doesn't really matter, but it's paranoid, and that's good */ + /* Decode salt */ if (!salt_encoded) /* this would be if asterisk-notation is used, but it is not */ abort(); /* $covered$ */ @@ -140,13 +158,14 @@ static int discarded_int; static void check(const char *phrase, const char *settings, const char *hash, size_t hashlen) { - size_t len = strlen(phrase); + size_t i, len = strlen(phrase); size_t prefix = strlen(settings); char buf[1024], expected[256]; ssize_t r; assert(hashlen <= sizeof(buf)); assert(hashlen <= sizeof(expected)); + assert(2u * hashlen <= sizeof(buf)); r = librecrypt_decode(expected, sizeof(expected), hash, strlen(hash), librecrypt_common_rfc4848s4_decoding_lut_, @@ -161,12 +180,15 @@ check(const char *phrase, const char *settings, const char *hash, size_t hashlen EXPECT(librecrypt__argon2__hash(buf, hashlen, phrase, len, settings, prefix, NULL) == 0); EXPECT(!memcmp(expected, buf, hashlen)); - memset(buf, 0, sizeof(buf)); - EXPECT(librecrypt__argon2__hash(buf, 1u, phrase, len, settings, prefix, NULL) == 0); - EXPECT(!memcmp(expected, buf, 1u)); - EXPECT(librecrypt__argon2__hash(buf, 0u, phrase, len, settings, prefix, NULL) == 0); EXPECT(librecrypt__argon2__hash(NULL, 0u, phrase, len, settings, prefix, NULL) == 0); + + for (i = 1u; i <= hashlen * 2u; i++) { + memset(buf, 0, sizeof(buf)); + EXPECT(librecrypt__argon2__hash(buf, i, phrase, len, settings, prefix, NULL) == 0); + EXPECT(!memcmp(expected, buf, i < hashlen ? i : hashlen)); + } + } @@ -182,14 +204,30 @@ check(const char *phrase, const char *settings, const char *hash, size_t hashlen } while (0) +#if SIZE_MAX > UINT32_MAX +# define CHECK_MEGAPASSPHRASE(ALGO)\ + libtest_set_alloc_failure_in(3u);\ + errno = 0;\ + EXPECT(librecrypt__argon2__hash(NULL, 0u, NULL, (size_t)UINT32_MAX + 1u,\ + S(ALGO"m=1024,t=10,p=1$ABCDabcdABCDabcd$"), NULL) == -1);\ + EXPECT(errno == EINVAL) +#else +# define CHECK_MEGAPASSPHRASE(ALGO)\ + ((void)0) +#endif + + +#define COMMON buf, 1u, NULL, 0u #define CHECK_BAD(ALGO)\ do {\ errno = 0;\ - EXPECT(librecrypt__argon2__hash(NULL, 0u, NULL, 0u, S(ALGO"m=0,t=999999999999999999,p=0$AAAABBBB$*0"), NULL) == -1);\ + EXPECT(librecrypt__argon2__hash(COMMON, S(ALGO"m=0,t=999999999999999999,p=0$AAAABBBB$*0"), NULL) == -1);\ EXPECT(errno == EINVAL);\ \ + CHECK_MEGAPASSPHRASE(ALGO);\ + \ /* target `if (!salt_encoded)` */\ - EXPECT_ABORT(discarded_int = librecrypt__argon2__hash(NULL, 0u, NULL, 0u, S(ALGO"m=1024,t=10,p=1$*10$"), NULL));\ + EXPECT_ABORT(discarded_int = librecrypt__argon2__hash(COMMON, S(ALGO"m=1024,t=10,p=1$*10$"), NULL));\ \ if (!libtest_have_custom_malloc())\ break;\ @@ -197,19 +235,19 @@ check(const char *phrase, const char *settings, const char *hash, size_t hashlen /* target `salt = malloc((size_t)r);` */\ libtest_set_alloc_failure_in(1u);\ errno = 0;\ - EXPECT(librecrypt__argon2__hash(NULL, 0u, NULL, 0u, S(ALGO"m=1024,t=10,p=1$AAAABBBBCCCCDDDD$"), NULL) == -1);\ + EXPECT(librecrypt__argon2__hash(COMMON, S(ALGO"m=1024,t=10,p=1$AAAABBBBCCCCDDDD$"), NULL) == -1);\ EXPECT(errno == ENOMEM);\ \ /* target `scratch = malloc(scratch_size);` */\ libtest_set_alloc_failure_in(2u);\ errno = 0;\ - EXPECT(librecrypt__argon2__hash(NULL, 0u, NULL, 0u, S(ALGO"m=1024,t=10,p=1$AAAABBBBCCCCDDDD$"), NULL) == -1);\ + EXPECT(librecrypt__argon2__hash(COMMON, S(ALGO"m=1024,t=10,p=1$BBBBCCCCDDDDAAAA$"), NULL) == -1);\ EXPECT(errno == ENOMEM);\ \ /* target `libar2_hash` */\ libtest_set_alloc_failure_in(3u);\ errno = 0;\ - EXPECT(librecrypt__argon2__hash(NULL, 0u, NULL, 0u, S(ALGO"m=1024,t=10,p=1$AAAABBBBCCCCDDDD$"), NULL) == -1);\ + EXPECT(librecrypt__argon2__hash(COMMON, S(ALGO"m=1024,t=10,p=1$CCCCDDDDAAAABBBB$"), NULL) == -1);\ EXPECT(errno == ENOMEM);\ \ assert(!libtest_get_alloc_failure_in());\ @@ -219,6 +257,8 @@ check(const char *phrase, const char *settings, const char *hash, size_t hashlen int main(void) { + char buf[1024]; + SET_UP_ALARM(); INIT_TEST_ABORT(); INIT_RESOURCE_TEST(); @@ -525,9 +525,11 @@ int librecrypt_check_settings_(const char *settings, size_t len, const char *fmt # define EXPECT(EXPR)\ do {\ if (!(EXPR)) {\ + int test_expect_saved_errno__ = errno;\ libtest_expect_zeroed_on_free(0);\ libtest_stop_tracking();\ - fprintf(stderr, "Failure at %s:%i: %s\n", __FILE__, __LINE__, #EXPR);\ + fprintf(stderr, "Failure at %s:%i: %s (errno = %i)\n",\ + __FILE__, __LINE__, #EXPR, test_expect_saved_errno__);\ libtest_dump_stack(NULL, "\t");\ exit(1);\ }\ @@ -538,7 +540,8 @@ int librecrypt_check_settings_(const char *settings, size_t len, const char *fmt if (!(EXPR)) {\ libtest_expect_zeroed_on_free(0);\ libtest_stop_tracking();\ - fprintf(stderr, "Assertion failure at %s:%i: %s\n", __FILE__, __LINE__, #EXPR);\ + fprintf(stderr, "Assertion failure at %s:%i: %s\n",\ + __FILE__, __LINE__, #EXPR);\ libtest_dump_stack(NULL, "\t");\ exit(2);\ }\ diff --git a/librecrypt_hash_.c b/librecrypt_hash_.c index dc32df1..d9da5e4 100644 --- a/librecrypt_hash_.c +++ b/librecrypt_hash_.c @@ -8,7 +8,7 @@ zero_generator(void *out, size_t n, void *user) { (void) user; if (n > (size_t)SSIZE_MAX) - n = (size_t)SSIZE_MAX; + n = (size_t)SSIZE_MAX; /* $covered$ (impossible, but covered otherwise) */ memset(out, 0, n); return (ssize_t)n; } @@ -17,14 +17,28 @@ zero_generator(void *out, size_t n, void *user) static int has_asterisk_encoded_salt(const char *settings) { - const char *asterisk; - /* Check whether there is an asterisk */ - asterisk = strchr(settings, '*'); - if (!asterisk) - return 0; - /* Check that the first asterisk is not part of the hash result - * (would specify hash size) rather than be a salt */ - return !!strchr(&asterisk[1u], LIBRECRYPT_HASH_COMPOSITION_DELIMITER); + int asterisk = 0; + for (; *settings; settings++) { + if (*settings == '*') { + /* Require digit after '*' to recognise as asterisk-encoding */ + if ('0' <= settings[1u] && settings[1u] <= '9') { + settings++; + asterisk = 1; + } + } else if (*settings == LIBRECRYPT_HASH_COMPOSITION_DELIMITER) { + /* If asterisk was found before a '$' in an algorithm + * it it was for the salt (or other random parameter) */ + if (asterisk) + return 1; + } else if (*settings == LIBRECRYPT_ALGORITHM_LINK_DELIMITER) { + /* If asterisk was found between '$' and '>', it was + * the hash size specificiation */ + asterisk = 0; + } + } + /* If asterisk was found after the last '$' or '>', or if + * there was no '$', it was the hash size specificiation */ + return 0; } @@ -78,7 +92,7 @@ librecrypt_hash_(char *restrict out_buffer, size_t size, const char *phrase, siz if (!settings_scratch) return -1; if (librecrypt_realise_salts(settings_scratch, (size_t)r_len + 1u, settings, rng, NULL) != r_len) - abort(); + abort(); /* $covered$ (impossible) */ settings = settings_scratch; } } @@ -107,15 +121,15 @@ next: prefix = i + 1u; if (n && !prefix && settings[i] == '_') { /* Special case for bsdicrypt */ - prefix = 1u; + prefix = 1u; /* $covered$ (TODO we currently don't have an algorithm to trigger this) */ } if (!algo->flexible_hash_size && prefix != n) - goto einval; + goto einval; /* $covered$ (TODO we currently don't have an algorithm to trigger this) */ /* Get hash size */ if (!algo->flexible_hash_size) { /* fixed */ - hash_size = algo->hash_size; + hash_size = algo->hash_size; /* $covered$ (TODO we currently don't have an algorithm to trigger this) */ } else if (prefix == n) { /* default */ hash_size = algo->hash_size; @@ -144,6 +158,7 @@ next: break; hash_size = i - prefix; if (algo->pad && algo->strict_pad) { + /* $covered{$ (TODO we currently don't have an algorithm to trigger this) */ for (; i < n; i++) if (settings[i] != algo->pad) break; @@ -151,6 +166,7 @@ next: goto einval; if (i - prefix - hash_size >= 4u) goto einval; + /* $covered}$ */ } if (i != n) goto einval; @@ -224,7 +240,7 @@ next: ascii_len = hash_size % 3u; if (ascii_len) { if (algo->pad && algo->strict_pad) - ascii_len = 4u; /* padding to for bytes */ + ascii_len = 4u; /* padding to for bytes */ /* $covered$ (TODO we currently don't have an algorithm to trigger this) */ else ascii_len += 1u; /* 3n+m bytes: 4n+m+1 chars, unless m=0 */ } @@ -260,7 +276,7 @@ next: /* For `librecrypt_crypt`: add '>' to the password hash string */ if (action == ASCII_CRYPT) { ret += 1u; - if (size) { + if (size > 1u) { *out_buffer++ = LIBRECRYPT_ALGORITHM_LINK_DELIMITER; size -= 1u; } @@ -320,6 +336,20 @@ fail: int main(void) { +#define SALT "saltSALTsaltSALTsaltSALTsaltSALTsaltSALT" +#define LARGE "99999999999999999999999999999999999999999999999999999999999999999999999999" +#define X2(X) X">"X +#define X3(X) X">"X">"X +#define X4(X) X">"X">"X">"X + + char buf[1024]; + char buf1[sizeof(buf)]; + char buf2[sizeof(buf)]; + char buf3[sizeof(buf)]; + char sbuf[160]; + size_t i, n; + ssize_t r, r1, r1b, r1c, r2, r3; + SET_UP_ALARM(); INIT_RESOURCE_TEST(); @@ -331,6 +361,143 @@ main(void) EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, "$~no~such~algorithm~$", NULL, ASCII_CRYPT) == -1); EXPECT(errno == ENOSYS); + errno = 0; + EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, "$~no~such~algorithm~$*100$", NULL, ASCII_CRYPT) == -1); + EXPECT(errno == ENOSYS); + +#if defined(SUPPORT_ARGON2ID) +# define ARGON2ID_PREFIX "$argon2id$v=19$m=8,t=1,p=1$" +# define ARGON2ID_STR ARGON2ID_PREFIX SALT"$*32" + + errno = 0; + EXPECT(librecrypt_hash_(buf, sizeof(buf), "hello", 5u, "!"ARGON2ID_STR, NULL, ASCII_CRYPT) == -1); + EXPECT(errno == ENOSYS); + + errno = 0; + EXPECT(librecrypt_hash_(buf, sizeof(buf), "hello", 5u, ARGON2ID_PREFIX"*"LARGE"$", NULL, ASCII_CRYPT) == -1); + EXPECT(errno == ENOMEM); + + r = librecrypt_hash_(NULL, 0u, "hello", 5u, ARGON2ID_PREFIX"*1000$", NULL, ASCII_CRYPT); + EXPECT(r > 0); + EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, ARGON2ID_PREFIX"*1000$", NULL, ASCII_CRYPT) == r); + for (i = 0u; i <= sizeof(sbuf); i++) + EXPECT(librecrypt_hash_(sbuf, i, NULL, 0u, ARGON2ID_PREFIX"*1000$", NULL, ASCII_CRYPT) == r); + + if (libtest_have_custom_malloc()) { + /* target if-statement in zero_generator, using alloc failure as guarding; + * however librecrypt_realise_salts should return ERANGE, which + * librecrypt_hash_ coverts to ENOMEM */ + libtest_set_alloc_failure_in(1u); + r = (ssize_t)snprintf(buf, sizeof(buf), "%s*%zu$", ARGON2ID_PREFIX, (size_t)SSIZE_MAX + 1u); + assert(r > 0 && r < sizeof(buf)); + errno = 0; + EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, buf, NULL, ASCII_CRYPT) == -1); + EXPECT(errno == ENOMEM); + libtest_set_alloc_failure_in(0u); + + /* target settings_scratch */ + errno = 0; + libtest_set_alloc_failure_in(1u); + EXPECT(librecrypt_hash_(NULL, 0, "hello", 5u, ARGON2ID_PREFIX"*1000$", NULL, ASCII_CRYPT) == -1); + EXPECT(errno == ENOMEM); + EXPECT(libtest_get_alloc_failure_in() == 0u); + + /* target phrase_scratches */ + errno = 0; + libtest_set_alloc_failure_in(1u); + EXPECT(librecrypt_hash_(buf, sizeof(buf), "hello", 5u, X2(ARGON2ID_STR), NULL, ASCII_CRYPT) == -1); + EXPECT(errno == ENOMEM); + EXPECT(libtest_get_alloc_failure_in() == 0u); + + /* target *algo->hash */ + errno = 0; + libtest_set_alloc_failure_in(2u); + EXPECT(librecrypt_hash_(buf, sizeof(buf), "hello", 5u, X2(ARGON2ID_STR), NULL, ASCII_CRYPT) == -1); + EXPECT(errno == ENOMEM); + EXPECT(libtest_get_alloc_failure_in() == 0u); + + /* target deallocation of settings_scratch */ + errno = 0; + libtest_set_alloc_failure_in(2u); + EXPECT(librecrypt_hash_(buf, 1u, "hello", 5u, ARGON2ID_PREFIX"*1000$>"ARGON2ID_STR, NULL, ASCII_CRYPT) == -1); + EXPECT(errno == ENOMEM); + EXPECT(libtest_get_alloc_failure_in() == 0u); + + /* target deallocation of phrase_scratches[1] */ + libtest_set_alloc_failure_in(SIZE_MAX); + EXPECT(librecrypt_hash_(buf, 1u, "hello", 5u, X3(ARGON2ID_STR), NULL, ASCII_CRYPT) > 0); + n = SIZE_MAX - libtest_get_alloc_failure_in(); + errno = 0; + libtest_set_alloc_failure_in(n); + EXPECT(librecrypt_hash_(buf, 1u, "hello", 5u, X3(ARGON2ID_STR), NULL, ASCII_CRYPT) == -1); + EXPECT(errno == ENOMEM); + EXPECT(libtest_get_alloc_failure_in() == 0u); + + } + + memset(buf1, 99, sizeof(buf1)); + r1 = librecrypt_hash_(buf1, sizeof(buf1), NULL, 0u, X2(ARGON2ID_STR), NULL, ASCII_CRYPT); + EXPECT(r1 > 0); + EXPECT(r1 > 2 * (ssize_t)sizeof(ARGON2ID_STR)); + r1b = librecrypt_hash_(buf, sizeof(buf), NULL, 0u, X3(ARGON2ID_STR), NULL, ASCII_CRYPT); + EXPECT(r1b > 0); + EXPECT(r1b == r1 + 1 * (ssize_t)sizeof(ARGON2ID_STR)); + r1c = librecrypt_hash_(buf, sizeof(buf), NULL, 0u, X4(ARGON2ID_STR), NULL, ASCII_CRYPT); + EXPECT(r1c > 0); + EXPECT(r1c == r1 + 2 * (ssize_t)sizeof(ARGON2ID_STR)); + + memset(buf2, 99, sizeof(buf2)); + EXPECT((r2 = librecrypt_hash_(buf2, sizeof(buf2), NULL, 0u, X2(ARGON2ID_STR), NULL, ASCII_HASH)) > 0); + EXPECT(librecrypt_hash_(buf, sizeof(buf), NULL, 0u, X3(ARGON2ID_STR), NULL, ASCII_HASH) == r2); + EXPECT(librecrypt_hash_(buf, sizeof(buf), NULL, 0u, X4(ARGON2ID_STR), NULL, ASCII_HASH == r2)); + EXPECT(r2 < r1); + + memset(buf3, 99, sizeof(buf3)); + EXPECT((r3 = librecrypt_hash_(buf3, sizeof(buf3), NULL, 0u, X2(ARGON2ID_STR), NULL, BINARY_HASH)) > 0); + EXPECT(librecrypt_hash_(buf, sizeof(buf), NULL, 0u, X3(ARGON2ID_STR), NULL, BINARY_HASH) == r3); + EXPECT(librecrypt_hash_(buf, sizeof(buf), NULL, 0u, X4(ARGON2ID_STR), NULL, BINARY_HASH) == r3); + EXPECT(r3 < r2); + + assert((size_t)r1 < sizeof(buf) - 11u); + for (i = (size_t)r1 + 11u; i < SIZE_MAX; i--) { + if (i <= (size_t)r1 + 10u) { + memset(buf, 88, sizeof(buf)); + EXPECT(librecrypt_hash_(buf, i, NULL, 0u, X2(ARGON2ID_STR), NULL, ASCII_CRYPT) == r1); + if (i) { + n = i - 1u < (size_t)r1 ? i - 1u : (size_t)r1; + EXPECT(!memcmp(buf, buf1, n)); + EXPECT(buf[n] == '\0'); + } + } + if (i <= (size_t)r2 + 10u) { + memset(buf, 88, sizeof(buf)); + EXPECT(librecrypt_hash_(buf, i, NULL, 0u, X2(ARGON2ID_STR), NULL, ASCII_HASH) == r2); + if (i) { + n = i - 1u < (size_t)r2 ? i - 1u : (size_t)r2; + EXPECT(!memcmp(buf, buf2, n)); + EXPECT(buf[n] == '\0'); + } + } + if (i <= (size_t)r3 + 10u) { + memset(buf, 88, sizeof(buf)); + EXPECT(librecrypt_hash_(buf, i, NULL, 0u, X2(ARGON2ID_STR), NULL, BINARY_HASH) == r3); + EXPECT(!memcmp(buf, buf3, i < (size_t)r3 ? i : (size_t)r3)); + } + } + + EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, X2(ARGON2ID_STR), NULL, ASCII_CRYPT) == r1); + EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, X3(ARGON2ID_STR), NULL, ASCII_CRYPT) == r1b); + EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, X4(ARGON2ID_STR), NULL, ASCII_CRYPT) == r1c); + + EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, X2(ARGON2ID_STR), NULL, ASCII_HASH) == r2); + EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, X3(ARGON2ID_STR), NULL, ASCII_HASH) == r2); + EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, X4(ARGON2ID_STR), NULL, ASCII_HASH) == r2); + + EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, X2(ARGON2ID_STR), NULL, BINARY_HASH) == r3); + EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, X3(ARGON2ID_STR), NULL, BINARY_HASH) == r3); + EXPECT(librecrypt_hash_(NULL, 0u, NULL, 0u, X4(ARGON2ID_STR), NULL, BINARY_HASH) == r3); +#endif + STOP_RESOURCE_TEST(); return 0; } diff --git a/librecrypt_realise_salts.c b/librecrypt_realise_salts.c index 58ba6d3..3fcce88 100644 --- a/librecrypt_realise_salts.c +++ b/librecrypt_realise_salts.c @@ -126,7 +126,7 @@ librecrypt_realise_salts(char *restrict out_buffer, size_t size, const char *set /* Write padding charaters */ right = right < size ? right : size; for (i = 0u; i < right; i++) - out_buffer[right] = pad; + out_buffer[right] = pad; /* $covered$ (TODO we currently don't have an algorithm to trigger this) */ out_buffer = &out_buffer[right]; size -= right; } diff --git a/librecrypt_rng_.c b/librecrypt_rng_.c index f9a6cc7..e5fe6ec 100644 --- a/librecrypt_rng_.c +++ b/librecrypt_rng_.c @@ -75,7 +75,7 @@ librecrypt_rng_(void *out, size_t n, void *user) fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_CLOFORK); if (fd < 0) goto no_urandom; /* this is a goto to make coverage test more comprehensive */ - /* TODO we should make sure this is a character special device */ + /* TODO we should make sure this is a character special device and validate output */ for (;;) { r = read(fd, buf, n); if (r < 0) { @@ -347,11 +347,10 @@ test_oversized(void) buf[0] = 99; libtest_getentropy_jmp_val = 1; - if (!setjmp(libtest_getentropy_jmp)) { + if (!setjmp(libtest_getentropy_jmp)) EXPECT(librecrypt_rng_(buf, beyond_ssize_max, NULL) == 9999); - } else { + else jumped = 1; - } EXPECT(jumped); EXPECT(buf[0] == 99); @@ -365,6 +364,7 @@ main(void) unsigned char buf1[1024u]; unsigned char buf2[sizeof(buf1)]; ssize_t n1, n2; + size_t i; void *user = NULL; SET_UP_ALARM(); @@ -388,7 +388,25 @@ main(void) EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));\ } while (0) - /* TODO Test with output pattern (useful for other tests) */ + /* Test with output pattern (useful for other tests) */ +#if defined(__linux__) + libtest_getrandom_real = 0; +#endif + libtest_getentropy_real = 0; + libtest_random_pattern = buf2; + libtest_random_pattern_offset = 0u; + libtest_random_pattern_length = 32u; + for (i = 0u; i < sizeof(buf2); i++) + buf2[i] = (unsigned char)(i % libtest_random_pattern_length * 3u + 1u); + EXPECT(librecrypt_rng_(buf1, 128u, NULL) == 128); + EXPECT(!memcmp(buf1, buf2, 128u)); + libtest_random_pattern = NULL; + libtest_random_pattern_offset = 0u; + libtest_random_pattern_length = 0u; +#if defined(__linux__) + libtest_getrandom_real = 1; +#endif + libtest_getentropy_real = 1; /* Check that output is random */ CHECK2(); diff --git a/librecrypt_settings_prefix.c b/librecrypt_settings_prefix.c index 0fcf8ae..a2a75f9 100644 --- a/librecrypt_settings_prefix.c +++ b/librecrypt_settings_prefix.c @@ -33,8 +33,10 @@ librecrypt_settings_prefix(const char *hash, size_t *hashsize_out) goto zero; /* Return 0 as hash size if algorithm cannot be identified or has fixed hash size */ algo = librecrypt_find_first_algorithm_(&hash[last_offset], len - last_offset); - if (!algo || !algo->flexible_hash_size) + if (!algo) goto zero; + if (!algo->flexible_hash_size) + goto zero; /* $covered$ (TODO we currently don't have an algorithm to trigger this) */ /* Get the hash size */ if (!librecrypt_check_settings_(&hash[ret], len - ret, "%^b", @@ -61,14 +63,6 @@ out: EXPECT(librecrypt_settings_prefix(PREFIX, NULL) == sizeof(PREFIX) - 1u); \ } while (0) -#if 0 -#define CHECK_ASTERISK(PREFIX, SUFFIX, HASH)\ - do {\ - size_t hashsize = 99999u;\ - EXPECT(librecrypt_settings_prefix(PREFIX SUFFIX #HASH, &hashsize) == sizeof(PREFIX) - 1u);\ - EXPECT(hashsize == HASH##u);\ - } while (0) - #define CHECK_ZERO(PREFIX, SUFFIX)\ do {\ size_t hashsize = 99999u;\ @@ -76,13 +70,12 @@ out: EXPECT(hashsize == 0u);\ } while (0) -#define CHECK_HASHED(PREFIX, SUFFIX, HASH)\ +#define CHECK_HASH(PREFIX, SUFFIX, HASH)\ do {\ size_t hashsize = 99999u;\ EXPECT(librecrypt_settings_prefix(PREFIX SUFFIX, &hashsize) == sizeof(PREFIX) - 1u);\ EXPECT(hashsize == HASH##u);\ } while (0) -#endif int @@ -115,7 +108,46 @@ main(void) CHECK_NULL("_", ""); CHECK_NULL("$x$*10>_", "_"); - /* TODO test hash size output (requires algorithms) */ + /* Check without hash */ + CHECK_ZERO("a$b$", ""); + CHECK_ZERO("a$b$>", ""); + CHECK_ZERO("a$b$x>", ""); + CHECK_ZERO("a$b$*10>", ""); + + /* Check without invalid algorithm */ + CHECK_ZERO("$~no~such~algorithm~$", "hash"); + + /* Check without hash and hashlen */ +#if defined(SUPPORT_ARGON2I) + CHECK_HASH("$argon2i$m=8,t=1,p=1$*99$", "*100", 100); + CHECK_HASH("x$*99>$argon2i$m=8,t=1,p=1$*99$", "*100", 100); + CHECK_HASH("$argon2i$m=8,t=1,p=1$*99$", "NineByteHash", 9); + CHECK_HASH("x$*99>$argon2i$m=8,t=1,p=1$*99$", "NineByteHash", 9); +#endif +#if defined(SUPPORT_ARGON2ID) + CHECK_HASH("$argon2id$m=8,t=1,p=1$*99$", "*100", 100); + CHECK_HASH("x$*99>$argon2id$m=8,t=1,p=1$*99$", "*100", 100); + CHECK_HASH("$argon2id$m=8,t=1,p=1$*99$", "NineByteHash", 9); + CHECK_HASH("x$*99>$argon2id$m=8,t=1,p=1$*99$", "NineByteHash", 9); +#endif +#if defined(SUPPORT_ARGON2D) + CHECK_HASH("$argon2d$m=8,t=1,p=1$*99$", "*100", 100); + CHECK_HASH("x$*99>$argon2d$m=8,t=1,p=1$*99$", "*100", 100); + CHECK_HASH("$argon2d$m=8,t=1,p=1$*99$", "NineByteHash", 9); + CHECK_HASH("x$*99>$argon2d$m=8,t=1,p=1$*99$", "NineByteHash", 9); +#endif +#if defined(SUPPORT_ARGON2DS) + CHECK_HASH("$argon2ds$m=8,t=1,p=1$*99$", "*100", 100); + CHECK_HASH("x$*99>$argon2ds$m=8,t=1,p=1$*99$", "*100", 100); + CHECK_HASH("$argon2ds$m=8,t=1,p=1$*99$", "NineByteHash", 9); + CHECK_HASH("x$*99>$argon2ds$m=8,t=1,p=1$*99$", "NineByteHash", 9); +#endif + + /* Check without invalid hash */ + IF__argon2i__SUPPORTED(CHECK_ZERO("$argon2i$m=8,t=1,p=1$*99$", "#");) + IF__argon2d__SUPPORTED(CHECK_ZERO("$argon2d$m=8,t=1,p=1$*99$", "#");) + IF__argon2id__SUPPORTED(CHECK_ZERO("$argon2id$m=8,t=1,p=1$*99$", "#");) + IF__argon2ds__SUPPORTED(CHECK_ZERO("$argon2ds$m=8,t=1,p=1$*99$", "#");) STOP_RESOURCE_TEST(); return 0; diff --git a/libtest/alloc.c b/libtest/alloc.c index f89ba94..e154624 100644 --- a/libtest/alloc.c +++ b/libtest/alloc.c @@ -717,8 +717,6 @@ check(int use_free) free(p); else free_aligned_sized(p, sizeof(void *), 11u); - - /* TODO mmap, munmap, mremap */ } @@ -728,6 +726,7 @@ check_successfuls(void) size_t pagesize; char *s; wchar_t *w; + void *q; check(1); check(0); @@ -817,7 +816,12 @@ check_successfuls(void) EXPECT(!memcmp(w, (wchar_t[]){11, 22, 0}, 3u * sizeof(wchar_t))); free(w); - /* TODO mmap, munmap, mremap */ + p = mmap(NULL, 1u, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(p != MAP_FAILED); + p = mremap(p, 1u, 2u, 0); + assert(p != MAP_FAILED); + assert(malloc_usable_size(p) >= 6u); + asser(!munmap(p, 2u)); } @@ -826,55 +830,64 @@ check_failures(void) { void *q; - libtest_set_alloc_failure_in(1u); + libtest_set_alloc_failure_in(2u); + p = malloc(1u); + EXPECT(p); + free(p); + assert(libtest_get_alloc_failure_in() == 1u); errno = 0; - EXPECT(!malloc(1u)); + p = malloc(1u); + EXPECT(!p); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!calloc(1u, 1u)); + p = calloc(1u, 1u); + EXPECT(!p); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!realloc(NULL, 1u)); + p = realloc(NULL, 1u); + EXPECT(!p); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); - q = realloc(NULL, 1u); - assert(q); + p = realloc(NULL, 1u); + assert(p); libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!realloc(q, 1u)); + EXPECT(!realloc(p, 1u)); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); - free(q); + free(p); libtest_set_alloc_failure_in(1u); errno = 0; EXPECT(!reallocarray(NULL, 1u, 1u)); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); - q = reallocarray(NULL, 1u, 1u); - assert(q); + p = reallocarray(NULL, 1u, 1u); + assert(p); libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!reallocarray(q, 1u, 1u)); + EXPECT(!reallocarray(p, 1u, 1u)); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); - free(q); + free(p); libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!memalign(1u, 1u)); + p = memalign(1u, 1u); + EXPECT(!p); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!aligned_alloc(1u, 1u)); + p = aligned_alloc(1u, 1u); + EXPECT(!p); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); @@ -885,47 +898,69 @@ check_failures(void) libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!valloc(1u)); + p = valloc(1u); + EXPECT(!p); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!pvalloc(1u)); + p = pvalloc(1u); + EXPECT(!p); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!strdup("x")); + p = strdup("x"); + EXPECT(!p); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!strndup("x", 1u)); + p = strndup("x", 1u); + EXPECT(!p); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!wcsdup((wchar_t[]){1, 0})); + p = wcsdup((wchar_t[]){1, 0}); + EXPECT(!p); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!wcsndup((wchar_t[]){1, 0}, 1u)); + p = wcsndup((wchar_t[]){1, 0}, 1u); + EXPECT(!p); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); libtest_set_alloc_failure_in(1u); errno = 0; - EXPECT(!memdup("x", 1u)); + p = memdup("x", 1u); + EXPECT(!p); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); - /* TODO mmap, munmap, mremap */ + libtest_set_alloc_failure_in(1u); + errno = 0; + p = mmap(NULL, 1u, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT(p == MAP_FAILED); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + + p = mmap(NULL, 1u, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(p != MAP_FAILED); + q = p; + libtest_set_alloc_failure_in(1u); + errno = 0; + p = mremap(p, 1u, 2u, 0); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + munmap(q, 1u); } diff --git a/libtest/random.c b/libtest/random.c index 77e9218..2eb22e6 100644 --- a/libtest/random.c +++ b/libtest/random.c @@ -12,10 +12,13 @@ genpattern(void *buf, size_t size) { unsigned char *out = buf; size_t n; + ssize_t ret; if (size > (size_t)SSIZE_MAX) size = (size_t)SSIZE_MAX; + ret = (ssize_t)size; + if (libtest_random_pattern_length) { while (size) { if (libtest_random_pattern_offset == libtest_random_pattern_length) @@ -33,7 +36,7 @@ genpattern(void *buf, size_t size) out[0] = (unsigned char)rand(); } - return (ssize_t)size; + return ret; } |
