1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <ctype.h>
4 #include <errno.h>
5 #include <stdint.h>
6 #include <stdlib.h>
7
8 #include "alloc-util.h"
9 #include "hexdecoct.h"
10 #include "macro.h"
11 #include "memory-util.h"
12 #include "string-util.h"
13
octchar(int x)14 char octchar(int x) {
15 return '0' + (x & 7);
16 }
17
unoctchar(char c)18 int unoctchar(char c) {
19
20 if (c >= '0' && c <= '7')
21 return c - '0';
22
23 return -EINVAL;
24 }
25
decchar(int x)26 char decchar(int x) {
27 return '0' + (x % 10);
28 }
29
undecchar(char c)30 int undecchar(char c) {
31
32 if (c >= '0' && c <= '9')
33 return c - '0';
34
35 return -EINVAL;
36 }
37
hexchar(int x)38 char hexchar(int x) {
39 static const char table[16] = "0123456789abcdef";
40
41 return table[x & 15];
42 }
43
unhexchar(char c)44 int unhexchar(char c) {
45
46 if (c >= '0' && c <= '9')
47 return c - '0';
48
49 if (c >= 'a' && c <= 'f')
50 return c - 'a' + 10;
51
52 if (c >= 'A' && c <= 'F')
53 return c - 'A' + 10;
54
55 return -EINVAL;
56 }
57
hexmem(const void * p,size_t l)58 char *hexmem(const void *p, size_t l) {
59 const uint8_t *x;
60 char *r, *z;
61
62 z = r = new(char, l * 2 + 1);
63 if (!r)
64 return NULL;
65
66 for (x = p; x < (const uint8_t*) p + l; x++) {
67 *(z++) = hexchar(*x >> 4);
68 *(z++) = hexchar(*x & 15);
69 }
70
71 *z = 0;
72 return r;
73 }
74
unhex_next(const char ** p,size_t * l)75 static int unhex_next(const char **p, size_t *l) {
76 int r;
77
78 assert(p);
79 assert(l);
80
81 /* Find the next non-whitespace character, and decode it. We
82 * greedily skip all preceding and all following whitespace. */
83
84 for (;;) {
85 if (*l == 0)
86 return -EPIPE;
87
88 if (!strchr(WHITESPACE, **p))
89 break;
90
91 /* Skip leading whitespace */
92 (*p)++, (*l)--;
93 }
94
95 r = unhexchar(**p);
96 if (r < 0)
97 return r;
98
99 for (;;) {
100 (*p)++, (*l)--;
101
102 if (*l == 0 || !strchr(WHITESPACE, **p))
103 break;
104
105 /* Skip following whitespace */
106 }
107
108 return r;
109 }
110
unhexmem_full(const char * p,size_t l,bool secure,void ** ret,size_t * ret_len)111 int unhexmem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_len) {
112 _cleanup_free_ uint8_t *buf = NULL;
113 size_t buf_size;
114 const char *x;
115 uint8_t *z;
116 int r;
117
118 assert(p || l == 0);
119
120 if (l == SIZE_MAX)
121 l = strlen(p);
122
123 /* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */
124 buf_size = (l + 1) / 2 + 1;
125 buf = malloc(buf_size);
126 if (!buf)
127 return -ENOMEM;
128
129 for (x = p, z = buf;;) {
130 int a, b;
131
132 a = unhex_next(&x, &l);
133 if (a == -EPIPE) /* End of string */
134 break;
135 if (a < 0) {
136 r = a;
137 goto on_failure;
138 }
139
140 b = unhex_next(&x, &l);
141 if (b < 0) {
142 r = b;
143 goto on_failure;
144 }
145
146 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
147 }
148
149 *z = 0;
150
151 if (ret_len)
152 *ret_len = (size_t) (z - buf);
153 if (ret)
154 *ret = TAKE_PTR(buf);
155
156 return 0;
157
158 on_failure:
159 if (secure)
160 explicit_bzero_safe(buf, buf_size);
161
162 return r;
163 }
164
165 /* https://tools.ietf.org/html/rfc4648#section-6
166 * Notice that base32hex differs from base32 in the alphabet it uses.
167 * The distinction is that the base32hex representation preserves the
168 * order of the underlying data when compared as bytestrings, this is
169 * useful when representing NSEC3 hashes, as one can then verify the
170 * order of hashes directly from their representation. */
base32hexchar(int x)171 char base32hexchar(int x) {
172 static const char table[32] = "0123456789"
173 "ABCDEFGHIJKLMNOPQRSTUV";
174
175 return table[x & 31];
176 }
177
unbase32hexchar(char c)178 int unbase32hexchar(char c) {
179 unsigned offset;
180
181 if (c >= '0' && c <= '9')
182 return c - '0';
183
184 offset = '9' - '0' + 1;
185
186 if (c >= 'A' && c <= 'V')
187 return c - 'A' + offset;
188
189 return -EINVAL;
190 }
191
base32hexmem(const void * p,size_t l,bool padding)192 char *base32hexmem(const void *p, size_t l, bool padding) {
193 char *r, *z;
194 const uint8_t *x;
195 size_t len;
196
197 assert(p || l == 0);
198
199 if (padding)
200 /* five input bytes makes eight output bytes, padding is added so we must round up */
201 len = 8 * (l + 4) / 5;
202 else {
203 /* same, but round down as there is no padding */
204 len = 8 * l / 5;
205
206 switch (l % 5) {
207 case 4:
208 len += 7;
209 break;
210 case 3:
211 len += 5;
212 break;
213 case 2:
214 len += 4;
215 break;
216 case 1:
217 len += 2;
218 break;
219 }
220 }
221
222 z = r = malloc(len + 1);
223 if (!r)
224 return NULL;
225
226 for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
227 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
228 * x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
229 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
230 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
231 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
232 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
233 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
234 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
235 *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
236 *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
237 }
238
239 switch (l % 5) {
240 case 4:
241 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
242 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
243 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
244 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
245 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
246 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
247 *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
248 if (padding)
249 *(z++) = '=';
250
251 break;
252
253 case 3:
254 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
255 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
256 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
257 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
258 *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
259 if (padding) {
260 *(z++) = '=';
261 *(z++) = '=';
262 *(z++) = '=';
263 }
264
265 break;
266
267 case 2:
268 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
269 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
270 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
271 *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
272 if (padding) {
273 *(z++) = '=';
274 *(z++) = '=';
275 *(z++) = '=';
276 *(z++) = '=';
277 }
278
279 break;
280
281 case 1:
282 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
283 *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
284 if (padding) {
285 *(z++) = '=';
286 *(z++) = '=';
287 *(z++) = '=';
288 *(z++) = '=';
289 *(z++) = '=';
290 *(z++) = '=';
291 }
292
293 break;
294 }
295
296 *z = 0;
297 return r;
298 }
299
unbase32hexmem(const char * p,size_t l,bool padding,void ** mem,size_t * _len)300 int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
301 _cleanup_free_ uint8_t *r = NULL;
302 int a, b, c, d, e, f, g, h;
303 uint8_t *z;
304 const char *x;
305 size_t len;
306 unsigned pad = 0;
307
308 assert(p || l == 0);
309 assert(mem);
310 assert(_len);
311
312 if (l == SIZE_MAX)
313 l = strlen(p);
314
315 /* padding ensures any base32hex input has input divisible by 8 */
316 if (padding && l % 8 != 0)
317 return -EINVAL;
318
319 if (padding) {
320 /* strip the padding */
321 while (l > 0 && p[l - 1] == '=' && pad < 7) {
322 pad++;
323 l--;
324 }
325 }
326
327 /* a group of eight input bytes needs five output bytes, in case of
328 * padding we need to add some extra bytes */
329 len = (l / 8) * 5;
330
331 switch (l % 8) {
332 case 7:
333 len += 4;
334 break;
335 case 5:
336 len += 3;
337 break;
338 case 4:
339 len += 2;
340 break;
341 case 2:
342 len += 1;
343 break;
344 case 0:
345 break;
346 default:
347 return -EINVAL;
348 }
349
350 z = r = malloc(len + 1);
351 if (!r)
352 return -ENOMEM;
353
354 for (x = p; x < p + (l / 8) * 8; x += 8) {
355 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
356 * e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
357 a = unbase32hexchar(x[0]);
358 if (a < 0)
359 return -EINVAL;
360
361 b = unbase32hexchar(x[1]);
362 if (b < 0)
363 return -EINVAL;
364
365 c = unbase32hexchar(x[2]);
366 if (c < 0)
367 return -EINVAL;
368
369 d = unbase32hexchar(x[3]);
370 if (d < 0)
371 return -EINVAL;
372
373 e = unbase32hexchar(x[4]);
374 if (e < 0)
375 return -EINVAL;
376
377 f = unbase32hexchar(x[5]);
378 if (f < 0)
379 return -EINVAL;
380
381 g = unbase32hexchar(x[6]);
382 if (g < 0)
383 return -EINVAL;
384
385 h = unbase32hexchar(x[7]);
386 if (h < 0)
387 return -EINVAL;
388
389 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
390 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
391 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
392 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
393 *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
394 }
395
396 switch (l % 8) {
397 case 7:
398 a = unbase32hexchar(x[0]);
399 if (a < 0)
400 return -EINVAL;
401
402 b = unbase32hexchar(x[1]);
403 if (b < 0)
404 return -EINVAL;
405
406 c = unbase32hexchar(x[2]);
407 if (c < 0)
408 return -EINVAL;
409
410 d = unbase32hexchar(x[3]);
411 if (d < 0)
412 return -EINVAL;
413
414 e = unbase32hexchar(x[4]);
415 if (e < 0)
416 return -EINVAL;
417
418 f = unbase32hexchar(x[5]);
419 if (f < 0)
420 return -EINVAL;
421
422 g = unbase32hexchar(x[6]);
423 if (g < 0)
424 return -EINVAL;
425
426 /* g == 000VV000 */
427 if (g & 7)
428 return -EINVAL;
429
430 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
431 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
432 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
433 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
434
435 break;
436 case 5:
437 a = unbase32hexchar(x[0]);
438 if (a < 0)
439 return -EINVAL;
440
441 b = unbase32hexchar(x[1]);
442 if (b < 0)
443 return -EINVAL;
444
445 c = unbase32hexchar(x[2]);
446 if (c < 0)
447 return -EINVAL;
448
449 d = unbase32hexchar(x[3]);
450 if (d < 0)
451 return -EINVAL;
452
453 e = unbase32hexchar(x[4]);
454 if (e < 0)
455 return -EINVAL;
456
457 /* e == 000SSSS0 */
458 if (e & 1)
459 return -EINVAL;
460
461 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
462 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
463 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
464
465 break;
466 case 4:
467 a = unbase32hexchar(x[0]);
468 if (a < 0)
469 return -EINVAL;
470
471 b = unbase32hexchar(x[1]);
472 if (b < 0)
473 return -EINVAL;
474
475 c = unbase32hexchar(x[2]);
476 if (c < 0)
477 return -EINVAL;
478
479 d = unbase32hexchar(x[3]);
480 if (d < 0)
481 return -EINVAL;
482
483 /* d == 000W0000 */
484 if (d & 15)
485 return -EINVAL;
486
487 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
488 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
489
490 break;
491 case 2:
492 a = unbase32hexchar(x[0]);
493 if (a < 0)
494 return -EINVAL;
495
496 b = unbase32hexchar(x[1]);
497 if (b < 0)
498 return -EINVAL;
499
500 /* b == 000YYY00 */
501 if (b & 3)
502 return -EINVAL;
503
504 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
505
506 break;
507 case 0:
508 break;
509 default:
510 return -EINVAL;
511 }
512
513 *z = 0;
514
515 *mem = TAKE_PTR(r);
516 *_len = len;
517
518 return 0;
519 }
520
521 /* https://tools.ietf.org/html/rfc4648#section-4 */
base64char(int x)522 char base64char(int x) {
523 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
524 "abcdefghijklmnopqrstuvwxyz"
525 "0123456789+/";
526 return table[x & 63];
527 }
528
529 /* This is almost base64char(), but not entirely, as it uses the "url and filename safe" alphabet,
530 * since we don't want "/" appear in interface names (since interfaces appear in sysfs as filenames).
531 * See section #5 of RFC 4648. */
urlsafe_base64char(int x)532 char urlsafe_base64char(int x) {
533 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
534 "abcdefghijklmnopqrstuvwxyz"
535 "0123456789-_";
536 return table[x & 63];
537 }
538
unbase64char(char c)539 int unbase64char(char c) {
540 unsigned offset;
541
542 if (c >= 'A' && c <= 'Z')
543 return c - 'A';
544
545 offset = 'Z' - 'A' + 1;
546
547 if (c >= 'a' && c <= 'z')
548 return c - 'a' + offset;
549
550 offset += 'z' - 'a' + 1;
551
552 if (c >= '0' && c <= '9')
553 return c - '0' + offset;
554
555 offset += '9' - '0' + 1;
556
557 if (c == '+')
558 return offset;
559
560 offset++;
561
562 if (c == '/')
563 return offset;
564
565 return -EINVAL;
566 }
567
maybe_line_break(char ** x,char * start,size_t line_break)568 static void maybe_line_break(char **x, char *start, size_t line_break) {
569 size_t n;
570
571 assert(x);
572 assert(*x);
573 assert(start);
574 assert(*x >= start);
575
576 if (line_break == SIZE_MAX)
577 return;
578
579 n = *x - start;
580
581 if (n % (line_break + 1) == line_break)
582 *((*x)++) = '\n';
583 }
584
base64mem_full(const void * p,size_t l,size_t line_break,char ** out)585 ssize_t base64mem_full(
586 const void *p,
587 size_t l,
588 size_t line_break,
589 char **out) {
590
591 const uint8_t *x;
592 char *r, *z;
593 size_t m;
594
595 assert(p || l == 0);
596 assert(out);
597 assert(line_break > 0);
598
599 /* three input bytes makes four output bytes, padding is added so we must round up */
600 m = 4 * (l + 2) / 3 + 1;
601
602 if (line_break != SIZE_MAX)
603 m += m / line_break;
604
605 z = r = malloc(m);
606 if (!r)
607 return -ENOMEM;
608
609 for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
610 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
611 maybe_line_break(&z, r, line_break);
612 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
613 maybe_line_break(&z, r, line_break);
614 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
615 maybe_line_break(&z, r, line_break);
616 *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
617 maybe_line_break(&z, r, line_break);
618 *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
619 }
620
621 switch (l % 3) {
622 case 2:
623 maybe_line_break(&z, r, line_break);
624 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
625 maybe_line_break(&z, r, line_break);
626 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
627 maybe_line_break(&z, r, line_break);
628 *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
629 maybe_line_break(&z, r, line_break);
630 *(z++) = '=';
631
632 break;
633 case 1:
634 maybe_line_break(&z, r, line_break);
635 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
636 maybe_line_break(&z, r, line_break);
637 *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
638 maybe_line_break(&z, r, line_break);
639 *(z++) = '=';
640 maybe_line_break(&z, r, line_break);
641 *(z++) = '=';
642
643 break;
644 }
645
646 *z = 0;
647 *out = r;
648 assert(z >= r); /* Let static analyzers know that the answer is non-negative. */
649 return z - r;
650 }
651
base64_append_width(char ** prefix,int plen,char sep,int indent,const void * p,size_t l,int width)652 static int base64_append_width(
653 char **prefix, int plen,
654 char sep, int indent,
655 const void *p, size_t l,
656 int width) {
657
658 _cleanup_free_ char *x = NULL;
659 char *t, *s;
660 ssize_t len, avail, line, lines;
661
662 len = base64mem(p, l, &x);
663 if (len <= 0)
664 return len;
665
666 lines = DIV_ROUND_UP(len, width);
667
668 if ((size_t) plen >= SSIZE_MAX - 1 - 1 ||
669 lines > (SSIZE_MAX - plen - 1 - 1) / (indent + width + 1))
670 return -ENOMEM;
671
672 t = realloc(*prefix, (ssize_t) plen + 1 + 1 + (indent + width + 1) * lines);
673 if (!t)
674 return -ENOMEM;
675
676 t[plen] = sep;
677
678 for (line = 0, s = t + plen + 1, avail = len; line < lines; line++) {
679 int act = MIN(width, avail);
680
681 if (line > 0 || sep == '\n') {
682 memset(s, ' ', indent);
683 s += indent;
684 }
685
686 s = mempcpy(s, x + width * line, act);
687 *(s++) = line < lines - 1 ? '\n' : '\0';
688 avail -= act;
689 }
690 assert(avail == 0);
691
692 *prefix = t;
693 return 0;
694 }
695
base64_append(char ** prefix,int plen,const void * p,size_t l,int indent,int width)696 int base64_append(
697 char **prefix, int plen,
698 const void *p, size_t l,
699 int indent, int width) {
700
701 if (plen > width / 2 || plen + indent > width)
702 /* leave indent on the left, keep last column free */
703 return base64_append_width(prefix, plen, '\n', indent, p, l, width - indent - 1);
704 else
705 /* leave plen on the left, keep last column free */
706 return base64_append_width(prefix, plen, ' ', plen + 1, p, l, width - plen - 1);
707 }
708
unbase64_next(const char ** p,size_t * l)709 static int unbase64_next(const char **p, size_t *l) {
710 int ret;
711
712 assert(p);
713 assert(l);
714
715 /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
716 * greedily skip all preceding and all following whitespace. */
717
718 for (;;) {
719 if (*l == 0)
720 return -EPIPE;
721
722 if (!strchr(WHITESPACE, **p))
723 break;
724
725 /* Skip leading whitespace */
726 (*p)++, (*l)--;
727 }
728
729 if (**p == '=')
730 ret = INT_MAX; /* return padding as INT_MAX */
731 else {
732 ret = unbase64char(**p);
733 if (ret < 0)
734 return ret;
735 }
736
737 for (;;) {
738 (*p)++, (*l)--;
739
740 if (*l == 0)
741 break;
742 if (!strchr(WHITESPACE, **p))
743 break;
744
745 /* Skip following whitespace */
746 }
747
748 return ret;
749 }
750
unbase64mem_full(const char * p,size_t l,bool secure,void ** ret,size_t * ret_size)751 int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_size) {
752 _cleanup_free_ uint8_t *buf = NULL;
753 const char *x;
754 uint8_t *z;
755 size_t len;
756 int r;
757
758 assert(p || l == 0);
759
760 if (l == SIZE_MAX)
761 l = strlen(p);
762
763 /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
764 * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
765 len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
766
767 buf = malloc(len + 1);
768 if (!buf)
769 return -ENOMEM;
770
771 for (x = p, z = buf;;) {
772 int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
773
774 a = unbase64_next(&x, &l);
775 if (a == -EPIPE) /* End of string */
776 break;
777 if (a < 0) {
778 r = a;
779 goto on_failure;
780 }
781 if (a == INT_MAX) { /* Padding is not allowed at the beginning of a 4ch block */
782 r = -EINVAL;
783 goto on_failure;
784 }
785
786 b = unbase64_next(&x, &l);
787 if (b < 0) {
788 r = b;
789 goto on_failure;
790 }
791 if (b == INT_MAX) { /* Padding is not allowed at the second character of a 4ch block either */
792 r = -EINVAL;
793 goto on_failure;
794 }
795
796 c = unbase64_next(&x, &l);
797 if (c < 0) {
798 r = c;
799 goto on_failure;
800 }
801
802 d = unbase64_next(&x, &l);
803 if (d < 0) {
804 r = d;
805 goto on_failure;
806 }
807
808 if (c == INT_MAX) { /* Padding at the third character */
809
810 if (d != INT_MAX) { /* If the third character is padding, the fourth must be too */
811 r = -EINVAL;
812 goto on_failure;
813 }
814
815 /* b == 00YY0000 */
816 if (b & 15) {
817 r = -EINVAL;
818 goto on_failure;
819 }
820
821 if (l > 0) { /* Trailing rubbish? */
822 r = -ENAMETOOLONG;
823 goto on_failure;
824 }
825
826 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
827 break;
828 }
829
830 if (d == INT_MAX) {
831 /* c == 00ZZZZ00 */
832 if (c & 3) {
833 r = -EINVAL;
834 goto on_failure;
835 }
836
837 if (l > 0) { /* Trailing rubbish? */
838 r = -ENAMETOOLONG;
839 goto on_failure;
840 }
841
842 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
843 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
844 break;
845 }
846
847 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
848 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
849 *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
850 }
851
852 *z = 0;
853
854 if (ret_size)
855 *ret_size = (size_t) (z - buf);
856 if (ret)
857 *ret = TAKE_PTR(buf);
858
859 return 0;
860
861 on_failure:
862 if (secure)
863 explicit_bzero_safe(buf, len);
864
865 return r;
866 }
867
hexdump(FILE * f,const void * p,size_t s)868 void hexdump(FILE *f, const void *p, size_t s) {
869 const uint8_t *b = p;
870 unsigned n = 0;
871
872 assert(b || s == 0);
873
874 if (!f)
875 f = stdout;
876
877 while (s > 0) {
878 size_t i;
879
880 fprintf(f, "%04x ", n);
881
882 for (i = 0; i < 16; i++) {
883
884 if (i >= s)
885 fputs(" ", f);
886 else
887 fprintf(f, "%02x ", b[i]);
888
889 if (i == 7)
890 fputc(' ', f);
891 }
892
893 fputc(' ', f);
894
895 for (i = 0; i < 16; i++) {
896
897 if (i >= s)
898 fputc(' ', f);
899 else
900 fputc(isprint(b[i]) ? (char) b[i] : '.', f);
901 }
902
903 fputc('\n', f);
904
905 if (s < 16)
906 break;
907
908 n += 16;
909 b += 16;
910 s -= 16;
911 }
912 }
913