blob: 83daa0bcc67f61526891a94e3fc02d3baf9f4ef2 [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é-Gonnard2cf5a7c2015-04-08 12:49:31 +020031#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000032#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010033#else
Rich Evans00ab4702015-02-06 13:43:58 +000034#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020035#define mbedtls_printf printf
36#endif /* MBEDTLS_PLATFORM_C */
37#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010038
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010039#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
40
Paul Bakker5121ce52009-01-03 21:22:43 +000041/*
42 * Encode a buffer into base64 format
43 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010044int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +000045 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000046{
Paul Bakker23986e52011-04-24 08:57:21 +000047 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000048 int C1, C2, C3;
49 unsigned char *p;
50
51 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000052 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010053 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000054 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000055 }
Paul Bakker5121ce52009-01-03 21:22:43 +000056
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020057 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000058
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010059 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000060 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010061 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020062 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000063 }
64
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020065 n *= 4;
66
Janos Follath98e28a72016-05-31 14:03:54 +010067 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +000068 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010069 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020070 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000071 }
72
Paul Bakker66d5d072014-06-17 16:39:18 +020073 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +000074
75 for( i = 0, p = dst; i < n; i += 3 )
76 {
77 C1 = *src++;
78 C2 = *src++;
79 C3 = *src++;
80
Gabor Mezeib8d78922021-11-15 16:03:24 +010081 *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F );
82 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
Gilles Peskined7d32792021-08-03 12:19:30 +020083 & 0x3F );
Gabor Mezeib8d78922021-11-15 16:03:24 +010084 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) )
Gilles Peskined7d32792021-08-03 12:19:30 +020085 & 0x3F );
Gabor Mezeib8d78922021-11-15 16:03:24 +010086 *p++ = mbedtls_ct_base64_enc_char( C3 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +000087 }
88
89 if( i < slen )
90 {
91 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +020092 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000093
Gabor Mezeib8d78922021-11-15 16:03:24 +010094 *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F );
95 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
Gilles Peskined7d32792021-08-03 12:19:30 +020096 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +000097
Paul Bakker66d5d072014-06-17 16:39:18 +020098 if( ( i + 1 ) < slen )
Gabor Mezeib8d78922021-11-15 16:03:24 +010099 *p++ = mbedtls_ct_base64_enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000100 else *p++ = '=';
101
102 *p++ = '=';
103 }
104
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100105 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000106 *p = 0;
107
108 return( 0 );
109}
110
111/*
112 * Decode a base64-formatted buffer
113 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100114int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000115 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000116{
Gilles Peskine1121cd22021-07-28 14:20:06 +0200117 size_t i; /* index in source */
118 size_t n; /* number of digits or trailing = in source */
119 uint32_t x; /* value accumulator */
Gilles Peskine67468e82021-07-30 12:56:21 +0200120 unsigned accumulated_digits = 0;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200121 unsigned equals = 0;
122 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000123 unsigned char *p;
124
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200125 /* First pass: check for validity and get output length */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200126 for( i = n = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000127 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200128 /* Skip spaces before checking for EOL */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200129 spaces_present = 0;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200130 while( i < slen && src[i] == ' ' )
131 {
132 ++i;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200133 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200134 }
135
136 /* Spaces at end of buffer are OK */
137 if( i == slen )
138 break;
139
Paul Bakker5121ce52009-01-03 21:22:43 +0000140 if( ( slen - i ) >= 2 &&
141 src[i] == '\r' && src[i + 1] == '\n' )
142 continue;
143
144 if( src[i] == '\n' )
145 continue;
146
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200147 /* Space inside a line is an error */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200148 if( spaces_present )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200149 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200150
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200151 if( src[i] > 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200152 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000153
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200154 if( src[i] == '=' )
155 {
Gilles Peskine1121cd22021-07-28 14:20:06 +0200156 if( ++equals > 2 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200157 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
158 }
159 else
160 {
Gilles Peskine1121cd22021-07-28 14:20:06 +0200161 if( equals != 0 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200162 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Gabor Mezeib8d78922021-11-15 16:03:24 +0100163 if( mbedtls_ct_base64_dec_value( src[i] ) < 0 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200164 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
165 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000166 n++;
167 }
168
169 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100170 {
171 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000172 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100173 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000174
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000175 /* The following expression is to calculate the following formula without
176 * risk of integer overflow in n:
177 * n = ( ( n * 6 ) + 7 ) >> 3;
178 */
Andres AG4623d832017-01-18 17:21:03 +0000179 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Gilles Peskine1121cd22021-07-28 14:20:06 +0200180 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000181
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100182 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000183 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100184 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200185 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000186 }
187
Gilles Peskine1121cd22021-07-28 14:20:06 +0200188 equals = 0;
Gilles Peskine67468e82021-07-30 12:56:21 +0200189 for( x = 0, p = dst; i > 0; i--, src++ )
Gilles Peskine1121cd22021-07-28 14:20:06 +0200190 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200191 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000192 continue;
193
Gilles Peskine1121cd22021-07-28 14:20:06 +0200194 x = x << 6;
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200195 if( *src == '=' )
Gilles Peskine1121cd22021-07-28 14:20:06 +0200196 ++equals;
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200197 else
Gabor Mezeib8d78922021-11-15 16:03:24 +0100198 x |= mbedtls_ct_base64_dec_value( *src );
Paul Bakker5121ce52009-01-03 21:22:43 +0000199
Gilles Peskine67468e82021-07-30 12:56:21 +0200200 if( ++accumulated_digits == 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000201 {
Gilles Peskine67468e82021-07-30 12:56:21 +0200202 accumulated_digits = 0;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200203 *p++ = MBEDTLS_BYTE_2( x );
204 if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
205 if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
Paul Bakker5121ce52009-01-03 21:22:43 +0000206 }
207 }
208
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100209 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000210
211 return( 0 );
212}
213
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200214#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000215
Paul Bakker5121ce52009-01-03 21:22:43 +0000216static const unsigned char base64_test_dec[64] =
217{
218 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
219 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
220 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
221 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
222 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
223 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
224 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
225 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
226};
227
228static const unsigned char base64_test_enc[] =
229 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
230 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
231
232/*
233 * Checkup routine
234 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200235int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000236{
Paul Bakker23986e52011-04-24 08:57:21 +0000237 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200238 const unsigned char *src;
239 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000240
241 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200242 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000243
Paul Bakker3c2122f2013-06-24 19:03:14 +0200244 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000245
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100246 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200247 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000248 {
249 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200250 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000251
252 return( 1 );
253 }
254
255 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200256 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000257
Paul Bakker3c2122f2013-06-24 19:03:14 +0200258 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000259
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100260 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000261 memcmp( base64_test_dec, buffer, 64 ) != 0 )
262 {
263 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200264 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000265
266 return( 1 );
267 }
268
269 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200270 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000271
272 return( 0 );
273}
274
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200275#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000276
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200277#endif /* MBEDTLS_BASE64_C */