0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
},
};
+
+/*
+ * "base64url" encoding scheme (RFC 4648, Section 5)
+ */
+
+struct base64_scheme base64url_scheme = {
+ .encmap = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '-', '_',
+ },
+ .decmap = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0-7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 8-15 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16-23 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 24-31 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32-39 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, /* 40-47 */
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, /* 48-55 */
+ 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 56-63 */
+ 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* 64-71 */
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, /* 72-79 */
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* 80-87 */
+ 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0x3f, /* 88-95 */
+ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* 96-103 */
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* 104-111 */
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, /* 112-119 */
+ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, /* 120-127 */
+
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128-255 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+};
#include "str.h"
#include "base64.h"
-
static void test_base64_encode(void)
{
const struct {
{ "hello world", "aGVsbG8gd29ybGQ=" },
{ "foo barits", "Zm9vIGJhcml0cw==" },
{ "just niin", "anVzdCBuaWlu" },
+ { "\xe7\x8c\xbf\xe3\x82\x82\xe6\x9c\xa8\xe3\x81\x8b"
+ "\xe3\x82\x89\xe8\x90\xbd\xe3\x81\xa1\xe3\x82\x8b",
+ "54y/44KC5pyo44GL44KJ6JC944Gh44KL" },
+ { "\xe8\xa7\x92\xe3\x82\x92\xe7\x9f\xaf\xe3\x82\x81\xe3\x81"
+ "\xa6\xe7\x89\x9b\xe3\x82\x92\xe6\xae\xba\xe3\x81\x99",
+ "6KeS44KS55+v44KB44Gm54mb44KS5q6644GZ" },
};
string_t *str;
unsigned int i;
"hel", -1, 4 },
{ "aGVs!!!!!",
"hel", -1, 4 },
+ { "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
+ "C+INC60YPRgCDQtNC+0Y/MgdGCLg==",
+ "\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
+ "\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
+ "\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
+ "\x81\xd1\x82\x2e", 0, UINT_MAX },
};
string_t *str;
buffer_t buf;
test_end();
}
+static void test_base64url_encode(void)
+{
+ const struct {
+ const char *input;
+ const char *output;
+ } tests[] = {
+ { "hello world", "aGVsbG8gd29ybGQ=" },
+ { "foo barits", "Zm9vIGJhcml0cw==" },
+ { "just niin", "anVzdCBuaWlu" },
+ { "\xe7\x8c\xbf\xe3\x82\x82\xe6\x9c\xa8\xe3\x81\x8b"
+ "\xe3\x82\x89\xe8\x90\xbd\xe3\x81\xa1\xe3\x82\x8b",
+ "54y_44KC5pyo44GL44KJ6JC944Gh44KL" },
+ { "\xe8\xa7\x92\xe3\x82\x92\xe7\x9f\xaf\xe3\x82\x81\xe3\x81"
+ "\xa6\xe7\x89\x9b\xe3\x82\x92\xe6\xae\xba\xe3\x81\x99",
+ "6KeS44KS55-v44KB44Gm54mb44KS5q6644GZ" },
+ };
+ string_t *str;
+ unsigned int i;
+
+ test_begin("base64url_encode()");
+ str = t_str_new(256);
+ for (i = 0; i < N_ELEMENTS(tests); i++) {
+ str_truncate(str, 0);
+ base64url_encode(tests[i].input, strlen(tests[i].input), str);
+ test_assert_idx(strcmp(tests[i].output, str_c(str)) == 0, i);
+ test_assert_idx(
+ str_len(str) == MAX_BASE64_ENCODED_SIZE(
+ strlen(tests[i].input)), i);
+ }
+ test_end();
+}
+
+struct test_base64url_decode {
+ const char *input;
+ const char *output;
+ int ret;
+ unsigned int src_pos;
+};
+
+static void test_base64url_decode(void)
+{
+ static const struct test_base64url_decode tests[] = {
+ { "\taGVsbG8gd29ybGQ=",
+ "hello world", 0, UINT_MAX },
+ { "\nZm9v\n \tIGJh \t\ncml0cw==",
+ "foo barits", 0, UINT_MAX },
+ { " anVzdCBuaWlu \n",
+ "just niin", 1, UINT_MAX },
+ { "aGVsb",
+ "hel", 1, 4 },
+ { "aGVsb!!!!!",
+ "hel", -1, 4 },
+ { "aGVs!!!!!",
+ "hel", -1, 4 },
+ { "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
+ "C-INC60YPRgCDQtNC-0Y_MgdGCLg==",
+ "\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
+ "\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
+ "\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
+ "\x81\xd1\x82\x2e", 0, UINT_MAX },
+ };
+ string_t *str;
+ unsigned int i;
+ size_t src_pos;
+ int ret;
+
+ test_begin("base64url_decode()");
+ str = t_str_new(256);
+ for (i = 0; i < N_ELEMENTS(tests); i++) {
+ str_truncate(str, 0);
+
+ src_pos = 0;
+ ret = base64url_decode(tests[i].input, strlen(tests[i].input),
+ &src_pos, str);
+
+ test_assert_idx(tests[i].ret == ret, i);
+ test_assert_idx(strcmp(tests[i].output, str_c(str)) == 0, i);
+ test_assert_idx(src_pos == tests[i].src_pos ||
+ (tests[i].src_pos == UINT_MAX &&
+ src_pos == strlen(tests[i].input)), i);
+ if (ret >= 0) {
+ test_assert_idx(
+ str_len(str) <= MAX_BASE64_DECODED_SIZE(
+ strlen(tests[i].input)), i);
+ }
+ }
+ test_end();
+}
+
+static void test_base64url_random(void)
+{
+ string_t *str, *dest;
+ char buf[10];
+ unsigned int i, j, max;
+
+ str = t_str_new(256);
+ dest = t_str_new(256);
+
+ test_begin("base64url encode/decode with random input");
+ for (i = 0; i < 1000; i++) {
+ max = i_rand_limit(sizeof(buf));
+ for (j = 0; j < max; j++)
+ buf[j] = i_rand();
+
+ str_truncate(str, 0);
+ str_truncate(dest, 0);
+ base64url_encode(buf, max, str);
+ test_assert_idx(base64url_decode(str_data(str), str_len(str),
+ NULL, dest) >= 0, i);
+ test_assert_idx(str_len(dest) == max &&
+ memcmp(buf, str_data(dest), max) == 0, i);
+ }
+ test_end();
+}
+
void test_base64(void)
{
test_base64_encode();
test_base64_decode();
test_base64_random();
+ test_base64url_encode();
+ test_base64url_decode();
+ test_base64url_random();
}