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