1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
/*
* 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 <samuel@kodafritt.se>
*
* SPDX-License-Identifier: EUPL-1.2+ OR LGPL-2.1-or-later
*/
#include "compiler.h"
#include <assert.h>
#include <string.h>
#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;
}
|