#include <ccan/endian/endian.h>
#include <string.h> /* for memcpy, memset */
+const char *base32_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=";
+
/* RFC 4648:
*
* (1) The final quantum of encoding input is an integral multiple of 40
size_t max = (strlen + 7) / 8 * 5, padding = 0;
/* Count trailing padding bytes. */
- while (strlen && str[strlen-1] == '=' && padding < 6) {
+ while (strlen && str[strlen-1] == base32_chars[32] && padding < 6) {
strlen--;
padding++;
}
uint64_t acc = 0;
size_t num_pad = 0;
for (int i = 0; i < 8; i++) {
- uint8_t val;
+ const char *p;
+
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
+ p = memchr(base32_chars, c[i], 32);
+ if (!p) {
+ if (c[i] == base32_chars[32]) {
+ num_pad++;
+ continue;
+ }
return false;
+ }
/* Can't have padding then non-pad */
if (num_pad)
return false;
- acc |= val;
+ acc |= (p - base32_chars);
}
*res = cpu_to_be64(acc);
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 = base32_chars[(res >> 35) & 0x1F];
dest++;
res <<= 5;
bits -= 5;
}
if (bytes != 5)
- memset(dest, '=', padlen(bytes));
+ memset(dest, base32_chars[32], padlen(bytes));
}
bool base32_encode(const void *buf, size_t bufsize, char *dest, size_t destsize)
* base32_decode(str, strlen(str), buf, sizeof(buf));
*/
size_t base32_data_size(const char *str, size_t strlen);
+
+/**
+ * base32_chars - the encoding/decoding array to use.
+ *
+ * It must be at least 33 characters long, representing 32 values and
+ * the pad value. The default array is "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=".
+ */
+extern const char *base32_chars;
+
#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);
+
+ base32_chars = "abcdefghijklmnopqrstuvwxyz234567=";
+
+ /* Test vectors from RFC, but lower-case */
+ 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();
+}