1 /*
2  *  RFC 1521 base64 encoding/decoding
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8  *  not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *  http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  */
19 
20 #include "common.h"
21 
22 #if defined(MBEDTLS_BASE64_C)
23 
24 #include "mbedtls/base64.h"
25 #include "constant_time_internal.h"
26 
27 #include <stdint.h>
28 
29 #if defined(MBEDTLS_SELF_TEST)
30 #include <string.h>
31 #include "mbedtls/platform.h"
32 #endif /* MBEDTLS_SELF_TEST */
33 
34 #define BASE64_SIZE_T_MAX   ((size_t) -1)   /* SIZE_T_MAX is not standard */
35 
36 /*
37  * Encode a buffer into base64 format
38  */
mbedtls_base64_encode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)39 int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
40                           const unsigned char *src, size_t slen)
41 {
42     size_t i, n;
43     int C1, C2, C3;
44     unsigned char *p;
45 
46     if (slen == 0) {
47         *olen = 0;
48         return 0;
49     }
50 
51     n = slen / 3 + (slen % 3 != 0);
52 
53     if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
54         *olen = BASE64_SIZE_T_MAX;
55         return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
56     }
57 
58     n *= 4;
59 
60     if ((dlen < n + 1) || (NULL == dst)) {
61         *olen = n + 1;
62         return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
63     }
64 
65     n = (slen / 3) * 3;
66 
67     for (i = 0, p = dst; i < n; i += 3) {
68         C1 = *src++;
69         C2 = *src++;
70         C3 = *src++;
71 
72         *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
73         *p++ = mbedtls_ct_base64_enc_char((((C1 &  3) << 4) + (C2 >> 4))
74                                           & 0x3F);
75         *p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6))
76                                           & 0x3F);
77         *p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F);
78     }
79 
80     if (i < slen) {
81         C1 = *src++;
82         C2 = ((i + 1) < slen) ? *src++ : 0;
83 
84         *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
85         *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
86                                           & 0x3F);
87 
88         if ((i + 1) < slen) {
89             *p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F);
90         } else {
91             *p++ = '=';
92         }
93 
94         *p++ = '=';
95     }
96 
97     *olen = p - dst;
98     *p = 0;
99 
100     return 0;
101 }
102 
103 /*
104  * Decode a base64-formatted buffer
105  */
mbedtls_base64_decode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)106 int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen,
107                           const unsigned char *src, size_t slen)
108 {
109     size_t i; /* index in source */
110     size_t n; /* number of digits or trailing = in source */
111     uint32_t x; /* value accumulator */
112     unsigned accumulated_digits = 0;
113     unsigned equals = 0;
114     int spaces_present = 0;
115     unsigned char *p;
116 
117     /* First pass: check for validity and get output length */
118     for (i = n = 0; i < slen; i++) {
119         /* Skip spaces before checking for EOL */
120         spaces_present = 0;
121         while (i < slen && src[i] == ' ') {
122             ++i;
123             spaces_present = 1;
124         }
125 
126         /* Spaces at end of buffer are OK */
127         if (i == slen) {
128             break;
129         }
130 
131         if ((slen - i) >= 2 &&
132             src[i] == '\r' && src[i + 1] == '\n') {
133             continue;
134         }
135 
136         if (src[i] == '\n') {
137             continue;
138         }
139 
140         /* Space inside a line is an error */
141         if (spaces_present) {
142             return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
143         }
144 
145         if (src[i] > 127) {
146             return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
147         }
148 
149         if (src[i] == '=') {
150             if (++equals > 2) {
151                 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
152             }
153         } else {
154             if (equals != 0) {
155                 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
156             }
157             if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
158                 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
159             }
160         }
161         n++;
162     }
163 
164     if (n == 0) {
165         *olen = 0;
166         return 0;
167     }
168 
169     /* The following expression is to calculate the following formula without
170      * risk of integer overflow in n:
171      *     n = ( ( n * 6 ) + 7 ) >> 3;
172      */
173     n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
174     n -= equals;
175 
176     if (dst == NULL || dlen < n) {
177         *olen = n;
178         return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
179     }
180 
181     equals = 0;
182     for (x = 0, p = dst; i > 0; i--, src++) {
183         if (*src == '\r' || *src == '\n' || *src == ' ') {
184             continue;
185         }
186 
187         x = x << 6;
188         if (*src == '=') {
189             ++equals;
190         } else {
191             x |= mbedtls_ct_base64_dec_value(*src);
192         }
193 
194         if (++accumulated_digits == 4) {
195             accumulated_digits = 0;
196             *p++ = MBEDTLS_BYTE_2(x);
197             if (equals <= 1) {
198                 *p++ = MBEDTLS_BYTE_1(x);
199             }
200             if (equals <= 0) {
201                 *p++ = MBEDTLS_BYTE_0(x);
202             }
203         }
204     }
205 
206     *olen = p - dst;
207 
208     return 0;
209 }
210 
211 #if defined(MBEDTLS_SELF_TEST)
212 
213 static const unsigned char base64_test_dec[64] =
214 {
215     0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
216     0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
217     0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
218     0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
219     0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
220     0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
221     0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
222     0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
223 };
224 
225 static const unsigned char base64_test_enc[] =
226     "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
227     "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
228 
229 /*
230  * Checkup routine
231  */
mbedtls_base64_self_test(int verbose)232 int mbedtls_base64_self_test(int verbose)
233 {
234     size_t len;
235     const unsigned char *src;
236     unsigned char buffer[128];
237 
238     if (verbose != 0) {
239         mbedtls_printf("  Base64 encoding test: ");
240     }
241 
242     src = base64_test_dec;
243 
244     if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
245         memcmp(base64_test_enc, buffer, 88) != 0) {
246         if (verbose != 0) {
247             mbedtls_printf("failed\n");
248         }
249 
250         return 1;
251     }
252 
253     if (verbose != 0) {
254         mbedtls_printf("passed\n  Base64 decoding test: ");
255     }
256 
257     src = base64_test_enc;
258 
259     if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
260         memcmp(base64_test_dec, buffer, 64) != 0) {
261         if (verbose != 0) {
262             mbedtls_printf("failed\n");
263         }
264 
265         return 1;
266     }
267 
268     if (verbose != 0) {
269         mbedtls_printf("passed\n\n");
270     }
271 
272     return 0;
273 }
274 
275 #endif /* MBEDTLS_SELF_TEST */
276 
277 #endif /* MBEDTLS_BASE64_C */
278