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 
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 
25 MBEDTLS_STATIC_TESTABLE
mbedtls_ct_base64_enc_char(unsigned char value)26 unsigned 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 
40 MBEDTLS_STATIC_TESTABLE
mbedtls_ct_base64_dec_value(unsigned char c)41 signed 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  */
mbedtls_base64_encode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)61 int 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 = p - dst;
120     *p = 0;
121 
122     return 0;
123 }
124 
125 /*
126  * Decode a base64-formatted buffer
127  */
mbedtls_base64_decode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)128 int 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     if (n == 0) {
187         *olen = 0;
188         return 0;
189     }
190 
191     /* The following expression is to calculate the following formula without
192      * risk of integer overflow in n:
193      *     n = ( ( n * 6 ) + 7 ) >> 3;
194      */
195     n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
196     n -= equals;
197 
198     if (dst == NULL || dlen < n) {
199         *olen = n;
200         return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
201     }
202 
203     equals = 0;
204     for (x = 0, p = dst; i > 0; i--, src++) {
205         if (*src == '\r' || *src == '\n' || *src == ' ') {
206             continue;
207         }
208 
209         x = x << 6;
210         if (*src == '=') {
211             ++equals;
212         } else {
213             x |= mbedtls_ct_base64_dec_value(*src);
214         }
215 
216         if (++accumulated_digits == 4) {
217             accumulated_digits = 0;
218             *p++ = MBEDTLS_BYTE_2(x);
219             if (equals <= 1) {
220                 *p++ = MBEDTLS_BYTE_1(x);
221             }
222             if (equals <= 0) {
223                 *p++ = MBEDTLS_BYTE_0(x);
224             }
225         }
226     }
227 
228     *olen = p - dst;
229 
230     return 0;
231 }
232 
233 #if defined(MBEDTLS_SELF_TEST)
234 
235 static const unsigned char base64_test_dec[64] =
236 {
237     0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
238     0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
239     0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
240     0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
241     0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
242     0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
243     0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
244     0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
245 };
246 
247 static const unsigned char base64_test_enc[] =
248     "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
249     "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
250 
251 /*
252  * Checkup routine
253  */
mbedtls_base64_self_test(int verbose)254 int mbedtls_base64_self_test(int verbose)
255 {
256     size_t len;
257     const unsigned char *src;
258     unsigned char buffer[128];
259 
260     if (verbose != 0) {
261         mbedtls_printf("  Base64 encoding test: ");
262     }
263 
264     src = base64_test_dec;
265 
266     if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
267         memcmp(base64_test_enc, buffer, 88) != 0) {
268         if (verbose != 0) {
269             mbedtls_printf("failed\n");
270         }
271 
272         return 1;
273     }
274 
275     if (verbose != 0) {
276         mbedtls_printf("passed\n  Base64 decoding test: ");
277     }
278 
279     src = base64_test_enc;
280 
281     if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
282         memcmp(base64_test_dec, buffer, 64) != 0) {
283         if (verbose != 0) {
284             mbedtls_printf("failed\n");
285         }
286 
287         return 1;
288     }
289 
290     if (verbose != 0) {
291         mbedtls_printf("passed\n\n");
292     }
293 
294     return 0;
295 }
296 
297 #endif /* MBEDTLS_SELF_TEST */
298 
299 #endif /* MBEDTLS_BASE64_C */
300