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