--- /dev/null
+../../../licenses/CC0
\ No newline at end of file
--- /dev/null
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+
+/**
+ * str/base32 - RFC4648 base32 encoder/decoder.
+ *
+ * This code implements RFC4638 encoding, but you should use bech32 for most
+ * things anyway.
+ *
+ * License: CC0 (Public domain)
+ * Author: Rusty Russell <rusty@rustcorp.com.au>
+ */
+int main(int argc, char *argv[])
+{
+ /* Expect exactly one argument */
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0) {
+ printf("ccan/endian\n");
+ return 0;
+ }
+
+ return 1;
+}
--- /dev/null
+/* CC0 license (public domain) - see LICENSE file for details */
+#include "base32.h"
+#include <assert.h>
+#include <ccan/endian/endian.h>
+#include <string.h> /* for memcpy, memset */
+
+/* RFC 4648:
+ *
+ * (1) The final quantum of encoding input is an integral multiple of 40
+ * bits; here, the final unit of encoded output will be an integral
+ * multiple of 8 characters with no "=" padding.
+ *
+ * (2) The final quantum of encoding input is exactly 8 bits; here, the
+ * final unit of encoded output will be two characters followed by
+ * six "=" padding characters.
+ *
+ * (3) The final quantum of encoding input is exactly 16 bits; here, the
+ * final unit of encoded output will be four characters followed by
+ * four "=" padding characters.
+ *
+ * (4) The final quantum of encoding input is exactly 24 bits; here, the
+ * final unit of encoded output will be five characters followed by
+ * three "=" padding characters.
+ *
+ * (5) The final quantum of encoding input is exactly 32 bits; here, the
+ * final unit of encoded output will be seven characters followed by
+ * one "=" padding character.
+ */
+static size_t padlen(size_t remainder)
+{
+ switch (remainder) {
+ case 0:
+ return 0;
+ case 1:
+ return 6;
+ case 2:
+ return 4;
+ case 3:
+ return 3;
+ case 4:
+ return 1;
+ default:
+ abort();
+ }
+}
+
+size_t base32_str_size(size_t bytes)
+{
+ return (bytes + 4) / 5 * 8 + 1;
+}
+
+size_t base32_data_size(const char *str, size_t strlen)
+{
+ /* 8 chars == 5 bytes, round up to avoid overflow even though
+ * not required for well-formed strings. */
+ size_t max = (strlen + 7) / 8 * 5, padding = 0;
+
+ /* Count trailing padding bytes. */
+ while (strlen && str[strlen-1] == '=' && padding < 6) {
+ strlen--;
+ padding++;
+ }
+
+ return max - (padding * 5 + 7) / 8;
+}
+
+static bool decode_8_chars(const char c[8], beint64_t *res, int *bytes)
+{
+ uint64_t acc = 0;
+ size_t num_pad = 0;
+ for (int i = 0; i < 8; i++) {
+ uint8_t val;
+ acc <<= 5;
+ if (c[i] >= 'a' && c[i] <= 'z')
+ val = c[i] - 'a';
+ else if (c[i] >= 'A' && c[i] <= 'Z')
+ val = c[i] - 'A';
+ else if (c[i] >= '2' && c[i] <= '7')
+ val = c[i] - '2' + 26;
+ else if (c[i] == '=') {
+ num_pad++;
+ continue;
+ } else
+ return false;
+ /* Can't have padding then non-pad */
+ if (num_pad)
+ return false;
+ acc |= val;
+ }
+ *res = cpu_to_be64(acc);
+
+ /* Can't have 2 or 5 padding bytes */
+ if (num_pad == 5 || num_pad == 2)
+ return false;
+ *bytes = (40 - num_pad * 5) / 8;
+ return true;
+}
+
+bool base32_decode(const char *str, size_t slen, void *buf, size_t bufsize)
+{
+ while (slen >= 8) {
+ beint64_t val;
+ int bytes;
+ if (!decode_8_chars(str, &val, &bytes))
+ return false;
+ str += 8;
+ slen -= 8;
+ /* Copy bytes into dst. */
+ if (bufsize < bytes)
+ return false;
+ memcpy(buf, (char *)&val + 3, bytes);
+ buf = (char *)buf + bytes;
+ bufsize -= bytes;
+ }
+ return slen == 0 && bufsize == 0;
+}
+
+static void encode_8_chars(char *dest, const uint8_t *buf, int bytes)
+{
+ beint64_t val = 0;
+ uint64_t res;
+ int bits = bytes * 8;
+ static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+
+ assert(bytes > 0 && bytes <= 5);
+ memcpy((char *)&val + 3, buf, bytes);
+ res = be64_to_cpu(val);
+
+ while (bits > 0) {
+ *dest = enc[(res >> 35) & 0x1F];
+ dest++;
+ res <<= 5;
+ bits -= 5;
+ }
+
+ if (bytes != 5)
+ memset(dest, '=', padlen(bytes));
+}
+
+bool base32_encode(const void *buf, size_t bufsize, char *dest, size_t destsize)
+{
+ while (bufsize) {
+ int bytes = 5;
+
+ if (bytes > bufsize)
+ bytes = bufsize;
+
+ if (destsize < 8)
+ return false;
+ encode_8_chars(dest, buf, bytes);
+ buf = (const char *)buf + bytes;
+ bufsize -= bytes;
+ destsize -= 8;
+ dest += 8;
+ }
+ if (destsize != 1)
+ return false;
+ *dest = '\0';
+ return true;
+}
--- /dev/null
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_STR_BASE32_H
+#define CCAN_STR_BASE32_H
+#include "config.h"
+#include <stdbool.h>
+#include <stdlib.h>
+
+/**
+ * base32_decode - Unpack a base32 string.
+ * @str: the base32 string
+ * @slen: the length of @str
+ * @buf: the buffer to write the data into
+ * @bufsize: the length of @buf
+ *
+ * Returns false if there are any characters which aren't valid encodings
+ * or the string wasn't the right length for @bufsize.
+ *
+ * Example:
+ * unsigned char data[20];
+ *
+ * if (!base32_decode(argv[1], strlen(argv[1]), data, 20))
+ * printf("String is malformed!\n");
+ */
+bool base32_decode(const char *str, size_t slen, void *buf, size_t bufsize);
+
+/**
+ * base32_encode - Create a nul-terminated base32 string
+ * @buf: the buffer to read the data from
+ * @bufsize: the length of @buf
+ * @dest: the string to fill
+ * @destsize: the max size of the string
+ *
+ * Returns true if the string, including terminator, fits in @destsize;
+ *
+ * Example:
+ * unsigned char buf[] = { 'f', 'o' };
+ * char str[9];
+ *
+ * if (!base32_encode(buf, sizeof(buf), str, sizeof(str)))
+ * abort();
+ */
+bool base32_encode(const void *buf, size_t bufsize, char *dest, size_t destsize);
+
+/**
+ * base32_str_size - Calculate how big a nul-terminated base32 string is
+ * @bytes: bytes of data to represent
+ *
+ * Example:
+ * unsigned char buf[] = { 'f', 'o' };
+ * char str[base32_str_size(sizeof(buf))];
+ *
+ * base32_encode(buf, sizeof(buf), str, sizeof(str));
+ */
+size_t base32_str_size(size_t bytes);
+
+/**
+ * base32_data_size - Calculate how many bytes of data in a base32 string
+ * @str: the string
+ * @strlen: the length of str to examine.
+ *
+ * Example:
+ * const char str[] = "MZXQ====";
+ * unsigned char buf[base32_data_size(str, strlen(str))];
+ *
+ * base32_decode(str, strlen(str), buf, sizeof(buf));
+ */
+size_t base32_data_size(const char *str, size_t strlen);
+#endif /* CCAN_STR_BASE32_H */
--- /dev/null
+#include <ccan/str/base32/base32.h>
+/* Include the C files directly. */
+#include <ccan/str/base32/base32.c>
+#include <ccan/tap/tap.h>
+
+static void test(const char *data, const char *b32)
+{
+ char test[1000];
+
+ ok1(base32_str_size(strlen(data)) == strlen(b32) + 1);
+ ok1(base32_data_size(b32, strlen(b32)) == strlen(data));
+ ok1(base32_encode(data, strlen(data), test, strlen(b32)+1));
+ ok1(strcmp(test, b32) == 0);
+ test[strlen(data)] = '\0';
+ ok1(base32_decode(b32, strlen(b32), test, strlen(data)));
+ ok1(strcmp(test, data) == 0);
+}
+
+int main(void)
+{
+ /* This is how many tests you plan to run */
+ plan_tests(8 * 6);
+
+ /* Test vectors from RFC */
+ test("", "");
+ test("f", "MY======");
+ test("fo", "MZXQ====");
+ test("foo", "MZXW6===");
+ test("foob", "MZXW6YQ=");
+ test("fooba", "MZXW6YTB");
+ test("r", "OI======");
+ test("foobar", "MZXW6YTBOI======");
+
+ /* This exits depending on whether all tests passed */
+ return exit_status();
+}