chiark / gitweb /
Prep v228: Add remaining updates from upstream (3/3)
[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 char *base64mem(const void *p, size_t l) {
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 NULL;
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         return r;
551 }
552
553 int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
554         _cleanup_free_ uint8_t *r = NULL;
555         int a, b, c, d;
556         uint8_t *z;
557         const char *x;
558         size_t len;
559
560         assert(p);
561
562         /* padding ensures any base63 input has input divisible by 4 */
563         if (l % 4 != 0)
564                 return -EINVAL;
565
566         /* strip the padding */
567         if (l > 0 && p[l - 1] == '=')
568                 l --;
569         if (l > 0 && p[l - 1] == '=')
570                 l --;
571
572         /* a group of four input bytes needs three output bytes, in case of
573            padding we need to add two or three extra bytes */
574         len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
575
576         z = r = malloc(len + 1);
577         if (!r)
578                 return -ENOMEM;
579
580         for (x = p; x < p + (l / 4) * 4; x += 4) {
581                 /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
582                 a = unbase64char(x[0]);
583                 if (a < 0)
584                         return -EINVAL;
585
586                 b = unbase64char(x[1]);
587                 if (b < 0)
588                         return -EINVAL;
589
590                 c = unbase64char(x[2]);
591                 if (c < 0)
592                         return -EINVAL;
593
594                 d = unbase64char(x[3]);
595                 if (d < 0)
596                         return -EINVAL;
597
598                 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
599                 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
600                 *(z++) = (uint8_t) c << 6 | (uint8_t) d;      /* ZZWWWWWW */
601         }
602
603         switch (l % 4) {
604         case 3:
605                 a = unbase64char(x[0]);
606                 if (a < 0)
607                         return -EINVAL;
608
609                 b = unbase64char(x[1]);
610                 if (b < 0)
611                         return -EINVAL;
612
613                 c = unbase64char(x[2]);
614                 if (c < 0)
615                         return -EINVAL;
616
617                 /* c == 00ZZZZ00 */
618                 if (c & 3)
619                         return -EINVAL;
620
621                 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
622                 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
623
624                 break;
625         case 2:
626                 a = unbase64char(x[0]);
627                 if (a < 0)
628                         return -EINVAL;
629
630                 b = unbase64char(x[1]);
631                 if (b < 0)
632                         return -EINVAL;
633
634                 /* b == 00YY0000 */
635                 if (b & 15)
636                         return -EINVAL;
637
638                 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
639
640                 break;
641         case 0:
642
643                 break;
644         default:
645                 return -EINVAL;
646         }
647
648         *z = 0;
649
650         *mem = r;
651         r = NULL;
652         *_len = len;
653
654         return 0;
655 }
656
657 void hexdump(FILE *f, const void *p, size_t s) {
658         const uint8_t *b = p;
659         unsigned n = 0;
660
661         assert(s == 0 || b);
662
663         while (s > 0) {
664                 size_t i;
665
666                 fprintf(f, "%04x  ", n);
667
668                 for (i = 0; i < 16; i++) {
669
670                         if (i >= s)
671                                 fputs("   ", f);
672                         else
673                                 fprintf(f, "%02x ", b[i]);
674
675                         if (i == 7)
676                                 fputc(' ', f);
677                 }
678
679                 fputc(' ', f);
680
681                 for (i = 0; i < 16; i++) {
682
683                         if (i >= s)
684                                 fputc(' ', f);
685                         else
686                                 fputc(isprint(b[i]) ? (char) b[i] : '.', f);
687                 }
688
689                 fputc('\n', f);
690
691                 if (s < 16)
692                         break;
693
694                 n += 16;
695                 b += 16;
696                 s -= 16;
697         }
698 }