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