blob: 49a0612d2b3a93d47959bcff5e6a77f92169e412 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * RFC 1521 base64 encoding/decoding
3 *
Bence Szépkútia2947ac2020-08-19 16:37:36 +02004 * Copyright The Mbed TLS Contributors
Bence Szépkútif744bd72020-06-05 13:02:18 +02005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6 *
7 * This file is provided under the Apache License 2.0, or the
8 * GNU General Public License v2.0 or later.
9 *
10 * **********
11 * Apache License 2.0:
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +020012 *
13 * Licensed under the Apache License, Version 2.0 (the "License"); you may
14 * not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
21 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
Paul Bakkerb96f1542010-07-18 20:36:00 +000024 *
Bence Szépkútif744bd72020-06-05 13:02:18 +020025 * **********
26 *
27 * **********
28 * GNU General Public License v2.0 or later:
29 *
30 * This program is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version.
34 *
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
39 *
40 * You should have received a copy of the GNU General Public License along
41 * with this program; if not, write to the Free Software Foundation, Inc.,
42 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
43 *
44 * **********
Paul Bakker5121ce52009-01-03 21:22:43 +000045 */
46
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020047#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000048#include "mbedtls/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020049#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020050#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020051#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000052
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020053#if defined(MBEDTLS_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000054
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000055#include "mbedtls/base64.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000056
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020057#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000058
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020059#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000060#include <string.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020061#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000062#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010063#else
Rich Evans00ab4702015-02-06 13:43:58 +000064#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020065#define mbedtls_printf printf
66#endif /* MBEDTLS_PLATFORM_C */
67#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010068
Paul Bakker5121ce52009-01-03 21:22:43 +000069static const unsigned char base64_enc_map[64] =
70{
71 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
72 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
73 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
74 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
75 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
76 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
77 '8', '9', '+', '/'
78};
79
80static const unsigned char base64_dec_map[128] =
81{
82 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
83 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
84 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
85 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
86 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
87 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
88 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
89 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
90 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
91 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
92 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
93 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
94 49, 50, 51, 127, 127, 127, 127, 127
95};
96
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010097#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
98
Paul Elliott738d2312021-02-05 17:49:23 +000099static void mbedtls_base64_cond_assign(unsigned char * dest, const unsigned char * const src,
100 unsigned char condition)
101{
102 /* make sure assign is 0 or 1 in a time-constant manner */
103 condition = (condition | (unsigned char)-condition) >> 7;
104
105 *dest = ( *dest ) * ( 1 - condition ) + ( *src ) * condition;
106}
107
108/*
109 * Constant time check for equality
110*/
111static unsigned char mbedtls_base64_eq(uint32_t in_a, uint32_t in_b)
112{
113 uint32_t difference = in_a ^ in_b;
114
115 difference |= -difference;
116 difference >>= 31;
117 return (unsigned char) ( 1 ^ difference );
118}
119
120/*
121 * Constant time lookup into table.
122*/
123static unsigned char mbedtls_base64_table_lookup(const unsigned char * const table,
124 const size_t table_size, const size_t table_index)
125{
126 size_t i;
127 unsigned char result = 0;
128
129 for( i = 0; i < table_size; ++i )
130 {
131 mbedtls_base64_cond_assign(&result, &table[i], mbedtls_base64_eq(i, table_index));
132 }
133
134 return result;
135}
136
Paul Bakker5121ce52009-01-03 21:22:43 +0000137/*
138 * Encode a buffer into base64 format
139 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100140int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000141 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000142{
Paul Bakker23986e52011-04-24 08:57:21 +0000143 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000144 int C1, C2, C3;
145 unsigned char *p;
146
147 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +0000148 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100149 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000150 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +0000151 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000152
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200153 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +0000154
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +0100155 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000156 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +0100157 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200158 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000159 }
160
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200161 n *= 4;
162
Janos Follath98e28a72016-05-31 14:03:54 +0100163 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +0000164 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100165 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200166 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000167 }
168
Paul Bakker66d5d072014-06-17 16:39:18 +0200169 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000170
171 for( i = 0, p = dst; i < n; i += 3 )
172 {
173 C1 = *src++;
174 C2 = *src++;
175 C3 = *src++;
176
Paul Elliott738d2312021-02-05 17:49:23 +0000177 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
178 ( ( C1 >> 2 ) & 0x3F ) );
179
180 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
181 ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
182
183 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
184 ( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F ) );
185
186 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
187 ( C3 & 0x3F ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000188 }
189
190 if( i < slen )
191 {
192 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200193 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000194
Paul Elliott738d2312021-02-05 17:49:23 +0000195 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
196 ( ( C1 >> 2 ) & 0x3F ) );
197
198 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
199 ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000200
Paul Bakker66d5d072014-06-17 16:39:18 +0200201 if( ( i + 1 ) < slen )
Paul Elliott738d2312021-02-05 17:49:23 +0000202 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
203 ( ( ( C2 & 15 ) << 2 ) & 0x3F ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000204 else *p++ = '=';
205
206 *p++ = '=';
207 }
208
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100209 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000210 *p = 0;
211
212 return( 0 );
213}
214
215/*
216 * Decode a base64-formatted buffer
217 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100218int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000219 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000220{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000221 size_t i, n;
222 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000223 unsigned char *p;
224
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200225 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200226 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000227 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200228 /* Skip spaces before checking for EOL */
229 x = 0;
230 while( i < slen && src[i] == ' ' )
231 {
232 ++i;
233 ++x;
234 }
235
236 /* Spaces at end of buffer are OK */
237 if( i == slen )
238 break;
239
Paul Bakker5121ce52009-01-03 21:22:43 +0000240 if( ( slen - i ) >= 2 &&
241 src[i] == '\r' && src[i + 1] == '\n' )
242 continue;
243
244 if( src[i] == '\n' )
245 continue;
246
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200247 /* Space inside a line is an error */
248 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200249 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200250
Paul Bakker5121ce52009-01-03 21:22:43 +0000251 if( src[i] == '=' && ++j > 2 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200252 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000253
Paul Elliott738d2312021-02-05 17:49:23 +0000254 if( src[i] > 127 ||
255 mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] ) == 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200256 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000257
258 if( base64_dec_map[src[i]] < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200259 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000260
261 n++;
262 }
263
264 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100265 {
266 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000267 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100268 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000269
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000270 /* The following expression is to calculate the following formula without
271 * risk of integer overflow in n:
272 * n = ( ( n * 6 ) + 7 ) >> 3;
273 */
Andres AG4623d832017-01-18 17:21:03 +0000274 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Paul Bakkerd5983182014-07-04 13:50:31 +0200275 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000276
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100277 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000278 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100279 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200280 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000281 }
282
283 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
284 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200285 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000286 continue;
287
Paul Elliott738d2312021-02-05 17:49:23 +0000288 j -= ( mbedtls_base64_table_lookup(base64_dec_map, sizeof( base64_dec_map ), *src ) == 64 );
289 x = ( x << 6 ) |
290 ( mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000291
292 if( ++n == 4 )
293 {
294 n = 0;
295 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
296 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
297 if( j > 2 ) *p++ = (unsigned char)( x );
298 }
299 }
300
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100301 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000302
303 return( 0 );
304}
305
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200306#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000307
Paul Bakker5121ce52009-01-03 21:22:43 +0000308static const unsigned char base64_test_dec[64] =
309{
310 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
311 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
312 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
313 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
314 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
315 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
316 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
317 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
318};
319
320static const unsigned char base64_test_enc[] =
321 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
322 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
323
324/*
325 * Checkup routine
326 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200327int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000328{
Paul Bakker23986e52011-04-24 08:57:21 +0000329 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200330 const unsigned char *src;
331 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000332
333 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200334 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000335
Paul Bakker3c2122f2013-06-24 19:03:14 +0200336 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000337
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100338 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200339 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000340 {
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 Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000349
Paul Bakker3c2122f2013-06-24 19:03:14 +0200350 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000351
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100352 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000353 memcmp( base64_test_dec, buffer, 64 ) != 0 )
354 {
355 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200356 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000357
358 return( 1 );
359 }
360
361 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200362 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000363
364 return( 0 );
365}
366
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200367#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000368
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200369#endif /* MBEDTLS_BASE64_C */