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 #include "base64_invasive.h"
26 
27 #include <stdint.h>
28 
29 #if defined(MBEDTLS_SELF_TEST)
30 #include <string.h>
31 #if defined(MBEDTLS_PLATFORM_C)
32 #include "mbedtls/platform.h"
33 #else
34 #include <stdio.h>
35 #define mbedtls_printf printf
36 #endif /* MBEDTLS_PLATFORM_C */
37 #endif /* MBEDTLS_SELF_TEST */
38 
39 #define BASE64_SIZE_T_MAX   ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
40 
41 /* Return 0xff if low <= c <= high, 0 otherwise.
42  *
43  * Constant flow with respect to c.
44  */
45 MBEDTLS_STATIC_TESTABLE
mbedtls_base64_mask_of_range(unsigned char low,unsigned char high,unsigned char c)46 unsigned char mbedtls_base64_mask_of_range( unsigned char low,
47                                             unsigned char high,
48                                             unsigned char c )
49 {
50     /* low_mask is: 0 if low <= c, 0x...ff if low > c */
51     unsigned low_mask = ( (unsigned) c - low ) >> 8;
52     /* high_mask is: 0 if c <= high, 0x...ff if c > high */
53     unsigned high_mask = ( (unsigned) high - c ) >> 8;
54     return( ~( low_mask | high_mask ) & 0xff );
55 }
56 
57 /* Given a value in the range 0..63, return the corresponding Base64 digit.
58  * The implementation assumes that letters are consecutive (e.g. ASCII
59  * but not EBCDIC).
60  */
61 MBEDTLS_STATIC_TESTABLE
mbedtls_base64_enc_char(unsigned char val)62 unsigned char mbedtls_base64_enc_char( unsigned char val )
63 {
64     unsigned char digit = 0;
65     /* For each range of values, if val is in that range, mask digit with
66      * the corresponding value. Since val can only be in a single range,
67      * only at most one masking will change digit. */
68     digit |= mbedtls_base64_mask_of_range(  0, 25, val ) & ( 'A' + val );
69     digit |= mbedtls_base64_mask_of_range( 26, 51, val ) & ( 'a' + val - 26 );
70     digit |= mbedtls_base64_mask_of_range( 52, 61, val ) & ( '0' + val - 52 );
71     digit |= mbedtls_base64_mask_of_range( 62, 62, val ) & '+';
72     digit |= mbedtls_base64_mask_of_range( 63, 63, val ) & '/';
73     return( digit );
74 }
75 
76 /*
77  * Encode a buffer into base64 format
78  */
mbedtls_base64_encode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)79 int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
80                    const unsigned char *src, size_t slen )
81 {
82     size_t i, n;
83     int C1, C2, C3;
84     unsigned char *p;
85 
86     if( slen == 0 )
87     {
88         *olen = 0;
89         return( 0 );
90     }
91 
92     n = slen / 3 + ( slen % 3 != 0 );
93 
94     if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
95     {
96         *olen = BASE64_SIZE_T_MAX;
97         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
98     }
99 
100     n *= 4;
101 
102     if( ( dlen < n + 1 ) || ( NULL == dst ) )
103     {
104         *olen = n + 1;
105         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
106     }
107 
108     n = ( slen / 3 ) * 3;
109 
110     for( i = 0, p = dst; i < n; i += 3 )
111     {
112         C1 = *src++;
113         C2 = *src++;
114         C3 = *src++;
115 
116         *p++ = mbedtls_base64_enc_char( ( C1 >> 2 ) & 0x3F );
117         *p++ = mbedtls_base64_enc_char( ( ( ( C1 &  3 ) << 4 ) + ( C2 >> 4 ) )
118                                         & 0x3F );
119         *p++ = mbedtls_base64_enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) )
120                                         & 0x3F );
121         *p++ = mbedtls_base64_enc_char( C3 & 0x3F );
122     }
123 
124     if( i < slen )
125     {
126         C1 = *src++;
127         C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
128 
129         *p++ = mbedtls_base64_enc_char( ( C1 >> 2 ) & 0x3F );
130         *p++ = mbedtls_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
131                                         & 0x3F );
132 
133         if( ( i + 1 ) < slen )
134              *p++ = mbedtls_base64_enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F );
135         else *p++ = '=';
136 
137         *p++ = '=';
138     }
139 
140     *olen = p - dst;
141     *p = 0;
142 
143     return( 0 );
144 }
145 
146 /* Given a Base64 digit, return its value.
147  * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'),
148  * return -1.
149  *
150  * The implementation assumes that letters are consecutive (e.g. ASCII
151  * but not EBCDIC).
152  *
153  * The implementation is constant-flow (no branch or memory access depending
154  * on the value of c) unless the compiler inlines and optimizes a specific
155  * access.
156  */
157 MBEDTLS_STATIC_TESTABLE
mbedtls_base64_dec_value(unsigned char c)158 signed char mbedtls_base64_dec_value( unsigned char c )
159 {
160     unsigned char val = 0;
161     /* For each range of digits, if c is in that range, mask val with
162      * the corresponding value. Since c can only be in a single range,
163      * only at most one masking will change val. Set val to one plus
164      * the desired value so that it stays 0 if c is in none of the ranges. */
165     val |= mbedtls_base64_mask_of_range( 'A', 'Z', c ) & ( c - 'A' +  0 + 1 );
166     val |= mbedtls_base64_mask_of_range( 'a', 'z', c ) & ( c - 'a' + 26 + 1 );
167     val |= mbedtls_base64_mask_of_range( '0', '9', c ) & ( c - '0' + 52 + 1 );
168     val |= mbedtls_base64_mask_of_range( '+', '+', c ) & ( c - '+' + 62 + 1 );
169     val |= mbedtls_base64_mask_of_range( '/', '/', c ) & ( c - '/' + 63 + 1 );
170     /* At this point, val is 0 if c is an invalid digit and v+1 if c is
171      * a digit with the value v. */
172     return( val - 1 );
173 }
174 
175 /*
176  * Decode a base64-formatted buffer
177  */
mbedtls_base64_decode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)178 int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
179                    const unsigned char *src, size_t slen )
180 {
181     size_t i; /* index in source */
182     size_t n; /* number of digits or trailing = in source */
183     uint32_t x; /* value accumulator */
184     unsigned accumulated_digits = 0;
185     unsigned equals = 0;
186     int spaces_present = 0;
187     unsigned char *p;
188 
189     /* First pass: check for validity and get output length */
190     for( i = n = 0; i < slen; i++ )
191     {
192         /* Skip spaces before checking for EOL */
193         spaces_present = 0;
194         while( i < slen && src[i] == ' ' )
195         {
196             ++i;
197             spaces_present = 1;
198         }
199 
200         /* Spaces at end of buffer are OK */
201         if( i == slen )
202             break;
203 
204         if( ( slen - i ) >= 2 &&
205             src[i] == '\r' && src[i + 1] == '\n' )
206             continue;
207 
208         if( src[i] == '\n' )
209             continue;
210 
211         /* Space inside a line is an error */
212         if( spaces_present )
213             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
214 
215         if( src[i] > 127 )
216             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
217 
218         if( src[i] == '=' )
219         {
220             if( ++equals > 2 )
221                 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
222         }
223         else
224         {
225             if( equals != 0 )
226                 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
227             if( mbedtls_base64_dec_value( src[i] ) < 0 )
228                 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
229         }
230         n++;
231     }
232 
233     if( n == 0 )
234     {
235         *olen = 0;
236         return( 0 );
237     }
238 
239     /* The following expression is to calculate the following formula without
240      * risk of integer overflow in n:
241      *     n = ( ( n * 6 ) + 7 ) >> 3;
242      */
243     n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
244     n -= equals;
245 
246     if( dst == NULL || dlen < n )
247     {
248         *olen = n;
249         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
250     }
251 
252     equals = 0;
253     for( x = 0, p = dst; i > 0; i--, src++ )
254     {
255         if( *src == '\r' || *src == '\n' || *src == ' ' )
256             continue;
257 
258         x = x << 6;
259         if( *src == '=' )
260             ++equals;
261         else
262             x |= mbedtls_base64_dec_value( *src );
263 
264         if( ++accumulated_digits == 4 )
265         {
266             accumulated_digits = 0;
267             *p++ = MBEDTLS_BYTE_2( x );
268             if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
269             if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
270         }
271     }
272 
273     *olen = p - dst;
274 
275     return( 0 );
276 }
277 
278 #if defined(MBEDTLS_SELF_TEST)
279 
280 static const unsigned char base64_test_dec[64] =
281 {
282     0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
283     0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
284     0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
285     0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
286     0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
287     0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
288     0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
289     0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
290 };
291 
292 static const unsigned char base64_test_enc[] =
293     "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
294     "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
295 
296 /*
297  * Checkup routine
298  */
mbedtls_base64_self_test(int verbose)299 int mbedtls_base64_self_test( int verbose )
300 {
301     size_t len;
302     const unsigned char *src;
303     unsigned char buffer[128];
304 
305     if( verbose != 0 )
306         mbedtls_printf( "  Base64 encoding test: " );
307 
308     src = base64_test_dec;
309 
310     if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
311          memcmp( base64_test_enc, buffer, 88 ) != 0 )
312     {
313         if( verbose != 0 )
314             mbedtls_printf( "failed\n" );
315 
316         return( 1 );
317     }
318 
319     if( verbose != 0 )
320         mbedtls_printf( "passed\n  Base64 decoding test: " );
321 
322     src = base64_test_enc;
323 
324     if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
325          memcmp( base64_test_dec, buffer, 64 ) != 0 )
326     {
327         if( verbose != 0 )
328             mbedtls_printf( "failed\n" );
329 
330         return( 1 );
331     }
332 
333     if( verbose != 0 )
334         mbedtls_printf( "passed\n\n" );
335 
336     return( 0 );
337 }
338 
339 #endif /* MBEDTLS_SELF_TEST */
340 
341 #endif /* MBEDTLS_BASE64_C */
342