]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hexdecoct.c
Merge pull request #7198 from poettering/stdin-stdout
[thirdparty/systemd.git] / src / basic / hexdecoct.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <ctype.h>
22 #include <errno.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25
26 #include "alloc-util.h"
27 #include "hexdecoct.h"
28 #include "macro.h"
29 #include "string-util.h"
30 #include "util.h"
31
32 char octchar(int x) {
33 return '0' + (x & 7);
34 }
35
36 int unoctchar(char c) {
37
38 if (c >= '0' && c <= '7')
39 return c - '0';
40
41 return -EINVAL;
42 }
43
44 char decchar(int x) {
45 return '0' + (x % 10);
46 }
47
48 int undecchar(char c) {
49
50 if (c >= '0' && c <= '9')
51 return c - '0';
52
53 return -EINVAL;
54 }
55
56 char hexchar(int x) {
57 static const char table[16] = "0123456789abcdef";
58
59 return table[x & 15];
60 }
61
62 int unhexchar(char c) {
63
64 if (c >= '0' && c <= '9')
65 return c - '0';
66
67 if (c >= 'a' && c <= 'f')
68 return c - 'a' + 10;
69
70 if (c >= 'A' && c <= 'F')
71 return c - 'A' + 10;
72
73 return -EINVAL;
74 }
75
76 char *hexmem(const void *p, size_t l) {
77 const uint8_t *x;
78 char *r, *z;
79
80 z = r = new(char, l * 2 + 1);
81 if (!r)
82 return NULL;
83
84 for (x = p; x < (const uint8_t*) p + l; x++) {
85 *(z++) = hexchar(*x >> 4);
86 *(z++) = hexchar(*x & 15);
87 }
88
89 *z = 0;
90 return r;
91 }
92
93 int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
94 _cleanup_free_ uint8_t *r = NULL;
95 uint8_t *z;
96 const char *x;
97
98 assert(mem);
99 assert(len);
100 assert(p || l == 0);
101
102 if (l == (size_t) -1)
103 l = strlen(p);
104
105 if (l % 2 != 0)
106 return -EINVAL;
107
108 z = r = malloc((l + 1) / 2 + 1);
109 if (!r)
110 return -ENOMEM;
111
112 for (x = p; x < p + l; x += 2) {
113 int a, b;
114
115 a = unhexchar(x[0]);
116 if (a < 0)
117 return a;
118
119 b = unhexchar(x[1]);
120 if (b < 0)
121 return b;
122
123 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
124 }
125
126 *z = 0;
127
128 *mem = r;
129 r = NULL;
130 *len = (l + 1) / 2;
131
132 return 0;
133 }
134
135 /* https://tools.ietf.org/html/rfc4648#section-6
136 * Notice that base32hex differs from base32 in the alphabet it uses.
137 * The distinction is that the base32hex representation preserves the
138 * order of the underlying data when compared as bytestrings, this is
139 * useful when representing NSEC3 hashes, as one can then verify the
140 * order of hashes directly from their representation. */
141 char base32hexchar(int x) {
142 static const char table[32] = "0123456789"
143 "ABCDEFGHIJKLMNOPQRSTUV";
144
145 return table[x & 31];
146 }
147
148 int unbase32hexchar(char c) {
149 unsigned offset;
150
151 if (c >= '0' && c <= '9')
152 return c - '0';
153
154 offset = '9' - '0' + 1;
155
156 if (c >= 'A' && c <= 'V')
157 return c - 'A' + offset;
158
159 return -EINVAL;
160 }
161
162 char *base32hexmem(const void *p, size_t l, bool padding) {
163 char *r, *z;
164 const uint8_t *x;
165 size_t len;
166
167 assert(p || l == 0);
168
169 if (padding)
170 /* five input bytes makes eight output bytes, padding is added so we must round up */
171 len = 8 * (l + 4) / 5;
172 else {
173 /* same, but round down as there is no padding */
174 len = 8 * l / 5;
175
176 switch (l % 5) {
177 case 4:
178 len += 7;
179 break;
180 case 3:
181 len += 5;
182 break;
183 case 2:
184 len += 4;
185 break;
186 case 1:
187 len += 2;
188 break;
189 }
190 }
191
192 z = r = malloc(len + 1);
193 if (!r)
194 return NULL;
195
196 for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
197 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
198 x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
199 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
200 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
201 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
202 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
203 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
204 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
205 *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
206 *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
207 }
208
209 switch (l % 5) {
210 case 4:
211 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
212 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
213 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
214 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
215 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
216 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
217 *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
218 if (padding)
219 *(z++) = '=';
220
221 break;
222
223 case 3:
224 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
225 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
226 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
227 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
228 *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
229 if (padding) {
230 *(z++) = '=';
231 *(z++) = '=';
232 *(z++) = '=';
233 }
234
235 break;
236
237 case 2:
238 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
239 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
240 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
241 *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
242 if (padding) {
243 *(z++) = '=';
244 *(z++) = '=';
245 *(z++) = '=';
246 *(z++) = '=';
247 }
248
249 break;
250
251 case 1:
252 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
253 *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
254 if (padding) {
255 *(z++) = '=';
256 *(z++) = '=';
257 *(z++) = '=';
258 *(z++) = '=';
259 *(z++) = '=';
260 *(z++) = '=';
261 }
262
263 break;
264 }
265
266 *z = 0;
267 return r;
268 }
269
270 int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
271 _cleanup_free_ uint8_t *r = NULL;
272 int a, b, c, d, e, f, g, h;
273 uint8_t *z;
274 const char *x;
275 size_t len;
276 unsigned pad = 0;
277
278 assert(p || l == 0);
279 assert(mem);
280 assert(_len);
281
282 if (l == (size_t) -1)
283 l = strlen(p);
284
285 /* padding ensures any base32hex input has input divisible by 8 */
286 if (padding && l % 8 != 0)
287 return -EINVAL;
288
289 if (padding) {
290 /* strip the padding */
291 while (l > 0 && p[l - 1] == '=' && pad < 7) {
292 pad++;
293 l--;
294 }
295 }
296
297 /* a group of eight input bytes needs five output bytes, in case of
298 padding we need to add some extra bytes */
299 len = (l / 8) * 5;
300
301 switch (l % 8) {
302 case 7:
303 len += 4;
304 break;
305 case 5:
306 len += 3;
307 break;
308 case 4:
309 len += 2;
310 break;
311 case 2:
312 len += 1;
313 break;
314 case 0:
315 break;
316 default:
317 return -EINVAL;
318 }
319
320 z = r = malloc(len + 1);
321 if (!r)
322 return -ENOMEM;
323
324 for (x = p; x < p + (l / 8) * 8; x += 8) {
325 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
326 e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
327 a = unbase32hexchar(x[0]);
328 if (a < 0)
329 return -EINVAL;
330
331 b = unbase32hexchar(x[1]);
332 if (b < 0)
333 return -EINVAL;
334
335 c = unbase32hexchar(x[2]);
336 if (c < 0)
337 return -EINVAL;
338
339 d = unbase32hexchar(x[3]);
340 if (d < 0)
341 return -EINVAL;
342
343 e = unbase32hexchar(x[4]);
344 if (e < 0)
345 return -EINVAL;
346
347 f = unbase32hexchar(x[5]);
348 if (f < 0)
349 return -EINVAL;
350
351 g = unbase32hexchar(x[6]);
352 if (g < 0)
353 return -EINVAL;
354
355 h = unbase32hexchar(x[7]);
356 if (h < 0)
357 return -EINVAL;
358
359 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
360 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
361 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
362 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
363 *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
364 }
365
366 switch (l % 8) {
367 case 7:
368 a = unbase32hexchar(x[0]);
369 if (a < 0)
370 return -EINVAL;
371
372 b = unbase32hexchar(x[1]);
373 if (b < 0)
374 return -EINVAL;
375
376 c = unbase32hexchar(x[2]);
377 if (c < 0)
378 return -EINVAL;
379
380 d = unbase32hexchar(x[3]);
381 if (d < 0)
382 return -EINVAL;
383
384 e = unbase32hexchar(x[4]);
385 if (e < 0)
386 return -EINVAL;
387
388 f = unbase32hexchar(x[5]);
389 if (f < 0)
390 return -EINVAL;
391
392 g = unbase32hexchar(x[6]);
393 if (g < 0)
394 return -EINVAL;
395
396 /* g == 000VV000 */
397 if (g & 7)
398 return -EINVAL;
399
400 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
401 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
402 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
403 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
404
405 break;
406 case 5:
407 a = unbase32hexchar(x[0]);
408 if (a < 0)
409 return -EINVAL;
410
411 b = unbase32hexchar(x[1]);
412 if (b < 0)
413 return -EINVAL;
414
415 c = unbase32hexchar(x[2]);
416 if (c < 0)
417 return -EINVAL;
418
419 d = unbase32hexchar(x[3]);
420 if (d < 0)
421 return -EINVAL;
422
423 e = unbase32hexchar(x[4]);
424 if (e < 0)
425 return -EINVAL;
426
427 /* e == 000SSSS0 */
428 if (e & 1)
429 return -EINVAL;
430
431 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
432 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
433 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
434
435 break;
436 case 4:
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 /* d == 000W0000 */
454 if (d & 15)
455 return -EINVAL;
456
457 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
458 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
459
460 break;
461 case 2:
462 a = unbase32hexchar(x[0]);
463 if (a < 0)
464 return -EINVAL;
465
466 b = unbase32hexchar(x[1]);
467 if (b < 0)
468 return -EINVAL;
469
470 /* b == 000YYY00 */
471 if (b & 3)
472 return -EINVAL;
473
474 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
475
476 break;
477 case 0:
478 break;
479 default:
480 return -EINVAL;
481 }
482
483 *z = 0;
484
485 *mem = r;
486 r = NULL;
487 *_len = len;
488
489 return 0;
490 }
491
492 /* https://tools.ietf.org/html/rfc4648#section-4 */
493 char base64char(int x) {
494 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
495 "abcdefghijklmnopqrstuvwxyz"
496 "0123456789+/";
497 return table[x & 63];
498 }
499
500 int unbase64char(char c) {
501 unsigned offset;
502
503 if (c >= 'A' && c <= 'Z')
504 return c - 'A';
505
506 offset = 'Z' - 'A' + 1;
507
508 if (c >= 'a' && c <= 'z')
509 return c - 'a' + offset;
510
511 offset += 'z' - 'a' + 1;
512
513 if (c >= '0' && c <= '9')
514 return c - '0' + offset;
515
516 offset += '9' - '0' + 1;
517
518 if (c == '+')
519 return offset;
520
521 offset++;
522
523 if (c == '/')
524 return offset;
525
526 return -EINVAL;
527 }
528
529 ssize_t base64mem(const void *p, size_t l, char **out) {
530 char *r, *z;
531 const uint8_t *x;
532
533 assert(p || l == 0);
534 assert(out);
535
536 /* three input bytes makes four output bytes, padding is added so we must round up */
537 z = r = malloc(4 * (l + 2) / 3 + 1);
538 if (!r)
539 return -ENOMEM;
540
541 for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
542 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
543 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
544 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
545 *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
546 *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
547 }
548
549 switch (l % 3) {
550 case 2:
551 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
552 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
553 *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
554 *(z++) = '=';
555
556 break;
557 case 1:
558 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
559 *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
560 *(z++) = '=';
561 *(z++) = '=';
562
563 break;
564 }
565
566 *z = 0;
567 *out = r;
568 return z - r;
569 }
570
571 static int base64_append_width(
572 char **prefix, int plen,
573 const char *sep, int indent,
574 const void *p, size_t l,
575 int width) {
576
577 _cleanup_free_ char *x = NULL;
578 char *t, *s;
579 ssize_t slen, len, avail;
580 int line, lines;
581
582 len = base64mem(p, l, &x);
583 if (len <= 0)
584 return len;
585
586 lines = (len + width - 1) / width;
587
588 slen = strlen_ptr(sep);
589 t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
590 if (!t)
591 return -ENOMEM;
592
593 memcpy_safe(t + plen, sep, slen);
594
595 for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
596 int act = MIN(width, avail);
597
598 if (line > 0 || sep) {
599 memset(s, ' ', indent);
600 s += indent;
601 }
602
603 memcpy(s, x + width * line, act);
604 s += act;
605 *(s++) = line < lines - 1 ? '\n' : '\0';
606 avail -= act;
607 }
608 assert(avail == 0);
609
610 *prefix = t;
611 return 0;
612 }
613
614 int base64_append(
615 char **prefix, int plen,
616 const void *p, size_t l,
617 int indent, int width) {
618
619 if (plen > width / 2 || plen + indent > width)
620 /* leave indent on the left, keep last column free */
621 return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
622 else
623 /* leave plen on the left, keep last column free */
624 return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1);
625 }
626
627 int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
628 _cleanup_free_ uint8_t *r = NULL;
629 int a, b, c, d;
630 uint8_t *z;
631 const char *x;
632 size_t len;
633
634 assert(p || l == 0);
635 assert(mem);
636 assert(_len);
637
638 if (l == (size_t) -1)
639 l = strlen(p);
640
641 /* padding ensures any base63 input has input divisible by 4 */
642 if (l % 4 != 0)
643 return -EINVAL;
644
645 /* strip the padding */
646 if (l > 0 && p[l - 1] == '=')
647 l--;
648 if (l > 0 && p[l - 1] == '=')
649 l--;
650
651 /* a group of four input bytes needs three output bytes, in case of
652 padding we need to add two or three extra bytes */
653 len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
654
655 z = r = malloc(len + 1);
656 if (!r)
657 return -ENOMEM;
658
659 for (x = p; x < p + (l / 4) * 4; x += 4) {
660 /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
661 a = unbase64char(x[0]);
662 if (a < 0)
663 return -EINVAL;
664
665 b = unbase64char(x[1]);
666 if (b < 0)
667 return -EINVAL;
668
669 c = unbase64char(x[2]);
670 if (c < 0)
671 return -EINVAL;
672
673 d = unbase64char(x[3]);
674 if (d < 0)
675 return -EINVAL;
676
677 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
678 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
679 *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
680 }
681
682 switch (l % 4) {
683
684 case 3:
685 a = unbase64char(x[0]);
686 if (a < 0)
687 return -EINVAL;
688
689 b = unbase64char(x[1]);
690 if (b < 0)
691 return -EINVAL;
692
693 c = unbase64char(x[2]);
694 if (c < 0)
695 return -EINVAL;
696
697 /* c == 00ZZZZ00 */
698 if (c & 3)
699 return -EINVAL;
700
701 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
702 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
703
704 break;
705 case 2:
706 a = unbase64char(x[0]);
707 if (a < 0)
708 return -EINVAL;
709
710 b = unbase64char(x[1]);
711 if (b < 0)
712 return -EINVAL;
713
714 /* b == 00YY0000 */
715 if (b & 15)
716 return -EINVAL;
717
718 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
719
720 break;
721 case 0:
722
723 break;
724 default:
725 return -EINVAL;
726 }
727
728 *z = 0;
729
730 *mem = r;
731 r = NULL;
732 *_len = len;
733
734 return 0;
735 }
736
737 void hexdump(FILE *f, const void *p, size_t s) {
738 const uint8_t *b = p;
739 unsigned n = 0;
740
741 assert(b || s == 0);
742
743 if (!f)
744 f = stdout;
745
746 while (s > 0) {
747 size_t i;
748
749 fprintf(f, "%04x ", n);
750
751 for (i = 0; i < 16; i++) {
752
753 if (i >= s)
754 fputs(" ", f);
755 else
756 fprintf(f, "%02x ", b[i]);
757
758 if (i == 7)
759 fputc(' ', f);
760 }
761
762 fputc(' ', f);
763
764 for (i = 0; i < 16; i++) {
765
766 if (i >= s)
767 fputc(' ', f);
768 else
769 fputc(isprint(b[i]) ? (char) b[i] : '.', f);
770 }
771
772 fputc('\n', f);
773
774 if (s < 16)
775 break;
776
777 n += 16;
778 b += 16;
779 s -= 16;
780 }
781 }