]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hexdecoct.c
util: extend unhexmem() to accept secure flag
[thirdparty/systemd.git] / src / basic / hexdecoct.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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
14 char octchar(int x) {
15 return '0' + (x & 7);
16 }
17
18 int unoctchar(char c) {
19
20 if (c >= '0' && c <= '7')
21 return c - '0';
22
23 return -EINVAL;
24 }
25
26 char decchar(int x) {
27 return '0' + (x % 10);
28 }
29
30 int undecchar(char c) {
31
32 if (c >= '0' && c <= '9')
33 return c - '0';
34
35 return -EINVAL;
36 }
37
38 char hexchar(int x) {
39 static const char table[16] = "0123456789abcdef";
40
41 return table[x & 15];
42 }
43
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
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
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
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(ret);
119 assert(ret_len);
120 assert(p || l == 0);
121
122 if (l == (size_t) -1)
123 l = strlen(p);
124
125 /* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */
126 buf_size = (l + 1) / 2 + 1;
127 buf = malloc(buf_size);
128 if (!buf)
129 return -ENOMEM;
130
131 for (x = p, z = buf;;) {
132 int a, b;
133
134 a = unhex_next(&x, &l);
135 if (a == -EPIPE) /* End of string */
136 break;
137 if (a < 0) {
138 r = a;
139 goto on_failure;
140 }
141
142 b = unhex_next(&x, &l);
143 if (b < 0) {
144 r = b;
145 goto on_failure;
146 }
147
148 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
149 }
150
151 *z = 0;
152
153 *ret_len = (size_t) (z - buf);
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. */
171 char base32hexchar(int x) {
172 static const char table[32] = "0123456789"
173 "ABCDEFGHIJKLMNOPQRSTUV";
174
175 return table[x & 31];
176 }
177
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
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
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_t) -1)
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 */
522 char base64char(int x) {
523 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
524 "abcdefghijklmnopqrstuvwxyz"
525 "0123456789+/";
526 return table[x & 63];
527 }
528
529 int 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
550 offset++;
551
552 if (c == '/')
553 return offset;
554
555 return -EINVAL;
556 }
557
558 ssize_t base64mem(const void *p, size_t l, char **out) {
559 char *r, *z;
560 const uint8_t *x;
561
562 assert(p || l == 0);
563 assert(out);
564
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)
568 return -ENOMEM;
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;
596 *out = r;
597 return z - r;
598 }
599
600 static int base64_append_width(
601 char **prefix, int plen,
602 const char *sep, int indent,
603 const void *p, size_t l,
604 int width) {
605
606 _cleanup_free_ char *x = NULL;
607 char *t, *s;
608 ssize_t len, slen, avail, line, lines;
609
610 len = base64mem(p, l, &x);
611 if (len <= 0)
612 return len;
613
614 lines = DIV_ROUND_UP(len, width);
615
616 slen = strlen_ptr(sep);
617 if (plen >= SSIZE_MAX - 1 - slen ||
618 lines > (SSIZE_MAX - plen - 1 - slen) / (indent + width + 1))
619 return -ENOMEM;
620
621 t = realloc(*prefix, (ssize_t) plen + 1 + slen + (indent + width + 1) * lines);
622 if (!t)
623 return -ENOMEM;
624
625 memcpy_safe(t + plen, sep, slen);
626
627 for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
628 int act = MIN(width, avail);
629
630 if (line > 0 || sep) {
631 memset(s, ' ', indent);
632 s += indent;
633 }
634
635 memcpy(s, x + width * line, act);
636 s += act;
637 *(s++) = line < lines - 1 ? '\n' : '\0';
638 avail -= act;
639 }
640 assert(avail == 0);
641
642 *prefix = t;
643 return 0;
644 }
645
646 int base64_append(
647 char **prefix, int plen,
648 const void *p, size_t l,
649 int indent, int width) {
650
651 if (plen > width / 2 || plen + indent > width)
652 /* leave indent on the left, keep last column free */
653 return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
654 else
655 /* leave plen on the left, keep last column free */
656 return base64_append_width(prefix, plen, " ", plen, p, l, width - plen - 1);
657 }
658
659 static int unbase64_next(const char **p, size_t *l) {
660 int ret;
661
662 assert(p);
663 assert(l);
664
665 /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
666 * greedily skip all preceding and all following whitespace. */
667
668 for (;;) {
669 if (*l == 0)
670 return -EPIPE;
671
672 if (!strchr(WHITESPACE, **p))
673 break;
674
675 /* Skip leading whitespace */
676 (*p)++, (*l)--;
677 }
678
679 if (**p == '=')
680 ret = INT_MAX; /* return padding as INT_MAX */
681 else {
682 ret = unbase64char(**p);
683 if (ret < 0)
684 return ret;
685 }
686
687 for (;;) {
688 (*p)++, (*l)--;
689
690 if (*l == 0)
691 break;
692 if (!strchr(WHITESPACE, **p))
693 break;
694
695 /* Skip following whitespace */
696 }
697
698 return ret;
699 }
700
701 int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_size) {
702 _cleanup_free_ uint8_t *buf = NULL;
703 const char *x;
704 uint8_t *z;
705 size_t len;
706 int r;
707
708 assert(p || l == 0);
709 assert(ret);
710 assert(ret_size);
711
712 if (l == (size_t) -1)
713 l = strlen(p);
714
715 /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
716 * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
717 len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
718
719 buf = malloc(len + 1);
720 if (!buf)
721 return -ENOMEM;
722
723 for (x = p, z = buf;;) {
724 int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
725
726 a = unbase64_next(&x, &l);
727 if (a == -EPIPE) /* End of string */
728 break;
729 if (a < 0) {
730 r = a;
731 goto on_failure;
732 }
733 if (a == INT_MAX) { /* Padding is not allowed at the beginning of a 4ch block */
734 r = -EINVAL;
735 goto on_failure;
736 }
737
738 b = unbase64_next(&x, &l);
739 if (b < 0) {
740 r = b;
741 goto on_failure;
742 }
743 if (b == INT_MAX) { /* Padding is not allowed at the second character of a 4ch block either */
744 r = -EINVAL;
745 goto on_failure;
746 }
747
748 c = unbase64_next(&x, &l);
749 if (c < 0) {
750 r = c;
751 goto on_failure;
752 }
753
754 d = unbase64_next(&x, &l);
755 if (d < 0) {
756 r = d;
757 goto on_failure;
758 }
759
760 if (c == INT_MAX) { /* Padding at the third character */
761
762 if (d != INT_MAX) { /* If the third character is padding, the fourth must be too */
763 r = -EINVAL;
764 goto on_failure;
765 }
766
767 /* b == 00YY0000 */
768 if (b & 15) {
769 r = -EINVAL;
770 goto on_failure;
771 }
772
773 if (l > 0) { /* Trailing rubbish? */
774 r = -ENAMETOOLONG;
775 goto on_failure;
776 }
777
778 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
779 break;
780 }
781
782 if (d == INT_MAX) {
783 /* c == 00ZZZZ00 */
784 if (c & 3) {
785 r = -EINVAL;
786 goto on_failure;
787 }
788
789 if (l > 0) { /* Trailing rubbish? */
790 r = -ENAMETOOLONG;
791 goto on_failure;
792 }
793
794 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
795 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
796 break;
797 }
798
799 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
800 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
801 *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
802 }
803
804 *z = 0;
805
806 *ret_size = (size_t) (z - buf);
807 *ret = TAKE_PTR(buf);
808
809 return 0;
810
811 on_failure:
812 if (secure)
813 explicit_bzero_safe(buf, len);
814
815 return r;
816 }
817
818 void hexdump(FILE *f, const void *p, size_t s) {
819 const uint8_t *b = p;
820 unsigned n = 0;
821
822 assert(b || s == 0);
823
824 if (!f)
825 f = stdout;
826
827 while (s > 0) {
828 size_t i;
829
830 fprintf(f, "%04x ", n);
831
832 for (i = 0; i < 16; i++) {
833
834 if (i >= s)
835 fputs(" ", f);
836 else
837 fprintf(f, "%02x ", b[i]);
838
839 if (i == 7)
840 fputc(' ', f);
841 }
842
843 fputc(' ', f);
844
845 for (i = 0; i < 16; i++) {
846
847 if (i >= s)
848 fputc(' ', f);
849 else
850 fputc(isprint(b[i]) ? (char) b[i] : '.', f);
851 }
852
853 fputc('\n', f);
854
855 if (s < 16)
856 break;
857
858 n += 16;
859 b += 16;
860 s -= 16;
861 }
862 }