1 /*
2  *  RFC 1521 base64 encoding/decoding
3  *
4  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
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  *  This file is part of mbed TLS (https://tls.mbed.org)
20  */
21 
22 #if !defined(MBEDTLS_CONFIG_FILE)
23 #include "mbedtls/config.h"
24 #else
25 #include MBEDTLS_CONFIG_FILE
26 #endif
27 
28 #if defined(MBEDTLS_BASE64_C)
29 
30 #include "mbedtls/base64.h"
31 
32 #include <stdint.h>
33 
34 #if defined(MBEDTLS_SELF_TEST)
35 #include <string.h>
36 #if defined(MBEDTLS_PLATFORM_C)
37 #include "mbedtls/platform.h"
38 #else
39 #include <stdio.h>
40 #define mbedtls_printf printf
41 #endif /* MBEDTLS_PLATFORM_C */
42 #endif /* MBEDTLS_SELF_TEST */
43 
44 static const unsigned char base64_enc_map[64] =
45 {
46     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
47     'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
48     'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
49     'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
50     'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
51     'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
52     '8', '9', '+', '/'
53 };
54 
55 static const unsigned char base64_dec_map[128] =
56 {
57     127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
58     127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
59     127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
60     127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
61     127, 127, 127,  62, 127, 127, 127,  63,  52,  53,
62      54,  55,  56,  57,  58,  59,  60,  61, 127, 127,
63     127,  64, 127, 127, 127,   0,   1,   2,   3,   4,
64       5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
65      15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
66      25, 127, 127, 127, 127, 127, 127,  26,  27,  28,
67      29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
68      39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
69      49,  50,  51, 127, 127, 127, 127, 127
70 };
71 
72 #define BASE64_SIZE_T_MAX   ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
73 
74 /*
75  * Encode a buffer into base64 format
76  */
mbedtls_base64_encode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)77 int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
78                    const unsigned char *src, size_t slen )
79 {
80     size_t i, n;
81     int C1, C2, C3;
82     unsigned char *p;
83 
84     if( slen == 0 )
85     {
86         *olen = 0;
87         return( 0 );
88     }
89 
90     n = slen / 3 + ( slen % 3 != 0 );
91 
92     if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
93     {
94         *olen = BASE64_SIZE_T_MAX;
95         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
96     }
97 
98     n *= 4;
99 
100     if( dlen < n + 1 )
101     {
102         *olen = n + 1;
103         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
104     }
105 
106     n = ( slen / 3 ) * 3;
107 
108     for( i = 0, p = dst; i < n; i += 3 )
109     {
110         C1 = *src++;
111         C2 = *src++;
112         C3 = *src++;
113 
114         *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
115         *p++ = base64_enc_map[(((C1 &  3) << 4) + (C2 >> 4)) & 0x3F];
116         *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
117         *p++ = base64_enc_map[C3 & 0x3F];
118     }
119 
120     if( i < slen )
121     {
122         C1 = *src++;
123         C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
124 
125         *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
126         *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
127 
128         if( ( i + 1 ) < slen )
129              *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
130         else *p++ = '=';
131 
132         *p++ = '=';
133     }
134 
135     *olen = p - dst;
136     *p = 0;
137 
138     return( 0 );
139 }
140 
141 /*
142  * Decode a base64-formatted buffer
143  */
mbedtls_base64_decode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)144 int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
145                    const unsigned char *src, size_t slen )
146 {
147     size_t i, n;
148     uint32_t j, x;
149     unsigned char *p;
150 
151     /* First pass: check for validity and get output length */
152     for( i = n = j = 0; i < slen; i++ )
153     {
154         /* Skip spaces before checking for EOL */
155         x = 0;
156         while( i < slen && src[i] == ' ' )
157         {
158             ++i;
159             ++x;
160         }
161 
162         /* Spaces at end of buffer are OK */
163         if( i == slen )
164             break;
165 
166         if( ( slen - i ) >= 2 &&
167             src[i] == '\r' && src[i + 1] == '\n' )
168             continue;
169 
170         if( src[i] == '\n' )
171             continue;
172 
173         /* Space inside a line is an error */
174         if( x != 0 )
175             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
176 
177         if( src[i] == '=' && ++j > 2 )
178             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
179 
180         if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
181             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
182 
183         if( base64_dec_map[src[i]] < 64 && j != 0 )
184             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
185 
186         n++;
187     }
188 
189     if( n == 0 )
190     {
191         *olen = 0;
192         return( 0 );
193     }
194 
195     n = ( ( n * 6 ) + 7 ) >> 3;
196     n -= j;
197 
198     if( dst == NULL || dlen < n )
199     {
200         *olen = n;
201         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
202     }
203 
204    for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
205    {
206         if( *src == '\r' || *src == '\n' || *src == ' ' )
207             continue;
208 
209         j -= ( base64_dec_map[*src] == 64 );
210         x  = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
211 
212         if( ++n == 4 )
213         {
214             n = 0;
215             if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
216             if( j > 1 ) *p++ = (unsigned char)( x >>  8 );
217             if( j > 2 ) *p++ = (unsigned char)( x       );
218         }
219     }
220 
221     *olen = p - dst;
222 
223     return( 0 );
224 }
225 
226 #if defined(MBEDTLS_SELF_TEST)
227 
228 static const unsigned char base64_test_dec[64] =
229 {
230     0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
231     0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
232     0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
233     0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
234     0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
235     0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
236     0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
237     0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
238 };
239 
240 static const unsigned char base64_test_enc[] =
241     "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
242     "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
243 
244 /*
245  * Checkup routine
246  */
mbedtls_base64_self_test(int verbose)247 int mbedtls_base64_self_test( int verbose )
248 {
249     size_t len;
250     const unsigned char *src;
251     unsigned char buffer[128];
252 
253     if( verbose != 0 )
254         mbedtls_printf( "  Base64 encoding test: " );
255 
256     src = base64_test_dec;
257 
258     if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
259          memcmp( base64_test_enc, buffer, 88 ) != 0 )
260     {
261         if( verbose != 0 )
262             mbedtls_printf( "failed\n" );
263 
264         return( 1 );
265     }
266 
267     if( verbose != 0 )
268         mbedtls_printf( "passed\n  Base64 decoding test: " );
269 
270     src = base64_test_enc;
271 
272     if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
273          memcmp( base64_test_dec, buffer, 64 ) != 0 )
274     {
275         if( verbose != 0 )
276             mbedtls_printf( "failed\n" );
277 
278         return( 1 );
279     }
280 
281     if( verbose != 0 )
282         mbedtls_printf( "passed\n\n" );
283 
284     return( 0 );
285 }
286 
287 #endif /* MBEDTLS_SELF_TEST */
288 
289 #endif /* MBEDTLS_BASE64_C */