blob: 97b43041642105e6fe35b112dfaa3384aef24f96 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * RFC 1521 base64 encoding/decoding
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * 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.
Paul Bakker5121ce52009-01-03 21:22:43 +000018 */
19
Gilles Peskinedb09ef62020-06-03 01:43:33 +020020#include "common.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000021
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020022#if defined(MBEDTLS_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000023
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000024#include "mbedtls/base64.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000025
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020026#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000027
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020028#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000029#include <string.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020030#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000031#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010032#else
Rich Evans00ab4702015-02-06 13:43:58 +000033#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020034#define mbedtls_printf printf
35#endif /* MBEDTLS_PLATFORM_C */
36#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010037
Paul Bakker5121ce52009-01-03 21:22:43 +000038static 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
49static 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
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010066#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
67
Paul Elliott3e790812021-02-25 12:28:49 +000068/*
69 * Constant flow conditional assignment
70*/
Paul Elliottdadd10d2021-02-05 17:49:23 +000071static void mbedtls_base64_cond_assign(unsigned char * dest, const unsigned char * const src,
72 unsigned char condition)
73{
74 /* make sure assign is 0 or 1 in a time-constant manner */
75 condition = (condition | (unsigned char)-condition) >> 7;
76
77 *dest = ( *dest ) * ( 1 - condition ) + ( *src ) * condition;
78}
79
80/*
Paul Elliott3e790812021-02-25 12:28:49 +000081 * Constant flow check for equality
Paul Elliottdadd10d2021-02-05 17:49:23 +000082*/
Paul Elliott3e790812021-02-25 12:28:49 +000083static unsigned char mbedtls_base64_eq(size_t in_a, size_t in_b)
Paul Elliottdadd10d2021-02-05 17:49:23 +000084{
85 uint32_t difference = in_a ^ in_b;
86
Paul Elliott3e790812021-02-25 12:28:49 +000087 /* MSVC has a warning about unary minus on unsigned integer types,
88 * but this is well-defined and precisely what we want to do here. */
89#if defined(_MSC_VER)
90#pragma warning( push )
91#pragma warning( disable : 4146 )
92#endif
93
Paul Elliottdadd10d2021-02-05 17:49:23 +000094 difference |= -difference;
Paul Elliott3e790812021-02-25 12:28:49 +000095
96#if defined(_MSC_VER)
97#pragma warning( pop )
98#endif
99
Paul Elliottdadd10d2021-02-05 17:49:23 +0000100 difference >>= 31;
101 return (unsigned char) ( 1 ^ difference );
102}
103
104/*
Paul Elliott3e790812021-02-25 12:28:49 +0000105 * Constant flow lookup into table.
Paul Elliottdadd10d2021-02-05 17:49:23 +0000106*/
107static unsigned char mbedtls_base64_table_lookup(const unsigned char * const table,
108 const size_t table_size, const size_t table_index)
109{
110 size_t i;
111 unsigned char result = 0;
112
113 for( i = 0; i < table_size; ++i )
114 {
115 mbedtls_base64_cond_assign(&result, &table[i], mbedtls_base64_eq(i, table_index));
116 }
117
118 return result;
119}
120
Paul Bakker5121ce52009-01-03 21:22:43 +0000121/*
122 * Encode a buffer into base64 format
123 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100124int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000125 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000126{
Paul Bakker23986e52011-04-24 08:57:21 +0000127 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000128 int C1, C2, C3;
129 unsigned char *p;
130
131 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +0000132 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100133 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000134 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +0000135 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000136
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200137 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +0000138
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +0100139 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000140 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +0100141 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200142 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000143 }
144
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200145 n *= 4;
146
Janos Follath98e28a72016-05-31 14:03:54 +0100147 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +0000148 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100149 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200150 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000151 }
152
Paul Bakker66d5d072014-06-17 16:39:18 +0200153 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000154
155 for( i = 0, p = dst; i < n; i += 3 )
156 {
157 C1 = *src++;
158 C2 = *src++;
159 C3 = *src++;
160
Paul Elliottdadd10d2021-02-05 17:49:23 +0000161 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
162 ( ( C1 >> 2 ) & 0x3F ) );
163
164 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
165 ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
166
167 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
168 ( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F ) );
169
170 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
171 ( C3 & 0x3F ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000172 }
173
174 if( i < slen )
175 {
176 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200177 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000178
Paul Elliottdadd10d2021-02-05 17:49:23 +0000179 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
180 ( ( C1 >> 2 ) & 0x3F ) );
181
182 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
183 ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000184
Paul Bakker66d5d072014-06-17 16:39:18 +0200185 if( ( i + 1 ) < slen )
Paul Elliottdadd10d2021-02-05 17:49:23 +0000186 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
187 ( ( ( C2 & 15 ) << 2 ) & 0x3F ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000188 else *p++ = '=';
189
190 *p++ = '=';
191 }
192
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100193 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000194 *p = 0;
195
196 return( 0 );
197}
198
199/*
200 * Decode a base64-formatted buffer
201 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100202int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000203 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000204{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000205 size_t i, n;
206 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000207 unsigned char *p;
208
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200209 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200210 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000211 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200212 /* Skip spaces before checking for EOL */
213 x = 0;
214 while( i < slen && src[i] == ' ' )
215 {
216 ++i;
217 ++x;
218 }
219
220 /* Spaces at end of buffer are OK */
221 if( i == slen )
222 break;
223
Paul Bakker5121ce52009-01-03 21:22:43 +0000224 if( ( slen - i ) >= 2 &&
225 src[i] == '\r' && src[i + 1] == '\n' )
226 continue;
227
228 if( src[i] == '\n' )
229 continue;
230
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200231 /* Space inside a line is an error */
232 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200233 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200234
Paul Bakker5121ce52009-01-03 21:22:43 +0000235 if( src[i] == '=' && ++j > 2 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200236 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000237
Paul Elliottdadd10d2021-02-05 17:49:23 +0000238 if( src[i] > 127 ||
239 mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] ) == 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200240 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000241
242 if( base64_dec_map[src[i]] < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200243 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000244
245 n++;
246 }
247
248 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100249 {
250 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000251 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100252 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000253
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000254 /* The following expression is to calculate the following formula without
255 * risk of integer overflow in n:
256 * n = ( ( n * 6 ) + 7 ) >> 3;
257 */
Andres AG4623d832017-01-18 17:21:03 +0000258 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Paul Bakkerd5983182014-07-04 13:50:31 +0200259 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000260
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100261 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000262 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100263 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200264 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000265 }
266
267 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
268 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200269 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000270 continue;
271
Paul Elliottdadd10d2021-02-05 17:49:23 +0000272 j -= ( mbedtls_base64_table_lookup(base64_dec_map, sizeof( base64_dec_map ), *src ) == 64 );
273 x = ( x << 6 ) |
274 ( mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000275
276 if( ++n == 4 )
277 {
278 n = 0;
279 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
280 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
281 if( j > 2 ) *p++ = (unsigned char)( x );
282 }
283 }
284
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100285 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000286
287 return( 0 );
288}
289
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200290#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000291
Paul Bakker5121ce52009-01-03 21:22:43 +0000292static const unsigned char base64_test_dec[64] =
293{
294 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
295 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
296 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
297 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
298 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
299 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
300 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
301 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
302};
303
304static const unsigned char base64_test_enc[] =
305 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
306 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
307
308/*
309 * Checkup routine
310 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200311int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000312{
Paul Bakker23986e52011-04-24 08:57:21 +0000313 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200314 const unsigned char *src;
315 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000316
317 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200318 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000319
Paul Bakker3c2122f2013-06-24 19:03:14 +0200320 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000321
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100322 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200323 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000324 {
325 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200326 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000327
328 return( 1 );
329 }
330
331 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200332 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000333
Paul Bakker3c2122f2013-06-24 19:03:14 +0200334 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000335
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100336 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000337 memcmp( base64_test_dec, buffer, 64 ) != 0 )
338 {
339 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200340 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000341
342 return( 1 );
343 }
344
345 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200346 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000347
348 return( 0 );
349}
350
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200351#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000352
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200353#endif /* MBEDTLS_BASE64_C */