aboutsummaryrefslogtreecommitdiffstats
path: root/librecrypt_add_algorithm.c
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-05-01 17:45:39 +0200
committerMattias Andrée <m@maandree.se>2026-05-01 17:45:39 +0200
commitadfa8e1265f6155d1a582baa9929af198bb5d4de (patch)
treee3cee62aa5a8768621cd294295f787b8cc54141b /librecrypt_add_algorithm.c
parentAdd librecrypt.7 and README (diff)
downloadlibrecrypt-adfa8e1265f6155d1a582baa9929af198bb5d4de.tar.gz
librecrypt-adfa8e1265f6155d1a582baa9929af198bb5d4de.tar.bz2
librecrypt-adfa8e1265f6155d1a582baa9929af198bb5d4de.tar.xz
Misc
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
-rw-r--r--librecrypt_add_algorithm.c101
1 files changed, 86 insertions, 15 deletions
diff --git a/librecrypt_add_algorithm.c b/librecrypt_add_algorithm.c
index a2d8aa4..167713f 100644
--- a/librecrypt_add_algorithm.c
+++ b/librecrypt_add_algorithm.c
@@ -3,51 +3,109 @@
#ifndef TEST
+#if defined(__GNUC__)
+# pragma GCC diagnostic ignored "-Wformat-truncation=" /* we rely on snprintf(3) doing truncation */
+#endif
+
+
ssize_t
librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char *restrict augment, void *reserved)
{
- size_t prefix1 = librecrypt_settings_prefix(augend);
- size_t prefix2, min, ret, len, phraselen;
+ size_t prefix1, prefix2, min, ret, len, phraselen;
+ size_t hashsize1, hashsize2;
char *phrase, pad;
- int strict_pad;
+ int strict_pad, r_int, nul_term;
const unsigned char *lut;
ssize_t r;
#define COPY_PREFIX()\
do {\
- size -= 1u;\
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;\
- }\
} while (0)
+ /* Reserve space for NUL-termination */
+ if (size) {
+ nul_term = 1;
+ size -= 1u;
+ } else {
+ nul_term = 0;
+ }
+
+ /* Get the prefix and hash size in `augend` and `augment` */
+ 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[prefix1] == '*') {
+ prefix1 += strlen(&augend[prefix1]);
+ hashsize1 = 0u;
+ }
+
+ /* If `augend` doesn't contain a hash, we do not need to hash the hash,
+ * but we do need to include the final hash size if it is configurable */
if (!augend[prefix1]) {
- prefix2 = librecrypt_settings_prefix(augment);
+ if (augment[prefix2] == '*') {
+ prefix2 += strlen(&augment[prefix2]);
+ hashsize2 = 0u;
+ }
ret = prefix1 + 1u + prefix2;
if (size) {
COPY_PREFIX();
+ if (size) {
+ *out_buffer++ = LIBRECRYPT_ALGORITHM_LINK_DELIMITER;
+ size -= 1u;
+ }
min = prefix2 < size ? prefix2 : size;
memcpy(out_buffer, augment, min);
- out_buffer[min] = '\0';
+ if (hashsize2) {
+ r_int = snprintf(&out_buffer[min], size + 1u, "*%zu", hashsize2);
+ if (r_int < 2)
+ abort();
+ ret += (size_t)r_int;
+ } else {
+ out_buffer[min] = '\0';
+ }
+ } else {
+ r_int = snprintf(NULL, 0, "*%zu", hashsize2);
+ if (r_int < 2)
+ abort();
+ ret += (size_t)r_int;
}
return (ssize_t)ret;
}
- if (size <= prefix1 + 2u) {
+ /* Measure size of hash size specification for `augend` */
+ if (hashsize1) {
+ r_int = snprintf(NULL, 0, "*%zu", hashsize1);
+ if (r_int < 2)
+ abort();
+ } else {
+ r_int = 0;
+ }
+
+ /* Measure `augent` and '>' in output */
+ ret = prefix1 + (size_t)r_int + 1u;
+
+ /* Decode the hash from base-64 to binary */
+ if (size <= ret + prefix2 + 1u) {
+ /* If the new hash doesn't fit, don't bother;
+ * hash sizes are independent of password size */
phrase = NULL;
phraselen = 0u;
} else {
- lut = librecrypt_get_encoding(augend, strlen(augend), &pad, &strict_pad, 1);
+ /* Measure old ASCII hash; `strlen(augent)` will be `prefix1 + len` */
+ len = strlen(&augend[prefix1]);
+
+ /* Get encoding information */
+ lut = librecrypt_get_encoding(augend, prefix1 + len, &pad, &strict_pad, 1);
if (!lut)
return -1;
- len = strlen(&augend[prefix1]);
+ /* Measure old binary hash */
r = librecrypt_decode(NULL, 0, &augend[prefix1], len, lut, pad, strict_pad);
if (r <= 0) {
if (!r)
@@ -55,6 +113,8 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char
return -1;
}
phraselen = (size_t)r;
+
+ /* Decode old hash from ASCII to binary */
phrase = malloc(phraselen);
if (!phrase)
return -1;
@@ -62,9 +122,20 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char
abort();
}
+ /* Chain the hash algorithms: write `augent` */
COPY_PREFIX();
- ret = prefix1 + 1u;
- r = librecrypt_crypt(out_buffer, size + 1u, phrase, phraselen, augment, reserved);
+ if (hashsize1 && size)
+ if (snprintf(out_buffer, size + 1u, "*%zu", hashsize1) != r_int)
+ abort();
+
+ /* Chain the hash algorithms: write '>' */
+ if (size) {
+ *out_buffer++ = LIBRECRYPT_ALGORITHM_LINK_DELIMITER;
+ size -= 1u;
+ }
+
+ /* Chain the hash algorithms: write `augment` and hash */
+ r = librecrypt_crypt(out_buffer, size + (nul_term ? 1u : 0u), phrase, phraselen, augment, reserved);
if (r <= 0) {
librecrypt_wipe(phrase, phraselen);
free(phrase);