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