blob: 9021a041bb11b8edf5be8e0850d470cc1e3c987e [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"
Gabor Mezei9a4074a2021-11-15 16:18:54 +010025#include "constant_time_internal.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000026
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020027#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000028
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020029#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000030#include <string.h>
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000031#include "mbedtls/platform.h"
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020032#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010033
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010034#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
35
Paul Bakker5121ce52009-01-03 21:22:43 +000036/*
37 * Encode a buffer into base64 format
38 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010039int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +000040 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000041{
Paul Bakker23986e52011-04-24 08:57:21 +000042 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000043 int C1, C2, C3;
44 unsigned char *p;
45
46 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000047 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010048 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000049 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000050 }
Paul Bakker5121ce52009-01-03 21:22:43 +000051
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020052 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000053
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010054 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000055 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010056 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020057 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000058 }
59
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020060 n *= 4;
61
Janos Follath98e28a72016-05-31 14:03:54 +010062 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +000063 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010064 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020065 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000066 }
67
Paul Bakker66d5d072014-06-17 16:39:18 +020068 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +000069
70 for( i = 0, p = dst; i < n; i += 3 )
71 {
72 C1 = *src++;
73 C2 = *src++;
74 C3 = *src++;
75
Gabor Mezeib8d78922021-11-15 16:03:24 +010076 *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F );
77 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
Gilles Peskined7d32792021-08-03 12:19:30 +020078 & 0x3F );
Gabor Mezeib8d78922021-11-15 16:03:24 +010079 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) )
Gilles Peskined7d32792021-08-03 12:19:30 +020080 & 0x3F );
Gabor Mezeib8d78922021-11-15 16:03:24 +010081 *p++ = mbedtls_ct_base64_enc_char( C3 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +000082 }
83
84 if( i < slen )
85 {
86 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +020087 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000088
Gabor Mezeib8d78922021-11-15 16:03:24 +010089 *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F );
90 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
Gilles Peskined7d32792021-08-03 12:19:30 +020091 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +000092
Paul Bakker66d5d072014-06-17 16:39:18 +020093 if( ( i + 1 ) < slen )
Gabor Mezeib8d78922021-11-15 16:03:24 +010094 *p++ = mbedtls_ct_base64_enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +000095 else *p++ = '=';
96
97 *p++ = '=';
98 }
99
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100100 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000101 *p = 0;
102
103 return( 0 );
104}
105
106/*
107 * Decode a base64-formatted buffer
108 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100109int mbedtls_base64_decode( 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{
Gilles Peskine1121cd22021-07-28 14:20:06 +0200112 size_t i; /* index in source */
113 size_t n; /* number of digits or trailing = in source */
114 uint32_t x; /* value accumulator */
Gilles Peskine67468e82021-07-30 12:56:21 +0200115 unsigned accumulated_digits = 0;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200116 unsigned equals = 0;
117 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000118 unsigned char *p;
119
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200120 /* First pass: check for validity and get output length */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200121 for( i = n = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000122 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200123 /* Skip spaces before checking for EOL */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200124 spaces_present = 0;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200125 while( i < slen && src[i] == ' ' )
126 {
127 ++i;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200128 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200129 }
130
131 /* Spaces at end of buffer are OK */
132 if( i == slen )
133 break;
134
Paul Bakker5121ce52009-01-03 21:22:43 +0000135 if( ( slen - i ) >= 2 &&
136 src[i] == '\r' && src[i + 1] == '\n' )
137 continue;
138
139 if( src[i] == '\n' )
140 continue;
141
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200142 /* Space inside a line is an error */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200143 if( spaces_present )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200144 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200145
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200146 if( src[i] > 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200147 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000148
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200149 if( src[i] == '=' )
150 {
Gilles Peskine1121cd22021-07-28 14:20:06 +0200151 if( ++equals > 2 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200152 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
153 }
154 else
155 {
Gilles Peskine1121cd22021-07-28 14:20:06 +0200156 if( equals != 0 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200157 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Gabor Mezeib8d78922021-11-15 16:03:24 +0100158 if( mbedtls_ct_base64_dec_value( src[i] ) < 0 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200159 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
160 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000161 n++;
162 }
163
164 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100165 {
166 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000167 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100168 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000169
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000170 /* The following expression is to calculate the following formula without
171 * risk of integer overflow in n:
172 * n = ( ( n * 6 ) + 7 ) >> 3;
173 */
Andres AG4623d832017-01-18 17:21:03 +0000174 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Gilles Peskine1121cd22021-07-28 14:20:06 +0200175 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000176
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100177 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000178 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100179 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200180 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000181 }
182
Gilles Peskine1121cd22021-07-28 14:20:06 +0200183 equals = 0;
Gilles Peskine67468e82021-07-30 12:56:21 +0200184 for( x = 0, p = dst; i > 0; i--, src++ )
Gilles Peskine1121cd22021-07-28 14:20:06 +0200185 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200186 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000187 continue;
188
Gilles Peskine1121cd22021-07-28 14:20:06 +0200189 x = x << 6;
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200190 if( *src == '=' )
Gilles Peskine1121cd22021-07-28 14:20:06 +0200191 ++equals;
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200192 else
Gabor Mezeib8d78922021-11-15 16:03:24 +0100193 x |= mbedtls_ct_base64_dec_value( *src );
Paul Bakker5121ce52009-01-03 21:22:43 +0000194
Gilles Peskine67468e82021-07-30 12:56:21 +0200195 if( ++accumulated_digits == 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000196 {
Gilles Peskine67468e82021-07-30 12:56:21 +0200197 accumulated_digits = 0;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200198 *p++ = MBEDTLS_BYTE_2( x );
199 if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
200 if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
Paul Bakker5121ce52009-01-03 21:22:43 +0000201 }
202 }
203
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100204 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000205
206 return( 0 );
207}
208
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200209#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000210
Paul Bakker5121ce52009-01-03 21:22:43 +0000211static const unsigned char base64_test_dec[64] =
212{
213 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
214 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
215 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
216 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
217 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
218 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
219 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
220 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
221};
222
223static const unsigned char base64_test_enc[] =
224 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
225 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
226
227/*
228 * Checkup routine
229 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200230int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000231{
Paul Bakker23986e52011-04-24 08:57:21 +0000232 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200233 const unsigned char *src;
234 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000235
236 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200237 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000238
Paul Bakker3c2122f2013-06-24 19:03:14 +0200239 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000240
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100241 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200242 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000243 {
244 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200245 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000246
247 return( 1 );
248 }
249
250 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200251 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000252
Paul Bakker3c2122f2013-06-24 19:03:14 +0200253 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000254
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100255 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000256 memcmp( base64_test_dec, buffer, 64 ) != 0 )
257 {
258 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200259 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000260
261 return( 1 );
262 }
263
264 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200265 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000266
267 return( 0 );
268}
269
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200270#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000271
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200272#endif /* MBEDTLS_BASE64_C */