blob: b2e6dabcb141ac372e8167a5b00322092becfe77 [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"
Gilles Peskinea1388022021-08-06 14:47:10 +020025#include "base64_invasive.h"
Gabor Mezei200708d2021-11-15 16:18:54 +010026#include "constant_time_internal.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000027
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020028#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000029
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020030#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000031#include <string.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020032#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000033#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010034#else
Rich Evans00ab4702015-02-06 13:43:58 +000035#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020036#define mbedtls_printf printf
37#endif /* MBEDTLS_PLATFORM_C */
38#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010039
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010040#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
41
Paul Bakker5121ce52009-01-03 21:22:43 +000042/*
43 * Encode a buffer into base64 format
44 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010045int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +000046 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000047{
Paul Bakker23986e52011-04-24 08:57:21 +000048 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000049 int C1, C2, C3;
50 unsigned char *p;
51
52 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000053 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010054 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000055 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000056 }
Paul Bakker5121ce52009-01-03 21:22:43 +000057
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020058 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000059
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010060 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000061 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010062 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020063 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000064 }
65
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020066 n *= 4;
67
Janos Follath98e28a72016-05-31 14:03:54 +010068 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +000069 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010070 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020071 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000072 }
73
Paul Bakker66d5d072014-06-17 16:39:18 +020074 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +000075
76 for( i = 0, p = dst; i < n; i += 3 )
77 {
78 C1 = *src++;
79 C2 = *src++;
80 C3 = *src++;
81
Gabor Mezei7464f372021-11-15 16:03:24 +010082 *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F );
83 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
Gilles Peskine2c78f982021-08-03 12:19:30 +020084 & 0x3F );
Gabor Mezei7464f372021-11-15 16:03:24 +010085 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) )
Gilles Peskine2c78f982021-08-03 12:19:30 +020086 & 0x3F );
Gabor Mezei7464f372021-11-15 16:03:24 +010087 *p++ = mbedtls_ct_base64_enc_char( C3 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +000088 }
89
90 if( i < slen )
91 {
92 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +020093 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000094
Gabor Mezei7464f372021-11-15 16:03:24 +010095 *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F );
96 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
Gilles Peskine2c78f982021-08-03 12:19:30 +020097 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +000098
Paul Bakker66d5d072014-06-17 16:39:18 +020099 if( ( i + 1 ) < slen )
Gabor Mezei7464f372021-11-15 16:03:24 +0100100 *p++ = mbedtls_ct_base64_enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000101 else *p++ = '=';
102
103 *p++ = '=';
104 }
105
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100106 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000107 *p = 0;
108
109 return( 0 );
110}
111
112/*
113 * Decode a base64-formatted buffer
114 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100115int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000116 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000117{
Gilles Peskinea97e9112021-07-28 14:20:06 +0200118 size_t i; /* index in source */
119 size_t n; /* number of digits or trailing = in source */
120 uint32_t x; /* value accumulator */
Gilles Peskine831fd762021-07-30 12:56:21 +0200121 unsigned accumulated_digits = 0;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200122 unsigned equals = 0;
123 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000124 unsigned char *p;
125
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200126 /* First pass: check for validity and get output length */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200127 for( i = n = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000128 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200129 /* Skip spaces before checking for EOL */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200130 spaces_present = 0;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200131 while( i < slen && src[i] == ' ' )
132 {
133 ++i;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200134 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200135 }
136
137 /* Spaces at end of buffer are OK */
138 if( i == slen )
139 break;
140
Paul Bakker5121ce52009-01-03 21:22:43 +0000141 if( ( slen - i ) >= 2 &&
142 src[i] == '\r' && src[i + 1] == '\n' )
143 continue;
144
145 if( src[i] == '\n' )
146 continue;
147
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200148 /* Space inside a line is an error */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200149 if( spaces_present )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200150 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200151
Gilles Peskine6b541a02021-07-28 11:33:04 +0200152 if( src[i] > 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200153 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000154
Gilles Peskine6b541a02021-07-28 11:33:04 +0200155 if( src[i] == '=' )
156 {
Gilles Peskinea97e9112021-07-28 14:20:06 +0200157 if( ++equals > 2 )
Gilles Peskine6b541a02021-07-28 11:33:04 +0200158 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
159 }
160 else
161 {
Gilles Peskinea97e9112021-07-28 14:20:06 +0200162 if( equals != 0 )
Gilles Peskine6b541a02021-07-28 11:33:04 +0200163 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Gabor Mezei7464f372021-11-15 16:03:24 +0100164 if( mbedtls_ct_base64_dec_value( src[i] ) < 0 )
Gilles Peskine6b541a02021-07-28 11:33:04 +0200165 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
166 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000167 n++;
168 }
169
170 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100171 {
172 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000173 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100174 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000175
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000176 /* The following expression is to calculate the following formula without
177 * risk of integer overflow in n:
178 * n = ( ( n * 6 ) + 7 ) >> 3;
179 */
Andres AG4623d832017-01-18 17:21:03 +0000180 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Gilles Peskinea97e9112021-07-28 14:20:06 +0200181 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000182
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100183 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000184 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100185 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200186 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000187 }
188
Gilles Peskinea97e9112021-07-28 14:20:06 +0200189 equals = 0;
Gilles Peskine831fd762021-07-30 12:56:21 +0200190 for( x = 0, p = dst; i > 0; i--, src++ )
Gilles Peskinea97e9112021-07-28 14:20:06 +0200191 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200192 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000193 continue;
194
Gilles Peskinea97e9112021-07-28 14:20:06 +0200195 x = x << 6;
Gilles Peskine6b541a02021-07-28 11:33:04 +0200196 if( *src == '=' )
Gilles Peskinea97e9112021-07-28 14:20:06 +0200197 ++equals;
Gilles Peskine6b541a02021-07-28 11:33:04 +0200198 else
Gabor Mezei7464f372021-11-15 16:03:24 +0100199 x |= mbedtls_ct_base64_dec_value( *src );
Paul Bakker5121ce52009-01-03 21:22:43 +0000200
Gilles Peskine831fd762021-07-30 12:56:21 +0200201 if( ++accumulated_digits == 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000202 {
Gilles Peskine831fd762021-07-30 12:56:21 +0200203 accumulated_digits = 0;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200204 *p++ = MBEDTLS_BYTE_2( x );
205 if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
206 if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
Paul Bakker5121ce52009-01-03 21:22:43 +0000207 }
208 }
209
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100210 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000211
212 return( 0 );
213}
214
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200215#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000216
Paul Bakker5121ce52009-01-03 21:22:43 +0000217static const unsigned char base64_test_dec[64] =
218{
219 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
220 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
221 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
222 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
223 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
224 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
225 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
226 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
227};
228
229static const unsigned char base64_test_enc[] =
230 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
231 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
232
233/*
234 * Checkup routine
235 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200236int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000237{
Paul Bakker23986e52011-04-24 08:57:21 +0000238 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200239 const unsigned char *src;
240 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000241
242 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200243 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000244
Paul Bakker3c2122f2013-06-24 19:03:14 +0200245 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000246
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100247 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200248 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000249 {
250 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200251 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000252
253 return( 1 );
254 }
255
256 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200257 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000258
Paul Bakker3c2122f2013-06-24 19:03:14 +0200259 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000260
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100261 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000262 memcmp( base64_test_dec, buffer, 64 ) != 0 )
263 {
264 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200265 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000266
267 return( 1 );
268 }
269
270 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200271 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000272
273 return( 0 );
274}
275
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200276#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000277
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200278#endif /* MBEDTLS_BASE64_C */