blob: 1c16a8801cbf41c50dd71189326b334a9f8b8eac [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;
Paul Elliott6e152fa2021-03-01 18:33:09 +0000210 unsigned char dec_map_lookup;
Paul Bakker5121ce52009-01-03 21:22:43 +0000211
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200212 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200213 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000214 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200215 /* Skip spaces before checking for EOL */
216 x = 0;
217 while( i < slen && src[i] == ' ' )
218 {
219 ++i;
220 ++x;
221 }
222
223 /* Spaces at end of buffer are OK */
224 if( i == slen )
225 break;
226
Paul Bakker5121ce52009-01-03 21:22:43 +0000227 if( ( slen - i ) >= 2 &&
228 src[i] == '\r' && src[i + 1] == '\n' )
229 continue;
230
231 if( src[i] == '\n' )
232 continue;
233
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200234 /* Space inside a line is an error */
235 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200236 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200237
Paul Bakker5121ce52009-01-03 21:22:43 +0000238 if( src[i] == '=' && ++j > 2 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200239 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000240
Paul Elliott6e152fa2021-03-01 18:33:09 +0000241 dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] );
242
243 if( src[i] > 127 || dec_map_lookup == 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200244 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000245
Paul Elliott6e152fa2021-03-01 18:33:09 +0000246 if( dec_map_lookup < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200247 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000248
249 n++;
250 }
251
252 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100253 {
254 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000255 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100256 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000257
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000258 /* The following expression is to calculate the following formula without
259 * risk of integer overflow in n:
260 * n = ( ( n * 6 ) + 7 ) >> 3;
261 */
Andres AG4623d832017-01-18 17:21:03 +0000262 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Paul Bakkerd5983182014-07-04 13:50:31 +0200263 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000264
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100265 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000266 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100267 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200268 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000269 }
270
271 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
272 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200273 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000274 continue;
275
Paul Elliott6e152fa2021-03-01 18:33:09 +0000276 dec_map_lookup = mbedtls_base64_table_lookup(base64_dec_map, sizeof( base64_dec_map ), *src );
277
278 j -= ( dec_map_lookup == 64 );
279 x = ( x << 6 ) | ( dec_map_lookup & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000280
281 if( ++n == 4 )
282 {
283 n = 0;
284 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
285 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
286 if( j > 2 ) *p++ = (unsigned char)( x );
287 }
288 }
289
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100290 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000291
292 return( 0 );
293}
294
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200295#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000296
Paul Bakker5121ce52009-01-03 21:22:43 +0000297static const unsigned char base64_test_dec[64] =
298{
299 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
300 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
301 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
302 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
303 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
304 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
305 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
306 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
307};
308
309static const unsigned char base64_test_enc[] =
310 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
311 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
312
313/*
314 * Checkup routine
315 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200316int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000317{
Paul Bakker23986e52011-04-24 08:57:21 +0000318 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200319 const unsigned char *src;
320 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000321
322 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200323 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000324
Paul Bakker3c2122f2013-06-24 19:03:14 +0200325 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000326
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100327 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200328 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000329 {
330 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200331 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000332
333 return( 1 );
334 }
335
336 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200337 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000338
Paul Bakker3c2122f2013-06-24 19:03:14 +0200339 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000340
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100341 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000342 memcmp( base64_test_dec, buffer, 64 ) != 0 )
343 {
344 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200345 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000346
347 return( 1 );
348 }
349
350 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200351 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000352
353 return( 0 );
354}
355
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200356#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000357
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200358#endif /* MBEDTLS_BASE64_C */