]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hexdecoct.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "alloc-util.h"
11 #include "memory-util.h"
12 #include "string-util.h"
18 int unoctchar(char c
) {
20 if (c
>= '0' && c
<= '7')
27 return '0' + (x
% 10);
30 int undecchar(char c
) {
32 if (c
>= '0' && c
<= '9')
39 static const char table
[16] = "0123456789abcdef";
44 int unhexchar(char c
) {
46 if (c
>= '0' && c
<= '9')
49 if (c
>= 'a' && c
<= 'f')
52 if (c
>= 'A' && c
<= 'F')
58 char *hexmem(const void *p
, size_t l
) {
62 z
= r
= new(char, l
* 2 + 1);
66 for (x
= p
; x
< (const uint8_t*) p
+ l
; x
++) {
67 *(z
++) = hexchar(*x
>> 4);
68 *(z
++) = hexchar(*x
& 15);
75 static int unhex_next(const char **p
, size_t *l
) {
81 /* Find the next non-whitespace character, and decode it. We
82 * greedily skip all preceding and all following whitespace. */
88 if (!strchr(WHITESPACE
, **p
))
91 /* Skip leading whitespace */
102 if (*l
== 0 || !strchr(WHITESPACE
, **p
))
105 /* Skip following whitespace */
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
;
122 if (l
== (size_t) -1)
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
);
131 for (x
= p
, z
= buf
;;) {
134 a
= unhex_next(&x
, &l
);
135 if (a
== -EPIPE
) /* End of string */
142 b
= unhex_next(&x
, &l
);
148 *(z
++) = (uint8_t) a
<< 4 | (uint8_t) b
;
153 *ret_len
= (size_t) (z
- buf
);
154 *ret
= TAKE_PTR(buf
);
160 explicit_bzero_safe(buf
, buf_size
);
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";
175 return table
[x
& 31];
178 int unbase32hexchar(char c
) {
181 if (c
>= '0' && c
<= '9')
184 offset
= '9' - '0' + 1;
186 if (c
>= 'A' && c
<= 'V')
187 return c
- 'A' + offset
;
192 char *base32hexmem(const void *p
, size_t l
, bool padding
) {
200 /* five input bytes makes eight output bytes, padding is added so we must round up */
201 len
= 8 * (l
+ 4) / 5;
203 /* same, but round down as there is no padding */
222 z
= r
= malloc(len
+ 1);
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 */
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 */
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 */
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 */
282 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
283 *(z
++) = base32hexchar((x
[0] & 7) << 2); /* 000XXX00 */
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
;
312 if (l
== (size_t) -1)
315 /* padding ensures any base32hex input has input divisible by 8 */
316 if (padding
&& l
% 8 != 0)
320 /* strip the padding */
321 while (l
> 0 && p
[l
- 1] == '=' && pad
< 7) {
327 /* a group of eight input bytes needs five output bytes, in case of
328 * padding we need to add some extra bytes */
350 z
= r
= malloc(len
+ 1);
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]);
361 b
= unbase32hexchar(x
[1]);
365 c
= unbase32hexchar(x
[2]);
369 d
= unbase32hexchar(x
[3]);
373 e
= unbase32hexchar(x
[4]);
377 f
= unbase32hexchar(x
[5]);
381 g
= unbase32hexchar(x
[6]);
385 h
= unbase32hexchar(x
[7]);
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 */
398 a
= unbase32hexchar(x
[0]);
402 b
= unbase32hexchar(x
[1]);
406 c
= unbase32hexchar(x
[2]);
410 d
= unbase32hexchar(x
[3]);
414 e
= unbase32hexchar(x
[4]);
418 f
= unbase32hexchar(x
[5]);
422 g
= unbase32hexchar(x
[6]);
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 */
437 a
= unbase32hexchar(x
[0]);
441 b
= unbase32hexchar(x
[1]);
445 c
= unbase32hexchar(x
[2]);
449 d
= unbase32hexchar(x
[3]);
453 e
= unbase32hexchar(x
[4]);
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 */
467 a
= unbase32hexchar(x
[0]);
471 b
= unbase32hexchar(x
[1]);
475 c
= unbase32hexchar(x
[2]);
479 d
= unbase32hexchar(x
[3]);
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 */
492 a
= unbase32hexchar(x
[0]);
496 b
= unbase32hexchar(x
[1]);
504 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
521 /* https://tools.ietf.org/html/rfc4648#section-4 */
522 char base64char(int x
) {
523 static const char table
[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
524 "abcdefghijklmnopqrstuvwxyz"
526 return table
[x
& 63];
529 int unbase64char(char c
) {
532 if (c
>= 'A' && c
<= 'Z')
535 offset
= 'Z' - 'A' + 1;
537 if (c
>= 'a' && c
<= 'z')
538 return c
- 'a' + offset
;
540 offset
+= 'z' - 'a' + 1;
542 if (c
>= '0' && c
<= '9')
543 return c
- '0' + offset
;
545 offset
+= '9' - '0' + 1;
558 ssize_t
base64mem(const void *p
, size_t l
, char **out
) {
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);
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 */
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 */
587 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
588 *(z
++) = base64char((x
[0] & 3) << 4); /* 00XX0000 */
600 static int base64_append_width(
601 char **prefix
, int plen
,
602 const char *sep
, int indent
,
603 const void *p
, size_t l
,
606 _cleanup_free_
char *x
= NULL
;
608 ssize_t len
, slen
, avail
, line
, lines
;
610 len
= base64mem(p
, l
, &x
);
614 lines
= DIV_ROUND_UP(len
, width
);
616 slen
= strlen_ptr(sep
);
617 if (plen
>= SSIZE_MAX
- 1 - slen
||
618 lines
> (SSIZE_MAX
- plen
- 1 - slen
) / (indent
+ width
+ 1))
621 t
= realloc(*prefix
, (ssize_t
) plen
+ 1 + slen
+ (indent
+ width
+ 1) * lines
);
625 memcpy_safe(t
+ plen
, sep
, slen
);
627 for (line
= 0, s
= t
+ plen
+ slen
, avail
= len
; line
< lines
; line
++) {
628 int act
= MIN(width
, avail
);
630 if (line
> 0 || sep
) {
631 memset(s
, ' ', indent
);
635 memcpy(s
, x
+ width
* line
, act
);
637 *(s
++) = line
< lines
- 1 ? '\n' : '\0';
647 char **prefix
, int plen
,
648 const void *p
, size_t l
,
649 int indent
, int width
) {
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);
655 /* leave plen on the left, keep last column free */
656 return base64_append_width(prefix
, plen
, " ", plen
, p
, l
, width
- plen
- 1);
659 static int unbase64_next(const char **p
, size_t *l
) {
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. */
672 if (!strchr(WHITESPACE
, **p
))
675 /* Skip leading whitespace */
680 ret
= INT_MAX
; /* return padding as INT_MAX */
682 ret
= unbase64char(**p
);
692 if (!strchr(WHITESPACE
, **p
))
695 /* Skip following whitespace */
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
;
712 if (l
== (size_t) -1)
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);
719 buf
= malloc(len
+ 1);
723 for (x
= p
, z
= buf
;;) {
724 int a
, b
, c
, d
; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
726 a
= unbase64_next(&x
, &l
);
727 if (a
== -EPIPE
) /* End of string */
733 if (a
== INT_MAX
) { /* Padding is not allowed at the beginning of a 4ch block */
738 b
= unbase64_next(&x
, &l
);
743 if (b
== INT_MAX
) { /* Padding is not allowed at the second character of a 4ch block either */
748 c
= unbase64_next(&x
, &l
);
754 d
= unbase64_next(&x
, &l
);
760 if (c
== INT_MAX
) { /* Padding at the third character */
762 if (d
!= INT_MAX
) { /* If the third character is padding, the fourth must be too */
773 if (l
> 0) { /* Trailing rubbish? */
778 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) (b
>> 4); /* XXXXXXYY */
789 if (l
> 0) { /* Trailing rubbish? */
794 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
795 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
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 */
806 *ret_size
= (size_t) (z
- buf
);
807 *ret
= TAKE_PTR(buf
);
813 explicit_bzero_safe(buf
, len
);
818 void hexdump(FILE *f
, const void *p
, size_t s
) {
819 const uint8_t *b
= p
;
830 fprintf(f
, "%04x ", n
);
832 for (i
= 0; i
< 16; i
++) {
837 fprintf(f
, "%02x ", b
[i
]);
845 for (i
= 0; i
< 16; i
++) {
850 fputc(isprint(b
[i
]) ? (char) b
[i
] : '.', f
);