/* * Base64url (RFC 4648 section 5) decoding function. Since SLUL explicitly * does NOT use padding, the variant without padding is used (see section 3.2). * * Copyright © 2021-2026 Samuel Lidén Borell * * SPDX-License-Identifier: EUPL-1.2+ OR LGPL-2.1-or-later */ #include "compiler.h" #include #include #define X 0xFF static const unsigned char unb64url[128-32] = { /* 20-2F: special characters */ X, X, X, X, X, X, X, X, X, X, X, X, X, 62, X, X, /* 30-3F: 01234... */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, X, X, X, X, X, X, /* 40-4F: @ABCD... */ X, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 50-5F: PQRST... */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, X, X, X, X, 63, /* 60-6F: `abcd... */ X, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 70-7F: pqrst... */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, X, X, X, X, X }; #undef X #define GETCHAR \ c = (unsigned char)*(in++); \ if (c < 32 || c > 127) return 0; \ c = unb64url[c-32]; \ if (c > 63) return 0; bool unbase64url(const char *in, size_t inlen, unsigned char *out, size_t outlen) { SlulInt v; unsigned char c; for (;;) { if (inlen < 4) goto end_chunk; if (outlen < 3) return 0; GETCHAR v = (SlulInt)c << 18; GETCHAR v |= (SlulInt)c << 12; GETCHAR v |= (SlulInt)c << 6; GETCHAR v |= (SlulInt)c; *(out++) = (v >> 16) & 0xFF; *(out++) = (v >> 8) & 0xFF; *(out++) = v & 0xFF; inlen -= 4; outlen -= 3; } end_chunk: if (!inlen) return true; /* We can have 2 or 3 trailing characters */ if (inlen == 1) return false; GETCHAR v = (SlulInt)c << 18; GETCHAR v |= (SlulInt)c << 12; if (inlen >= 3) { GETCHAR v |= (SlulInt)c << 6; if (outlen < 2) return false; } else if (outlen < 1) return false; *(out++) = (v >> 16) & 0xFF; /* Check that there are no extranous bits */ v &= ~0xFF0000U; if (inlen >= 3) { *(out++) = (v >> 8) & 0xFF; v &= ~0xFF00U; } return !v; }