]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/hexdecoct.c
tree-wide: use UINT64_MAX or friends
[thirdparty/systemd.git] / src / basic / hexdecoct.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
e4e73a63
LP
2
3#include <ctype.h>
11c3a366
TA
4#include <errno.h>
5#include <stdint.h>
6#include <stdlib.h>
e4e73a63 7
b5efdb8a 8#include "alloc-util.h"
e4e73a63 9#include "hexdecoct.h"
11c3a366 10#include "macro.h"
0a970718 11#include "memory-util.h"
7bf7ce28 12#include "string-util.h"
e4e73a63
LP
13
14char octchar(int x) {
15 return '0' + (x & 7);
16}
17
18int unoctchar(char c) {
19
20 if (c >= '0' && c <= '7')
21 return c - '0';
22
23 return -EINVAL;
24}
25
26char decchar(int x) {
27 return '0' + (x % 10);
28}
29
30int undecchar(char c) {
31
32 if (c >= '0' && c <= '9')
33 return c - '0';
34
35 return -EINVAL;
36}
37
38char hexchar(int x) {
39 static const char table[16] = "0123456789abcdef";
40
41 return table[x & 15];
42}
43
44int 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
58char *hexmem(const void *p, size_t l) {
e4e73a63 59 const uint8_t *x;
9ff233dc 60 char *r, *z;
e4e73a63 61
9ff233dc 62 z = r = new(char, l * 2 + 1);
e4e73a63
LP
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
4937b81a
YW
75static 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
f21f31b2 82 * greedily skip all preceding and all following whitespace. */
4937b81a
YW
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
7088befb 111int unhexmem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_len) {
4937b81a 112 _cleanup_free_ uint8_t *buf = NULL;
7088befb 113 size_t buf_size;
e4e73a63 114 const char *x;
4937b81a 115 uint8_t *z;
7088befb 116 int r;
e4e73a63 117
4937b81a
YW
118 assert(ret);
119 assert(ret_len);
ae6e414a
LP
120 assert(p || l == 0);
121
f5fbe71d 122 if (l == SIZE_MAX)
ae6e414a 123 l = strlen(p);
e4e73a63 124
4937b81a 125 /* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */
7088befb
YW
126 buf_size = (l + 1) / 2 + 1;
127 buf = malloc(buf_size);
4937b81a 128 if (!buf)
e4e73a63
LP
129 return -ENOMEM;
130
4937b81a 131 for (x = p, z = buf;;) {
e4e73a63
LP
132 int a, b;
133
4937b81a
YW
134 a = unhex_next(&x, &l);
135 if (a == -EPIPE) /* End of string */
136 break;
7088befb
YW
137 if (a < 0) {
138 r = a;
139 goto on_failure;
140 }
a93c4776 141
4937b81a 142 b = unhex_next(&x, &l);
7088befb
YW
143 if (b < 0) {
144 r = b;
145 goto on_failure;
146 }
e4e73a63
LP
147
148 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
149 }
150
151 *z = 0;
152
4937b81a
YW
153 *ret_len = (size_t) (z - buf);
154 *ret = TAKE_PTR(buf);
e4e73a63
LP
155
156 return 0;
7088befb
YW
157
158on_failure:
159 if (secure)
160 explicit_bzero_safe(buf, buf_size);
161
162 return r;
e4e73a63
LP
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. */
171char base32hexchar(int x) {
172 static const char table[32] = "0123456789"
173 "ABCDEFGHIJKLMNOPQRSTUV";
174
175 return table[x & 31];
176}
177
178int 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
192char *base32hexmem(const void *p, size_t l, bool padding) {
193 char *r, *z;
194 const uint8_t *x;
195 size_t len;
196
ae6e414a
LP
197 assert(p || l == 0);
198
e4e73a63
LP
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
aba13524 228 * x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
e4e73a63
LP
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
300int 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
ae6e414a
LP
308 assert(p || l == 0);
309 assert(mem);
310 assert(_len);
311
f5fbe71d 312 if (l == SIZE_MAX)
ae6e414a 313 l = strlen(p);
e4e73a63
LP
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) {
313cefa1
VC
322 pad++;
323 l--;
e4e73a63
LP
324 }
325 }
326
327 /* a group of eight input bytes needs five output bytes, in case of
aba13524 328 * padding we need to add some extra bytes */
e4e73a63
LP
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
aba13524 356 * e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
e4e73a63
LP
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
1cc6c93a 515 *mem = TAKE_PTR(r);
e4e73a63
LP
516 *_len = len;
517
518 return 0;
519}
520
521/* https://tools.ietf.org/html/rfc4648#section-4 */
522char base64char(int x) {
523 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
524 "abcdefghijklmnopqrstuvwxyz"
525 "0123456789+/";
526 return table[x & 63];
527}
528
529int unbase64char(char c) {
530 unsigned offset;
531
532 if (c >= 'A' && c <= 'Z')
533 return c - 'A';
534
535 offset = 'Z' - 'A' + 1;
536
537 if (c >= 'a' && c <= 'z')
538 return c - 'a' + offset;
539
540 offset += 'z' - 'a' + 1;
541
542 if (c >= '0' && c <= '9')
543 return c - '0' + offset;
544
545 offset += '9' - '0' + 1;
546
547 if (c == '+')
548 return offset;
549
313cefa1 550 offset++;
e4e73a63
LP
551
552 if (c == '/')
553 return offset;
554
555 return -EINVAL;
556}
557
d7671a3e 558ssize_t base64mem(const void *p, size_t l, char **out) {
e4e73a63
LP
559 char *r, *z;
560 const uint8_t *x;
561
ae6e414a
LP
562 assert(p || l == 0);
563 assert(out);
564
e4e73a63
LP
565 /* three input bytes makes four output bytes, padding is added so we must round up */
566 z = r = malloc(4 * (l + 2) / 3 + 1);
567 if (!r)
d7671a3e 568 return -ENOMEM;
e4e73a63
LP
569
570 for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
571 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
572 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
573 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
574 *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
575 *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
576 }
577
578 switch (l % 3) {
579 case 2:
580 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
581 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
582 *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
583 *(z++) = '=';
584
585 break;
586 case 1:
587 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
588 *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
589 *(z++) = '=';
590 *(z++) = '=';
591
592 break;
593 }
594
595 *z = 0;
d7671a3e
ZJS
596 *out = r;
597 return z - r;
598}
599
ae6e414a
LP
600static int base64_append_width(
601 char **prefix, int plen,
0136b1d1 602 char sep, int indent,
ae6e414a
LP
603 const void *p, size_t l,
604 int width) {
d7671a3e
ZJS
605
606 _cleanup_free_ char *x = NULL;
607 char *t, *s;
0136b1d1 608 ssize_t len, avail, line, lines;
d7671a3e
ZJS
609
610 len = base64mem(p, l, &x);
611 if (len <= 0)
612 return len;
613
be6b0c21 614 lines = DIV_ROUND_UP(len, width);
d7671a3e 615
0136b1d1
ZJS
616 if ((size_t) plen >= SSIZE_MAX - 1 - 1 ||
617 lines > (SSIZE_MAX - plen - 1 - 1) / (indent + width + 1))
3d6c1844
ZJS
618 return -ENOMEM;
619
0136b1d1 620 t = realloc(*prefix, (ssize_t) plen + 1 + 1 + (indent + width + 1) * lines);
d7671a3e
ZJS
621 if (!t)
622 return -ENOMEM;
623
0136b1d1 624 t[plen] = sep;
d7671a3e 625
0136b1d1 626 for (line = 0, s = t + plen + 1, avail = len; line < lines; line++) {
d7671a3e
ZJS
627 int act = MIN(width, avail);
628
0136b1d1 629 if (line > 0 || sep == '\n') {
d7671a3e
ZJS
630 memset(s, ' ', indent);
631 s += indent;
632 }
633
634 memcpy(s, x + width * line, act);
635 s += act;
636 *(s++) = line < lines - 1 ? '\n' : '\0';
637 avail -= act;
638 }
639 assert(avail == 0);
640
641 *prefix = t;
642 return 0;
e4e73a63
LP
643}
644
ae6e414a
LP
645int base64_append(
646 char **prefix, int plen,
647 const void *p, size_t l,
648 int indent, int width) {
649
d7671a3e
ZJS
650 if (plen > width / 2 || plen + indent > width)
651 /* leave indent on the left, keep last column free */
0136b1d1 652 return base64_append_width(prefix, plen, '\n', indent, p, l, width - indent - 1);
d7671a3e
ZJS
653 else
654 /* leave plen on the left, keep last column free */
0136b1d1 655 return base64_append_width(prefix, plen, ' ', plen + 1, p, l, width - plen - 1);
ae6e414a 656}
d7671a3e 657
081f36d8
LP
658static int unbase64_next(const char **p, size_t *l) {
659 int ret;
660
661 assert(p);
662 assert(l);
663
664 /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
f21f31b2 665 * greedily skip all preceding and all following whitespace. */
081f36d8
LP
666
667 for (;;) {
668 if (*l == 0)
669 return -EPIPE;
670
671 if (!strchr(WHITESPACE, **p))
672 break;
673
674 /* Skip leading whitespace */
675 (*p)++, (*l)--;
676 }
677
678 if (**p == '=')
679 ret = INT_MAX; /* return padding as INT_MAX */
680 else {
681 ret = unbase64char(**p);
682 if (ret < 0)
683 return ret;
684 }
685
686 for (;;) {
687 (*p)++, (*l)--;
688
689 if (*l == 0)
690 break;
691 if (!strchr(WHITESPACE, **p))
692 break;
693
694 /* Skip following whitespace */
695 }
696
697 return ret;
698}
699
2432d09c 700int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_size) {
081f36d8 701 _cleanup_free_ uint8_t *buf = NULL;
e4e73a63 702 const char *x;
081f36d8 703 uint8_t *z;
e4e73a63 704 size_t len;
2432d09c 705 int r;
e4e73a63 706
ae6e414a 707 assert(p || l == 0);
081f36d8
LP
708 assert(ret);
709 assert(ret_size);
ae6e414a 710
f5fbe71d 711 if (l == SIZE_MAX)
ae6e414a 712 l = strlen(p);
e4e73a63 713
081f36d8 714 /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
aba13524 715 * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
081f36d8 716 len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
e4e73a63 717
081f36d8
LP
718 buf = malloc(len + 1);
719 if (!buf)
e4e73a63
LP
720 return -ENOMEM;
721
081f36d8
LP
722 for (x = p, z = buf;;) {
723 int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
724
725 a = unbase64_next(&x, &l);
726 if (a == -EPIPE) /* End of string */
727 break;
2432d09c
YW
728 if (a < 0) {
729 r = a;
730 goto on_failure;
731 }
732 if (a == INT_MAX) { /* Padding is not allowed at the beginning of a 4ch block */
733 r = -EINVAL;
734 goto on_failure;
735 }
e4e73a63 736
081f36d8 737 b = unbase64_next(&x, &l);
2432d09c
YW
738 if (b < 0) {
739 r = b;
740 goto on_failure;
741 }
742 if (b == INT_MAX) { /* Padding is not allowed at the second character of a 4ch block either */
743 r = -EINVAL;
744 goto on_failure;
745 }
e4e73a63 746
081f36d8 747 c = unbase64_next(&x, &l);
2432d09c
YW
748 if (c < 0) {
749 r = c;
750 goto on_failure;
751 }
e4e73a63 752
081f36d8 753 d = unbase64_next(&x, &l);
2432d09c
YW
754 if (d < 0) {
755 r = d;
756 goto on_failure;
757 }
ae6e414a 758
081f36d8 759 if (c == INT_MAX) { /* Padding at the third character */
e4e73a63 760
2432d09c
YW
761 if (d != INT_MAX) { /* If the third character is padding, the fourth must be too */
762 r = -EINVAL;
763 goto on_failure;
764 }
e4e73a63 765
081f36d8 766 /* b == 00YY0000 */
2432d09c
YW
767 if (b & 15) {
768 r = -EINVAL;
769 goto on_failure;
770 }
e4e73a63 771
2432d09c
YW
772 if (l > 0) { /* Trailing rubbish? */
773 r = -ENAMETOOLONG;
774 goto on_failure;
775 }
e4e73a63 776
081f36d8
LP
777 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
778 break;
779 }
e4e73a63 780
081f36d8
LP
781 if (d == INT_MAX) {
782 /* c == 00ZZZZ00 */
2432d09c
YW
783 if (c & 3) {
784 r = -EINVAL;
785 goto on_failure;
786 }
e4e73a63 787
2432d09c
YW
788 if (l > 0) { /* Trailing rubbish? */
789 r = -ENAMETOOLONG;
790 goto on_failure;
791 }
e4e73a63 792
081f36d8
LP
793 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
794 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
795 break;
796 }
e4e73a63 797
081f36d8
LP
798 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
799 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
800 *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
e4e73a63
LP
801 }
802
803 *z = 0;
804
9ec578a3 805 *ret_size = (size_t) (z - buf);
1cc6c93a 806 *ret = TAKE_PTR(buf);
e4e73a63
LP
807
808 return 0;
2432d09c
YW
809
810on_failure:
811 if (secure)
812 explicit_bzero_safe(buf, len);
813
814 return r;
e4e73a63
LP
815}
816
817void hexdump(FILE *f, const void *p, size_t s) {
818 const uint8_t *b = p;
819 unsigned n = 0;
820
a3ab8f2a
LP
821 assert(b || s == 0);
822
823 if (!f)
824 f = stdout;
e4e73a63
LP
825
826 while (s > 0) {
827 size_t i;
828
829 fprintf(f, "%04x ", n);
830
831 for (i = 0; i < 16; i++) {
832
833 if (i >= s)
834 fputs(" ", f);
835 else
836 fprintf(f, "%02x ", b[i]);
837
838 if (i == 7)
839 fputc(' ', f);
840 }
841
842 fputc(' ', f);
843
844 for (i = 0; i < 16; i++) {
845
846 if (i >= s)
847 fputc(' ', f);
848 else
849 fputc(isprint(b[i]) ? (char) b[i] : '.', f);
850 }
851
852 fputc('\n', f);
853
854 if (s < 16)
855 break;
856
857 n += 16;
858 b += 16;
859 s -= 16;
860 }
861}