chiark / gitweb /
7e84550b6d49770175ac478be79768ea10a38ad0
[elogind.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 "alloc-util.h"
26 #include "hexdecoct.h"
27 #include "util.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 }