chiark / gitweb /
592df53cb56b9cee5e111c31ff0b7ad9092bc92d
[elogind.git] / src / basic / hexdecoct.c
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>
21 #include <errno.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24
25 #include "alloc-util.h"
26 #include "hexdecoct.h"
27 #include "macro.h"
28
29 char octchar(int x) {
30         return '0' + (x & 7);
31 }
32
33 int unoctchar(char c) {
34
35         if (c >= '0' && c <= '7')
36                 return c - '0';
37
38         return -EINVAL;
39 }
40
41 char decchar(int x) {
42         return '0' + (x % 10);
43 }
44
45 int undecchar(char c) {
46
47         if (c >= '0' && c <= '9')
48                 return c - '0';
49
50         return -EINVAL;
51 }
52
53 char hexchar(int x) {
54         static const char table[16] = "0123456789abcdef";
55
56         return table[x & 15];
57 }
58
59 int 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
73 char *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
90 int 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. */
134 char base32hexchar(int x) {
135         static const char table[32] = "0123456789"
136                                       "ABCDEFGHIJKLMNOPQRSTUV";
137
138         return table[x & 31];
139 }
140
141 int 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
155 char *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
261 int 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 */
479 char base64char(int x) {
480         static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
481                                       "abcdefghijklmnopqrstuvwxyz"
482                                       "0123456789+/";
483         return table[x & 63];
484 }
485
486 int 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
515 ssize_t base64mem(const void *p, size_t l, char **out) {
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)
522                 return -ENOMEM;
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;
550         *out = r;
551         return z - r;
552 }
553
554 static 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;
594 }
595
596 int 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
608 int 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
712 void 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 }