aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-09-23 23:26:11 +0200
committerMattias Andrée <m@maandree.se>2026-09-23 23:26:11 +0200
commite60342575a888dd13fc2df841a8d4c7ef683ae6e (patch)
treeb0265cc2a6349fcf2907f55c1c0058a53a4304d4
parentAdd version testing functionality and bump to version 1.2 (diff)
downloadlibrecrypt-e60342575a888dd13fc2df841a8d4c7ef683ae6e.tar.gz
librecrypt-e60342575a888dd13fc2df841a8d4c7ef683ae6e.tar.bz2
librecrypt-e60342575a888dd13fc2df841a8d4c7ef683ae6e.tar.xz
Introduce librecrypt_concat_*_
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
-rw-r--r--Makefile4
-rw-r--r--argon2/make_settings.c49
-rw-r--r--common.h89
-rw-r--r--librecrypt.h2
-rw-r--r--librecrypt_add_algorithm.c56
-rw-r--r--librecrypt_concat_mem_.c25
-rw-r--r--librecrypt_concat_str_.c25
-rw-r--r--librecrypt_concat_uint_.c41
-rw-r--r--librecrypt_concat_void_.c25
-rw-r--r--librecrypt_hash_.c2
-rw-r--r--librecrypt_realise_salts.c2
11 files changed, 262 insertions, 58 deletions
diff --git a/Makefile b/Makefile
index 572b9ab..33e9c8a 100644
--- a/Makefile
+++ b/Makefile
@@ -68,6 +68,10 @@ OBJ_PRIVATE =\
librecrypt_fill_with_random_.o\
librecrypt_find_first_algorithm_.o\
librecrypt_get_pepper_.o\
+ librecrypt_concat_mem_.o\
+ librecrypt_concat_str_.o\
+ librecrypt_concat_uint_.o\
+ librecrypt_concat_void_.o\
$(OBJ_COMMON_RFC4848S4)
USE_OBJ_COMMON_RFC4848S4 =\
diff --git a/argon2/make_settings.c b/argon2/make_settings.c
index c6d2128..63062f3 100644
--- a/argon2/make_settings.c
+++ b/argon2/make_settings.c
@@ -7,9 +7,9 @@ static ssize_t
make_settings(char *out_buffer, size_t size, const char *algorithm, size_t memcost, uintmax_t timecost,
int gensalt, ssize_t (*rng)(void *out, size_t n, void *user), void *user)
{
+ struct concat_state concat_state = {out_buffer, size, 0u};
const char *p, *version;
- size_t algolen, ret, min, len, i;
- int r;
+ size_t algolen, min, len, i;
/* Use default RNG if NULL is specified */
if (!rng)
@@ -44,7 +44,7 @@ make_settings(char *out_buffer, size_t size, const char *algorithm, size_t memco
abort(); /* $covered$ */
p = strchr(p, '$');
algolen = p ? (size_t)(p - algorithm) : strlen(algorithm);
- if (algolen > 32u) /* just some small value absolute will fit all variants */
+ if (algolen > 32u) /* just some small value that absolutely will fit all variants */
abort(); /* $covered$ */
if (p && p[1u] == 'v') {
p = &p[2u];
@@ -63,21 +63,23 @@ make_settings(char *out_buffer, size_t size, const char *algorithm, size_t memco
}
/* Write algorithm and parameters */
- r = snprintf(out_buffer, size, "%.*s%s$m=%zu,t=%ju,p=1$",
- (int)algolen, algorithm, version, memcost, timecost);
- if (r < (int)sizeof("$argon2_$v=__$m=_,t=_,p=1$") - 1)
+ librecrypt_concat_mem_(&concat_state, algorithm, algolen);
+ librecrypt_concat_str_(&concat_state, version);
+ librecrypt_concat_str_(&concat_state, "$m=");
+ librecrypt_concat_uint_(&concat_state, memcost);
+ librecrypt_concat_str_(&concat_state, ",t=");
+ librecrypt_concat_uint_(&concat_state, timecost);
+ librecrypt_concat_str_(&concat_state, ",p=1$");
+ if (concat_state.len < sizeof("$argon2_$v=__$m=_,t=_,p=1$") - 1u)
abort(); /* $covered$ (impossible) */
- ret = (size_t)r;
- min = size ? MIN(ret, size - 1u) : 0u;
- out_buffer = &out_buffer[min];
- size -= min;
/* Add 16 bytes of salt */
if (gensalt) {
/* 16 bytes is 128 bits, and 128 = 21*6+2, so that is
* 21 full base-64 characeters and 1 that only use 2 bits */
- ret += len = 22u;
- min = size ? MIN(len, size - 1u) : 0u;
+ out_buffer = concat_state.buf;
+ len = 22u;
+ min = librecrypt_concat_void_(&concat_state, len);
if (librecrypt_fill_with_random_(out_buffer, min, rng, user))
return -1;
if (min == len)
@@ -85,30 +87,13 @@ make_settings(char *out_buffer, size_t size, const char *algorithm, size_t memco
for (i = 0u; i < min; i++)
out_buffer[i] = librecrypt_common_rfc4848s4_encoding_lut_[((unsigned char *)out_buffer)[i]];
} else {
- ret += len = sizeof("*16") - 1u;
- min = size ? MIN(len, size - 1u) : 0u;
- if (min)
- memcpy(out_buffer, "*16", min);
+ librecrypt_concat_str_(&concat_state, "*16");
}
- out_buffer = &out_buffer[min];
- size -= min;
/* Add tag size (size of hash result) */
- ret += len = sizeof("$*32") - 1u;
- min = size ? MIN(len, size - 1u) : 0u;
- if (min)
- memcpy(out_buffer, "$*32", min);
- out_buffer = &out_buffer[min];
- size -= min;
+ librecrypt_concat_str_(&concat_state, "$*32");
- /* NUL terminate */
- if (size) {
- /* We were careful to make sure size is positive at
- * the end if it was when the function was called */
- *out_buffer = '\0';
- }
-
- return (ssize_t)ret;
+ return (ssize_t)concat_state.len;
enosys:
errno = ENOSYS;
diff --git a/common.h b/common.h
index bc04b44..fd53468 100644
--- a/common.h
+++ b/common.h
@@ -19,8 +19,8 @@
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
-#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#if defined(__GNUC__)
@@ -118,6 +118,50 @@ struct pepper {
/**
+ * Structure used for doing truncated text concatenation
+ *
+ * This structure is laid out so that `{buf, size, 0u}` will
+ * properly initialise the state to use a buffer and have
+ * it's size properly set, and have the resulting length
+ * initialised to zero. This will not change.
+ */
+struct concat_state {
+ /**
+ * Where the function shall write to
+ *
+ * Update to an offset of it by the called function.
+ * Shall be set to the beginning of the output buffer
+ * before the first function call.
+ */
+ char *buf;
+
+ /**
+ * The (remaining) size of the output buffer
+ *
+ * This is decremented by the called function
+ * Shall be set to the size of the output buffer
+ * before the first function call.
+ */
+ size_t size;
+
+ /**
+ * The length the constructed text would
+ * have had if it wasn't truncated
+ *
+ * This length does not include NUL termination
+ * which is added by every function
+ *
+ * This is increased by the called function.
+ * Should be set to 0 before the first function call.
+ *
+ * After the last concatenation call, this field
+ * is read to get the final size before truncation
+ */
+ size_t len;
+};
+
+
+/**
* The real type of `LIBRECRYPT_CONTEXT`
*/
struct librecrypt_context {
@@ -330,10 +374,51 @@ const struct librecrypt_algorithm *librecrypt_find_first_algorithm_(const char *
* @throws EINVAL The size of the pepper is unsupported
* for the hash algorithm `algo`
*/
-LIBRECRYPT_NONNULL_1__
+LIBRECRYPT_NONNULL_1__ HIDDEN
struct pepper *librecrypt_get_pepper_(LIBRECRYPT_CONTEXT *ctx, enum librecrypt_hash_algorithm algo, size_t len);
+LIBRECRYPT_NONNULL_1__ HIDDEN
+inline size_t
+librecrypt_concat_void_(struct concat_state *state, size_t len) /* TODO doc */
+{
+ size_t n = state->size ? MIN(state->size - 1u, len) : 0u;
+ if (len > SIZE_MAX - state->len)
+ abort(); /* TODO not covered */
+ state->len += len;
+ if (n) {
+ state->buf = &state->buf[n];
+ state->size -= n;
+ }
+ if (state->size)
+ state->buf[0u] = '\0';
+ return n;
+}
+
+
+LIBRECRYPT_NONNULL_1__ LIBRECRYPT_READ_MEM__(2, 3) HIDDEN
+inline void
+librecrypt_concat_mem_(struct concat_state *state, const char *text, size_t len) /* TODO doc */
+{
+ char *buf = state->buf;
+ size_t n = librecrypt_concat_void_(state, len);
+ if (n)
+ memcpy(buf, text, n);
+}
+
+
+LIBRECRYPT_NONNULL_1__ LIBRECRYPT_READ_STR__(2) HIDDEN
+inline void
+librecrypt_concat_str_(struct concat_state *state, const char *text) /* TODO doc */
+{
+ librecrypt_concat_mem_(state, text, strlen(text));
+}
+
+
+LIBRECRYPT_NONNULL_1__ HIDDEN
+void librecrypt_concat_uint_(struct concat_state *state, uintmax_t value); /* TODO doc */
+
+
#ifdef TEST
# include "libtest/libtest.h"
diff --git a/librecrypt.h b/librecrypt.h
index 11d6007..aec7574 100644
--- a/librecrypt.h
+++ b/librecrypt.h
@@ -442,7 +442,7 @@ struct librecrypt_algorithm {
* @return See `librecrypt_make_settings`
* @throws See `librecrypt_make_settings`
*
- * This function shall be MT-Safe but may be AS-Safe
+ * This function shall be MT-Safe but may be AS-Unsafe
*/
ssize_t (*make_settings)(char *out_buffer, size_t size, const char *algorithm,
size_t memcost, uintmax_t timecost, int gensalt,
diff --git a/librecrypt_add_algorithm.c b/librecrypt_add_algorithm.c
index d561983..24a17c7 100644
--- a/librecrypt_add_algorithm.c
+++ b/librecrypt_add_algorithm.c
@@ -3,19 +3,35 @@
#ifndef TEST
-#if defined(__GNUC__)
-# pragma GCC diagnostic ignored "-Wformat-truncation=" /* we rely on snprintf(3) doing truncation */
-#endif
+static size_t
+truncated_asterisk(char *out_buffer, size_t out_buffer_size, size_t asterisk)
+{
+ struct concat_state concat_state = {out_buffer, out_buffer_size, 0u};
+ librecrypt_concat_str_(&concat_state, "*");
+ librecrypt_concat_uint_(&concat_state, asterisk);
+ if (concat_state.len < 2u)
+ abort(); /* $covered$ (impossible) */
+ return concat_state.len;
+}
+
+
+static size_t
+measure_asterisk(size_t asterisk)
+{
+ return truncated_asterisk(NULL, 0u, asterisk);
+}
ssize_t
librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend,
const char *restrict augment, LIBRECRYPT_CONTEXT *ctx)
{
+ /* TODO rewrite to use the string building functions */
+
size_t prefix1, prefix2, min, ret, len, phraselen;
- size_t hashsize1, hashsize2;
+ size_t hashsize1, hashsize2, asterisk_len;
char *phrase, pad;
- int strict_pad, r_int, nul_term, saved_errno;
+ int strict_pad, nul_term, saved_errno;
const unsigned char *lut;
ssize_t r;
@@ -60,12 +76,10 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend,
out_buffer = &out_buffer[min];
size -= min;
if (hashsize2) {
- r_int = snprintf(out_buffer, size + 1u, "*%zu", hashsize2);
- if (r_int < 2)
- abort(); /* $covered$ (impossible reliably) */
- if (ret > SIZE_MAX - (size_t)r_int)
+ asterisk_len = truncated_asterisk(out_buffer, size + 1u, hashsize2);
+ if (ret > SIZE_MAX - asterisk_len)
abort(); /* $covered$ (impossible) */
- ret += (size_t)r_int;
+ ret += asterisk_len;
} else {
out_buffer[0u] = '\0';
}
@@ -79,12 +93,10 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend,
#if defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
- r_int = snprintf(NULL, 0u, "*%zu", hashsize2);
- if (r_int < 2)
- abort(); /* $covered$ (impossible reliably) */
- if (ret > SIZE_MAX - (size_t)r_int)
+ asterisk_len = measure_asterisk(hashsize2);
+ if (ret > SIZE_MAX - asterisk_len)
abort(); /* $covered$ (impossible) */
- ret += (size_t)r_int;
+ ret += asterisk_len;
out:
if (nul_term)
out_buffer[0u] = '\0';
@@ -100,17 +112,15 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend,
/* Measure size of hash size specification for `augend` */
if (hashsize1) {
- r_int = snprintf(NULL, 0u, "*%zu", hashsize1);
- if (r_int < 2)
- abort(); /* $covered$ (impossible reliably) */
+ asterisk_len = measure_asterisk(hashsize1);
} else {
- r_int = 0;
+ asterisk_len = 0;
}
/* Measure `augend` and '>' in output */
- if (prefix1 > SIZE_MAX - 1u - (size_t)r_int)
+ if (prefix1 > SIZE_MAX - 1u - asterisk_len)
abort(); /* $covered$ (impossible) */
- ret = prefix1 + (size_t)r_int + 1u;
+ ret = prefix1 + asterisk_len + 1u;
/* Decode the hash from base-64 to binary */
if (size <= ret + prefix2) {
@@ -151,9 +161,9 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend,
out_buffer = &out_buffer[min];
size -= min;
if (hashsize1 && size) {
- if (snprintf(out_buffer, size + 1u, "*%zu", hashsize1) != r_int)
+ if (truncated_asterisk(out_buffer, size + 1u, hashsize1) != asterisk_len)
abort(); /* $covered$ (impossible reliably) */
- min = MIN((size_t)r_int, size);
+ min = MIN(asterisk_len, size);
out_buffer = &out_buffer[min];
size -= min;
}
diff --git a/librecrypt_concat_mem_.c b/librecrypt_concat_mem_.c
new file mode 100644
index 0000000..edc826a
--- /dev/null
+++ b/librecrypt_concat_mem_.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+extern inline void librecrypt_concat_mem_(struct concat_state *state, const char *text, size_t len);
+
+
+#else
+
+
+int
+main(void)
+{
+ SET_UP_ALARM();
+ INIT_RESOURCE_TEST();
+
+ /* TODO test */
+
+ STOP_RESOURCE_TEST();
+ return 0;
+}
+
+
+#endif
diff --git a/librecrypt_concat_str_.c b/librecrypt_concat_str_.c
new file mode 100644
index 0000000..6ad7e48
--- /dev/null
+++ b/librecrypt_concat_str_.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+extern inline void librecrypt_concat_str_(struct concat_state *state, const char *text);
+
+
+#else
+
+
+int
+main(void)
+{
+ SET_UP_ALARM();
+ INIT_RESOURCE_TEST();
+
+ /* TODO test */
+
+ STOP_RESOURCE_TEST();
+ return 0;
+}
+
+
+#endif
diff --git a/librecrypt_concat_uint_.c b/librecrypt_concat_uint_.c
new file mode 100644
index 0000000..a492e0b
--- /dev/null
+++ b/librecrypt_concat_uint_.c
@@ -0,0 +1,41 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+#include <stdio.h>
+
+/* TODO use of sprintf(3) should be eliminated;
+ * this will make it easier to use in an unhosted environment (kernels)
+ * and make_settings will be AS-Safe,
+ * however librecrypt_add_algorithm will not be AS-Safe as hash
+ * functions may require memory allocations which is AS-Unsafe
+ */
+
+
+void
+librecrypt_concat_uint_(struct concat_state *state, uintmax_t value)
+{
+ char buf[3u * sizeof(uintmax_t) + 1u];
+ int len = sprintf(buf, "%ju", value);
+ if (len < 1)
+ abort(); /* $covered$ (impossible reliably) */
+ librecrypt_concat_mem_(state, buf, (size_t)len);
+}
+
+
+#else
+
+
+int
+main(void)
+{
+ SET_UP_ALARM();
+ INIT_RESOURCE_TEST();
+
+ /* TODO test */
+
+ STOP_RESOURCE_TEST();
+ return 0;
+}
+
+
+#endif
diff --git a/librecrypt_concat_void_.c b/librecrypt_concat_void_.c
new file mode 100644
index 0000000..889aed1
--- /dev/null
+++ b/librecrypt_concat_void_.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+extern inline size_t librecrypt_concat_void_(struct concat_state *state, size_t len);
+
+
+#else
+
+
+int
+main(void)
+{
+ SET_UP_ALARM();
+ INIT_RESOURCE_TEST();
+
+ /* TODO test */
+
+ STOP_RESOURCE_TEST();
+ return 0;
+}
+
+
+#endif
diff --git a/librecrypt_hash_.c b/librecrypt_hash_.c
index 164a47b..fcaa795 100644
--- a/librecrypt_hash_.c
+++ b/librecrypt_hash_.c
@@ -46,6 +46,8 @@ ssize_t
librecrypt_hash_(char *restrict out_buffer, size_t size, const char *phrase, size_t len,
const char *settings, LIBRECRYPT_CONTEXT *ctx, enum action action)
{
+ /* TODO rewrite to use the string building functions */
+
const struct librecrypt_algorithm *algo;
ssize_t (*rng)(void *out, size_t n, void *user) = NULL;
char *settings_scratch = NULL;
diff --git a/librecrypt_realise_salts.c b/librecrypt_realise_salts.c
index 0c8002a..256cf68 100644
--- a/librecrypt_realise_salts.c
+++ b/librecrypt_realise_salts.c
@@ -8,6 +8,8 @@ librecrypt_realise_salts(char *restrict out_buffer, size_t size, const char *set
ssize_t (*rng)(void *out, size_t n, void *user), void *user,
LIBRECRYPT_CONTEXT *ctx)
{
+ /* TODO rewrite to use the string building functions */
+
const char *lut;
char pad;
int strict_pad, nul_term = 0;