blob: 2c4df833819c2f47b1ef1f158d42106353e0dbfe [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"
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
Gilles Peskine2c4a3682021-07-28 14:31:39 +020041/* Given a value in the range 0..63, return the corresponding Base64 digit.
42 * The implementation assumes that letters are consecutive (e.g. ASCII
43 * but not EBCDIC).
44 */
Gilles Peskined7d32792021-08-03 12:19:30 +020045MBEDTLS_STATIC_TESTABLE
Gabor Mezeib8d78922021-11-15 16:03:24 +010046unsigned char mbedtls_ct_base64_enc_char( unsigned char val )
Gilles Peskine2c4a3682021-07-28 14:31:39 +020047{
48 unsigned char digit = 0;
49 /* For each range of values, if val is in that range, mask digit with
50 * the corresponding value. Since val can only be in a single range,
51 * only at most one masking will change digit. */
Gabor Mezeib8d78922021-11-15 16:03:24 +010052 digit |= mbedtls_ct_uchar_mask_of_range( 0, 25, val ) & ( 'A' + val );
53 digit |= mbedtls_ct_uchar_mask_of_range( 26, 51, val ) & ( 'a' + val - 26 );
54 digit |= mbedtls_ct_uchar_mask_of_range( 52, 61, val ) & ( '0' + val - 52 );
55 digit |= mbedtls_ct_uchar_mask_of_range( 62, 62, val ) & '+';
56 digit |= mbedtls_ct_uchar_mask_of_range( 63, 63, val ) & '/';
Gilles Peskine2c4a3682021-07-28 14:31:39 +020057 return( digit );
58}
59
Paul Bakker5121ce52009-01-03 21:22:43 +000060/*
61 * Encode a buffer into base64 format
62 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010063int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +000064 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000065{
Paul Bakker23986e52011-04-24 08:57:21 +000066 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000067 int C1, C2, C3;
68 unsigned char *p;
69
70 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000071 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010072 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000073 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000074 }
Paul Bakker5121ce52009-01-03 21:22:43 +000075
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020076 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000077
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010078 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000079 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010080 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020081 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000082 }
83
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020084 n *= 4;
85
Janos Follath98e28a72016-05-31 14:03:54 +010086 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +000087 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010088 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020089 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000090 }
91
Paul Bakker66d5d072014-06-17 16:39:18 +020092 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +000093
94 for( i = 0, p = dst; i < n; i += 3 )
95 {
96 C1 = *src++;
97 C2 = *src++;
98 C3 = *src++;
99
Gabor Mezeib8d78922021-11-15 16:03:24 +0100100 *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F );
101 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
Gilles Peskined7d32792021-08-03 12:19:30 +0200102 & 0x3F );
Gabor Mezeib8d78922021-11-15 16:03:24 +0100103 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) )
Gilles Peskined7d32792021-08-03 12:19:30 +0200104 & 0x3F );
Gabor Mezeib8d78922021-11-15 16:03:24 +0100105 *p++ = mbedtls_ct_base64_enc_char( C3 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000106 }
107
108 if( i < slen )
109 {
110 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200111 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000112
Gabor Mezeib8d78922021-11-15 16:03:24 +0100113 *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F );
114 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
Gilles Peskined7d32792021-08-03 12:19:30 +0200115 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000116
Paul Bakker66d5d072014-06-17 16:39:18 +0200117 if( ( i + 1 ) < slen )
Gabor Mezeib8d78922021-11-15 16:03:24 +0100118 *p++ = mbedtls_ct_base64_enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000119 else *p++ = '=';
120
121 *p++ = '=';
122 }
123
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100124 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000125 *p = 0;
126
127 return( 0 );
128}
129
Gilles Peskineab043352021-07-28 13:54:02 +0200130/* Given a Base64 digit, return its value.
131 * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'),
132 * return -1.
133 *
134 * The implementation assumes that letters are consecutive (e.g. ASCII
135 * but not EBCDIC).
136 *
137 * The implementation is constant-flow (no branch or memory access depending
138 * on the value of c) unless the compiler inlines and optimizes a specific
139 * access.
140 */
Gilles Peskined7d32792021-08-03 12:19:30 +0200141MBEDTLS_STATIC_TESTABLE
Gabor Mezeib8d78922021-11-15 16:03:24 +0100142signed char mbedtls_ct_base64_dec_value( unsigned char c )
Gilles Peskineab043352021-07-28 13:54:02 +0200143{
144 unsigned char val = 0;
145 /* For each range of digits, if c is in that range, mask val with
146 * the corresponding value. Since c can only be in a single range,
147 * only at most one masking will change val. Set val to one plus
148 * the desired value so that it stays 0 if c is in none of the ranges. */
Gabor Mezeib8d78922021-11-15 16:03:24 +0100149 val |= mbedtls_ct_uchar_mask_of_range( 'A', 'Z', c ) & ( c - 'A' + 0 + 1 );
150 val |= mbedtls_ct_uchar_mask_of_range( 'a', 'z', c ) & ( c - 'a' + 26 + 1 );
151 val |= mbedtls_ct_uchar_mask_of_range( '0', '9', c ) & ( c - '0' + 52 + 1 );
152 val |= mbedtls_ct_uchar_mask_of_range( '+', '+', c ) & ( c - '+' + 62 + 1 );
153 val |= mbedtls_ct_uchar_mask_of_range( '/', '/', c ) & ( c - '/' + 63 + 1 );
Gilles Peskineab043352021-07-28 13:54:02 +0200154 /* At this point, val is 0 if c is an invalid digit and v+1 if c is
155 * a digit with the value v. */
156 return( val - 1 );
157}
158
Paul Bakker5121ce52009-01-03 21:22:43 +0000159/*
160 * Decode a base64-formatted buffer
161 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100162int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000163 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000164{
Gilles Peskine1121cd22021-07-28 14:20:06 +0200165 size_t i; /* index in source */
166 size_t n; /* number of digits or trailing = in source */
167 uint32_t x; /* value accumulator */
Gilles Peskine67468e82021-07-30 12:56:21 +0200168 unsigned accumulated_digits = 0;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200169 unsigned equals = 0;
170 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000171 unsigned char *p;
172
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200173 /* First pass: check for validity and get output length */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200174 for( i = n = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000175 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200176 /* Skip spaces before checking for EOL */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200177 spaces_present = 0;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200178 while( i < slen && src[i] == ' ' )
179 {
180 ++i;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200181 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200182 }
183
184 /* Spaces at end of buffer are OK */
185 if( i == slen )
186 break;
187
Paul Bakker5121ce52009-01-03 21:22:43 +0000188 if( ( slen - i ) >= 2 &&
189 src[i] == '\r' && src[i + 1] == '\n' )
190 continue;
191
192 if( src[i] == '\n' )
193 continue;
194
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200195 /* Space inside a line is an error */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200196 if( spaces_present )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200197 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200198
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200199 if( src[i] > 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200200 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000201
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200202 if( src[i] == '=' )
203 {
Gilles Peskine1121cd22021-07-28 14:20:06 +0200204 if( ++equals > 2 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200205 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
206 }
207 else
208 {
Gilles Peskine1121cd22021-07-28 14:20:06 +0200209 if( equals != 0 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200210 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Gabor Mezeib8d78922021-11-15 16:03:24 +0100211 if( mbedtls_ct_base64_dec_value( src[i] ) < 0 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200212 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
213 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000214 n++;
215 }
216
217 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100218 {
219 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000220 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100221 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000222
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000223 /* The following expression is to calculate the following formula without
224 * risk of integer overflow in n:
225 * n = ( ( n * 6 ) + 7 ) >> 3;
226 */
Andres AG4623d832017-01-18 17:21:03 +0000227 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Gilles Peskine1121cd22021-07-28 14:20:06 +0200228 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000229
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100230 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000231 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100232 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200233 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000234 }
235
Gilles Peskine1121cd22021-07-28 14:20:06 +0200236 equals = 0;
Gilles Peskine67468e82021-07-30 12:56:21 +0200237 for( x = 0, p = dst; i > 0; i--, src++ )
Gilles Peskine1121cd22021-07-28 14:20:06 +0200238 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200239 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000240 continue;
241
Gilles Peskine1121cd22021-07-28 14:20:06 +0200242 x = x << 6;
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200243 if( *src == '=' )
Gilles Peskine1121cd22021-07-28 14:20:06 +0200244 ++equals;
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200245 else
Gabor Mezeib8d78922021-11-15 16:03:24 +0100246 x |= mbedtls_ct_base64_dec_value( *src );
Paul Bakker5121ce52009-01-03 21:22:43 +0000247
Gilles Peskine67468e82021-07-30 12:56:21 +0200248 if( ++accumulated_digits == 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000249 {
Gilles Peskine67468e82021-07-30 12:56:21 +0200250 accumulated_digits = 0;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200251 *p++ = MBEDTLS_BYTE_2( x );
252 if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
253 if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
Paul Bakker5121ce52009-01-03 21:22:43 +0000254 }
255 }
256
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100257 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000258
259 return( 0 );
260}
261
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200262#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000263
Paul Bakker5121ce52009-01-03 21:22:43 +0000264static const unsigned char base64_test_dec[64] =
265{
266 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
267 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
268 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
269 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
270 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
271 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
272 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
273 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
274};
275
276static const unsigned char base64_test_enc[] =
277 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
278 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
279
280/*
281 * Checkup routine
282 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200283int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000284{
Paul Bakker23986e52011-04-24 08:57:21 +0000285 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200286 const unsigned char *src;
287 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000288
289 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200290 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000291
Paul Bakker3c2122f2013-06-24 19:03:14 +0200292 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000293
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100294 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200295 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000296 {
297 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200298 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000299
300 return( 1 );
301 }
302
303 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200304 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000305
Paul Bakker3c2122f2013-06-24 19:03:14 +0200306 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000307
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100308 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000309 memcmp( base64_test_dec, buffer, 64 ) != 0 )
310 {
311 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200312 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000313
314 return( 1 );
315 }
316
317 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200318 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000319
320 return( 0 );
321}
322
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200323#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000324
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200325#endif /* MBEDTLS_BASE64_C */