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