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 "constant_time_internal.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 /*
42  * Encode a buffer into base64 format
43  */
mbedtls_base64_encode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)44 int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
45                    const unsigned char *src, size_t slen )
46 {
47     size_t i, n;
48     int C1, C2, C3;
49     unsigned char *p;
50 
51     if( slen == 0 )
52     {
53         *olen = 0;
54         return( 0 );
55     }
56 
57     n = slen / 3 + ( slen % 3 != 0 );
58 
59     if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
60     {
61         *olen = BASE64_SIZE_T_MAX;
62         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
63     }
64 
65     n *= 4;
66 
67     if( ( dlen < n + 1 ) || ( NULL == dst ) )
68     {
69         *olen = n + 1;
70         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
71     }
72 
73     n = ( slen / 3 ) * 3;
74 
75     for( i = 0, p = dst; i < n; i += 3 )
76     {
77         C1 = *src++;
78         C2 = *src++;
79         C3 = *src++;
80 
81         *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F );
82         *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 &  3 ) << 4 ) + ( C2 >> 4 ) )
83                                         & 0x3F );
84         *p++ = mbedtls_ct_base64_enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) )
85                                         & 0x3F );
86         *p++ = mbedtls_ct_base64_enc_char( C3 & 0x3F );
87     }
88 
89     if( i < slen )
90     {
91         C1 = *src++;
92         C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
93 
94         *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F );
95         *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
96                                         & 0x3F );
97 
98         if( ( i + 1 ) < slen )
99              *p++ = mbedtls_ct_base64_enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F );
100         else *p++ = '=';
101 
102         *p++ = '=';
103     }
104 
105     *olen = p - dst;
106     *p = 0;
107 
108     return( 0 );
109 }
110 
111 /*
112  * Decode a base64-formatted buffer
113  */
mbedtls_base64_decode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)114 int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
115                    const unsigned char *src, size_t slen )
116 {
117     size_t i; /* index in source */
118     size_t n; /* number of digits or trailing = in source */
119     uint32_t x; /* value accumulator */
120     unsigned accumulated_digits = 0;
121     unsigned equals = 0;
122     int spaces_present = 0;
123     unsigned char *p;
124 
125     /* First pass: check for validity and get output length */
126     for( i = n = 0; i < slen; i++ )
127     {
128         /* Skip spaces before checking for EOL */
129         spaces_present = 0;
130         while( i < slen && src[i] == ' ' )
131         {
132             ++i;
133             spaces_present = 1;
134         }
135 
136         /* Spaces at end of buffer are OK */
137         if( i == slen )
138             break;
139 
140         if( ( slen - i ) >= 2 &&
141             src[i] == '\r' && src[i + 1] == '\n' )
142             continue;
143 
144         if( src[i] == '\n' )
145             continue;
146 
147         /* Space inside a line is an error */
148         if( spaces_present )
149             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
150 
151         if( src[i] > 127 )
152             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
153 
154         if( src[i] == '=' )
155         {
156             if( ++equals > 2 )
157                 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
158         }
159         else
160         {
161             if( equals != 0 )
162                 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
163             if( mbedtls_ct_base64_dec_value( src[i] ) < 0 )
164                 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
165         }
166         n++;
167     }
168 
169     if( n == 0 )
170     {
171         *olen = 0;
172         return( 0 );
173     }
174 
175     /* The following expression is to calculate the following formula without
176      * risk of integer overflow in n:
177      *     n = ( ( n * 6 ) + 7 ) >> 3;
178      */
179     n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
180     n -= equals;
181 
182     if( dst == NULL || dlen < n )
183     {
184         *olen = n;
185         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
186     }
187 
188     equals = 0;
189     for( x = 0, p = dst; i > 0; i--, src++ )
190     {
191         if( *src == '\r' || *src == '\n' || *src == ' ' )
192             continue;
193 
194         x = x << 6;
195         if( *src == '=' )
196             ++equals;
197         else
198             x |= mbedtls_ct_base64_dec_value( *src );
199 
200         if( ++accumulated_digits == 4 )
201         {
202             accumulated_digits = 0;
203             *p++ = MBEDTLS_BYTE_2( x );
204             if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
205             if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
206         }
207     }
208 
209     *olen = p - dst;
210 
211     return( 0 );
212 }
213 
214 #if defined(MBEDTLS_SELF_TEST)
215 
216 static const unsigned char base64_test_dec[64] =
217 {
218     0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
219     0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
220     0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
221     0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
222     0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
223     0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
224     0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
225     0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
226 };
227 
228 static const unsigned char base64_test_enc[] =
229     "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
230     "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
231 
232 /*
233  * Checkup routine
234  */
mbedtls_base64_self_test(int verbose)235 int mbedtls_base64_self_test( int verbose )
236 {
237     size_t len;
238     const unsigned char *src;
239     unsigned char buffer[128];
240 
241     if( verbose != 0 )
242         mbedtls_printf( "  Base64 encoding test: " );
243 
244     src = base64_test_dec;
245 
246     if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
247          memcmp( base64_test_enc, buffer, 88 ) != 0 )
248     {
249         if( verbose != 0 )
250             mbedtls_printf( "failed\n" );
251 
252         return( 1 );
253     }
254 
255     if( verbose != 0 )
256         mbedtls_printf( "passed\n  Base64 decoding test: " );
257 
258     src = base64_test_enc;
259 
260     if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
261          memcmp( base64_test_dec, buffer, 64 ) != 0 )
262     {
263         if( verbose != 0 )
264             mbedtls_printf( "failed\n" );
265 
266         return( 1 );
267     }
268 
269     if( verbose != 0 )
270         mbedtls_printf( "passed\n\n" );
271 
272     return( 0 );
273 }
274 
275 #endif /* MBEDTLS_SELF_TEST */
276 
277 #endif /* MBEDTLS_BASE64_C */
278