aboutsummaryrefslogtreecommitdiffstats
path: root/librecrypt_add_algorithm.c
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-05-14 15:55:33 +0200
committerMattias Andrée <m@maandree.se>2026-05-14 15:55:33 +0200
commit4e6f25806e3c9fa4753ce959ef990167796acd32 (patch)
treee641de9953f5b58afc1f36efe9c42a0d20254cd2 /librecrypt_add_algorithm.c
parentFix libtest and add file descriptor leak detection (diff)
downloadlibrecrypt-4e6f25806e3c9fa4753ce959ef990167796acd32.tar.gz
librecrypt-4e6f25806e3c9fa4753ce959ef990167796acd32.tar.bz2
librecrypt-4e6f25806e3c9fa4753ce959ef990167796acd32.tar.xz
Tests and fixes
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
-rw-r--r--librecrypt_add_algorithm.c161
1 files changed, 137 insertions, 24 deletions
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 */