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