blob: 0b4ed56b10f961082b89c5d9a6b3aaab506551ba [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 Elliottdadd10d2021-02-05 17:49:23 +000068static void mbedtls_base64_cond_assign(unsigned char * dest, const unsigned char * const src,
69 unsigned char condition)
70{
71 /* make sure assign is 0 or 1 in a time-constant manner */
72 condition = (condition | (unsigned char)-condition) >> 7;
73
74 *dest = ( *dest ) * ( 1 - condition ) + ( *src ) * condition;
75}
76
77/*
78 * Constant time check for equality
79*/
80static unsigned char mbedtls_base64_eq(uint32_t in_a, uint32_t in_b)
81{
82 uint32_t difference = in_a ^ in_b;
83
84 difference |= -difference;
85 difference >>= 31;
86 return (unsigned char) ( 1 ^ difference );
87}
88
89/*
90 * Constant time lookup into table.
91*/
92static unsigned char mbedtls_base64_table_lookup(const unsigned char * const table,
93 const size_t table_size, const size_t table_index)
94{
95 size_t i;
96 unsigned char result = 0;
97
98 for( i = 0; i < table_size; ++i )
99 {
100 mbedtls_base64_cond_assign(&result, &table[i], mbedtls_base64_eq(i, table_index));
101 }
102
103 return result;
104}
105
Paul Bakker5121ce52009-01-03 21:22:43 +0000106/*
107 * Encode a buffer into base64 format
108 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100109int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000110 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000111{
Paul Bakker23986e52011-04-24 08:57:21 +0000112 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000113 int C1, C2, C3;
114 unsigned char *p;
115
116 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +0000117 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100118 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000119 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +0000120 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000121
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200122 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +0000123
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +0100124 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000125 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +0100126 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200127 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000128 }
129
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200130 n *= 4;
131
Janos Follath98e28a72016-05-31 14:03:54 +0100132 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +0000133 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100134 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200135 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000136 }
137
Paul Bakker66d5d072014-06-17 16:39:18 +0200138 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000139
140 for( i = 0, p = dst; i < n; i += 3 )
141 {
142 C1 = *src++;
143 C2 = *src++;
144 C3 = *src++;
145
Paul Elliottdadd10d2021-02-05 17:49:23 +0000146 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
147 ( ( C1 >> 2 ) & 0x3F ) );
148
149 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
150 ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
151
152 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
153 ( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F ) );
154
155 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
156 ( C3 & 0x3F ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000157 }
158
159 if( i < slen )
160 {
161 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200162 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000163
Paul Elliottdadd10d2021-02-05 17:49:23 +0000164 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
165 ( ( C1 >> 2 ) & 0x3F ) );
166
167 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
168 ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000169
Paul Bakker66d5d072014-06-17 16:39:18 +0200170 if( ( i + 1 ) < slen )
Paul Elliottdadd10d2021-02-05 17:49:23 +0000171 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
172 ( ( ( C2 & 15 ) << 2 ) & 0x3F ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000173 else *p++ = '=';
174
175 *p++ = '=';
176 }
177
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100178 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000179 *p = 0;
180
181 return( 0 );
182}
183
184/*
185 * Decode a base64-formatted buffer
186 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100187int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000188 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000189{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000190 size_t i, n;
191 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000192 unsigned char *p;
193
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200194 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200195 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000196 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200197 /* Skip spaces before checking for EOL */
198 x = 0;
199 while( i < slen && src[i] == ' ' )
200 {
201 ++i;
202 ++x;
203 }
204
205 /* Spaces at end of buffer are OK */
206 if( i == slen )
207 break;
208
Paul Bakker5121ce52009-01-03 21:22:43 +0000209 if( ( slen - i ) >= 2 &&
210 src[i] == '\r' && src[i + 1] == '\n' )
211 continue;
212
213 if( src[i] == '\n' )
214 continue;
215
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200216 /* Space inside a line is an error */
217 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200218 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200219
Paul Bakker5121ce52009-01-03 21:22:43 +0000220 if( src[i] == '=' && ++j > 2 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200221 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000222
Paul Elliottdadd10d2021-02-05 17:49:23 +0000223 if( src[i] > 127 ||
224 mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] ) == 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200225 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000226
227 if( base64_dec_map[src[i]] < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200228 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000229
230 n++;
231 }
232
233 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100234 {
235 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000236 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100237 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000238
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000239 /* The following expression is to calculate the following formula without
240 * risk of integer overflow in n:
241 * n = ( ( n * 6 ) + 7 ) >> 3;
242 */
Andres AG4623d832017-01-18 17:21:03 +0000243 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Paul Bakkerd5983182014-07-04 13:50:31 +0200244 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000245
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100246 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000247 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100248 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200249 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000250 }
251
252 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
253 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200254 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000255 continue;
256
Paul Elliottdadd10d2021-02-05 17:49:23 +0000257 j -= ( mbedtls_base64_table_lookup(base64_dec_map, sizeof( base64_dec_map ), *src ) == 64 );
258 x = ( x << 6 ) |
259 ( mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000260
261 if( ++n == 4 )
262 {
263 n = 0;
264 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
265 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
266 if( j > 2 ) *p++ = (unsigned char)( x );
267 }
268 }
269
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100270 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000271
272 return( 0 );
273}
274
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200275#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000276
Paul Bakker5121ce52009-01-03 21:22:43 +0000277static const unsigned char base64_test_dec[64] =
278{
279 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
280 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
281 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
282 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
283 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
284 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
285 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
286 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
287};
288
289static const unsigned char base64_test_enc[] =
290 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
291 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
292
293/*
294 * Checkup routine
295 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200296int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000297{
Paul Bakker23986e52011-04-24 08:57:21 +0000298 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200299 const unsigned char *src;
300 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000301
302 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200303 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000304
Paul Bakker3c2122f2013-06-24 19:03:14 +0200305 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000306
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100307 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200308 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000309 {
310 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200311 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000312
313 return( 1 );
314 }
315
316 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200317 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000318
Paul Bakker3c2122f2013-06-24 19:03:14 +0200319 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000320
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100321 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000322 memcmp( base64_test_dec, buffer, 64 ) != 0 )
323 {
324 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200325 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000326
327 return( 1 );
328 }
329
330 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200331 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000332
333 return( 0 );
334}
335
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200336#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000337
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200338#endif /* MBEDTLS_BASE64_C */