Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/mbedtls/library/base64.c
9898 views
1
/*
2
* RFC 1521 base64 encoding/decoding
3
*
4
* Copyright The Mbed TLS Contributors
5
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6
*/
7
8
#include <limits.h>
9
10
#include "common.h"
11
12
#if defined(MBEDTLS_BASE64_C)
13
14
#include "mbedtls/base64.h"
15
#include "base64_internal.h"
16
#include "constant_time_internal.h"
17
#include "mbedtls/error.h"
18
19
#include <stdint.h>
20
21
#if defined(MBEDTLS_SELF_TEST)
22
#include <string.h>
23
#include "mbedtls/platform.h"
24
#endif /* MBEDTLS_SELF_TEST */
25
26
MBEDTLS_STATIC_TESTABLE
27
unsigned char mbedtls_ct_base64_enc_char(unsigned char value)
28
{
29
unsigned char digit = 0;
30
/* For each range of values, if value is in that range, mask digit with
31
* the corresponding value. Since value can only be in a single range,
32
* only at most one masking will change digit. */
33
digit |= mbedtls_ct_uchar_in_range_if(0, 25, value, 'A' + value);
34
digit |= mbedtls_ct_uchar_in_range_if(26, 51, value, 'a' + value - 26);
35
digit |= mbedtls_ct_uchar_in_range_if(52, 61, value, '0' + value - 52);
36
digit |= mbedtls_ct_uchar_in_range_if(62, 62, value, '+');
37
digit |= mbedtls_ct_uchar_in_range_if(63, 63, value, '/');
38
return digit;
39
}
40
41
MBEDTLS_STATIC_TESTABLE
42
signed char mbedtls_ct_base64_dec_value(unsigned char c)
43
{
44
unsigned char val = 0;
45
/* For each range of digits, if c is in that range, mask val with
46
* the corresponding value. Since c can only be in a single range,
47
* only at most one masking will change val. Set val to one plus
48
* the desired value so that it stays 0 if c is in none of the ranges. */
49
val |= mbedtls_ct_uchar_in_range_if('A', 'Z', c, c - 'A' + 0 + 1);
50
val |= mbedtls_ct_uchar_in_range_if('a', 'z', c, c - 'a' + 26 + 1);
51
val |= mbedtls_ct_uchar_in_range_if('0', '9', c, c - '0' + 52 + 1);
52
val |= mbedtls_ct_uchar_in_range_if('+', '+', c, c - '+' + 62 + 1);
53
val |= mbedtls_ct_uchar_in_range_if('/', '/', c, c - '/' + 63 + 1);
54
/* At this point, val is 0 if c is an invalid digit and v+1 if c is
55
* a digit with the value v. */
56
return val - 1;
57
}
58
59
/*
60
* Encode a buffer into base64 format
61
*/
62
int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
63
const unsigned char *src, size_t slen)
64
{
65
size_t i, n;
66
int C1, C2, C3;
67
unsigned char *p;
68
69
if (slen == 0) {
70
*olen = 0;
71
return 0;
72
}
73
74
n = slen / 3 + (slen % 3 != 0);
75
76
if (n > (SIZE_MAX - 1) / 4) {
77
*olen = SIZE_MAX;
78
return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
79
}
80
81
n *= 4;
82
83
if ((dlen < n + 1) || (NULL == dst)) {
84
*olen = n + 1;
85
return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
86
}
87
88
n = (slen / 3) * 3;
89
90
for (i = 0, p = dst; i < n; i += 3) {
91
C1 = *src++;
92
C2 = *src++;
93
C3 = *src++;
94
95
*p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
96
*p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
97
& 0x3F);
98
*p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6))
99
& 0x3F);
100
*p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F);
101
}
102
103
if (i < slen) {
104
C1 = *src++;
105
C2 = ((i + 1) < slen) ? *src++ : 0;
106
107
*p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
108
*p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
109
& 0x3F);
110
111
if ((i + 1) < slen) {
112
*p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F);
113
} else {
114
*p++ = '=';
115
}
116
117
*p++ = '=';
118
}
119
120
*olen = (size_t) (p - dst);
121
*p = 0;
122
123
return 0;
124
}
125
126
/*
127
* Decode a base64-formatted buffer
128
*/
129
int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen,
130
const unsigned char *src, size_t slen)
131
{
132
size_t i; /* index in source */
133
size_t n; /* number of digits or trailing = in source */
134
uint32_t x; /* value accumulator */
135
unsigned accumulated_digits = 0;
136
unsigned equals = 0;
137
int spaces_present = 0;
138
unsigned char *p;
139
140
/* First pass: check for validity and get output length */
141
for (i = n = 0; i < slen; i++) {
142
/* Skip spaces before checking for EOL */
143
spaces_present = 0;
144
while (i < slen && src[i] == ' ') {
145
++i;
146
spaces_present = 1;
147
}
148
149
/* Spaces at end of buffer are OK */
150
if (i == slen) {
151
break;
152
}
153
154
if ((slen - i) >= 2 &&
155
src[i] == '\r' && src[i + 1] == '\n') {
156
continue;
157
}
158
159
if (src[i] == '\n') {
160
continue;
161
}
162
163
/* Space inside a line is an error */
164
if (spaces_present) {
165
return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
166
}
167
168
if (src[i] > 127) {
169
return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
170
}
171
172
if (src[i] == '=') {
173
if (++equals > 2) {
174
return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
175
}
176
} else {
177
if (equals != 0) {
178
return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
179
}
180
if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
181
return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
182
}
183
}
184
n++;
185
}
186
187
/* In valid base64, the number of digits (n-equals) is always of the form
188
* 4*k, 4*k+2 or *4k+3. Also, the number n of digits plus the number of
189
* equal signs at the end is always a multiple of 4. */
190
if ((n - equals) % 4 == 1) {
191
return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
192
}
193
if (n % 4 != 0) {
194
return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
195
}
196
197
/* We've determined that the input is valid, and that it contains
198
* exactly k blocks of digits-or-equals, with n = 4 * k,
199
* and equals only present at the end of the last block if at all.
200
* Now we can calculate the length of the output.
201
*
202
* Each block of 4 digits in the input map to 3 bytes of output.
203
* For the last block:
204
* - abcd (where abcd are digits) is a full 3-byte block;
205
* - abc= means 1 byte less than a full 3-byte block of output;
206
* - ab== means 2 bytes less than a full 3-byte block of output;
207
* - a==== and ==== is rejected above.
208
*/
209
*olen = (n / 4) * 3 - equals;
210
211
/* If the output buffer is too small, signal this and stop here.
212
* Also, as documented, stop here if `dst` is null, independently of
213
* `dlen`.
214
*
215
* There is an edge case when the output is empty: in this case,
216
* `dlen == 0` with `dst == NULL` is valid (on some platforms,
217
* `malloc(0)` returns `NULL`). Since the call is valid, we return
218
* 0 in this case.
219
*/
220
if ((*olen != 0 && dst == NULL) || dlen < *olen) {
221
return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
222
}
223
224
for (x = 0, p = dst; i > 0; i--, src++) {
225
if (*src == '\r' || *src == '\n' || *src == ' ') {
226
continue;
227
}
228
if (*src == '=') {
229
/* We already know from the first loop that equal signs are
230
* only at the end. */
231
break;
232
}
233
x = x << 6;
234
x |= mbedtls_ct_base64_dec_value(*src);
235
236
if (++accumulated_digits == 4) {
237
accumulated_digits = 0;
238
*p++ = MBEDTLS_BYTE_2(x);
239
*p++ = MBEDTLS_BYTE_1(x);
240
*p++ = MBEDTLS_BYTE_0(x);
241
}
242
}
243
if (accumulated_digits == 3) {
244
*p++ = MBEDTLS_BYTE_2(x << 6);
245
*p++ = MBEDTLS_BYTE_1(x << 6);
246
} else if (accumulated_digits == 2) {
247
*p++ = MBEDTLS_BYTE_2(x << 12);
248
}
249
250
if (*olen != (size_t) (p - dst)) {
251
return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
252
}
253
254
return 0;
255
}
256
257
#if defined(MBEDTLS_SELF_TEST)
258
259
static const unsigned char base64_test_dec[64] =
260
{
261
0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
262
0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
263
0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
264
0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
265
0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
266
0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
267
0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
268
0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
269
};
270
271
static const unsigned char base64_test_enc[] =
272
"JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
273
"swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
274
275
/*
276
* Checkup routine
277
*/
278
int mbedtls_base64_self_test(int verbose)
279
{
280
size_t len;
281
const unsigned char *src;
282
unsigned char buffer[128];
283
284
if (verbose != 0) {
285
mbedtls_printf(" Base64 encoding test: ");
286
}
287
288
src = base64_test_dec;
289
290
if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
291
memcmp(base64_test_enc, buffer, 88) != 0) {
292
if (verbose != 0) {
293
mbedtls_printf("failed\n");
294
}
295
296
return 1;
297
}
298
299
if (verbose != 0) {
300
mbedtls_printf("passed\n Base64 decoding test: ");
301
}
302
303
src = base64_test_enc;
304
305
if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
306
memcmp(base64_test_dec, buffer, 64) != 0) {
307
if (verbose != 0) {
308
mbedtls_printf("failed\n");
309
}
310
311
return 1;
312
}
313
314
if (verbose != 0) {
315
mbedtls_printf("passed\n\n");
316
}
317
318
return 0;
319
}
320
321
#endif /* MBEDTLS_SELF_TEST */
322
323
#endif /* MBEDTLS_BASE64_C */
324
325