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
mbedtls_ct_base64_enc_char(unsigned char value)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
mbedtls_ct_base64_dec_value(unsigned char c)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 */
mbedtls_base64_encode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)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 */
mbedtls_base64_decode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)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 */
mbedtls_base64_self_test(int verbose)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