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