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