xref: /reactos/dll/3rdparty/mbedtls/base64.c (revision 7353af1e)
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  *  This file is provided under the Apache License 2.0, or the
8  *  GNU General Public License v2.0 or later.
9  *
10  *  **********
11  *  Apache License 2.0:
12  *
13  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
14  *  not use this file except in compliance with the License.
15  *  You may obtain a copy of the License at
16  *
17  *  http://www.apache.org/licenses/LICENSE-2.0
18  *
19  *  Unless required by applicable law or agreed to in writing, software
20  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
21  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  *  See the License for the specific language governing permissions and
23  *  limitations under the License.
24  *
25  *  **********
26  *
27  *  **********
28  *  GNU General Public License v2.0 or later:
29  *
30  *  This program is free software; you can redistribute it and/or modify
31  *  it under the terms of the GNU General Public License as published by
32  *  the Free Software Foundation; either version 2 of the License, or
33  *  (at your option) any later version.
34  *
35  *  This program is distributed in the hope that it will be useful,
36  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
37  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  *  GNU General Public License for more details.
39  *
40  *  You should have received a copy of the GNU General Public License along
41  *  with this program; if not, write to the Free Software Foundation, Inc.,
42  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
43  *
44  *  **********
45  */
46 
47 #if !defined(MBEDTLS_CONFIG_FILE)
48 #include "mbedtls/config.h"
49 #else
50 #include MBEDTLS_CONFIG_FILE
51 #endif
52 
53 #if defined(MBEDTLS_BASE64_C)
54 
55 #include "mbedtls/base64.h"
56 
57 #include <stdint.h>
58 
59 #if defined(MBEDTLS_SELF_TEST)
60 #include <string.h>
61 #if defined(MBEDTLS_PLATFORM_C)
62 #include "mbedtls/platform.h"
63 #else
64 #include <stdio.h>
65 #define mbedtls_printf printf
66 #endif /* MBEDTLS_PLATFORM_C */
67 #endif /* MBEDTLS_SELF_TEST */
68 
69 static const unsigned char base64_enc_map[64] =
70 {
71     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
72     'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
73     'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
74     'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
75     'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
76     'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
77     '8', '9', '+', '/'
78 };
79 
80 static const unsigned char base64_dec_map[128] =
81 {
82     127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
83     127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
84     127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
85     127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
86     127, 127, 127,  62, 127, 127, 127,  63,  52,  53,
87      54,  55,  56,  57,  58,  59,  60,  61, 127, 127,
88     127,  64, 127, 127, 127,   0,   1,   2,   3,   4,
89       5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
90      15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
91      25, 127, 127, 127, 127, 127, 127,  26,  27,  28,
92      29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
93      39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
94      49,  50,  51, 127, 127, 127, 127, 127
95 };
96 
97 #define BASE64_SIZE_T_MAX   ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
98 
99 /*
100  * Constant flow conditional assignment to unsigned char
101  */
102 static void mbedtls_base64_cond_assign_uchar( unsigned char * dest, const unsigned char * const src,
103                                        unsigned char condition )
104 {
105     /* MSVC has a warning about unary minus on unsigned integer types,
106      * but this is well-defined and precisely what we want to do here. */
107 #if defined(_MSC_VER)
108 #pragma warning( push )
109 #pragma warning( disable : 4146 )
110 #endif
111 
112     /* Generate bitmask from condition, mask will either be 0xFF or 0 */
113     unsigned char mask = ( condition | -condition );
114     mask >>= 7;
115     mask = -mask;
116 
117 #if defined(_MSC_VER)
118 #pragma warning( pop )
119 #endif
120 
121     *dest = ( ( *src ) & mask ) | ( ( *dest ) & ~mask );
122 }
123 
124 /*
125  * Constant flow conditional assignment to uint_32
126  */
127 static void mbedtls_base64_cond_assign_uint32( uint32_t * dest, const uint32_t src,
128                                        uint32_t condition )
129 {
130     /* MSVC has a warning about unary minus on unsigned integer types,
131      * but this is well-defined and precisely what we want to do here. */
132 #if defined(_MSC_VER)
133 #pragma warning( push )
134 #pragma warning( disable : 4146 )
135 #endif
136 
137     /* Generate bitmask from condition, mask will either be 0xFFFFFFFF or 0 */
138     uint32_t mask = ( condition | -condition );
139     mask >>= 31;
140     mask = -mask;
141 
142 #if defined(_MSC_VER)
143 #pragma warning( pop )
144 #endif
145 
146     *dest = ( src & mask ) | ( ( *dest ) & ~mask );
147 }
148 
149 /*
150  * Constant flow check for equality
151  */
152 static unsigned char mbedtls_base64_eq( size_t in_a, size_t in_b )
153 {
154     size_t difference = in_a ^ in_b;
155 
156     /* MSVC has a warning about unary minus on unsigned integer types,
157      * but this is well-defined and precisely what we want to do here. */
158 #if defined(_MSC_VER)
159 #pragma warning( push )
160 #pragma warning( disable : 4146 )
161 #endif
162 
163     difference |= -difference;
164 
165 #if defined(_MSC_VER)
166 #pragma warning( pop )
167 #endif
168 
169     /* cope with the varying size of size_t per platform */
170     difference >>= ( sizeof( difference ) * 8 - 1 );
171 
172     return (unsigned char) ( 1 ^ difference );
173 }
174 
175 /*
176  * Constant flow lookup into table.
177  */
178 static unsigned char mbedtls_base64_table_lookup( const unsigned char * const table,
179                                                  const size_t table_size, const size_t table_index )
180 {
181     size_t i;
182     unsigned char result = 0;
183 
184     for( i = 0; i < table_size; ++i )
185     {
186         mbedtls_base64_cond_assign_uchar( &result, &table[i], mbedtls_base64_eq( i, table_index ) );
187     }
188 
189     return result;
190 }
191 
192 /*
193  * Encode a buffer into base64 format
194  */
195 int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
196                    const unsigned char *src, size_t slen )
197 {
198     size_t i, n;
199     int C1, C2, C3;
200     unsigned char *p;
201 
202     if( slen == 0 )
203     {
204         *olen = 0;
205         return( 0 );
206     }
207 
208     n = slen / 3 + ( slen % 3 != 0 );
209 
210     if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
211     {
212         *olen = BASE64_SIZE_T_MAX;
213         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
214     }
215 
216     n *= 4;
217 
218     if( ( dlen < n + 1 ) || ( NULL == dst ) )
219     {
220         *olen = n + 1;
221         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
222     }
223 
224     n = ( slen / 3 ) * 3;
225 
226     for( i = 0, p = dst; i < n; i += 3 )
227     {
228         C1 = *src++;
229         C2 = *src++;
230         C3 = *src++;
231 
232         *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
233                                             ( ( C1 >> 2 ) & 0x3F ) );
234 
235         *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
236                                             ( ( ( ( C1 &  3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
237 
238         *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
239                                             ( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F ) );
240 
241         *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
242                                             ( C3 & 0x3F ) );
243     }
244 
245     if( i < slen )
246     {
247         C1 = *src++;
248         C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
249 
250         *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
251                                             ( ( C1 >> 2 ) & 0x3F ) );
252 
253         *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
254                                             ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
255 
256         if( ( i + 1 ) < slen )
257              *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
258                                                  ( ( ( C2 & 15 ) << 2 ) & 0x3F ) );
259         else *p++ = '=';
260 
261         *p++ = '=';
262     }
263 
264     *olen = p - dst;
265     *p = 0;
266 
267     return( 0 );
268 }
269 
270 /*
271  * Decode a base64-formatted buffer
272  */
273 int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
274                    const unsigned char *src, size_t slen )
275 {
276     size_t i, n;
277     uint32_t j, x;
278     unsigned char *p;
279     unsigned char dec_map_lookup;
280 
281     /* First pass: check for validity and get output length */
282     for( i = n = j = 0; i < slen; i++ )
283     {
284         /* Skip spaces before checking for EOL */
285         x = 0;
286         while( i < slen && src[i] == ' ' )
287         {
288             ++i;
289             ++x;
290         }
291 
292         /* Spaces at end of buffer are OK */
293         if( i == slen )
294             break;
295 
296         if( ( slen - i ) >= 2 &&
297             src[i] == '\r' && src[i + 1] == '\n' )
298             continue;
299 
300         if( src[i] == '\n' )
301             continue;
302 
303         /* Space inside a line is an error */
304         if( x != 0 )
305             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
306 
307         if( src[i] == '=' && ++j > 2 )
308             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
309 
310         dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] );
311 
312         if( src[i] > 127 || dec_map_lookup == 127 )
313             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
314 
315         if( dec_map_lookup < 64 && j != 0 )
316             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
317 
318         n++;
319     }
320 
321     if( n == 0 )
322     {
323         *olen = 0;
324         return( 0 );
325     }
326 
327     /* The following expression is to calculate the following formula without
328      * risk of integer overflow in n:
329      *     n = ( ( n * 6 ) + 7 ) >> 3;
330      */
331     n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
332     n -= j;
333 
334     if( dst == NULL || dlen < n )
335     {
336         *olen = n;
337         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
338     }
339 
340    for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
341    {
342         if( *src == '\r' || *src == '\n' || *src == ' ' )
343             continue;
344 
345         dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src );
346 
347         mbedtls_base64_cond_assign_uint32( &j, j - 1, mbedtls_base64_eq( dec_map_lookup, 64 ) );
348         x  = ( x << 6 ) | ( dec_map_lookup & 0x3F );
349 
350         if( ++n == 4 )
351         {
352             n = 0;
353             if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
354             if( j > 1 ) *p++ = (unsigned char)( x >>  8 );
355             if( j > 2 ) *p++ = (unsigned char)( x       );
356         }
357     }
358 
359     *olen = p - dst;
360 
361     return( 0 );
362 }
363 
364 #if defined(MBEDTLS_SELF_TEST)
365 
366 static const unsigned char base64_test_dec[64] =
367 {
368     0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
369     0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
370     0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
371     0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
372     0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
373     0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
374     0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
375     0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
376 };
377 
378 static const unsigned char base64_test_enc[] =
379     "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
380     "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
381 
382 /*
383  * Checkup routine
384  */
385 int mbedtls_base64_self_test( int verbose )
386 {
387     size_t len;
388     const unsigned char *src;
389     unsigned char buffer[128];
390 
391     if( verbose != 0 )
392         mbedtls_printf( "  Base64 encoding test: " );
393 
394     src = base64_test_dec;
395 
396     if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
397          memcmp( base64_test_enc, buffer, 88 ) != 0 )
398     {
399         if( verbose != 0 )
400             mbedtls_printf( "failed\n" );
401 
402         return( 1 );
403     }
404 
405     if( verbose != 0 )
406         mbedtls_printf( "passed\n  Base64 decoding test: " );
407 
408     src = base64_test_enc;
409 
410     if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
411          memcmp( base64_test_dec, buffer, 64 ) != 0 )
412     {
413         if( verbose != 0 )
414             mbedtls_printf( "failed\n" );
415 
416         return( 1 );
417     }
418 
419     if( verbose != 0 )
420         mbedtls_printf( "passed\n\n" );
421 
422     return( 0 );
423 }
424 
425 #endif /* MBEDTLS_SELF_TEST */
426 
427 #endif /* MBEDTLS_BASE64_C */
428