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