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