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 : }
|