aboutsummaryrefslogtreecommitdiffstats
path: root/librecrypt_encode.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_encode.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_encode.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/librecrypt_encode.c b/librecrypt_encode.c
index 2199ac1..51a0a2e 100644
--- a/librecrypt_encode.c
+++ b/librecrypt_encode.c
@@ -22,16 +22,29 @@ librecrypt_encode(char *out_buffer, size_t size, const void *binary, size_t len,
unsigned char a, b, c;
size_t q, r, i, j, n;
+ /* 1 byte (8 bits) requires 2 base-64 characters (12 bits),
+ * 2 bytes (16 bits) requires 3 base-64 characters (18 bits), and
+ * 3 bytes (24 bits) requires 4 base-64 characters (24 bits) exactly */
q = len / 3u;
r = len % 3u;
n = q * 4u + (!r ? 0u : pad ? 4u : r + 1u);
+ /* Just return the encoding length if no output is requested */
if (!size)
return n;
+ /* We right backwards to ensure `out_buffer` and `binary` may alias each other
+ * (the output is at least as long as the input (actually always longer
+ * unless `len` is 0)) */
+
+ /* NUL-terminate output */
size -= 1u;
out_buffer[n < size ? n : size] = '\0';
+ /* Deal with situation where number of bytes is not divisible
+ * byte there, and set excess bits to 0; padding characters are
+ * appended if required (they are probably optional since padding
+ * is only useful to allow base-64 strings to be concatenated) */
if (r == 1u) {
a = data[q * 3u + 0u];
switch (size > q * 4u ? size - q * 4u : 0u) { /* fall-through */
@@ -66,8 +79,11 @@ librecrypt_encode(char *out_buffer, size_t size, const void *binary, size_t len,
}
}
+ /* Encode multiples of 3 bytes as multiples of 4 ASCII characters, */
i = q * 4u;
j = q * 3u;
+ /* however, first we may have to truncate the output to a non-multiple
+ * of 4 ASCII characters the output buffer is too small, */
if (i > size) {
q = size / 4u;
r = size % 4u;
@@ -87,6 +103,7 @@ librecrypt_encode(char *out_buffer, size_t size, const void *binary, size_t len,
break;
}
}
+ /* then we can efficiently write the multiple of 4 characters */
while (i) {
i -= 4u;
j -= 3u;
@@ -120,6 +137,7 @@ check(const char *binary, size_t binary_len, const char *ascii, size_t ascii_len
char buf[256u];
size_t i, j, n;
+ /* Check internal test correctness */
if (padded_ascii_len & 3u) {
padded_ascii_len |= 3u;
padded_ascii_len += 1u;
@@ -128,12 +146,15 @@ check(const char *binary, size_t binary_len, const char *ascii, size_t ascii_len
assert(padded_ascii_len / 4u == (ascii_len + 3u) / 4u);
assert(padded_ascii_len >= ascii_len);
+ /* Check length-only request without padding */
EXPECT(librecrypt_encode(NULL, 0u, binary, binary_len, lut, '\0') == ascii_len);
EXPECT(librecrypt_encode(buf, 0u, binary, binary_len, lut, '\0') == ascii_len);
+ /* Check length-only request with padding */
EXPECT(librecrypt_encode(NULL, 0u, binary, binary_len, lut, '=') == padded_ascii_len);
EXPECT(librecrypt_encode(buf, 0u, binary, binary_len, lut, '=') == padded_ascii_len);
+ /* Check encoding requests, with and without truncation, without padding */
for (i = 0u; i <= ascii_len; i++) {
memset(buf, 99, sizeof(buf));
EXPECT(librecrypt_encode(buf, i + 1u, binary, binary_len, lut, '\0') == ascii_len);
@@ -143,6 +164,7 @@ check(const char *binary, size_t binary_len, const char *ascii, size_t ascii_len
EXPECT(buf[j] == 99);
}
+ /* Check encoding requests, with and without truncation, with padding */
for (i = 0u; i <= padded_ascii_len; i++) {
memset(buf, 99, sizeof(buf));
EXPECT(librecrypt_encode(buf, i + 1u, binary, binary_len, lut, '=') == padded_ascii_len);