LCOV - code coverage report
Current view: top level - basic - hexdecoct.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 457 506 90.3 %
Date: 2019-08-22 15:41:25 Functions: 21 21 100.0 %

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

Generated by: LCOV version 1.14