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 "base64_invasive.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 /* Return 0xff if low <= c <= high, 0 otherwise.
42 *
43 * Constant flow with respect to c.
44 */
45 MBEDTLS_STATIC_TESTABLE
mbedtls_base64_mask_of_range(unsigned char low,unsigned char high,unsigned char c)46 unsigned char mbedtls_base64_mask_of_range( unsigned char low,
47 unsigned char high,
48 unsigned char c )
49 {
50 /* low_mask is: 0 if low <= c, 0x...ff if low > c */
51 unsigned low_mask = ( (unsigned) c - low ) >> 8;
52 /* high_mask is: 0 if c <= high, 0x...ff if c > high */
53 unsigned high_mask = ( (unsigned) high - c ) >> 8;
54 return( ~( low_mask | high_mask ) & 0xff );
55 }
56
57 /* Given a value in the range 0..63, return the corresponding Base64 digit.
58 * The implementation assumes that letters are consecutive (e.g. ASCII
59 * but not EBCDIC).
60 */
61 MBEDTLS_STATIC_TESTABLE
mbedtls_base64_enc_char(unsigned char val)62 unsigned char mbedtls_base64_enc_char( unsigned char val )
63 {
64 unsigned char digit = 0;
65 /* For each range of values, if val is in that range, mask digit with
66 * the corresponding value. Since val can only be in a single range,
67 * only at most one masking will change digit. */
68 digit |= mbedtls_base64_mask_of_range( 0, 25, val ) & ( 'A' + val );
69 digit |= mbedtls_base64_mask_of_range( 26, 51, val ) & ( 'a' + val - 26 );
70 digit |= mbedtls_base64_mask_of_range( 52, 61, val ) & ( '0' + val - 52 );
71 digit |= mbedtls_base64_mask_of_range( 62, 62, val ) & '+';
72 digit |= mbedtls_base64_mask_of_range( 63, 63, val ) & '/';
73 return( digit );
74 }
75
76 /*
77 * Encode a buffer into base64 format
78 */
mbedtls_base64_encode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)79 int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
80 const unsigned char *src, size_t slen )
81 {
82 size_t i, n;
83 int C1, C2, C3;
84 unsigned char *p;
85
86 if( slen == 0 )
87 {
88 *olen = 0;
89 return( 0 );
90 }
91
92 n = slen / 3 + ( slen % 3 != 0 );
93
94 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
95 {
96 *olen = BASE64_SIZE_T_MAX;
97 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
98 }
99
100 n *= 4;
101
102 if( ( dlen < n + 1 ) || ( NULL == dst ) )
103 {
104 *olen = n + 1;
105 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
106 }
107
108 n = ( slen / 3 ) * 3;
109
110 for( i = 0, p = dst; i < n; i += 3 )
111 {
112 C1 = *src++;
113 C2 = *src++;
114 C3 = *src++;
115
116 *p++ = mbedtls_base64_enc_char( ( C1 >> 2 ) & 0x3F );
117 *p++ = mbedtls_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
118 & 0x3F );
119 *p++ = mbedtls_base64_enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) )
120 & 0x3F );
121 *p++ = mbedtls_base64_enc_char( C3 & 0x3F );
122 }
123
124 if( i < slen )
125 {
126 C1 = *src++;
127 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
128
129 *p++ = mbedtls_base64_enc_char( ( C1 >> 2 ) & 0x3F );
130 *p++ = mbedtls_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
131 & 0x3F );
132
133 if( ( i + 1 ) < slen )
134 *p++ = mbedtls_base64_enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F );
135 else *p++ = '=';
136
137 *p++ = '=';
138 }
139
140 *olen = p - dst;
141 *p = 0;
142
143 return( 0 );
144 }
145
146 /* Given a Base64 digit, return its value.
147 * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'),
148 * return -1.
149 *
150 * The implementation assumes that letters are consecutive (e.g. ASCII
151 * but not EBCDIC).
152 *
153 * The implementation is constant-flow (no branch or memory access depending
154 * on the value of c) unless the compiler inlines and optimizes a specific
155 * access.
156 */
157 MBEDTLS_STATIC_TESTABLE
mbedtls_base64_dec_value(unsigned char c)158 signed char mbedtls_base64_dec_value( unsigned char c )
159 {
160 unsigned char val = 0;
161 /* For each range of digits, if c is in that range, mask val with
162 * the corresponding value. Since c can only be in a single range,
163 * only at most one masking will change val. Set val to one plus
164 * the desired value so that it stays 0 if c is in none of the ranges. */
165 val |= mbedtls_base64_mask_of_range( 'A', 'Z', c ) & ( c - 'A' + 0 + 1 );
166 val |= mbedtls_base64_mask_of_range( 'a', 'z', c ) & ( c - 'a' + 26 + 1 );
167 val |= mbedtls_base64_mask_of_range( '0', '9', c ) & ( c - '0' + 52 + 1 );
168 val |= mbedtls_base64_mask_of_range( '+', '+', c ) & ( c - '+' + 62 + 1 );
169 val |= mbedtls_base64_mask_of_range( '/', '/', c ) & ( c - '/' + 63 + 1 );
170 /* At this point, val is 0 if c is an invalid digit and v+1 if c is
171 * a digit with the value v. */
172 return( val - 1 );
173 }
174
175 /*
176 * Decode a base64-formatted buffer
177 */
mbedtls_base64_decode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)178 int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
179 const unsigned char *src, size_t slen )
180 {
181 size_t i; /* index in source */
182 size_t n; /* number of digits or trailing = in source */
183 uint32_t x; /* value accumulator */
184 unsigned accumulated_digits = 0;
185 unsigned equals = 0;
186 int spaces_present = 0;
187 unsigned char *p;
188
189 /* First pass: check for validity and get output length */
190 for( i = n = 0; i < slen; i++ )
191 {
192 /* Skip spaces before checking for EOL */
193 spaces_present = 0;
194 while( i < slen && src[i] == ' ' )
195 {
196 ++i;
197 spaces_present = 1;
198 }
199
200 /* Spaces at end of buffer are OK */
201 if( i == slen )
202 break;
203
204 if( ( slen - i ) >= 2 &&
205 src[i] == '\r' && src[i + 1] == '\n' )
206 continue;
207
208 if( src[i] == '\n' )
209 continue;
210
211 /* Space inside a line is an error */
212 if( spaces_present )
213 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
214
215 if( src[i] > 127 )
216 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
217
218 if( src[i] == '=' )
219 {
220 if( ++equals > 2 )
221 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
222 }
223 else
224 {
225 if( equals != 0 )
226 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
227 if( mbedtls_base64_dec_value( src[i] ) < 0 )
228 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
229 }
230 n++;
231 }
232
233 if( n == 0 )
234 {
235 *olen = 0;
236 return( 0 );
237 }
238
239 /* The following expression is to calculate the following formula without
240 * risk of integer overflow in n:
241 * n = ( ( n * 6 ) + 7 ) >> 3;
242 */
243 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
244 n -= equals;
245
246 if( dst == NULL || dlen < n )
247 {
248 *olen = n;
249 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
250 }
251
252 equals = 0;
253 for( x = 0, p = dst; i > 0; i--, src++ )
254 {
255 if( *src == '\r' || *src == '\n' || *src == ' ' )
256 continue;
257
258 x = x << 6;
259 if( *src == '=' )
260 ++equals;
261 else
262 x |= mbedtls_base64_dec_value( *src );
263
264 if( ++accumulated_digits == 4 )
265 {
266 accumulated_digits = 0;
267 *p++ = MBEDTLS_BYTE_2( x );
268 if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
269 if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
270 }
271 }
272
273 *olen = p - dst;
274
275 return( 0 );
276 }
277
278 #if defined(MBEDTLS_SELF_TEST)
279
280 static const unsigned char base64_test_dec[64] =
281 {
282 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
283 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
284 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
285 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
286 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
287 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
288 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
289 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
290 };
291
292 static const unsigned char base64_test_enc[] =
293 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
294 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
295
296 /*
297 * Checkup routine
298 */
mbedtls_base64_self_test(int verbose)299 int mbedtls_base64_self_test( int verbose )
300 {
301 size_t len;
302 const unsigned char *src;
303 unsigned char buffer[128];
304
305 if( verbose != 0 )
306 mbedtls_printf( " Base64 encoding test: " );
307
308 src = base64_test_dec;
309
310 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
311 memcmp( base64_test_enc, buffer, 88 ) != 0 )
312 {
313 if( verbose != 0 )
314 mbedtls_printf( "failed\n" );
315
316 return( 1 );
317 }
318
319 if( verbose != 0 )
320 mbedtls_printf( "passed\n Base64 decoding test: " );
321
322 src = base64_test_enc;
323
324 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
325 memcmp( base64_test_dec, buffer, 64 ) != 0 )
326 {
327 if( verbose != 0 )
328 mbedtls_printf( "failed\n" );
329
330 return( 1 );
331 }
332
333 if( verbose != 0 )
334 mbedtls_printf( "passed\n\n" );
335
336 return( 0 );
337 }
338
339 #endif /* MBEDTLS_SELF_TEST */
340
341 #endif /* MBEDTLS_BASE64_C */
342