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