blob: f1a6055019b79d9c7800665ee41bc3e97eb7f764 [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 Peskinec1776a02021-08-06 14:47:10 +020025#include "base64_invasive.h"
Gabor Mezei9a4074a2021-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 Mezeib8d78922021-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 Peskined7d32792021-08-03 12:19:30 +020084 & 0x3F );
Gabor Mezeib8d78922021-11-15 16:03:24 +010085 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) )
Gilles Peskined7d32792021-08-03 12:19:30 +020086 & 0x3F );
Gabor Mezeib8d78922021-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 Mezeib8d78922021-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 Peskined7d32792021-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 Mezeib8d78922021-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
Gilles Peskineab043352021-07-28 13:54:02 +0200112/* Given a Base64 digit, return its value.
113 * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'),
114 * return -1.
115 *
116 * The implementation assumes that letters are consecutive (e.g. ASCII
117 * but not EBCDIC).
118 *
119 * The implementation is constant-flow (no branch or memory access depending
120 * on the value of c) unless the compiler inlines and optimizes a specific
121 * access.
122 */
Gilles Peskined7d32792021-08-03 12:19:30 +0200123MBEDTLS_STATIC_TESTABLE
Gabor Mezeib8d78922021-11-15 16:03:24 +0100124signed char mbedtls_ct_base64_dec_value( unsigned char c )
Gilles Peskineab043352021-07-28 13:54:02 +0200125{
126 unsigned char val = 0;
127 /* For each range of digits, if c is in that range, mask val with
128 * the corresponding value. Since c can only be in a single range,
129 * only at most one masking will change val. Set val to one plus
130 * the desired value so that it stays 0 if c is in none of the ranges. */
Gabor Mezeib8d78922021-11-15 16:03:24 +0100131 val |= mbedtls_ct_uchar_mask_of_range( 'A', 'Z', c ) & ( c - 'A' + 0 + 1 );
132 val |= mbedtls_ct_uchar_mask_of_range( 'a', 'z', c ) & ( c - 'a' + 26 + 1 );
133 val |= mbedtls_ct_uchar_mask_of_range( '0', '9', c ) & ( c - '0' + 52 + 1 );
134 val |= mbedtls_ct_uchar_mask_of_range( '+', '+', c ) & ( c - '+' + 62 + 1 );
135 val |= mbedtls_ct_uchar_mask_of_range( '/', '/', c ) & ( c - '/' + 63 + 1 );
Gilles Peskineab043352021-07-28 13:54:02 +0200136 /* At this point, val is 0 if c is an invalid digit and v+1 if c is
137 * a digit with the value v. */
138 return( val - 1 );
139}
140
Paul Bakker5121ce52009-01-03 21:22:43 +0000141/*
142 * Decode a base64-formatted buffer
143 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100144int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000145 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000146{
Gilles Peskine1121cd22021-07-28 14:20:06 +0200147 size_t i; /* index in source */
148 size_t n; /* number of digits or trailing = in source */
149 uint32_t x; /* value accumulator */
Gilles Peskine67468e82021-07-30 12:56:21 +0200150 unsigned accumulated_digits = 0;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200151 unsigned equals = 0;
152 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000153 unsigned char *p;
154
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200155 /* First pass: check for validity and get output length */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200156 for( i = n = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000157 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200158 /* Skip spaces before checking for EOL */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200159 spaces_present = 0;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200160 while( i < slen && src[i] == ' ' )
161 {
162 ++i;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200163 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200164 }
165
166 /* Spaces at end of buffer are OK */
167 if( i == slen )
168 break;
169
Paul Bakker5121ce52009-01-03 21:22:43 +0000170 if( ( slen - i ) >= 2 &&
171 src[i] == '\r' && src[i + 1] == '\n' )
172 continue;
173
174 if( src[i] == '\n' )
175 continue;
176
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200177 /* Space inside a line is an error */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200178 if( spaces_present )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200179 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200180
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200181 if( src[i] > 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200182 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000183
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200184 if( src[i] == '=' )
185 {
Gilles Peskine1121cd22021-07-28 14:20:06 +0200186 if( ++equals > 2 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200187 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
188 }
189 else
190 {
Gilles Peskine1121cd22021-07-28 14:20:06 +0200191 if( equals != 0 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200192 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Gabor Mezeib8d78922021-11-15 16:03:24 +0100193 if( mbedtls_ct_base64_dec_value( src[i] ) < 0 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200194 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
195 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000196 n++;
197 }
198
199 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100200 {
201 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000202 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100203 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000204
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000205 /* The following expression is to calculate the following formula without
206 * risk of integer overflow in n:
207 * n = ( ( n * 6 ) + 7 ) >> 3;
208 */
Andres AG4623d832017-01-18 17:21:03 +0000209 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Gilles Peskine1121cd22021-07-28 14:20:06 +0200210 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000211
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100212 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000213 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100214 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200215 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000216 }
217
Gilles Peskine1121cd22021-07-28 14:20:06 +0200218 equals = 0;
Gilles Peskine67468e82021-07-30 12:56:21 +0200219 for( x = 0, p = dst; i > 0; i--, src++ )
Gilles Peskine1121cd22021-07-28 14:20:06 +0200220 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200221 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000222 continue;
223
Gilles Peskine1121cd22021-07-28 14:20:06 +0200224 x = x << 6;
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200225 if( *src == '=' )
Gilles Peskine1121cd22021-07-28 14:20:06 +0200226 ++equals;
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200227 else
Gabor Mezeib8d78922021-11-15 16:03:24 +0100228 x |= mbedtls_ct_base64_dec_value( *src );
Paul Bakker5121ce52009-01-03 21:22:43 +0000229
Gilles Peskine67468e82021-07-30 12:56:21 +0200230 if( ++accumulated_digits == 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000231 {
Gilles Peskine67468e82021-07-30 12:56:21 +0200232 accumulated_digits = 0;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200233 *p++ = MBEDTLS_BYTE_2( x );
234 if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
235 if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
Paul Bakker5121ce52009-01-03 21:22:43 +0000236 }
237 }
238
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100239 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000240
241 return( 0 );
242}
243
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200244#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000245
Paul Bakker5121ce52009-01-03 21:22:43 +0000246static const unsigned char base64_test_dec[64] =
247{
248 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
249 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
250 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
251 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
252 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
253 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
254 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
255 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
256};
257
258static const unsigned char base64_test_enc[] =
259 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
260 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
261
262/*
263 * Checkup routine
264 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200265int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000266{
Paul Bakker23986e52011-04-24 08:57:21 +0000267 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200268 const unsigned char *src;
269 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000270
271 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200272 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000273
Paul Bakker3c2122f2013-06-24 19:03:14 +0200274 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000275
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100276 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200277 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000278 {
279 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200280 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000281
282 return( 1 );
283 }
284
285 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200286 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000287
Paul Bakker3c2122f2013-06-24 19:03:14 +0200288 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000289
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100290 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000291 memcmp( base64_test_dec, buffer, 64 ) != 0 )
292 {
293 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200294 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000295
296 return( 1 );
297 }
298
299 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200300 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000301
302 return( 0 );
303}
304
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200305#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000306
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200307#endif /* MBEDTLS_BASE64_C */