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 * Constant flow conditional assignment to unsigned char
70 */
mbedtls_base64_cond_assign_uchar(unsigned char * dest,const unsigned char * const src,unsigned char condition)71 static void mbedtls_base64_cond_assign_uchar( unsigned char * dest, const unsigned char * const src,
72 unsigned char condition )
73 {
74 /* MSVC has a warning about unary minus on unsigned integer types,
75 * but this is well-defined and precisely what we want to do here. */
76 #if defined(_MSC_VER)
77 #pragma warning( push )
78 #pragma warning( disable : 4146 )
79 #endif
80
81 /* Generate bitmask from condition, mask will either be 0xFF or 0 */
82 unsigned char mask = ( condition | -condition );
83 mask >>= 7;
84 mask = -mask;
85
86 #if defined(_MSC_VER)
87 #pragma warning( pop )
88 #endif
89
90 *dest = ( ( *src ) & mask ) | ( ( *dest ) & ~mask );
91 }
92
93 /*
94 * Constant flow conditional assignment to uint_32
95 */
mbedtls_base64_cond_assign_uint32(uint32_t * dest,const uint32_t src,uint32_t condition)96 static void mbedtls_base64_cond_assign_uint32( uint32_t * dest, const uint32_t src,
97 uint32_t condition )
98 {
99 /* MSVC has a warning about unary minus on unsigned integer types,
100 * but this is well-defined and precisely what we want to do here. */
101 #if defined(_MSC_VER)
102 #pragma warning( push )
103 #pragma warning( disable : 4146 )
104 #endif
105
106 /* Generate bitmask from condition, mask will either be 0xFFFFFFFF or 0 */
107 uint32_t mask = ( condition | -condition );
108 mask >>= 31;
109 mask = -mask;
110
111 #if defined(_MSC_VER)
112 #pragma warning( pop )
113 #endif
114
115 *dest = ( src & mask ) | ( ( *dest ) & ~mask );
116 }
117
118 /*
119 * Constant flow check for equality
120 */
mbedtls_base64_eq(size_t in_a,size_t in_b)121 static unsigned char mbedtls_base64_eq( size_t in_a, size_t in_b )
122 {
123 size_t difference = in_a ^ in_b;
124
125 /* MSVC has a warning about unary minus on unsigned integer types,
126 * but this is well-defined and precisely what we want to do here. */
127 #if defined(_MSC_VER)
128 #pragma warning( push )
129 #pragma warning( disable : 4146 )
130 #endif
131
132 difference |= -difference;
133
134 #if defined(_MSC_VER)
135 #pragma warning( pop )
136 #endif
137
138 /* cope with the varying size of size_t per platform */
139 difference >>= ( sizeof( difference ) * 8 - 1 );
140
141 return (unsigned char) ( 1 ^ difference );
142 }
143
144 /*
145 * Constant flow lookup into table.
146 */
mbedtls_base64_table_lookup(const unsigned char * const table,const size_t table_size,const size_t table_index)147 static unsigned char mbedtls_base64_table_lookup( const unsigned char * const table,
148 const size_t table_size, const size_t table_index )
149 {
150 size_t i;
151 unsigned char result = 0;
152
153 for( i = 0; i < table_size; ++i )
154 {
155 mbedtls_base64_cond_assign_uchar( &result, &table[i], mbedtls_base64_eq( i, table_index ) );
156 }
157
158 return result;
159 }
160
161 /*
162 * Encode a buffer into base64 format
163 */
mbedtls_base64_encode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)164 int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
165 const unsigned char *src, size_t slen )
166 {
167 size_t i, n;
168 int C1, C2, C3;
169 unsigned char *p;
170
171 if( slen == 0 )
172 {
173 *olen = 0;
174 return( 0 );
175 }
176
177 n = slen / 3 + ( slen % 3 != 0 );
178
179 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
180 {
181 *olen = BASE64_SIZE_T_MAX;
182 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
183 }
184
185 n *= 4;
186
187 if( ( dlen < n + 1 ) || ( NULL == dst ) )
188 {
189 *olen = n + 1;
190 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
191 }
192
193 n = ( slen / 3 ) * 3;
194
195 for( i = 0, p = dst; i < n; i += 3 )
196 {
197 C1 = *src++;
198 C2 = *src++;
199 C3 = *src++;
200
201 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
202 ( ( C1 >> 2 ) & 0x3F ) );
203
204 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
205 ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
206
207 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
208 ( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F ) );
209
210 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
211 ( C3 & 0x3F ) );
212 }
213
214 if( i < slen )
215 {
216 C1 = *src++;
217 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
218
219 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
220 ( ( C1 >> 2 ) & 0x3F ) );
221
222 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
223 ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
224
225 if( ( i + 1 ) < slen )
226 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
227 ( ( ( C2 & 15 ) << 2 ) & 0x3F ) );
228 else *p++ = '=';
229
230 *p++ = '=';
231 }
232
233 *olen = p - dst;
234 *p = 0;
235
236 return( 0 );
237 }
238
239 /*
240 * Decode a base64-formatted buffer
241 */
mbedtls_base64_decode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)242 int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
243 const unsigned char *src, size_t slen )
244 {
245 size_t i, n;
246 uint32_t j, x;
247 unsigned char *p;
248 unsigned char dec_map_lookup;
249
250 /* First pass: check for validity and get output length */
251 for( i = n = j = 0; i < slen; i++ )
252 {
253 /* Skip spaces before checking for EOL */
254 x = 0;
255 while( i < slen && src[i] == ' ' )
256 {
257 ++i;
258 ++x;
259 }
260
261 /* Spaces at end of buffer are OK */
262 if( i == slen )
263 break;
264
265 if( ( slen - i ) >= 2 &&
266 src[i] == '\r' && src[i + 1] == '\n' )
267 continue;
268
269 if( src[i] == '\n' )
270 continue;
271
272 /* Space inside a line is an error */
273 if( x != 0 )
274 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
275
276 if( src[i] == '=' && ++j > 2 )
277 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
278
279 dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] );
280
281 if( src[i] > 127 || dec_map_lookup == 127 )
282 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
283
284 if( dec_map_lookup < 64 && j != 0 )
285 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
286
287 n++;
288 }
289
290 if( n == 0 )
291 {
292 *olen = 0;
293 return( 0 );
294 }
295
296 /* The following expression is to calculate the following formula without
297 * risk of integer overflow in n:
298 * n = ( ( n * 6 ) + 7 ) >> 3;
299 */
300 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
301 n -= j;
302
303 if( dst == NULL || dlen < n )
304 {
305 *olen = n;
306 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
307 }
308
309 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
310 {
311 if( *src == '\r' || *src == '\n' || *src == ' ' )
312 continue;
313
314 dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src );
315
316 mbedtls_base64_cond_assign_uint32( &j, j - 1, mbedtls_base64_eq( dec_map_lookup, 64 ) );
317 x = ( x << 6 ) | ( dec_map_lookup & 0x3F );
318
319 if( ++n == 4 )
320 {
321 n = 0;
322 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
323 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
324 if( j > 2 ) *p++ = (unsigned char)( x );
325 }
326 }
327
328 *olen = p - dst;
329
330 return( 0 );
331 }
332
333 #if defined(MBEDTLS_SELF_TEST)
334
335 static const unsigned char base64_test_dec[64] =
336 {
337 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
338 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
339 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
340 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
341 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
342 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
343 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
344 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
345 };
346
347 static const unsigned char base64_test_enc[] =
348 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
349 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
350
351 /*
352 * Checkup routine
353 */
mbedtls_base64_self_test(int verbose)354 int mbedtls_base64_self_test( int verbose )
355 {
356 size_t len;
357 const unsigned char *src;
358 unsigned char buffer[128];
359
360 if( verbose != 0 )
361 mbedtls_printf( " Base64 encoding test: " );
362
363 src = base64_test_dec;
364
365 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
366 memcmp( base64_test_enc, buffer, 88 ) != 0 )
367 {
368 if( verbose != 0 )
369 mbedtls_printf( "failed\n" );
370
371 return( 1 );
372 }
373
374 if( verbose != 0 )
375 mbedtls_printf( "passed\n Base64 decoding test: " );
376
377 src = base64_test_enc;
378
379 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
380 memcmp( base64_test_dec, buffer, 64 ) != 0 )
381 {
382 if( verbose != 0 )
383 mbedtls_printf( "failed\n" );
384
385 return( 1 );
386 }
387
388 if( verbose != 0 )
389 mbedtls_printf( "passed\n\n" );
390
391 return( 0 );
392 }
393
394 #endif /* MBEDTLS_SELF_TEST */
395
396 #endif /* MBEDTLS_BASE64_C */
397