Commit a8f32342 authored by Rusty Russell's avatar Rusty Russell

base32: add ability to substitute character set.

Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 61aee192
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include <ccan/endian/endian.h> #include <ccan/endian/endian.h>
#include <string.h> /* for memcpy, memset */ #include <string.h> /* for memcpy, memset */
const char *base32_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=";
/* RFC 4648: /* RFC 4648:
* *
* (1) The final quantum of encoding input is an integral multiple of 40 * (1) The final quantum of encoding input is an integral multiple of 40
...@@ -56,7 +58,7 @@ size_t base32_data_size(const char *str, size_t strlen) ...@@ -56,7 +58,7 @@ size_t base32_data_size(const char *str, size_t strlen)
size_t max = (strlen + 7) / 8 * 5, padding = 0; size_t max = (strlen + 7) / 8 * 5, padding = 0;
/* Count trailing padding bytes. */ /* Count trailing padding bytes. */
while (strlen && str[strlen-1] == '=' && padding < 6) { while (strlen && str[strlen-1] == base32_chars[32] && padding < 6) {
strlen--; strlen--;
padding++; padding++;
} }
...@@ -69,23 +71,21 @@ static bool decode_8_chars(const char c[8], beint64_t *res, int *bytes) ...@@ -69,23 +71,21 @@ static bool decode_8_chars(const char c[8], beint64_t *res, int *bytes)
uint64_t acc = 0; uint64_t acc = 0;
size_t num_pad = 0; size_t num_pad = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
uint8_t val; const char *p;
acc <<= 5; acc <<= 5;
if (c[i] >= 'a' && c[i] <= 'z') p = memchr(base32_chars, c[i], 32);
val = c[i] - 'a'; if (!p) {
else if (c[i] >= 'A' && c[i] <= 'Z') if (c[i] == base32_chars[32]) {
val = c[i] - 'A';
else if (c[i] >= '2' && c[i] <= '7')
val = c[i] - '2' + 26;
else if (c[i] == '=') {
num_pad++; num_pad++;
continue; continue;
} else }
return false; return false;
}
/* Can't have padding then non-pad */ /* Can't have padding then non-pad */
if (num_pad) if (num_pad)
return false; return false;
acc |= val; acc |= (p - base32_chars);
} }
*res = cpu_to_be64(acc); *res = cpu_to_be64(acc);
...@@ -120,21 +120,20 @@ static void encode_8_chars(char *dest, const uint8_t *buf, int bytes) ...@@ -120,21 +120,20 @@ static void encode_8_chars(char *dest, const uint8_t *buf, int bytes)
beint64_t val = 0; beint64_t val = 0;
uint64_t res; uint64_t res;
int bits = bytes * 8; int bits = bytes * 8;
static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
assert(bytes > 0 && bytes <= 5); assert(bytes > 0 && bytes <= 5);
memcpy((char *)&val + 3, buf, bytes); memcpy((char *)&val + 3, buf, bytes);
res = be64_to_cpu(val); res = be64_to_cpu(val);
while (bits > 0) { while (bits > 0) {
*dest = enc[(res >> 35) & 0x1F]; *dest = base32_chars[(res >> 35) & 0x1F];
dest++; dest++;
res <<= 5; res <<= 5;
bits -= 5; bits -= 5;
} }
if (bytes != 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) bool base32_encode(const void *buf, size_t bufsize, char *dest, size_t destsize)
......
...@@ -65,4 +65,13 @@ size_t base32_str_size(size_t bytes); ...@@ -65,4 +65,13 @@ size_t base32_str_size(size_t bytes);
* base32_decode(str, strlen(str), buf, sizeof(buf)); * base32_decode(str, strlen(str), buf, sizeof(buf));
*/ */
size_t base32_data_size(const char *str, size_t strlen); 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 */ #endif /* CCAN_STR_BASE32_H */
#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();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment