]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hexdecoct.c
Add SPDX license identifiers to source files under the LGPL
[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);
101
102 if (l % 2 != 0)
103 return -EINVAL;
104
105 z = r = malloc((l + 1) / 2 + 1);
106 if (!r)
107 return -ENOMEM;
108
109 for (x = p; x < p + l; x += 2) {
110 int a, b;
111
112 a = unhexchar(x[0]);
113 if (a < 0)
114 return a;
115
116 b = unhexchar(x[1]);
117 if (b < 0)
118 return b;
119
120 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
121 }
122
123 *z = 0;
124
125 *mem = r;
126 r = NULL;
127 *len = (l + 1) / 2;
128
129 return 0;
130 }
131
132 /* https://tools.ietf.org/html/rfc4648#section-6
133 * Notice that base32hex differs from base32 in the alphabet it uses.
134 * The distinction is that the base32hex representation preserves the
135 * order of the underlying data when compared as bytestrings, this is
136 * useful when representing NSEC3 hashes, as one can then verify the
137 * order of hashes directly from their representation. */
138 char base32hexchar(int x) {
139 static const char table[32] = "0123456789"
140 "ABCDEFGHIJKLMNOPQRSTUV";
141
142 return table[x & 31];
143 }
144
145 int unbase32hexchar(char c) {
146 unsigned offset;
147
148 if (c >= '0' && c <= '9')
149 return c - '0';
150
151 offset = '9' - '0' + 1;
152
153 if (c >= 'A' && c <= 'V')
154 return c - 'A' + offset;
155
156 return -EINVAL;
157 }
158
159 char *base32hexmem(const void *p, size_t l, bool padding) {
160 char *r, *z;
161 const uint8_t *x;
162 size_t len;
163
164 if (padding)
165 /* five input bytes makes eight output bytes, padding is added so we must round up */
166 len = 8 * (l + 4) / 5;
167 else {
168 /* same, but round down as there is no padding */
169 len = 8 * l / 5;
170
171 switch (l % 5) {
172 case 4:
173 len += 7;
174 break;
175 case 3:
176 len += 5;
177 break;
178 case 2:
179 len += 4;
180 break;
181 case 1:
182 len += 2;
183 break;
184 }
185 }
186
187 z = r = malloc(len + 1);
188 if (!r)
189 return NULL;
190
191 for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
192 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
193 x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
194 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
195 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
196 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
197 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
198 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
199 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
200 *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
201 *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
202 }
203
204 switch (l % 5) {
205 case 4:
206 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
207 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
208 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
209 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
210 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
211 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
212 *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
213 if (padding)
214 *(z++) = '=';
215
216 break;
217
218 case 3:
219 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
220 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
221 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
222 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
223 *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
224 if (padding) {
225 *(z++) = '=';
226 *(z++) = '=';
227 *(z++) = '=';
228 }
229
230 break;
231
232 case 2:
233 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
234 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
235 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
236 *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
237 if (padding) {
238 *(z++) = '=';
239 *(z++) = '=';
240 *(z++) = '=';
241 *(z++) = '=';
242 }
243
244 break;
245
246 case 1:
247 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
248 *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
249 if (padding) {
250 *(z++) = '=';
251 *(z++) = '=';
252 *(z++) = '=';
253 *(z++) = '=';
254 *(z++) = '=';
255 *(z++) = '=';
256 }
257
258 break;
259 }
260
261 *z = 0;
262 return r;
263 }
264
265 int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
266 _cleanup_free_ uint8_t *r = NULL;
267 int a, b, c, d, e, f, g, h;
268 uint8_t *z;
269 const char *x;
270 size_t len;
271 unsigned pad = 0;
272
273 assert(p);
274
275 /* padding ensures any base32hex input has input divisible by 8 */
276 if (padding && l % 8 != 0)
277 return -EINVAL;
278
279 if (padding) {
280 /* strip the padding */
281 while (l > 0 && p[l - 1] == '=' && pad < 7) {
282 pad++;
283 l--;
284 }
285 }
286
287 /* a group of eight input bytes needs five output bytes, in case of
288 padding we need to add some extra bytes */
289 len = (l / 8) * 5;
290
291 switch (l % 8) {
292 case 7:
293 len += 4;
294 break;
295 case 5:
296 len += 3;
297 break;
298 case 4:
299 len += 2;
300 break;
301 case 2:
302 len += 1;
303 break;
304 case 0:
305 break;
306 default:
307 return -EINVAL;
308 }
309
310 z = r = malloc(len + 1);
311 if (!r)
312 return -ENOMEM;
313
314 for (x = p; x < p + (l / 8) * 8; x += 8) {
315 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
316 e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
317 a = unbase32hexchar(x[0]);
318 if (a < 0)
319 return -EINVAL;
320
321 b = unbase32hexchar(x[1]);
322 if (b < 0)
323 return -EINVAL;
324
325 c = unbase32hexchar(x[2]);
326 if (c < 0)
327 return -EINVAL;
328
329 d = unbase32hexchar(x[3]);
330 if (d < 0)
331 return -EINVAL;
332
333 e = unbase32hexchar(x[4]);
334 if (e < 0)
335 return -EINVAL;
336
337 f = unbase32hexchar(x[5]);
338 if (f < 0)
339 return -EINVAL;
340
341 g = unbase32hexchar(x[6]);
342 if (g < 0)
343 return -EINVAL;
344
345 h = unbase32hexchar(x[7]);
346 if (h < 0)
347 return -EINVAL;
348
349 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
350 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
351 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
352 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
353 *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
354 }
355
356 switch (l % 8) {
357 case 7:
358 a = unbase32hexchar(x[0]);
359 if (a < 0)
360 return -EINVAL;
361
362 b = unbase32hexchar(x[1]);
363 if (b < 0)
364 return -EINVAL;
365
366 c = unbase32hexchar(x[2]);
367 if (c < 0)
368 return -EINVAL;
369
370 d = unbase32hexchar(x[3]);
371 if (d < 0)
372 return -EINVAL;
373
374 e = unbase32hexchar(x[4]);
375 if (e < 0)
376 return -EINVAL;
377
378 f = unbase32hexchar(x[5]);
379 if (f < 0)
380 return -EINVAL;
381
382 g = unbase32hexchar(x[6]);
383 if (g < 0)
384 return -EINVAL;
385
386 /* g == 000VV000 */
387 if (g & 7)
388 return -EINVAL;
389
390 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
391 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
392 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
393 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
394
395 break;
396 case 5:
397 a = unbase32hexchar(x[0]);
398 if (a < 0)
399 return -EINVAL;
400
401 b = unbase32hexchar(x[1]);
402 if (b < 0)
403 return -EINVAL;
404
405 c = unbase32hexchar(x[2]);
406 if (c < 0)
407 return -EINVAL;
408
409 d = unbase32hexchar(x[3]);
410 if (d < 0)
411 return -EINVAL;
412
413 e = unbase32hexchar(x[4]);
414 if (e < 0)
415 return -EINVAL;
416
417 /* e == 000SSSS0 */
418 if (e & 1)
419 return -EINVAL;
420
421 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
422 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
423 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
424
425 break;
426 case 4:
427 a = unbase32hexchar(x[0]);
428 if (a < 0)
429 return -EINVAL;
430
431 b = unbase32hexchar(x[1]);
432 if (b < 0)
433 return -EINVAL;
434
435 c = unbase32hexchar(x[2]);
436 if (c < 0)
437 return -EINVAL;
438
439 d = unbase32hexchar(x[3]);
440 if (d < 0)
441 return -EINVAL;
442
443 /* d == 000W0000 */
444 if (d & 15)
445 return -EINVAL;
446
447 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
448 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
449
450 break;
451 case 2:
452 a = unbase32hexchar(x[0]);
453 if (a < 0)
454 return -EINVAL;
455
456 b = unbase32hexchar(x[1]);
457 if (b < 0)
458 return -EINVAL;
459
460 /* b == 000YYY00 */
461 if (b & 3)
462 return -EINVAL;
463
464 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
465
466 break;
467 case 0:
468 break;
469 default:
470 return -EINVAL;
471 }
472
473 *z = 0;
474
475 *mem = r;
476 r = NULL;
477 *_len = len;
478
479 return 0;
480 }
481
482 /* https://tools.ietf.org/html/rfc4648#section-4 */
483 char base64char(int x) {
484 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
485 "abcdefghijklmnopqrstuvwxyz"
486 "0123456789+/";
487 return table[x & 63];
488 }
489
490 int unbase64char(char c) {
491 unsigned offset;
492
493 if (c >= 'A' && c <= 'Z')
494 return c - 'A';
495
496 offset = 'Z' - 'A' + 1;
497
498 if (c >= 'a' && c <= 'z')
499 return c - 'a' + offset;
500
501 offset += 'z' - 'a' + 1;
502
503 if (c >= '0' && c <= '9')
504 return c - '0' + offset;
505
506 offset += '9' - '0' + 1;
507
508 if (c == '+')
509 return offset;
510
511 offset++;
512
513 if (c == '/')
514 return offset;
515
516 return -EINVAL;
517 }
518
519 ssize_t base64mem(const void *p, size_t l, char **out) {
520 char *r, *z;
521 const uint8_t *x;
522
523 /* three input bytes makes four output bytes, padding is added so we must round up */
524 z = r = malloc(4 * (l + 2) / 3 + 1);
525 if (!r)
526 return -ENOMEM;
527
528 for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
529 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
530 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
531 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
532 *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
533 *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
534 }
535
536 switch (l % 3) {
537 case 2:
538 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
539 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
540 *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
541 *(z++) = '=';
542
543 break;
544 case 1:
545 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
546 *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
547 *(z++) = '=';
548 *(z++) = '=';
549
550 break;
551 }
552
553 *z = 0;
554 *out = r;
555 return z - r;
556 }
557
558 static int base64_append_width(char **prefix, int plen,
559 const char *sep, int indent,
560 const void *p, size_t l,
561 int width) {
562
563 _cleanup_free_ char *x = NULL;
564 char *t, *s;
565 ssize_t slen, len, avail;
566 int line, lines;
567
568 len = base64mem(p, l, &x);
569 if (len <= 0)
570 return len;
571
572 lines = (len + width - 1) / width;
573
574 slen = strlen_ptr(sep);
575 t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
576 if (!t)
577 return -ENOMEM;
578
579 memcpy_safe(t + plen, sep, slen);
580
581 for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
582 int act = MIN(width, avail);
583
584 if (line > 0 || sep) {
585 memset(s, ' ', indent);
586 s += indent;
587 }
588
589 memcpy(s, x + width * line, act);
590 s += act;
591 *(s++) = line < lines - 1 ? '\n' : '\0';
592 avail -= act;
593 }
594 assert(avail == 0);
595
596 *prefix = t;
597 return 0;
598 }
599
600 int base64_append(char **prefix, int plen,
601 const void *p, size_t l,
602 int indent, int width) {
603 if (plen > width / 2 || plen + indent > width)
604 /* leave indent on the left, keep last column free */
605 return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
606 else
607 /* leave plen on the left, keep last column free */
608 return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1);
609 };
610
611
612 int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
613 _cleanup_free_ uint8_t *r = NULL;
614 int a, b, c, d;
615 uint8_t *z;
616 const char *x;
617 size_t len;
618
619 assert(p);
620
621 /* padding ensures any base63 input has input divisible by 4 */
622 if (l % 4 != 0)
623 return -EINVAL;
624
625 /* strip the padding */
626 if (l > 0 && p[l - 1] == '=')
627 l--;
628 if (l > 0 && p[l - 1] == '=')
629 l--;
630
631 /* a group of four input bytes needs three output bytes, in case of
632 padding we need to add two or three extra bytes */
633 len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
634
635 z = r = malloc(len + 1);
636 if (!r)
637 return -ENOMEM;
638
639 for (x = p; x < p + (l / 4) * 4; x += 4) {
640 /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
641 a = unbase64char(x[0]);
642 if (a < 0)
643 return -EINVAL;
644
645 b = unbase64char(x[1]);
646 if (b < 0)
647 return -EINVAL;
648
649 c = unbase64char(x[2]);
650 if (c < 0)
651 return -EINVAL;
652
653 d = unbase64char(x[3]);
654 if (d < 0)
655 return -EINVAL;
656
657 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
658 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
659 *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
660 }
661
662 switch (l % 4) {
663 case 3:
664 a = unbase64char(x[0]);
665 if (a < 0)
666 return -EINVAL;
667
668 b = unbase64char(x[1]);
669 if (b < 0)
670 return -EINVAL;
671
672 c = unbase64char(x[2]);
673 if (c < 0)
674 return -EINVAL;
675
676 /* c == 00ZZZZ00 */
677 if (c & 3)
678 return -EINVAL;
679
680 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
681 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
682
683 break;
684 case 2:
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 /* b == 00YY0000 */
694 if (b & 15)
695 return -EINVAL;
696
697 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
698
699 break;
700 case 0:
701
702 break;
703 default:
704 return -EINVAL;
705 }
706
707 *z = 0;
708
709 *mem = r;
710 r = NULL;
711 *_len = len;
712
713 return 0;
714 }
715
716 void hexdump(FILE *f, const void *p, size_t s) {
717 const uint8_t *b = p;
718 unsigned n = 0;
719
720 assert(s == 0 || b);
721
722 while (s > 0) {
723 size_t i;
724
725 fprintf(f, "%04x ", n);
726
727 for (i = 0; i < 16; i++) {
728
729 if (i >= s)
730 fputs(" ", f);
731 else
732 fprintf(f, "%02x ", b[i]);
733
734 if (i == 7)
735 fputc(' ', f);
736 }
737
738 fputc(' ', f);
739
740 for (i = 0; i < 16; i++) {
741
742 if (i >= s)
743 fputc(' ', f);
744 else
745 fputc(isprint(b[i]) ? (char) b[i] : '.', f);
746 }
747
748 fputc('\n', f);
749
750 if (s < 16)
751 break;
752
753 n += 16;
754 b += 16;
755 s -= 16;
756 }
757 }