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