1 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
2
3 #include "test-lib.h"
4 #include "str.h"
5 #include "base64.h"
6
test_base64_encode(void)7 static void test_base64_encode(void)
8 {
9 const struct {
10 const char *input;
11 const char *output;
12 } tests[] = {
13 { "hello world", "aGVsbG8gd29ybGQ=" },
14 { "foo barits", "Zm9vIGJhcml0cw==" },
15 { "just niin", "anVzdCBuaWlu" },
16 { "\xe7\x8c\xbf\xe3\x82\x82\xe6\x9c\xa8\xe3\x81\x8b"
17 "\xe3\x82\x89\xe8\x90\xbd\xe3\x81\xa1\xe3\x82\x8b",
18 "54y/44KC5pyo44GL44KJ6JC944Gh44KL" },
19 { "\xe8\xa7\x92\xe3\x82\x92\xe7\x9f\xaf\xe3\x82\x81\xe3\x81"
20 "\xa6\xe7\x89\x9b\xe3\x82\x92\xe6\xae\xba\xe3\x81\x99",
21 "6KeS44KS55+v44KB44Gm54mb44KS5q6644GZ" },
22 };
23 string_t *str;
24 unsigned int i;
25
26 test_begin("base64_encode()");
27 str = t_str_new(256);
28 for (i = 0; i < N_ELEMENTS(tests); i++) {
29 str_truncate(str, 0);
30 base64_encode(tests[i].input, strlen(tests[i].input), str);
31 test_assert_idx(strcmp(tests[i].output, str_c(str)) == 0, i);
32 test_assert_idx(
33 str_len(str) == MAX_BASE64_ENCODED_SIZE(
34 strlen(tests[i].input)), i);
35 }
36 test_end();
37 }
38
39 struct test_base64_decode {
40 const char *input;
41 const char *output;
42 int ret;
43 };
44
test_base64_decode(void)45 static void test_base64_decode(void)
46 {
47 static const struct test_base64_decode tests[] = {
48 { "", "", 0 },
49 { "\taGVsbG8gd29ybGQ=",
50 "hello world", 0 },
51 { "\nZm9v\n \tIGJh \t\ncml0cw==",
52 "foo barits", 0 },
53 { " anVzdCBuaWlu \n",
54 "just niin", 0 },
55 { "aGVsb",
56 "hel", -1 },
57 { "aGVsb!!!!!",
58 "hel", -1 },
59 { "aGVs!!!!!",
60 "hel", -1 },
61 { "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
62 "C+INC60YPRgCDQtNC+0Y/MgdGCLg==",
63 "\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
64 "\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
65 "\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
66 "\x81\xd1\x82\x2e", 0 },
67 };
68 string_t *str;
69 buffer_t buf;
70 unsigned int i;
71 int ret;
72
73 test_begin("base64_decode()");
74 for (i = 0; i < N_ELEMENTS(tests); i++) {
75 /* Some of the base64_decode() callers use fixed size buffers.
76 Use a fixed size buffer here as well to test that
77 base64_decode() can't allocate any extra space even
78 temporarily. */
79 size_t max_decoded_size =
80 MAX_BASE64_DECODED_SIZE(strlen(tests[i].input));
81
82 buffer_create_from_data(&buf,
83 (max_decoded_size == 0 ? "" :
84 t_malloc0(max_decoded_size)),
85 max_decoded_size);
86 str = &buf;
87 ret = base64_decode(tests[i].input, strlen(tests[i].input),
88 NULL, str);
89
90 test_assert_idx(tests[i].ret == ret, i);
91 test_assert_idx(strlen(tests[i].output) == str_len(str) &&
92 memcmp(tests[i].output, str_data(str),
93 str_len(str)) == 0, i);
94 if (ret >= 0) {
95 test_assert_idx(
96 str_len(str) <= MAX_BASE64_DECODED_SIZE(
97 strlen(tests[i].input)), i);
98 }
99 }
100 test_end();
101 }
102
test_base64_random(void)103 static void test_base64_random(void)
104 {
105 string_t *str, *dest;
106 unsigned char buf[10];
107 unsigned int i, j, max;
108
109 str = t_str_new(256);
110 dest = t_str_new(256);
111
112 test_begin("base64 encode/decode with random input");
113 for (i = 0; i < 1000; i++) {
114 max = i_rand_limit(sizeof(buf));
115 for (j = 0; j < max; j++)
116 buf[j] = i_rand_uchar();
117
118 str_truncate(str, 0);
119 str_truncate(dest, 0);
120 base64_encode(buf, max, str);
121 test_assert_idx(base64_decode(str_data(str), str_len(str),
122 NULL, dest) >= 0, i);
123 test_assert_idx(str_len(dest) == max &&
124 memcmp(buf, str_data(dest), max) == 0, i);
125 }
126 test_end();
127 }
128
test_base64url_encode(void)129 static void test_base64url_encode(void)
130 {
131 const struct {
132 const char *input;
133 const char *output;
134 } tests[] = {
135 { "", "" },
136 { "hello world", "aGVsbG8gd29ybGQ=" },
137 { "foo barits", "Zm9vIGJhcml0cw==" },
138 { "just niin", "anVzdCBuaWlu" },
139 { "\xe7\x8c\xbf\xe3\x82\x82\xe6\x9c\xa8\xe3\x81\x8b"
140 "\xe3\x82\x89\xe8\x90\xbd\xe3\x81\xa1\xe3\x82\x8b",
141 "54y_44KC5pyo44GL44KJ6JC944Gh44KL" },
142 { "\xe8\xa7\x92\xe3\x82\x92\xe7\x9f\xaf\xe3\x82\x81\xe3\x81"
143 "\xa6\xe7\x89\x9b\xe3\x82\x92\xe6\xae\xba\xe3\x81\x99",
144 "6KeS44KS55-v44KB44Gm54mb44KS5q6644GZ" },
145 };
146 string_t *str;
147 unsigned int i;
148
149 test_begin("base64url_encode()");
150 str = t_str_new(256);
151 for (i = 0; i < N_ELEMENTS(tests); i++) {
152 str_truncate(str, 0);
153 base64url_encode(0, 0, tests[i].input, strlen(tests[i].input),
154 str);
155 test_assert_idx(strcmp(tests[i].output, str_c(str)) == 0, i);
156 test_assert_idx(
157 str_len(str) == MAX_BASE64_ENCODED_SIZE(
158 strlen(tests[i].input)), i);
159 }
160 test_end();
161 }
162
163 struct test_base64url_decode {
164 const char *input;
165 const char *output;
166 int ret;
167 };
168
test_base64url_decode(void)169 static void test_base64url_decode(void)
170 {
171 static const struct test_base64url_decode tests[] = {
172 { "", "", 0 },
173 { "\taGVsbG8gd29ybGQ=",
174 "hello world", 0 },
175 { "\nZm9v\n \tIGJh \t\ncml0cw==",
176 "foo barits", 0 },
177 { " anVzdCBuaWlu \n",
178 "just niin", 0 },
179 { "aGVsb",
180 "hel", -1 },
181 { "aGVsb!!!!!",
182 "hel", -1 },
183 { "aGVs!!!!!",
184 "hel", -1 },
185 { "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
186 "C-INC60YPRgCDQtNC-0Y_MgdGCLg==",
187 "\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
188 "\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
189 "\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
190 "\x81\xd1\x82\x2e", 0 },
191 };
192 string_t *str;
193 buffer_t buf;
194 unsigned int i;
195 int ret;
196
197 test_begin("base64url_decode()");
198 for (i = 0; i < N_ELEMENTS(tests); i++) {
199 /* Some of the base64_decode() callers use fixed size buffers.
200 Use a fixed size buffer here as well to test that
201 base64_decode() can't allocate any extra space even
202 temporarily. */
203 size_t max_decoded_size =
204 MAX_BASE64_DECODED_SIZE(strlen(tests[i].input));
205
206 buffer_create_from_data(&buf,
207 (max_decoded_size == 0 ? "" :
208 t_malloc0(max_decoded_size)),
209 max_decoded_size);
210 str = &buf;
211 ret = base64url_decode(0, tests[i].input,
212 strlen(tests[i].input), str);
213
214 test_assert_idx(tests[i].ret == ret, i);
215 test_assert_idx(strlen(tests[i].output) == str_len(str) &&
216 memcmp(tests[i].output, str_data(str),
217 str_len(str)) == 0, i);
218 if (ret >= 0) {
219 test_assert_idx(
220 str_len(str) <= MAX_BASE64_DECODED_SIZE(
221 strlen(tests[i].input)), i);
222 }
223 }
224 test_end();
225 }
226
test_base64url_random(void)227 static void test_base64url_random(void)
228 {
229 string_t *str, *dest;
230 unsigned char buf[10];
231 unsigned int i, j, max;
232
233 str = t_str_new(256);
234 dest = t_str_new(256);
235
236 test_begin("base64url encode/decode with random input");
237 for (i = 0; i < 1000; i++) {
238 max = i_rand_limit(sizeof(buf));
239 for (j = 0; j < max; j++)
240 buf[j] = i_rand_uchar();
241
242 str_truncate(str, 0);
243 str_truncate(dest, 0);
244 base64url_encode(0, 0, buf, max, str);
245 test_assert_idx(base64url_decode(0, str_data(str), str_len(str),
246 dest) >= 0, i);
247 test_assert_idx(str_len(dest) == max &&
248 memcmp(buf, str_data(dest), max) == 0, i);
249 }
250 test_end();
251 }
252
253 struct test_base64_encode_lowlevel {
254 const struct base64_scheme *scheme;
255 enum base64_encode_flags flags;
256 size_t max_line_len;
257
258 const char *input;
259 const char *output;
260 };
261
262 static const struct test_base64_encode_lowlevel
263 tests_base64_encode_lowlevel[] = {
264 {
265 .scheme = &base64_scheme,
266 .input = "",
267 .output = "",
268 },
269 {
270 .scheme = &base64_scheme,
271 .max_line_len = 2,
272 .input = "",
273 .output = "",
274 },
275 {
276 .scheme = &base64_scheme,
277 .flags = BASE64_ENCODE_FLAG_CRLF,
278 .max_line_len = 2,
279 .input = "",
280 .output = "",
281 },
282 {
283 .scheme = &base64_scheme,
284 .flags = BASE64_ENCODE_FLAG_NO_PADDING,
285 .input = "",
286 .output = "",
287 },
288 {
289 .scheme = &base64_scheme,
290 .input = "hello world",
291 .output = "aGVsbG8gd29ybGQ=",
292 },
293 {
294 .scheme = &base64url_scheme,
295 .input = "hello world",
296 .output = "aGVsbG8gd29ybGQ=",
297 },
298 {
299 .scheme = &base64_scheme,
300 .flags = BASE64_ENCODE_FLAG_NO_PADDING,
301 .input = "hello world",
302 .output = "aGVsbG8gd29ybGQ",
303 },
304 {
305 .scheme = &base64_scheme,
306 .input = "foo barits",
307 .output = "Zm9vIGJhcml0cw==",
308 },
309 {
310 .scheme = &base64url_scheme,
311 .input = "foo barits",
312 .output = "Zm9vIGJhcml0cw==",
313 },
314 {
315 .scheme = &base64_scheme,
316 .flags = BASE64_ENCODE_FLAG_NO_PADDING,
317 .input = "foo barits",
318 .output = "Zm9vIGJhcml0cw",
319 },
320 {
321 .scheme = &base64_scheme,
322 .input = "just niin",
323 .output = "anVzdCBuaWlu",
324 },
325 {
326 .scheme = &base64url_scheme,
327 .input = "just niin",
328 .output = "anVzdCBuaWlu",
329 },
330 {
331 .scheme = &base64_scheme,
332 .flags = BASE64_ENCODE_FLAG_NO_PADDING,
333 .input = "just niin",
334 .output = "anVzdCBuaWlu",
335 },
336 {
337 .scheme = &base64_scheme,
338 .input =
339 "\xe7\x8c\xbf\xe3\x82\x82\xe6\x9c\xa8\xe3\x81\x8b"
340 "\xe3\x82\x89\xe8\x90\xbd\xe3\x81\xa1\xe3\x82\x8b",
341 .output = "54y/44KC5pyo44GL44KJ6JC944Gh44KL",
342 },
343 {
344 .scheme = &base64url_scheme,
345 .input =
346 "\xe7\x8c\xbf\xe3\x82\x82\xe6\x9c\xa8\xe3\x81\x8b"
347 "\xe3\x82\x89\xe8\x90\xbd\xe3\x81\xa1\xe3\x82\x8b",
348 .output = "54y_44KC5pyo44GL44KJ6JC944Gh44KL",
349 },
350 {
351 .scheme = &base64_scheme,
352 .input =
353 "\xe8\xa7\x92\xe3\x82\x92\xe7\x9f\xaf\xe3\x82\x81\xe3"
354 "\x81\xa6\xe7\x89\x9b\xe3\x82\x92\xe6\xae\xba\xe3\x81"
355 "\x99",
356 .output = "6KeS44KS55+v44KB44Gm54mb44KS5q6644GZ",
357 },
358 {
359 .scheme = &base64url_scheme,
360 .input =
361 "\xe8\xa7\x92\xe3\x82\x92\xe7\x9f\xaf\xe3\x82\x81\xe3"
362 "\x81\xa6\xe7\x89\x9b\xe3\x82\x92\xe6\xae\xba\xe3\x81"
363 "\x99",
364 .output = "6KeS44KS55-v44KB44Gm54mb44KS5q6644GZ",
365 },
366 {
367 .scheme = &base64_scheme,
368 .flags = BASE64_ENCODE_FLAG_CRLF,
369 .input = "just niin",
370 .output = "anVzdCBuaWlu",
371 },
372 {
373 .scheme = &base64_scheme,
374 .flags = BASE64_ENCODE_FLAG_CRLF,
375 .max_line_len = 80,
376 .input = "just niin",
377 .output = "anVzdCBuaWlu",
378 },
379 {
380 .scheme = &base64_scheme,
381 .flags = BASE64_ENCODE_FLAG_CRLF,
382 .max_line_len = 48,
383 .input =
384 "Passer, deliciae meae puellae,\n"
385 "quicum ludere, quem in sinu tenere,\n"
386 "cui primum digitum dare appetenti\n"
387 "et acris solet incitare morsus,\n"
388 "cum desiderio meo nitenti\n"
389 "carum nescio quid lubet iocari,\n"
390 "credo ut, cum gravis acquiescet ardor,\n"
391 "sit solaciolum sui doloris,\n"
392 "tecum ludere sicut ipsa possem\n"
393 "et tristis animi levare curas!\n",
394 .output =
395 "UGFzc2VyLCBkZWxpY2lhZSBtZWFlIHB1ZWxsYWUsCnF1aWN1\r\n"
396 "bSBsdWRlcmUsIHF1ZW0gaW4gc2ludSB0ZW5lcmUsCmN1aSBw\r\n"
397 "cmltdW0gZGlnaXR1bSBkYXJlIGFwcGV0ZW50aQpldCBhY3Jp\r\n"
398 "cyBzb2xldCBpbmNpdGFyZSBtb3JzdXMsCmN1bSBkZXNpZGVy\r\n"
399 "aW8gbWVvIG5pdGVudGkKY2FydW0gbmVzY2lvIHF1aWQgbHVi\r\n"
400 "ZXQgaW9jYXJpLApjcmVkbyB1dCwgY3VtIGdyYXZpcyBhY3F1\r\n"
401 "aWVzY2V0IGFyZG9yLApzaXQgc29sYWNpb2x1bSBzdWkgZG9s\r\n"
402 "b3JpcywKdGVjdW0gbHVkZXJlIHNpY3V0IGlwc2EgcG9zc2Vt\r\n"
403 "CmV0IHRyaXN0aXMgYW5pbWkgbGV2YXJlIGN1cmFzIQo=",
404 },
405 {
406 .scheme = &base64_scheme,
407 .max_line_len = 48,
408 .input =
409 "Lugete, o Veneres Cupidinesque,\n"
410 "et quantum est hominum venustiorum:\n"
411 "passer mortuus est meae puellae, \n"
412 "passer, deliciae meae puellae\n"
413 "quem plus amat illa oculis suis amabat.\n"
414 "Nam mellitus erat suamque norat\n"
415 "ipsam tam bene quam puella matrem,\n"
416 "nec sese a gremio illius movebat,\n"
417 "sed circumsiliens modo huc modo illuc\n"
418 "ad solam dominam usque pipiabat;\n"
419 "qui nunc it per iter tenebricosum\n"
420 "illuc, unde negant redire quemquam.\n"
421 "At vobis male sint, malae tenebrae\n"
422 "Orci, quae omnia bella devoratis:\n"
423 "tam bellum mihi passerem abstulistis.\n"
424 "O factum male! O miselle passer!\n"
425 "Tua nunc opera meae puellae\n"
426 "flendo turgiduli rubent ocelli.\n",
427 .output =
428 "THVnZXRlLCBvIFZlbmVyZXMgQ3VwaWRpbmVzcXVlLApldCBx\n"
429 "dWFudHVtIGVzdCBob21pbnVtIHZlbnVzdGlvcnVtOgpwYXNz\n"
430 "ZXIgbW9ydHV1cyBlc3QgbWVhZSBwdWVsbGFlLCAKcGFzc2Vy\n"
431 "LCBkZWxpY2lhZSBtZWFlIHB1ZWxsYWUKcXVlbSBwbHVzIGFt\n"
432 "YXQgaWxsYSBvY3VsaXMgc3VpcyBhbWFiYXQuCk5hbSBtZWxs\n"
433 "aXR1cyBlcmF0IHN1YW1xdWUgbm9yYXQKaXBzYW0gdGFtIGJl\n"
434 "bmUgcXVhbSBwdWVsbGEgbWF0cmVtLApuZWMgc2VzZSBhIGdy\n"
435 "ZW1pbyBpbGxpdXMgbW92ZWJhdCwKc2VkIGNpcmN1bXNpbGll\n"
436 "bnMgbW9kbyBodWMgbW9kbyBpbGx1YwphZCBzb2xhbSBkb21p\n"
437 "bmFtIHVzcXVlIHBpcGlhYmF0OwpxdWkgbnVuYyBpdCBwZXIg\n"
438 "aXRlciB0ZW5lYnJpY29zdW0KaWxsdWMsIHVuZGUgbmVnYW50\n"
439 "IHJlZGlyZSBxdWVtcXVhbS4KQXQgdm9iaXMgbWFsZSBzaW50\n"
440 "LCBtYWxhZSB0ZW5lYnJhZQpPcmNpLCBxdWFlIG9tbmlhIGJl\n"
441 "bGxhIGRldm9yYXRpczoKdGFtIGJlbGx1bSBtaWhpIHBhc3Nl\n"
442 "cmVtIGFic3R1bGlzdGlzLgpPIGZhY3R1bSBtYWxlISBPIG1p\n"
443 "c2VsbGUgcGFzc2VyIQpUdWEgbnVuYyBvcGVyYSBtZWFlIHB1\n"
444 "ZWxsYWUKZmxlbmRvIHR1cmdpZHVsaSBydWJlbnQgb2NlbGxp\n"
445 "Lgo=",
446 },
447 };
448
test_base64_encode_lowlevel(void)449 static void test_base64_encode_lowlevel(void)
450 {
451 string_t *str;
452 unsigned int i;
453
454 test_begin("base64 encode low-level");
455 str = t_str_new(256);
456 for (i = 0; i < N_ELEMENTS(tests_base64_encode_lowlevel); i++) {
457 const struct test_base64_encode_lowlevel *test =
458 &tests_base64_encode_lowlevel[i];
459 struct base64_encoder enc;
460 uoff_t out_size;
461
462 str_truncate(str, 0);
463
464 base64_encode_init(&enc, test->scheme, test->flags,
465 test->max_line_len);
466 out_size = base64_get_full_encoded_size(
467 &enc, strlen(test->input));
468 test_assert_idx(base64_encode_more(&enc, test->input,
469 strlen(test->input),
470 NULL, str), i);
471 test_assert_idx(base64_encode_finish(&enc, str), i);
472
473 test_assert_idx(strcmp(test->output, str_c(str)) == 0, i);
474 test_assert_idx(test->flags != 0 || test->max_line_len != 0 ||
475 str_len(str) == MAX_BASE64_ENCODED_SIZE(
476 strlen(test->input)), i);
477 test_assert_idx(str_len(str) == out_size, i);
478 }
479 test_end();
480 }
481
482 struct test_base64_decode_lowlevel {
483 const struct base64_scheme *scheme;
484 enum base64_decode_flags flags;
485
486 const char *input;
487 const char *output;
488 int ret;
489 unsigned int src_pos;
490 };
491
492 static const struct test_base64_decode_lowlevel
493 tests_base64_decode_lowlevel[] = {
494 {
495 .scheme = &base64_scheme,
496 .input = "",
497 .output = "",
498 .ret = 0,
499 .src_pos = UINT_MAX,
500 },
501 {
502 .scheme = &base64_scheme,
503 .input = " ",
504 .output = "",
505 .ret = 0,
506 .src_pos = UINT_MAX,
507 },
508 {
509 .scheme = &base64_scheme,
510 .input = "",
511 .output = "",
512 .ret = 0,
513 .src_pos = UINT_MAX,
514 .flags = BASE64_DECODE_FLAG_EXPECT_BOUNDARY,
515 },
516 {
517 .scheme = &base64_scheme,
518 .input = "",
519 .output = "",
520 .ret = 0,
521 .src_pos = UINT_MAX,
522 .flags = BASE64_DECODE_FLAG_NO_WHITESPACE,
523 },
524 {
525 .scheme = &base64_scheme,
526 .input = " ",
527 .output = "",
528 .ret = -1,
529 .src_pos = 0,
530 .flags = BASE64_DECODE_FLAG_NO_WHITESPACE,
531 },
532 {
533 .scheme = &base64_scheme,
534 .input = "",
535 .output = "",
536 .ret = 0,
537 .src_pos = UINT_MAX,
538 .flags = BASE64_DECODE_FLAG_NO_PADDING,
539 },
540 {
541 .scheme = &base64_scheme,
542 .input = "",
543 .output = "",
544 .ret = 0,
545 .src_pos = UINT_MAX,
546 .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
547 },
548 {
549 .scheme = &base64_scheme,
550 .input = "\taGVsbG8gd29ybGQ=",
551 .output = "hello world",
552 .ret = 0,
553 .src_pos = UINT_MAX,
554 },
555 {
556 .scheme = &base64url_scheme,
557 .input = "\taGVsbG8gd29ybGQ=",
558 .output = "hello world",
559 .ret = 0,
560 .src_pos = UINT_MAX,
561 },
562 {
563 .scheme = &base64_scheme,
564 .input = "aGVsbG8gd29ybGQ=\t",
565 .output = "hello world",
566 .ret = 0,
567 .src_pos = UINT_MAX,
568 },
569 {
570 .scheme = &base64_scheme,
571 .input = "\taGVsbG8gd29ybGQ=\t",
572 .output = "hello world",
573 .ret = 0,
574 .src_pos = UINT_MAX,
575 },
576 {
577 .scheme = &base64_scheme,
578 .input = "aGVsbG8gd29ybGQ=:frop",
579 .output = "hello world",
580 .ret = 0,
581 .src_pos = 16,
582 .flags = BASE64_DECODE_FLAG_EXPECT_BOUNDARY,
583 },
584 {
585 .scheme = &base64_scheme,
586 .input = "\taGVsbG8gd29ybGQ=\t:frop",
587 .output = "hello world",
588 .ret = 0,
589 .src_pos = 18,
590 .flags = BASE64_DECODE_FLAG_EXPECT_BOUNDARY,
591 },
592 {
593 .scheme = &base64_scheme,
594 .input = "aGVsbG8gd29ybGQ=\t",
595 .output = "hello world",
596 .ret = -1,
597 .src_pos = 16,
598 .flags = BASE64_DECODE_FLAG_NO_WHITESPACE,
599 },
600 {
601 .scheme = &base64_scheme,
602 .input = "\taGVsbG8gd29ybGQ=\t",
603 .output = "",
604 .ret = -1,
605 .src_pos = 0,
606 .flags = BASE64_DECODE_FLAG_NO_WHITESPACE,
607 },
608 {
609 .scheme = &base64_scheme,
610 .flags = BASE64_DECODE_FLAG_NO_PADDING,
611 .input = "\taGVsbG8gd29ybGQ=",
612 .output = "hello world",
613 .ret = -1,
614 .src_pos = 16,
615 },
616 {
617 .scheme = &base64_scheme,
618 .flags = BASE64_DECODE_FLAG_NO_PADDING,
619 .input = "\taGVsbG8gd29ybGQ",
620 .output = "hello world",
621 .ret = 0,
622 .src_pos = 16,
623 },
624 {
625 .scheme = &base64_scheme,
626 .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
627 .input = "\taGVsbG8gd29ybGQ=",
628 .output = "hello world",
629 .ret = 0,
630 .src_pos = 17,
631 },
632 {
633 .scheme = &base64_scheme,
634 .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
635 .input = "\taGVsbG8gd29ybGQ",
636 .output = "hello world",
637 .ret = 0,
638 .src_pos = 16,
639 },
640 {
641 .scheme = &base64_scheme,
642 .input = "\nZm9v\n \tIGJh \t\ncml0cw==",
643 .output = "foo barits",
644 .ret = 0,
645 .src_pos = UINT_MAX,
646 },
647 {
648 .scheme = &base64url_scheme,
649 .input = "\nZm9v\n \tIGJh \t\ncml0cw==",
650 .output = "foo barits",
651 .ret = 0,
652 .src_pos = UINT_MAX,
653 },
654 {
655 .scheme = &base64_scheme,
656 .input = "\nZm9v\n \tIGJh \t\ncml0cw==\n ",
657 .output = "foo barits",
658 .ret = 0,
659 .src_pos = UINT_MAX,
660 },
661 {
662 .scheme = &base64_scheme,
663 .input = "\nZm9v\n \tIGJh \t\ncml0cw= =\n ",
664 .output = "foo barits",
665 .ret = 0,
666 .src_pos = UINT_MAX,
667 },
668 {
669 .scheme = &base64_scheme,
670 .input = "\nZm9v\n \tIGJh \t\ncml0cw\n= =\n ",
671 .output = "foo barits",
672 .ret = 0,
673 .src_pos = UINT_MAX,
674 },
675 {
676 .scheme = &base64_scheme,
677 .flags = BASE64_DECODE_FLAG_NO_PADDING,
678 .input = "\nZm9v\n \tIGJh \t\ncml0cw==",
679 .output = "foo barits",
680 .ret = -1,
681 .src_pos = 22,
682 },
683 {
684 .scheme = &base64_scheme,
685 .flags = BASE64_DECODE_FLAG_NO_PADDING,
686 .input = "\nZm9v\n \tIGJh \t\ncml0cw",
687 .output = "foo barits",
688 .ret = 0,
689 .src_pos = 22,
690 },
691 {
692 .scheme = &base64_scheme,
693 .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
694 .input = "\nZm9v\n \tIGJh \t\ncml0cw==",
695 .output = "foo barits",
696 .ret = 0,
697 .src_pos = 24,
698 },
699 {
700 .scheme = &base64_scheme,
701 .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
702 .input = "\nZm9v\n \tIGJh \t\ncml0cw",
703 .output = "foo barits",
704 .ret = 0,
705 .src_pos = 22,
706 },
707 {
708 .scheme = &base64_scheme,
709 .input = " anVzdCBuaWlu \n",
710 .output = "just niin",
711 .ret = 0,
712 .src_pos = UINT_MAX,
713 },
714 {
715 .scheme = &base64url_scheme,
716 .input = " anVzdCBuaWlu \n",
717 .output = "just niin",
718 .ret = 0,
719 .src_pos = UINT_MAX,
720 },
721 {
722 .scheme = &base64_scheme,
723 .flags = BASE64_DECODE_FLAG_NO_PADDING,
724 .input = " anVzdCBuaWlu \n",
725 .output = "just niin",
726 .ret = 0,
727 .src_pos = UINT_MAX,
728 },
729 {
730 .scheme = &base64_scheme,
731 .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
732 .input = " anVzdCBuaWlu \n",
733 .output = "just niin",
734 .ret = 0,
735 .src_pos = UINT_MAX,
736 },
737 {
738 .scheme = &base64_scheme,
739 .input = "aGVsb",
740 .output = "hel",
741 .ret = -1,
742 .src_pos = 5,
743 },
744 {
745 .scheme = &base64url_scheme,
746 .input = "aGVsb",
747 .output = "hel",
748 .ret = -1,
749 .src_pos = 5,
750 },
751 {
752 .scheme = &base64_scheme,
753 .flags = BASE64_DECODE_FLAG_NO_PADDING,
754 .input = "aGVsb",
755 .output = "hel",
756 .ret = 0,
757 .src_pos = 5,
758 },
759 {
760 .scheme = &base64_scheme,
761 .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
762 .input = "aGVsb",
763 .output = "hel",
764 .ret = 0,
765 .src_pos = 5,
766 },
767 {
768 .scheme = &base64_scheme,
769 .input = "aGVsb!!!!!",
770 .output = "hel",
771 .ret = -1,
772 .src_pos = 5,
773 },
774 {
775 .scheme = &base64url_scheme,
776 .input = "aGVsb!!!!!",
777 .output = "hel",
778 .ret = -1,
779 .src_pos = 5,
780 },
781 {
782 .scheme = &base64_scheme,
783 .input = "aGVs!!!!!",
784 .output = "hel",
785 .ret = -1,
786 .src_pos = 4,
787 },
788 {
789 .scheme = &base64url_scheme,
790 .input = "aGVs!!!!!",
791 .output = "hel",
792 .ret = -1,
793 .src_pos = 4,
794 },
795 {
796 .scheme = &base64_scheme,
797 .input =
798 "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
799 "C+INC60YPRgCDQtNC+0Y/MgdGCLg==",
800 .output =
801 "\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
802 "\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
803 "\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
804 "\x81\xd1\x82\x2e",
805 .ret = 0,
806 .src_pos = UINT_MAX,
807 },
808 {
809 .scheme = &base64url_scheme,
810 .input =
811 "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
812 "C-INC60YPRgCDQtNC-0Y_MgdGCLg==",
813 .output =
814 "\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
815 "\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
816 "\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
817 "\x81\xd1\x82\x2e",
818 .ret = 0,
819 .src_pos = UINT_MAX,
820 },
821 {
822 .scheme = &base64_scheme,
823 .flags = BASE64_DECODE_FLAG_NO_PADDING,
824 .input =
825 "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
826 "C+INC60YPRgCDQtNC+0Y/MgdGCLg",
827 .output =
828 "\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
829 "\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
830 "\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
831 "\x81\xd1\x82\x2e",
832 .ret = 0,
833 .src_pos = UINT_MAX,
834 },
835 {
836 .scheme = &base64_scheme,
837 .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
838 .input =
839 "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
840 "C+INC60YPRgCDQtNC+0Y/MgdGCLg",
841 .output =
842 "\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
843 "\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
844 "\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
845 "\x81\xd1\x82\x2e",
846 .ret = 0,
847 .src_pos = UINT_MAX,
848 },
849 {
850 .scheme = &base64_scheme,
851 .flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
852 .input =
853 "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
854 "C+INC60YPRgCDQtNC+0Y/MgdGCLg==",
855 .output =
856 "\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
857 "\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
858 "\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
859 "\x81\xd1\x82\x2e",
860 .ret = 0,
861 .src_pos = UINT_MAX,
862 },
863 };
864
test_base64_decode_lowlevel(void)865 static void test_base64_decode_lowlevel(void)
866 {
867 string_t *str;
868 buffer_t buf;
869 unsigned int i;
870
871 test_begin("base64 decode low-level");
872 for (i = 0; i < N_ELEMENTS(tests_base64_decode_lowlevel); i++) {
873 const struct test_base64_decode_lowlevel *test =
874 &tests_base64_decode_lowlevel[i];
875 struct base64_decoder dec;
876 size_t src_pos;
877 int ret;
878
879 /* Some of the base64_decode() callers use fixed size buffers.
880 Use a fixed size buffer here as well to test that
881 base64_decode() can't allocate any extra space even
882 temporarily. */
883 size_t max_decoded_size =
884 MAX_BASE64_DECODED_SIZE(strlen(test->input));
885
886 buffer_create_from_data(&buf,
887 (max_decoded_size == 0 ? "" :
888 t_malloc0(max_decoded_size)),
889 max_decoded_size);
890 str = &buf;
891 base64_decode_init(&dec, test->scheme, test->flags);
892 ret = base64_decode_more(&dec, test->input, strlen(test->input),
893 &src_pos, str);
894 if (ret >= 0)
895 ret = base64_decode_finish(&dec);
896
897 test_assert_idx(ret == test->ret, i);
898 test_assert_idx(strlen(test->output) == str_len(str) &&
899 memcmp(test->output, str_data(str),
900 str_len(str)) == 0, i);
901 test_assert_idx(src_pos == test->src_pos ||
902 (test->src_pos == UINT_MAX &&
903 src_pos == strlen(test->input)), i);
904 if (ret >= 0) {
905 test_assert_idx(
906 str_len(str) <= MAX_BASE64_DECODED_SIZE(
907 strlen(test->input)), i);
908 }
909 }
910 test_end();
911 }
912
913 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)914 test_base64_random_lowlevel_one_block(const struct base64_scheme *b64,
915 enum base64_encode_flags enc_flags,
916 enum base64_decode_flags dec_flags,
917 size_t max_line_len,
918 unsigned int test_idx,
919 const unsigned char *in_buf,
920 size_t in_buf_size,
921 buffer_t *buf1, buffer_t *buf2)
922 {
923 struct base64_encoder enc;
924 struct base64_decoder dec;
925 void *space;
926 size_t enc_size;
927 buffer_t buf;
928 int ret;
929
930 buffer_set_used_size(buf1, 0);
931 buffer_set_used_size(buf2, 0);
932
933 base64_encode_init(&enc, b64, enc_flags, max_line_len);
934 enc_size = base64_get_full_encoded_size(&enc, in_buf_size);
935 space = buffer_append_space_unsafe(buf1, enc_size);
936 buffer_create_from_data(&buf, space, enc_size);
937
938 if (!base64_encode_more(&enc, in_buf, in_buf_size, NULL, &buf))
939 test_assert_idx(FALSE, test_idx);
940 if (!base64_encode_finish(&enc, &buf))
941 test_assert_idx(FALSE, test_idx);
942
943 test_assert(base64_get_full_encoded_size(&enc, in_buf_size) ==
944 buf1->used);
945
946 base64_decode_init(&dec, b64, dec_flags);
947 space = buffer_append_space_unsafe(buf2, in_buf_size);
948 buffer_create_from_data(&buf, space, in_buf_size);
949
950 ret = base64_decode_more(&dec, buf1->data, buf1->used, NULL, &buf);
951 if (ret >= 0)
952 ret = base64_decode_finish(&dec);
953
954 test_assert_idx(ret >= 0, test_idx);
955 test_assert_idx(buf2->used == in_buf_size &&
956 memcmp(in_buf, buf2->data, in_buf_size) == 0, test_idx);
957 }
958
959 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)960 test_base64_random_lowlevel_stream(const struct base64_scheme *b64,
961 enum base64_encode_flags enc_flags,
962 enum base64_decode_flags dec_flags,
963 size_t max_line_len, unsigned int test_idx,
964 const unsigned char *in_buf,
965 size_t in_buf_size,
966 buffer_t *buf1, buffer_t *buf2,
967 size_t chunk_size)
968 {
969 struct base64_encoder enc;
970 struct base64_decoder dec;
971 const unsigned char *buf_p, *buf_begin, *buf_end;
972 int ret;
973 size_t out_space, out_full_size;
974 void *out_data;
975 buffer_t out;
976
977 /* Encode */
978
979 buffer_set_used_size(buf1, 0);
980
981 buf_begin = in_buf;
982 buf_end = buf_begin + in_buf_size;
983
984 base64_encode_init(&enc, b64, enc_flags, max_line_len);
985 out_full_size = base64_get_full_encoded_size(&enc, in_buf_size);
986 out_space = 0;
987 for (buf_p = buf_begin; buf_p < buf_end; ) {
988 size_t buf_ch, out_ch;
989 size_t left = (buf_end - buf_p);
990 size_t used = buf1->used;
991 size_t src_pos, out_size, src_full_space;
992 bool eres;
993
994 if (chunk_size == 0) {
995 buf_ch = i_rand_limit(32);
996 out_ch = i_rand_limit(32);
997 } else {
998 buf_ch = chunk_size;
999 out_ch = chunk_size;
1000 }
1001
1002 out_space += out_ch;
1003 out_data = buffer_append_space_unsafe(buf1, out_space);
1004 buffer_create_from_data(&out, out_data, out_space);
1005
1006 if (buf_ch > left)
1007 buf_ch = left;
1008
1009 src_full_space = base64_encode_get_full_space(
1010 &enc, out_full_size - used);
1011 test_assert_idx(src_full_space >= (size_t)(buf_end - buf_p),
1012 test_idx);
1013
1014 out_size = base64_encode_get_size(&enc, buf_ch);
1015
1016 eres = base64_encode_more(&enc, buf_p, buf_ch, &src_pos, &out);
1017 test_assert_idx((eres && src_pos == buf_ch) ||
1018 (!eres && src_pos < buf_ch), test_idx);
1019 test_assert_idx(out.used <= out_size, test_idx);
1020 buf_p += src_pos;
1021 i_assert(out_space >= out.used);
1022 out_space -= out.used;
1023 buffer_set_used_size(buf1, used + out.used);
1024 }
1025 test_assert_idx(base64_encode_finish(&enc, buf1), test_idx);
1026
1027 /* Verify encode */
1028
1029 test_assert(out_full_size == buf1->used);
1030
1031 buffer_set_used_size(buf2, 0);
1032 base64_encode_init(&enc, b64, enc_flags, max_line_len);
1033 test_assert_idx(base64_encode_more(&enc, in_buf, in_buf_size,
1034 NULL, buf2), test_idx);
1035 test_assert_idx(base64_encode_finish(&enc, buf2), test_idx);
1036 test_assert_idx(buffer_cmp(buf1, buf2), test_idx);
1037
1038 /* Decode */
1039
1040 buffer_set_used_size(buf2, 0);
1041
1042 buf_begin = buf1->data;
1043 buf_end = buf_begin + buf1->used;
1044
1045 base64_decode_init(&dec, b64, dec_flags);
1046 ret = 1;
1047 out_space = 0;
1048 for (buf_p = buf_begin; buf_p < buf_end; ) {
1049 size_t buf_ch, out_ch;
1050 size_t left = (buf_end - buf_p);
1051 size_t used = buf2->used;
1052 size_t src_pos;
1053
1054 if (chunk_size == 0) {
1055 buf_ch = i_rand_limit(32);
1056 out_ch = i_rand_limit(32);
1057 } else {
1058 buf_ch = chunk_size;
1059 out_ch = chunk_size;
1060 }
1061
1062 out_space += out_ch;
1063 out_data = buffer_append_space_unsafe(buf2, out_space);
1064 buffer_create_from_data(&out, out_data, out_space);
1065
1066 if (buf_ch > left)
1067 buf_ch = left;
1068 ret = base64_decode_more(&dec, buf_p, buf_ch,
1069 &src_pos, &out);
1070 test_assert_idx(ret >= 0, test_idx);
1071 if (ret < 0) {
1072 break;
1073 }
1074 buf_p += src_pos;
1075 i_assert(out_space >= out.used);
1076 out_space -= out.used;
1077 buffer_set_used_size(buf2, used + out.used);
1078 }
1079 test_assert_idx(ret >= 0, test_idx);
1080
1081 /* Verify decode */
1082 if (ret > 0) {
1083 ret = base64_decode_finish(&dec);
1084 test_assert_idx(ret == 0, test_idx);
1085 test_assert_idx(buf2->used == in_buf_size &&
1086 memcmp(in_buf, buf2->data, in_buf_size) == 0,
1087 test_idx);
1088 }
1089 }
1090
1091 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)1092 test_base64_random_lowlevel_case(const struct base64_scheme *b64,
1093 enum base64_encode_flags enc_flags,
1094 enum base64_decode_flags dec_flags,
1095 size_t max_line_len)
1096 {
1097 unsigned char in_buf[512];
1098 size_t in_buf_size;
1099 buffer_t *buf1, *buf2;
1100 unsigned int i, j;
1101
1102 if (test_has_failed())
1103 return;
1104
1105 buf1 = t_buffer_create(MAX_BASE64_ENCODED_SIZE(sizeof(in_buf)));
1106 buf2 = t_buffer_create(MAX_BASE64_ENCODED_SIZE(sizeof(in_buf)));
1107
1108 /* one block */
1109 for (i = 0; i < 1000; i++) {
1110 in_buf_size = i_rand_limit(sizeof(in_buf));
1111 for (j = 0; j < in_buf_size; j++)
1112 in_buf[j] = i_rand_uchar();
1113
1114 test_base64_random_lowlevel_one_block(b64, enc_flags, dec_flags,
1115 max_line_len, i,
1116 in_buf, in_buf_size,
1117 buf1, buf2);
1118
1119 if (test_has_failed()) {
1120 i_info("One block test failed ("
1121 "enc_flags=%02x dec_flags=%02x "
1122 "max_line_len=%zu size=%zu)",
1123 enc_flags, dec_flags, max_line_len,
1124 in_buf_size);
1125 return;
1126 }
1127 }
1128
1129 /* streaming; single-byte trickle */
1130 for (i = 0; i < 1000; i++) {
1131 in_buf_size = i_rand_limit(sizeof(in_buf));
1132 for (j = 0; j < in_buf_size; j++)
1133 in_buf[j] = i_rand_uchar();
1134
1135 test_base64_random_lowlevel_stream(b64, enc_flags, dec_flags,
1136 max_line_len, i,
1137 in_buf, in_buf_size,
1138 buf1, buf2, 1);
1139
1140 if (test_has_failed()) {
1141 i_info("Streaming single-byte trickle test failed ("
1142 "enc_flags=%02x dec_flags=%02x "
1143 "max_line_len=%zu size=%zu)",
1144 enc_flags, dec_flags, max_line_len,
1145 in_buf_size);
1146 return;
1147 }
1148 }
1149
1150 /* streaming; random chunks */
1151 for (i = 0; i < 1000; i++) {
1152 in_buf_size = i_rand_limit(sizeof(in_buf));
1153 for (j = 0; j < in_buf_size; j++)
1154 in_buf[j] = i_rand_uchar();
1155
1156 test_base64_random_lowlevel_stream(b64, enc_flags, dec_flags,
1157 max_line_len, i,
1158 in_buf, in_buf_size,
1159 buf1, buf2, 0);
1160 if (test_has_failed()) {
1161 i_info("Streaming random chunks test failed ("
1162 "enc_flags=%02x dec_flags=%02x "
1163 "max_line_len=%zu size=%zu)",
1164 enc_flags, dec_flags, max_line_len,
1165 in_buf_size);
1166 return;
1167 }
1168 }
1169 }
1170
1171 static void
test_base64_random_lowlevel(void)1172 test_base64_random_lowlevel(void)
1173 {
1174 test_begin("base64 encode/decode low-level with random input");
1175 test_base64_random_lowlevel_case(&base64_scheme, 0, 0, 0);
1176 test_base64_random_lowlevel_case(&base64url_scheme, 0, 0, 0);
1177 test_base64_random_lowlevel_case(&base64_scheme, 0,
1178 BASE64_DECODE_FLAG_EXPECT_BOUNDARY, 0);
1179 test_base64_random_lowlevel_case(&base64url_scheme, 0,
1180 BASE64_DECODE_FLAG_EXPECT_BOUNDARY, 0);
1181 test_base64_random_lowlevel_case(&base64_scheme, 0,
1182 BASE64_DECODE_FLAG_NO_WHITESPACE, 0);
1183 test_base64_random_lowlevel_case(&base64url_scheme, 0,
1184 BASE64_DECODE_FLAG_NO_WHITESPACE, 0);
1185 test_base64_random_lowlevel_case(&base64_scheme, 0, 0, 10);
1186 test_base64_random_lowlevel_case(&base64url_scheme, 0, 0, 10);
1187 test_base64_random_lowlevel_case(&base64_scheme,
1188 BASE64_ENCODE_FLAG_CRLF, 0, 10);
1189 test_base64_random_lowlevel_case(&base64url_scheme,
1190 BASE64_ENCODE_FLAG_CRLF, 0, 10);
1191 test_base64_random_lowlevel_case(&base64_scheme,
1192 BASE64_ENCODE_FLAG_NO_PADDING,
1193 BASE64_DECODE_FLAG_NO_PADDING, 0);
1194 test_base64_random_lowlevel_case(&base64url_scheme,
1195 BASE64_ENCODE_FLAG_NO_PADDING,
1196 BASE64_DECODE_FLAG_NO_PADDING, 0);
1197 test_base64_random_lowlevel_case(&base64_scheme,
1198 BASE64_ENCODE_FLAG_NO_PADDING |
1199 BASE64_ENCODE_FLAG_CRLF,
1200 BASE64_DECODE_FLAG_NO_PADDING, 15);
1201 test_base64_random_lowlevel_case(&base64url_scheme,
1202 BASE64_ENCODE_FLAG_NO_PADDING |
1203 BASE64_ENCODE_FLAG_CRLF,
1204 BASE64_DECODE_FLAG_NO_PADDING, 15);
1205 test_base64_random_lowlevel_case(&base64_scheme,
1206 BASE64_ENCODE_FLAG_NO_PADDING |
1207 BASE64_ENCODE_FLAG_CRLF,
1208 BASE64_DECODE_FLAG_NO_PADDING, 1);
1209 test_end();
1210 }
1211
1212 static void
_add_lines(const char * in,size_t max_line_len,bool crlf,string_t * out)1213 _add_lines(const char *in, size_t max_line_len, bool crlf, string_t *out)
1214 {
1215 size_t in_len = strlen(in);
1216
1217 while (max_line_len > 0 && in_len > max_line_len) {
1218 str_append_data(out, in, max_line_len);
1219 if (crlf)
1220 str_append(out, "\r\n");
1221 else
1222 str_append_c(out, '\n');
1223 in += max_line_len;
1224 in_len -= max_line_len;
1225 }
1226
1227 str_append_data(out, in, in_len);
1228 }
1229
test_base64_encode_lines(void)1230 static void test_base64_encode_lines(void)
1231 {
1232 static const char *input[] = {
1233 "Passer, deliciae meae puellae,\n"
1234 "quicum ludere, quem in sinu tenere,\n"
1235 "cui primum digitum dare appetenti\n"
1236 "et acris solet incitare morsus,\n"
1237 "cum desiderio meo nitenti\n"
1238 "carum nescio quid lubet iocari,\n"
1239 "credo ut, cum gravis acquiescet ardor,\n"
1240 "sit solaciolum sui doloris,\n"
1241 "tecum ludere sicut ipsa possem\n"
1242 "et tristis animi levare curas!\n"
1243 };
1244 static const char *output[] = {
1245 "UGFzc2VyLCBkZWxpY2lhZSBtZWFlIHB1ZWxsYWUsCnF1aWN1"
1246 "bSBsdWRlcmUsIHF1ZW0gaW4gc2ludSB0ZW5lcmUsCmN1aSBw"
1247 "cmltdW0gZGlnaXR1bSBkYXJlIGFwcGV0ZW50aQpldCBhY3Jp"
1248 "cyBzb2xldCBpbmNpdGFyZSBtb3JzdXMsCmN1bSBkZXNpZGVy"
1249 "aW8gbWVvIG5pdGVudGkKY2FydW0gbmVzY2lvIHF1aWQgbHVi"
1250 "ZXQgaW9jYXJpLApjcmVkbyB1dCwgY3VtIGdyYXZpcyBhY3F1"
1251 "aWVzY2V0IGFyZG9yLApzaXQgc29sYWNpb2x1bSBzdWkgZG9s"
1252 "b3JpcywKdGVjdW0gbHVkZXJlIHNpY3V0IGlwc2EgcG9zc2Vt"
1253 "CmV0IHRyaXN0aXMgYW5pbWkgbGV2YXJlIGN1cmFzIQo=",
1254 };
1255 string_t *out_test, *out_ref;
1256 unsigned int i, n;
1257
1258 out_test = t_str_new(256);
1259 out_ref = t_str_new(256);
1260
1261 test_begin("base64 encode lines (LF)");
1262 for (i = 0; i < N_ELEMENTS(input); i++) {
1263 struct base64_encoder b64enc;
1264
1265 for (n = 0; n <= 80; n++) {
1266 str_truncate(out_test, 0);
1267 base64_encode_init(&b64enc, &base64_scheme, 0, n);
1268 base64_encode_more(&b64enc, input[i], strlen(input[i]),
1269 NULL, out_test);
1270 base64_encode_finish(&b64enc, out_test);
1271
1272 str_truncate(out_ref, 0);
1273 _add_lines(output[i], n, FALSE, out_ref);
1274
1275 test_assert(strcmp(str_c(out_ref),
1276 str_c(out_test)) == 0);
1277
1278 }
1279 }
1280 test_end();
1281
1282 test_begin("base64 encode lines (CRLF)");
1283 for (i = 0; i < N_ELEMENTS(input); i++) {
1284 struct base64_encoder b64enc;
1285
1286 for (n = 0; n <= 80; n++) {
1287 str_truncate(out_test, 0);
1288 base64_encode_init(&b64enc, &base64_scheme,
1289 BASE64_ENCODE_FLAG_CRLF, n);
1290 base64_encode_more(&b64enc, input[i], strlen(input[i]),
1291 NULL, out_test);
1292 base64_encode_finish(&b64enc, out_test);
1293
1294 str_truncate(out_ref, 0);
1295 _add_lines(output[i], n, TRUE, out_ref);
1296
1297 test_assert(strcmp(str_c(out_ref),
1298 str_c(out_test)) == 0);
1299
1300 }
1301 }
1302 test_end();
1303 }
1304
test_base64(void)1305 void test_base64(void)
1306 {
1307 test_base64_encode();
1308 test_base64_decode();
1309 test_base64_random();
1310 test_base64url_encode();
1311 test_base64url_decode();
1312 test_base64url_random();
1313 test_base64_encode_lowlevel();
1314 test_base64_decode_lowlevel();
1315 test_base64_random_lowlevel();
1316 test_base64_encode_lines();
1317 }
1318