summaryrefslogtreecommitdiffstats
path: root/src/lib/test-base64.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/test-base64.c')
-rw-r--r--src/lib/test-base64.c1317
1 files changed, 1317 insertions, 0 deletions
diff --git a/src/lib/test-base64.c b/src/lib/test-base64.c
new file mode 100644
index 0000000..d024890
--- /dev/null
+++ b/src/lib/test-base64.c
@@ -0,0 +1,1317 @@
+/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
+
+#include "test-lib.h"
+#include "str.h"
+#include "base64.h"
+
+static void test_base64_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("base64_encode()");
+ str = t_str_new(256);
+ for (i = 0; i < N_ELEMENTS(tests); i++) {
+ str_truncate(str, 0);
+ base64_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_base64_decode {
+ const char *input;
+ const char *output;
+ int ret;
+};
+
+static void test_base64_decode(void)
+{
+ static const struct test_base64_decode tests[] = {
+ { "", "", 0 },
+ { "\taGVsbG8gd29ybGQ=",
+ "hello world", 0 },
+ { "\nZm9v\n \tIGJh \t\ncml0cw==",
+ "foo barits", 0 },
+ { " anVzdCBuaWlu \n",
+ "just niin", 0 },
+ { "aGVsb",
+ "hel", -1 },
+ { "aGVsb!!!!!",
+ "hel", -1 },
+ { "aGVs!!!!!",
+ "hel", -1 },
+ { "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 },
+ };
+ string_t *str;
+ buffer_t buf;
+ unsigned int i;
+ int ret;
+
+ test_begin("base64_decode()");
+ for (i = 0; i < N_ELEMENTS(tests); i++) {
+ /* Some of the base64_decode() callers use fixed size buffers.
+ Use a fixed size buffer here as well to test that
+ base64_decode() can't allocate any extra space even
+ temporarily. */
+ size_t max_decoded_size =
+ MAX_BASE64_DECODED_SIZE(strlen(tests[i].input));
+
+ buffer_create_from_data(&buf,
+ (max_decoded_size == 0 ? "" :
+ t_malloc0(max_decoded_size)),
+ max_decoded_size);
+ str = &buf;
+ ret = base64_decode(tests[i].input, strlen(tests[i].input),
+ NULL, str);
+
+ test_assert_idx(tests[i].ret == ret, i);
+ test_assert_idx(strlen(tests[i].output) == str_len(str) &&
+ memcmp(tests[i].output, str_data(str),
+ str_len(str)) == 0, i);
+ if (ret >= 0) {
+ test_assert_idx(
+ str_len(str) <= MAX_BASE64_DECODED_SIZE(
+ strlen(tests[i].input)), i);
+ }
+ }
+ test_end();
+}
+
+static void test_base64_random(void)
+{
+ string_t *str, *dest;
+ unsigned char buf[10];
+ unsigned int i, j, max;
+
+ str = t_str_new(256);
+ dest = t_str_new(256);
+
+ test_begin("base64 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_uchar();
+
+ str_truncate(str, 0);
+ str_truncate(dest, 0);
+ base64_encode(buf, max, str);
+ test_assert_idx(base64_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();
+}
+
+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(0, 0, 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;
+};
+
+static void test_base64url_decode(void)
+{
+ static const struct test_base64url_decode tests[] = {
+ { "", "", 0 },
+ { "\taGVsbG8gd29ybGQ=",
+ "hello world", 0 },
+ { "\nZm9v\n \tIGJh \t\ncml0cw==",
+ "foo barits", 0 },
+ { " anVzdCBuaWlu \n",
+ "just niin", 0 },
+ { "aGVsb",
+ "hel", -1 },
+ { "aGVsb!!!!!",
+ "hel", -1 },
+ { "aGVs!!!!!",
+ "hel", -1 },
+ { "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 },
+ };
+ string_t *str;
+ buffer_t buf;
+ unsigned int i;
+ int ret;
+
+ test_begin("base64url_decode()");
+ for (i = 0; i < N_ELEMENTS(tests); i++) {
+ /* Some of the base64_decode() callers use fixed size buffers.
+ Use a fixed size buffer here as well to test that
+ base64_decode() can't allocate any extra space even
+ temporarily. */
+ size_t max_decoded_size =
+ MAX_BASE64_DECODED_SIZE(strlen(tests[i].input));
+
+ buffer_create_from_data(&buf,
+ (max_decoded_size == 0 ? "" :
+ t_malloc0(max_decoded_size)),
+ max_decoded_size);
+ str = &buf;
+ ret = base64url_decode(0, tests[i].input,
+ strlen(tests[i].input), str);
+
+ test_assert_idx(tests[i].ret == ret, i);
+ test_assert_idx(strlen(tests[i].output) == str_len(str) &&
+ memcmp(tests[i].output, str_data(str),
+ str_len(str)) == 0, 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;
+ unsigned 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_uchar();
+
+ str_truncate(str, 0);
+ str_truncate(dest, 0);
+ base64url_encode(0, 0, buf, max, str);
+ test_assert_idx(base64url_decode(0, str_data(str), str_len(str),
+ dest) >= 0, i);
+ test_assert_idx(str_len(dest) == max &&
+ memcmp(buf, str_data(dest), max) == 0, i);
+ }
+ test_end();
+}
+
+struct test_base64_encode_lowlevel {
+ const struct base64_scheme *scheme;
+ enum base64_encode_flags flags;
+ size_t max_line_len;
+
+ const char *input;
+ const char *output;
+};
+
+static const struct test_base64_encode_lowlevel
+tests_base64_encode_lowlevel[] = {
+ {
+ .scheme = &base64_scheme,
+ .input = "",
+ .output = "",
+ },
+ {
+ .scheme = &base64_scheme,
+ .max_line_len = 2,
+ .input = "",
+ .output = "",
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_ENCODE_FLAG_CRLF,
+ .max_line_len = 2,
+ .input = "",
+ .output = "",
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_ENCODE_FLAG_NO_PADDING,
+ .input = "",
+ .output = "",
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "hello world",
+ .output = "aGVsbG8gd29ybGQ=",
+ },
+ {
+ .scheme = &base64url_scheme,
+ .input = "hello world",
+ .output = "aGVsbG8gd29ybGQ=",
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_ENCODE_FLAG_NO_PADDING,
+ .input = "hello world",
+ .output = "aGVsbG8gd29ybGQ",
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "foo barits",
+ .output = "Zm9vIGJhcml0cw==",
+ },
+ {
+ .scheme = &base64url_scheme,
+ .input = "foo barits",
+ .output = "Zm9vIGJhcml0cw==",
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_ENCODE_FLAG_NO_PADDING,
+ .input = "foo barits",
+ .output = "Zm9vIGJhcml0cw",
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "just niin",
+ .output = "anVzdCBuaWlu",
+ },
+ {
+ .scheme = &base64url_scheme,
+ .input = "just niin",
+ .output = "anVzdCBuaWlu",
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_ENCODE_FLAG_NO_PADDING,
+ .input = "just niin",
+ .output = "anVzdCBuaWlu",
+ },
+ {
+ .scheme = &base64_scheme,
+ .input =
+ "\xe7\x8c\xbf\xe3\x82\x82\xe6\x9c\xa8\xe3\x81\x8b"
+ "\xe3\x82\x89\xe8\x90\xbd\xe3\x81\xa1\xe3\x82\x8b",
+ .output = "54y/44KC5pyo44GL44KJ6JC944Gh44KL",
+ },
+ {
+ .scheme = &base64url_scheme,
+ .input =
+ "\xe7\x8c\xbf\xe3\x82\x82\xe6\x9c\xa8\xe3\x81\x8b"
+ "\xe3\x82\x89\xe8\x90\xbd\xe3\x81\xa1\xe3\x82\x8b",
+ .output = "54y_44KC5pyo44GL44KJ6JC944Gh44KL",
+ },
+ {
+ .scheme = &base64_scheme,
+ .input =
+ "\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",
+ .output = "6KeS44KS55+v44KB44Gm54mb44KS5q6644GZ",
+ },
+ {
+ .scheme = &base64url_scheme,
+ .input =
+ "\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",
+ .output = "6KeS44KS55-v44KB44Gm54mb44KS5q6644GZ",
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_ENCODE_FLAG_CRLF,
+ .input = "just niin",
+ .output = "anVzdCBuaWlu",
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_ENCODE_FLAG_CRLF,
+ .max_line_len = 80,
+ .input = "just niin",
+ .output = "anVzdCBuaWlu",
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_ENCODE_FLAG_CRLF,
+ .max_line_len = 48,
+ .input =
+ "Passer, deliciae meae puellae,\n"
+ "quicum ludere, quem in sinu tenere,\n"
+ "cui primum digitum dare appetenti\n"
+ "et acris solet incitare morsus,\n"
+ "cum desiderio meo nitenti\n"
+ "carum nescio quid lubet iocari,\n"
+ "credo ut, cum gravis acquiescet ardor,\n"
+ "sit solaciolum sui doloris,\n"
+ "tecum ludere sicut ipsa possem\n"
+ "et tristis animi levare curas!\n",
+ .output =
+ "UGFzc2VyLCBkZWxpY2lhZSBtZWFlIHB1ZWxsYWUsCnF1aWN1\r\n"
+ "bSBsdWRlcmUsIHF1ZW0gaW4gc2ludSB0ZW5lcmUsCmN1aSBw\r\n"
+ "cmltdW0gZGlnaXR1bSBkYXJlIGFwcGV0ZW50aQpldCBhY3Jp\r\n"
+ "cyBzb2xldCBpbmNpdGFyZSBtb3JzdXMsCmN1bSBkZXNpZGVy\r\n"
+ "aW8gbWVvIG5pdGVudGkKY2FydW0gbmVzY2lvIHF1aWQgbHVi\r\n"
+ "ZXQgaW9jYXJpLApjcmVkbyB1dCwgY3VtIGdyYXZpcyBhY3F1\r\n"
+ "aWVzY2V0IGFyZG9yLApzaXQgc29sYWNpb2x1bSBzdWkgZG9s\r\n"
+ "b3JpcywKdGVjdW0gbHVkZXJlIHNpY3V0IGlwc2EgcG9zc2Vt\r\n"
+ "CmV0IHRyaXN0aXMgYW5pbWkgbGV2YXJlIGN1cmFzIQo=",
+ },
+ {
+ .scheme = &base64_scheme,
+ .max_line_len = 48,
+ .input =
+ "Lugete, o Veneres Cupidinesque,\n"
+ "et quantum est hominum venustiorum:\n"
+ "passer mortuus est meae puellae, \n"
+ "passer, deliciae meae puellae\n"
+ "quem plus amat illa oculis suis amabat.\n"
+ "Nam mellitus erat suamque norat\n"
+ "ipsam tam bene quam puella matrem,\n"
+ "nec sese a gremio illius movebat,\n"
+ "sed circumsiliens modo huc modo illuc\n"
+ "ad solam dominam usque pipiabat;\n"
+ "qui nunc it per iter tenebricosum\n"
+ "illuc, unde negant redire quemquam.\n"
+ "At vobis male sint, malae tenebrae\n"
+ "Orci, quae omnia bella devoratis:\n"
+ "tam bellum mihi passerem abstulistis.\n"
+ "O factum male! O miselle passer!\n"
+ "Tua nunc opera meae puellae\n"
+ "flendo turgiduli rubent ocelli.\n",
+ .output =
+ "THVnZXRlLCBvIFZlbmVyZXMgQ3VwaWRpbmVzcXVlLApldCBx\n"
+ "dWFudHVtIGVzdCBob21pbnVtIHZlbnVzdGlvcnVtOgpwYXNz\n"
+ "ZXIgbW9ydHV1cyBlc3QgbWVhZSBwdWVsbGFlLCAKcGFzc2Vy\n"
+ "LCBkZWxpY2lhZSBtZWFlIHB1ZWxsYWUKcXVlbSBwbHVzIGFt\n"
+ "YXQgaWxsYSBvY3VsaXMgc3VpcyBhbWFiYXQuCk5hbSBtZWxs\n"
+ "aXR1cyBlcmF0IHN1YW1xdWUgbm9yYXQKaXBzYW0gdGFtIGJl\n"
+ "bmUgcXVhbSBwdWVsbGEgbWF0cmVtLApuZWMgc2VzZSBhIGdy\n"
+ "ZW1pbyBpbGxpdXMgbW92ZWJhdCwKc2VkIGNpcmN1bXNpbGll\n"
+ "bnMgbW9kbyBodWMgbW9kbyBpbGx1YwphZCBzb2xhbSBkb21p\n"
+ "bmFtIHVzcXVlIHBpcGlhYmF0OwpxdWkgbnVuYyBpdCBwZXIg\n"
+ "aXRlciB0ZW5lYnJpY29zdW0KaWxsdWMsIHVuZGUgbmVnYW50\n"
+ "IHJlZGlyZSBxdWVtcXVhbS4KQXQgdm9iaXMgbWFsZSBzaW50\n"
+ "LCBtYWxhZSB0ZW5lYnJhZQpPcmNpLCBxdWFlIG9tbmlhIGJl\n"
+ "bGxhIGRldm9yYXRpczoKdGFtIGJlbGx1bSBtaWhpIHBhc3Nl\n"
+ "cmVtIGFic3R1bGlzdGlzLgpPIGZhY3R1bSBtYWxlISBPIG1p\n"
+ "c2VsbGUgcGFzc2VyIQpUdWEgbnVuYyBvcGVyYSBtZWFlIHB1\n"
+ "ZWxsYWUKZmxlbmRvIHR1cmdpZHVsaSBydWJlbnQgb2NlbGxp\n"
+ "Lgo=",
+ },
+};
+
+static void test_base64_encode_lowlevel(void)
+{
+ string_t *str;
+ unsigned int i;
+
+ test_begin("base64 encode low-level");
+ str = t_str_new(256);
+ for (i = 0; i < N_ELEMENTS(tests_base64_encode_lowlevel); i++) {
+ const struct test_base64_encode_lowlevel *test =
+ &tests_base64_encode_lowlevel[i];
+ struct base64_encoder enc;
+ uoff_t out_size;
+
+ str_truncate(str, 0);
+
+ base64_encode_init(&enc, test->scheme, test->flags,
+ test->max_line_len);
+ out_size = base64_get_full_encoded_size(
+ &enc, strlen(test->input));
+ test_assert_idx(base64_encode_more(&enc, test->input,
+ strlen(test->input),
+ NULL, str), i);
+ test_assert_idx(base64_encode_finish(&enc, str), i);
+
+ test_assert_idx(strcmp(test->output, str_c(str)) == 0, i);
+ test_assert_idx(test->flags != 0 || test->max_line_len != 0 ||
+ str_len(str) == MAX_BASE64_ENCODED_SIZE(
+ strlen(test->input)), i);
+ test_assert_idx(str_len(str) == out_size, i);
+ }
+ test_end();
+}
+
+struct test_base64_decode_lowlevel {
+ const struct base64_scheme *scheme;
+ enum base64_decode_flags flags;
+
+ const char *input;
+ const char *output;
+ int ret;
+ unsigned int src_pos;
+};
+
+static const struct test_base64_decode_lowlevel
+tests_base64_decode_lowlevel[] = {
+ {
+ .scheme = &base64_scheme,
+ .input = "",
+ .output = "",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = " ",
+ .output = "",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "",
+ .output = "",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ .flags = BASE64_DECODE_FLAG_EXPECT_BOUNDARY,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "",
+ .output = "",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ .flags = BASE64_DECODE_FLAG_NO_WHITESPACE,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = " ",
+ .output = "",
+ .ret = -1,
+ .src_pos = 0,
+ .flags = BASE64_DECODE_FLAG_NO_WHITESPACE,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "",
+ .output = "",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ .flags = BASE64_DECODE_FLAG_NO_PADDING,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "",
+ .output = "",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "\taGVsbG8gd29ybGQ=",
+ .output = "hello world",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64url_scheme,
+ .input = "\taGVsbG8gd29ybGQ=",
+ .output = "hello world",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "aGVsbG8gd29ybGQ=\t",
+ .output = "hello world",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "\taGVsbG8gd29ybGQ=\t",
+ .output = "hello world",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "aGVsbG8gd29ybGQ=:frop",
+ .output = "hello world",
+ .ret = 0,
+ .src_pos = 16,
+ .flags = BASE64_DECODE_FLAG_EXPECT_BOUNDARY,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "\taGVsbG8gd29ybGQ=\t:frop",
+ .output = "hello world",
+ .ret = 0,
+ .src_pos = 18,
+ .flags = BASE64_DECODE_FLAG_EXPECT_BOUNDARY,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "aGVsbG8gd29ybGQ=\t",
+ .output = "hello world",
+ .ret = -1,
+ .src_pos = 16,
+ .flags = BASE64_DECODE_FLAG_NO_WHITESPACE,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "\taGVsbG8gd29ybGQ=\t",
+ .output = "",
+ .ret = -1,
+ .src_pos = 0,
+ .flags = BASE64_DECODE_FLAG_NO_WHITESPACE,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_NO_PADDING,
+ .input = "\taGVsbG8gd29ybGQ=",
+ .output = "hello world",
+ .ret = -1,
+ .src_pos = 16,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_NO_PADDING,
+ .input = "\taGVsbG8gd29ybGQ",
+ .output = "hello world",
+ .ret = 0,
+ .src_pos = 16,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
+ .input = "\taGVsbG8gd29ybGQ=",
+ .output = "hello world",
+ .ret = 0,
+ .src_pos = 17,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
+ .input = "\taGVsbG8gd29ybGQ",
+ .output = "hello world",
+ .ret = 0,
+ .src_pos = 16,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "\nZm9v\n \tIGJh \t\ncml0cw==",
+ .output = "foo barits",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64url_scheme,
+ .input = "\nZm9v\n \tIGJh \t\ncml0cw==",
+ .output = "foo barits",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "\nZm9v\n \tIGJh \t\ncml0cw==\n ",
+ .output = "foo barits",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "\nZm9v\n \tIGJh \t\ncml0cw= =\n ",
+ .output = "foo barits",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "\nZm9v\n \tIGJh \t\ncml0cw\n= =\n ",
+ .output = "foo barits",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_NO_PADDING,
+ .input = "\nZm9v\n \tIGJh \t\ncml0cw==",
+ .output = "foo barits",
+ .ret = -1,
+ .src_pos = 22,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_NO_PADDING,
+ .input = "\nZm9v\n \tIGJh \t\ncml0cw",
+ .output = "foo barits",
+ .ret = 0,
+ .src_pos = 22,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
+ .input = "\nZm9v\n \tIGJh \t\ncml0cw==",
+ .output = "foo barits",
+ .ret = 0,
+ .src_pos = 24,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
+ .input = "\nZm9v\n \tIGJh \t\ncml0cw",
+ .output = "foo barits",
+ .ret = 0,
+ .src_pos = 22,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = " anVzdCBuaWlu \n",
+ .output = "just niin",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64url_scheme,
+ .input = " anVzdCBuaWlu \n",
+ .output = "just niin",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_NO_PADDING,
+ .input = " anVzdCBuaWlu \n",
+ .output = "just niin",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
+ .input = " anVzdCBuaWlu \n",
+ .output = "just niin",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "aGVsb",
+ .output = "hel",
+ .ret = -1,
+ .src_pos = 5,
+ },
+ {
+ .scheme = &base64url_scheme,
+ .input = "aGVsb",
+ .output = "hel",
+ .ret = -1,
+ .src_pos = 5,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_NO_PADDING,
+ .input = "aGVsb",
+ .output = "hel",
+ .ret = 0,
+ .src_pos = 5,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
+ .input = "aGVsb",
+ .output = "hel",
+ .ret = 0,
+ .src_pos = 5,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "aGVsb!!!!!",
+ .output = "hel",
+ .ret = -1,
+ .src_pos = 5,
+ },
+ {
+ .scheme = &base64url_scheme,
+ .input = "aGVsb!!!!!",
+ .output = "hel",
+ .ret = -1,
+ .src_pos = 5,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input = "aGVs!!!!!",
+ .output = "hel",
+ .ret = -1,
+ .src_pos = 4,
+ },
+ {
+ .scheme = &base64url_scheme,
+ .input = "aGVs!!!!!",
+ .output = "hel",
+ .ret = -1,
+ .src_pos = 4,
+ },
+ {
+ .scheme = &base64_scheme,
+ .input =
+ "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
+ "C+INC60YPRgCDQtNC+0Y/MgdGCLg==",
+ .output =
+ "\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",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64url_scheme,
+ .input =
+ "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
+ "C-INC60YPRgCDQtNC-0Y_MgdGCLg==",
+ .output =
+ "\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",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_NO_PADDING,
+ .input =
+ "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
+ "C+INC60YPRgCDQtNC+0Y/MgdGCLg",
+ .output =
+ "\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",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
+ .input =
+ "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
+ "C+INC60YPRgCDQtNC+0Y/MgdGCLg",
+ .output =
+ "\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",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+ {
+ .scheme = &base64_scheme,
+ .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
+ .input =
+ "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
+ "C+INC60YPRgCDQtNC+0Y/MgdGCLg==",
+ .output =
+ "\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",
+ .ret = 0,
+ .src_pos = UINT_MAX,
+ },
+};
+
+static void test_base64_decode_lowlevel(void)
+{
+ string_t *str;
+ buffer_t buf;
+ unsigned int i;
+
+ test_begin("base64 decode low-level");
+ for (i = 0; i < N_ELEMENTS(tests_base64_decode_lowlevel); i++) {
+ const struct test_base64_decode_lowlevel *test =
+ &tests_base64_decode_lowlevel[i];
+ struct base64_decoder dec;
+ size_t src_pos;
+ int ret;
+
+ /* Some of the base64_decode() callers use fixed size buffers.
+ Use a fixed size buffer here as well to test that
+ base64_decode() can't allocate any extra space even
+ temporarily. */
+ size_t max_decoded_size =
+ MAX_BASE64_DECODED_SIZE(strlen(test->input));
+
+ buffer_create_from_data(&buf,
+ (max_decoded_size == 0 ? "" :
+ t_malloc0(max_decoded_size)),
+ max_decoded_size);
+ str = &buf;
+ base64_decode_init(&dec, test->scheme, test->flags);
+ ret = base64_decode_more(&dec, test->input, strlen(test->input),
+ &src_pos, str);
+ if (ret >= 0)
+ ret = base64_decode_finish(&dec);
+
+ test_assert_idx(ret == test->ret, i);
+ test_assert_idx(strlen(test->output) == str_len(str) &&
+ memcmp(test->output, str_data(str),
+ str_len(str)) == 0, i);
+ test_assert_idx(src_pos == test->src_pos ||
+ (test->src_pos == UINT_MAX &&
+ src_pos == strlen(test->input)), i);
+ if (ret >= 0) {
+ test_assert_idx(
+ str_len(str) <= MAX_BASE64_DECODED_SIZE(
+ strlen(test->input)), i);
+ }
+ }
+ test_end();
+}
+
+static void
+test_base64_random_lowlevel_one_block(const struct base64_scheme *b64,
+ enum base64_encode_flags enc_flags,
+ enum base64_decode_flags dec_flags,
+ size_t max_line_len,
+ unsigned int test_idx,
+ const unsigned char *in_buf,
+ size_t in_buf_size,
+ buffer_t *buf1, buffer_t *buf2)
+{
+ struct base64_encoder enc;
+ struct base64_decoder dec;
+ void *space;
+ size_t enc_size;
+ buffer_t buf;
+ int ret;
+
+ buffer_set_used_size(buf1, 0);
+ buffer_set_used_size(buf2, 0);
+
+ base64_encode_init(&enc, b64, enc_flags, max_line_len);
+ enc_size = base64_get_full_encoded_size(&enc, in_buf_size);
+ space = buffer_append_space_unsafe(buf1, enc_size);
+ buffer_create_from_data(&buf, space, enc_size);
+
+ if (!base64_encode_more(&enc, in_buf, in_buf_size, NULL, &buf))
+ test_assert_idx(FALSE, test_idx);
+ if (!base64_encode_finish(&enc, &buf))
+ test_assert_idx(FALSE, test_idx);
+
+ test_assert(base64_get_full_encoded_size(&enc, in_buf_size) ==
+ buf1->used);
+
+ base64_decode_init(&dec, b64, dec_flags);
+ space = buffer_append_space_unsafe(buf2, in_buf_size);
+ buffer_create_from_data(&buf, space, in_buf_size);
+
+ ret = base64_decode_more(&dec, buf1->data, buf1->used, NULL, &buf);
+ if (ret >= 0)
+ ret = base64_decode_finish(&dec);
+
+ test_assert_idx(ret >= 0, test_idx);
+ test_assert_idx(buf2->used == in_buf_size &&
+ memcmp(in_buf, buf2->data, in_buf_size) == 0, test_idx);
+}
+
+static void
+test_base64_random_lowlevel_stream(const struct base64_scheme *b64,
+ enum base64_encode_flags enc_flags,
+ enum base64_decode_flags dec_flags,
+ size_t max_line_len, unsigned int test_idx,
+ const unsigned char *in_buf,
+ size_t in_buf_size,
+ buffer_t *buf1, buffer_t *buf2,
+ size_t chunk_size)
+{
+ struct base64_encoder enc;
+ struct base64_decoder dec;
+ const unsigned char *buf_p, *buf_begin, *buf_end;
+ int ret;
+ size_t out_space, out_full_size;
+ void *out_data;
+ buffer_t out;
+
+ /* Encode */
+
+ buffer_set_used_size(buf1, 0);
+
+ buf_begin = in_buf;
+ buf_end = buf_begin + in_buf_size;
+
+ base64_encode_init(&enc, b64, enc_flags, max_line_len);
+ out_full_size = base64_get_full_encoded_size(&enc, in_buf_size);
+ out_space = 0;
+ for (buf_p = buf_begin; buf_p < buf_end; ) {
+ size_t buf_ch, out_ch;
+ size_t left = (buf_end - buf_p);
+ size_t used = buf1->used;
+ size_t src_pos, out_size, src_full_space;
+ bool eres;
+
+ if (chunk_size == 0) {
+ buf_ch = i_rand_limit(32);
+ out_ch = i_rand_limit(32);
+ } else {
+ buf_ch = chunk_size;
+ out_ch = chunk_size;
+ }
+
+ out_space += out_ch;
+ out_data = buffer_append_space_unsafe(buf1, out_space);
+ buffer_create_from_data(&out, out_data, out_space);
+
+ if (buf_ch > left)
+ buf_ch = left;
+
+ src_full_space = base64_encode_get_full_space(
+ &enc, out_full_size - used);
+ test_assert_idx(src_full_space >= (size_t)(buf_end - buf_p),
+ test_idx);
+
+ out_size = base64_encode_get_size(&enc, buf_ch);
+
+ eres = base64_encode_more(&enc, buf_p, buf_ch, &src_pos, &out);
+ test_assert_idx((eres && src_pos == buf_ch) ||
+ (!eres && src_pos < buf_ch), test_idx);
+ test_assert_idx(out.used <= out_size, test_idx);
+ buf_p += src_pos;
+ i_assert(out_space >= out.used);
+ out_space -= out.used;
+ buffer_set_used_size(buf1, used + out.used);
+ }
+ test_assert_idx(base64_encode_finish(&enc, buf1), test_idx);
+
+ /* Verify encode */
+
+ test_assert(out_full_size == buf1->used);
+
+ buffer_set_used_size(buf2, 0);
+ base64_encode_init(&enc, b64, enc_flags, max_line_len);
+ test_assert_idx(base64_encode_more(&enc, in_buf, in_buf_size,
+ NULL, buf2), test_idx);
+ test_assert_idx(base64_encode_finish(&enc, buf2), test_idx);
+ test_assert_idx(buffer_cmp(buf1, buf2), test_idx);
+
+ /* Decode */
+
+ buffer_set_used_size(buf2, 0);
+
+ buf_begin = buf1->data;
+ buf_end = buf_begin + buf1->used;
+
+ base64_decode_init(&dec, b64, dec_flags);
+ ret = 1;
+ out_space = 0;
+ for (buf_p = buf_begin; buf_p < buf_end; ) {
+ size_t buf_ch, out_ch;
+ size_t left = (buf_end - buf_p);
+ size_t used = buf2->used;
+ size_t src_pos;
+
+ if (chunk_size == 0) {
+ buf_ch = i_rand_limit(32);
+ out_ch = i_rand_limit(32);
+ } else {
+ buf_ch = chunk_size;
+ out_ch = chunk_size;
+ }
+
+ out_space += out_ch;
+ out_data = buffer_append_space_unsafe(buf2, out_space);
+ buffer_create_from_data(&out, out_data, out_space);
+
+ if (buf_ch > left)
+ buf_ch = left;
+ ret = base64_decode_more(&dec, buf_p, buf_ch,
+ &src_pos, &out);
+ test_assert_idx(ret >= 0, test_idx);
+ if (ret < 0) {
+ break;
+ }
+ buf_p += src_pos;
+ i_assert(out_space >= out.used);
+ out_space -= out.used;
+ buffer_set_used_size(buf2, used + out.used);
+ }
+ test_assert_idx(ret >= 0, test_idx);
+
+ /* Verify decode */
+ if (ret > 0) {
+ ret = base64_decode_finish(&dec);
+ test_assert_idx(ret == 0, test_idx);
+ test_assert_idx(buf2->used == in_buf_size &&
+ memcmp(in_buf, buf2->data, in_buf_size) == 0,
+ test_idx);
+ }
+}
+
+static void
+test_base64_random_lowlevel_case(const struct base64_scheme *b64,
+ enum base64_encode_flags enc_flags,
+ enum base64_decode_flags dec_flags,
+ size_t max_line_len)
+{
+ unsigned char in_buf[512];
+ size_t in_buf_size;
+ buffer_t *buf1, *buf2;
+ unsigned int i, j;
+
+ if (test_has_failed())
+ return;
+
+ buf1 = t_buffer_create(MAX_BASE64_ENCODED_SIZE(sizeof(in_buf)));
+ buf2 = t_buffer_create(MAX_BASE64_ENCODED_SIZE(sizeof(in_buf)));
+
+ /* one block */
+ for (i = 0; i < 1000; i++) {
+ in_buf_size = i_rand_limit(sizeof(in_buf));
+ for (j = 0; j < in_buf_size; j++)
+ in_buf[j] = i_rand_uchar();
+
+ test_base64_random_lowlevel_one_block(b64, enc_flags, dec_flags,
+ max_line_len, i,
+ in_buf, in_buf_size,
+ buf1, buf2);
+
+ if (test_has_failed()) {
+ i_info("One block test failed ("
+ "enc_flags=%02x dec_flags=%02x "
+ "max_line_len=%zu size=%zu)",
+ enc_flags, dec_flags, max_line_len,
+ in_buf_size);
+ return;
+ }
+ }
+
+ /* streaming; single-byte trickle */
+ for (i = 0; i < 1000; i++) {
+ in_buf_size = i_rand_limit(sizeof(in_buf));
+ for (j = 0; j < in_buf_size; j++)
+ in_buf[j] = i_rand_uchar();
+
+ test_base64_random_lowlevel_stream(b64, enc_flags, dec_flags,
+ max_line_len, i,
+ in_buf, in_buf_size,
+ buf1, buf2, 1);
+
+ if (test_has_failed()) {
+ i_info("Streaming single-byte trickle test failed ("
+ "enc_flags=%02x dec_flags=%02x "
+ "max_line_len=%zu size=%zu)",
+ enc_flags, dec_flags, max_line_len,
+ in_buf_size);
+ return;
+ }
+ }
+
+ /* streaming; random chunks */
+ for (i = 0; i < 1000; i++) {
+ in_buf_size = i_rand_limit(sizeof(in_buf));
+ for (j = 0; j < in_buf_size; j++)
+ in_buf[j] = i_rand_uchar();
+
+ test_base64_random_lowlevel_stream(b64, enc_flags, dec_flags,
+ max_line_len, i,
+ in_buf, in_buf_size,
+ buf1, buf2, 0);
+ if (test_has_failed()) {
+ i_info("Streaming random chunks test failed ("
+ "enc_flags=%02x dec_flags=%02x "
+ "max_line_len=%zu size=%zu)",
+ enc_flags, dec_flags, max_line_len,
+ in_buf_size);
+ return;
+ }
+ }
+}
+
+static void
+test_base64_random_lowlevel(void)
+{
+ test_begin("base64 encode/decode low-level with random input");
+ test_base64_random_lowlevel_case(&base64_scheme, 0, 0, 0);
+ test_base64_random_lowlevel_case(&base64url_scheme, 0, 0, 0);
+ test_base64_random_lowlevel_case(&base64_scheme, 0,
+ BASE64_DECODE_FLAG_EXPECT_BOUNDARY, 0);
+ test_base64_random_lowlevel_case(&base64url_scheme, 0,
+ BASE64_DECODE_FLAG_EXPECT_BOUNDARY, 0);
+ test_base64_random_lowlevel_case(&base64_scheme, 0,
+ BASE64_DECODE_FLAG_NO_WHITESPACE, 0);
+ test_base64_random_lowlevel_case(&base64url_scheme, 0,
+ BASE64_DECODE_FLAG_NO_WHITESPACE, 0);
+ test_base64_random_lowlevel_case(&base64_scheme, 0, 0, 10);
+ test_base64_random_lowlevel_case(&base64url_scheme, 0, 0, 10);
+ test_base64_random_lowlevel_case(&base64_scheme,
+ BASE64_ENCODE_FLAG_CRLF, 0, 10);
+ test_base64_random_lowlevel_case(&base64url_scheme,
+ BASE64_ENCODE_FLAG_CRLF, 0, 10);
+ test_base64_random_lowlevel_case(&base64_scheme,
+ BASE64_ENCODE_FLAG_NO_PADDING,
+ BASE64_DECODE_FLAG_NO_PADDING, 0);
+ test_base64_random_lowlevel_case(&base64url_scheme,
+ BASE64_ENCODE_FLAG_NO_PADDING,
+ BASE64_DECODE_FLAG_NO_PADDING, 0);
+ test_base64_random_lowlevel_case(&base64_scheme,
+ BASE64_ENCODE_FLAG_NO_PADDING |
+ BASE64_ENCODE_FLAG_CRLF,
+ BASE64_DECODE_FLAG_NO_PADDING, 15);
+ test_base64_random_lowlevel_case(&base64url_scheme,
+ BASE64_ENCODE_FLAG_NO_PADDING |
+ BASE64_ENCODE_FLAG_CRLF,
+ BASE64_DECODE_FLAG_NO_PADDING, 15);
+ test_base64_random_lowlevel_case(&base64_scheme,
+ BASE64_ENCODE_FLAG_NO_PADDING |
+ BASE64_ENCODE_FLAG_CRLF,
+ BASE64_DECODE_FLAG_NO_PADDING, 1);
+ test_end();
+}
+
+static void
+_add_lines(const char *in, size_t max_line_len, bool crlf, string_t *out)
+{
+ size_t in_len = strlen(in);
+
+ while (max_line_len > 0 && in_len > max_line_len) {
+ str_append_data(out, in, max_line_len);
+ if (crlf)
+ str_append(out, "\r\n");
+ else
+ str_append_c(out, '\n');
+ in += max_line_len;
+ in_len -= max_line_len;
+ }
+
+ str_append_data(out, in, in_len);
+}
+
+static void test_base64_encode_lines(void)
+{
+ static const char *input[] = {
+ "Passer, deliciae meae puellae,\n"
+ "quicum ludere, quem in sinu tenere,\n"
+ "cui primum digitum dare appetenti\n"
+ "et acris solet incitare morsus,\n"
+ "cum desiderio meo nitenti\n"
+ "carum nescio quid lubet iocari,\n"
+ "credo ut, cum gravis acquiescet ardor,\n"
+ "sit solaciolum sui doloris,\n"
+ "tecum ludere sicut ipsa possem\n"
+ "et tristis animi levare curas!\n"
+ };
+ static const char *output[] = {
+ "UGFzc2VyLCBkZWxpY2lhZSBtZWFlIHB1ZWxsYWUsCnF1aWN1"
+ "bSBsdWRlcmUsIHF1ZW0gaW4gc2ludSB0ZW5lcmUsCmN1aSBw"
+ "cmltdW0gZGlnaXR1bSBkYXJlIGFwcGV0ZW50aQpldCBhY3Jp"
+ "cyBzb2xldCBpbmNpdGFyZSBtb3JzdXMsCmN1bSBkZXNpZGVy"
+ "aW8gbWVvIG5pdGVudGkKY2FydW0gbmVzY2lvIHF1aWQgbHVi"
+ "ZXQgaW9jYXJpLApjcmVkbyB1dCwgY3VtIGdyYXZpcyBhY3F1"
+ "aWVzY2V0IGFyZG9yLApzaXQgc29sYWNpb2x1bSBzdWkgZG9s"
+ "b3JpcywKdGVjdW0gbHVkZXJlIHNpY3V0IGlwc2EgcG9zc2Vt"
+ "CmV0IHRyaXN0aXMgYW5pbWkgbGV2YXJlIGN1cmFzIQo=",
+ };
+ string_t *out_test, *out_ref;
+ unsigned int i, n;
+
+ out_test = t_str_new(256);
+ out_ref = t_str_new(256);
+
+ test_begin("base64 encode lines (LF)");
+ for (i = 0; i < N_ELEMENTS(input); i++) {
+ struct base64_encoder b64enc;
+
+ for (n = 0; n <= 80; n++) {
+ str_truncate(out_test, 0);
+ base64_encode_init(&b64enc, &base64_scheme, 0, n);
+ base64_encode_more(&b64enc, input[i], strlen(input[i]),
+ NULL, out_test);
+ base64_encode_finish(&b64enc, out_test);
+
+ str_truncate(out_ref, 0);
+ _add_lines(output[i], n, FALSE, out_ref);
+
+ test_assert(strcmp(str_c(out_ref),
+ str_c(out_test)) == 0);
+
+ }
+ }
+ test_end();
+
+ test_begin("base64 encode lines (CRLF)");
+ for (i = 0; i < N_ELEMENTS(input); i++) {
+ struct base64_encoder b64enc;
+
+ for (n = 0; n <= 80; n++) {
+ str_truncate(out_test, 0);
+ base64_encode_init(&b64enc, &base64_scheme,
+ BASE64_ENCODE_FLAG_CRLF, n);
+ base64_encode_more(&b64enc, input[i], strlen(input[i]),
+ NULL, out_test);
+ base64_encode_finish(&b64enc, out_test);
+
+ str_truncate(out_ref, 0);
+ _add_lines(output[i], n, TRUE, out_ref);
+
+ test_assert(strcmp(str_c(out_ref),
+ str_c(out_test)) == 0);
+
+ }
+ }
+ test_end();
+}
+
+void test_base64(void)
+{
+ test_base64_encode();
+ test_base64_decode();
+ test_base64_random();
+ test_base64url_encode();
+ test_base64url_decode();
+ test_base64url_random();
+ test_base64_encode_lowlevel();
+ test_base64_decode_lowlevel();
+ test_base64_random_lowlevel();
+ test_base64_encode_lines();
+}