blob: ed7db83dc7a019fa393aec0f982f8d4490429332 [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{
Paul Elliott717ba772021-03-01 17:49:42 +000085 size_t difference = in_a ^ in_b;
Paul Elliottdadd10d2021-02-05 17:49:23 +000086
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 Elliott717ba772021-03-01 17:49:42 +0000100 /* cope with the varying size of size_t per platform */
101 difference >>= ( sizeof( difference ) * 8 - 1 );
102
Paul Elliottdadd10d2021-02-05 17:49:23 +0000103 return (unsigned char) ( 1 ^ difference );
104}
105
106/*
Paul Elliott3e790812021-02-25 12:28:49 +0000107 * Constant flow lookup into table.
Paul Elliottdadd10d2021-02-05 17:49:23 +0000108*/
109static unsigned char mbedtls_base64_table_lookup(const unsigned char * const table,
110 const size_t table_size, const size_t table_index)
111{
112 size_t i;
113 unsigned char result = 0;
114
115 for( i = 0; i < table_size; ++i )
116 {
117 mbedtls_base64_cond_assign(&result, &table[i], mbedtls_base64_eq(i, table_index));
118 }
119
120 return result;
121}
122
Paul Bakker5121ce52009-01-03 21:22:43 +0000123/*
124 * Encode a buffer into base64 format
125 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100126int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000127 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000128{
Paul Bakker23986e52011-04-24 08:57:21 +0000129 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000130 int C1, C2, C3;
131 unsigned char *p;
132
133 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +0000134 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100135 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000136 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +0000137 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000138
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200139 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +0000140
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +0100141 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000142 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +0100143 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200144 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000145 }
146
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200147 n *= 4;
148
Janos Follath98e28a72016-05-31 14:03:54 +0100149 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +0000150 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100151 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200152 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000153 }
154
Paul Bakker66d5d072014-06-17 16:39:18 +0200155 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000156
157 for( i = 0, p = dst; i < n; i += 3 )
158 {
159 C1 = *src++;
160 C2 = *src++;
161 C3 = *src++;
162
Paul Elliottdadd10d2021-02-05 17:49:23 +0000163 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
164 ( ( C1 >> 2 ) & 0x3F ) );
165
166 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
167 ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
168
169 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
170 ( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F ) );
171
172 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
173 ( C3 & 0x3F ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000174 }
175
176 if( i < slen )
177 {
178 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200179 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000180
Paul Elliottdadd10d2021-02-05 17:49:23 +0000181 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
182 ( ( C1 >> 2 ) & 0x3F ) );
183
184 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
185 ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000186
Paul Bakker66d5d072014-06-17 16:39:18 +0200187 if( ( i + 1 ) < slen )
Paul Elliottdadd10d2021-02-05 17:49:23 +0000188 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
189 ( ( ( C2 & 15 ) << 2 ) & 0x3F ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000190 else *p++ = '=';
191
192 *p++ = '=';
193 }
194
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100195 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000196 *p = 0;
197
198 return( 0 );
199}
200
201/*
202 * Decode a base64-formatted buffer
203 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100204int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000205 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000206{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000207 size_t i, n;
208 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000209 unsigned char *p;
210
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200211 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200212 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000213 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200214 /* Skip spaces before checking for EOL */
215 x = 0;
216 while( i < slen && src[i] == ' ' )
217 {
218 ++i;
219 ++x;
220 }
221
222 /* Spaces at end of buffer are OK */
223 if( i == slen )
224 break;
225
Paul Bakker5121ce52009-01-03 21:22:43 +0000226 if( ( slen - i ) >= 2 &&
227 src[i] == '\r' && src[i + 1] == '\n' )
228 continue;
229
230 if( src[i] == '\n' )
231 continue;
232
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200233 /* Space inside a line is an error */
234 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200235 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200236
Paul Bakker5121ce52009-01-03 21:22:43 +0000237 if( src[i] == '=' && ++j > 2 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200238 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000239
Paul Elliottdadd10d2021-02-05 17:49:23 +0000240 if( src[i] > 127 ||
241 mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] ) == 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200242 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000243
244 if( base64_dec_map[src[i]] < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200245 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000246
247 n++;
248 }
249
250 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100251 {
252 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000253 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100254 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000255
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000256 /* The following expression is to calculate the following formula without
257 * risk of integer overflow in n:
258 * n = ( ( n * 6 ) + 7 ) >> 3;
259 */
Andres AG4623d832017-01-18 17:21:03 +0000260 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Paul Bakkerd5983182014-07-04 13:50:31 +0200261 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000262
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100263 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000264 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100265 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200266 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000267 }
268
269 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
270 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200271 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000272 continue;
273
Paul Elliottdadd10d2021-02-05 17:49:23 +0000274 j -= ( mbedtls_base64_table_lookup(base64_dec_map, sizeof( base64_dec_map ), *src ) == 64 );
275 x = ( x << 6 ) |
276 ( mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000277
278 if( ++n == 4 )
279 {
280 n = 0;
281 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
282 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
283 if( j > 2 ) *p++ = (unsigned char)( x );
284 }
285 }
286
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100287 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000288
289 return( 0 );
290}
291
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200292#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000293
Paul Bakker5121ce52009-01-03 21:22:43 +0000294static const unsigned char base64_test_dec[64] =
295{
296 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
297 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
298 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
299 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
300 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
301 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
302 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
303 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
304};
305
306static const unsigned char base64_test_enc[] =
307 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
308 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
309
310/*
311 * Checkup routine
312 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200313int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000314{
Paul Bakker23986e52011-04-24 08:57:21 +0000315 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200316 const unsigned char *src;
317 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000318
319 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200320 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000321
Paul Bakker3c2122f2013-06-24 19:03:14 +0200322 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000323
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100324 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200325 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000326 {
327 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200328 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000329
330 return( 1 );
331 }
332
333 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200334 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000335
Paul Bakker3c2122f2013-06-24 19:03:14 +0200336 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000337
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100338 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000339 memcmp( base64_test_dec, buffer, 64 ) != 0 )
340 {
341 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200342 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000343
344 return( 1 );
345 }
346
347 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200348 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000349
350 return( 0 );
351}
352
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200353#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000354
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200355#endif /* MBEDTLS_BASE64_C */