blob: edab35ec916116fae16d6dec741044897c1099cd [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * RFC 1521 base64 encoding/decoding
3 *
Bence Szépkútia2947ac2020-08-19 16:37:36 +02004 * Copyright The Mbed TLS Contributors
Bence Szépkútif744bd72020-06-05 13:02:18 +02005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6 *
7 * This file is provided under the Apache License 2.0, or the
8 * GNU General Public License v2.0 or later.
9 *
10 * **********
11 * Apache License 2.0:
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +020012 *
13 * Licensed under the Apache License, Version 2.0 (the "License"); you may
14 * not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
21 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
Paul Bakkerb96f1542010-07-18 20:36:00 +000024 *
Bence Szépkútif744bd72020-06-05 13:02:18 +020025 * **********
26 *
27 * **********
28 * GNU General Public License v2.0 or later:
29 *
30 * This program is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version.
34 *
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
39 *
40 * You should have received a copy of the GNU General Public License along
41 * with this program; if not, write to the Free Software Foundation, Inc.,
42 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
43 *
44 * **********
Paul Bakker5121ce52009-01-03 21:22:43 +000045 */
46
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020047#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000048#include "mbedtls/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020049#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020050#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020051#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000052
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020053#if defined(MBEDTLS_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000054
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000055#include "mbedtls/base64.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000056
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020057#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000058
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020059#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000060#include <string.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020061#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000062#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010063#else
Rich Evans00ab4702015-02-06 13:43:58 +000064#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020065#define mbedtls_printf printf
66#endif /* MBEDTLS_PLATFORM_C */
67#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010068
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010069#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
70
Gilles Peskinef4a0a272021-07-28 13:54:02 +020071/* Return 0xff if low <= c <= high, 0 otherwise.
72 *
73 * Constant flow with respect to c.
74 */
75static unsigned char mask_of_range( unsigned char low, unsigned char high,
76 unsigned char c )
77{
78 unsigned low_mask = ( c - low ) >> 8;
79 unsigned high_mask = ( c - high - 1 ) >> 8;
80 return( ~low_mask & high_mask & 0xff );
81}
82
Gilles Peskineb44517e2021-07-28 14:31:39 +020083/* Given a value in the range 0..63, return the corresponding Base64 digit.
84 * The implementation assumes that letters are consecutive (e.g. ASCII
85 * but not EBCDIC).
86 */
87static unsigned char enc_char( unsigned char val )
88{
89 unsigned char digit = 0;
90 /* For each range of values, if val is in that range, mask digit with
91 * the corresponding value. Since val can only be in a single range,
92 * only at most one masking will change digit. */
93 digit |= mask_of_range( 0, 25, val ) & ( 'A' + val );
94 digit |= mask_of_range( 26, 51, val ) & ( 'a' + val - 26 );
95 digit |= mask_of_range( 52, 61, val ) & ( '0' + val - 52 );
96 digit |= mask_of_range( 62, 62, val ) & '+';
97 digit |= mask_of_range( 63, 63, val ) & '/';
98 return( digit );
99}
100
Paul Bakker5121ce52009-01-03 21:22:43 +0000101/*
102 * Encode a buffer into base64 format
103 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100104int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000105 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000106{
Paul Bakker23986e52011-04-24 08:57:21 +0000107 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000108 int C1, C2, C3;
109 unsigned char *p;
110
111 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +0000112 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100113 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000114 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +0000115 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000116
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200117 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +0000118
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +0100119 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000120 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +0100121 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200122 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000123 }
124
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200125 n *= 4;
126
Janos Follath98e28a72016-05-31 14:03:54 +0100127 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +0000128 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100129 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200130 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000131 }
132
Paul Bakker66d5d072014-06-17 16:39:18 +0200133 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000134
135 for( i = 0, p = dst; i < n; i += 3 )
136 {
137 C1 = *src++;
138 C2 = *src++;
139 C3 = *src++;
140
Gilles Peskineb44517e2021-07-28 14:31:39 +0200141 *p++ = enc_char( ( C1 >> 2 ) & 0x3F );
142 *p++ = enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F );
143 *p++ = enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F );
144 *p++ = enc_char( C3 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000145 }
146
147 if( i < slen )
148 {
149 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200150 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000151
Gilles Peskineb44517e2021-07-28 14:31:39 +0200152 *p++ = enc_char( ( C1 >> 2 ) & 0x3F );
153 *p++ = enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000154
Paul Bakker66d5d072014-06-17 16:39:18 +0200155 if( ( i + 1 ) < slen )
Gilles Peskineb44517e2021-07-28 14:31:39 +0200156 *p++ = enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000157 else *p++ = '=';
158
159 *p++ = '=';
160 }
161
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100162 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000163 *p = 0;
164
165 return( 0 );
166}
167
Gilles Peskinef4a0a272021-07-28 13:54:02 +0200168/* Given a Base64 digit, return its value.
169 * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'),
170 * return -1.
171 *
172 * The implementation assumes that letters are consecutive (e.g. ASCII
173 * but not EBCDIC).
174 *
175 * The implementation is constant-flow (no branch or memory access depending
176 * on the value of c) unless the compiler inlines and optimizes a specific
177 * access.
178 */
179static signed char dec_value( unsigned char c )
180{
181 unsigned char val = 0;
182 /* For each range of digits, if c is in that range, mask val with
183 * the corresponding value. Since c can only be in a single range,
184 * only at most one masking will change val. Set val to one plus
185 * the desired value so that it stays 0 if c is in none of the ranges. */
186 val |= mask_of_range( 'A', 'Z', c ) & ( c - 'A' + 0 + 1 );
187 val |= mask_of_range( 'a', 'z', c ) & ( c - 'a' + 26 + 1 );
188 val |= mask_of_range( '0', '9', c ) & ( c - '0' + 52 + 1 );
189 val |= mask_of_range( '+', '+', c ) & ( c - '+' + 62 + 1 );
190 val |= mask_of_range( '/', '/', c ) & ( c - '/' + 63 + 1 );
191 /* At this point, val is 0 if c is an invalid digit and v+1 if c is
192 * a digit with the value v. */
193 return( val - 1 );
194}
195
Paul Bakker5121ce52009-01-03 21:22:43 +0000196/*
197 * Decode a base64-formatted buffer
198 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100199int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000200 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000201{
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200202 size_t i; /* index in source */
203 size_t n; /* number of digits or trailing = in source */
204 uint32_t x; /* value accumulator */
205 unsigned equals = 0;
206 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000207 unsigned char *p;
208
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200209 /* First pass: check for validity and get output length */
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200210 for( i = n = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000211 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200212 /* Skip spaces before checking for EOL */
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200213 spaces_present = 0;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200214 while( i < slen && src[i] == ' ' )
215 {
216 ++i;
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200217 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200218 }
219
220 /* Spaces at end of buffer are OK */
221 if( i == slen )
222 break;
223
Paul Bakker5121ce52009-01-03 21:22:43 +0000224 if( ( slen - i ) >= 2 &&
225 src[i] == '\r' && src[i + 1] == '\n' )
226 continue;
227
228 if( src[i] == '\n' )
229 continue;
230
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200231 /* Space inside a line is an error */
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200232 if( spaces_present )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200233 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200234
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200235 if( src[i] > 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200236 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000237
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200238 if( src[i] == '=' )
239 {
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200240 if( ++equals > 2 )
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200241 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
242 }
243 else
244 {
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200245 if( equals != 0 )
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200246 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Gilles Peskinef4a0a272021-07-28 13:54:02 +0200247 if( dec_value( src[i] ) < 0 )
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200248 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
249 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000250 n++;
251 }
252
253 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100254 {
255 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000256 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100257 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000258
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000259 /* The following expression is to calculate the following formula without
260 * risk of integer overflow in n:
261 * n = ( ( n * 6 ) + 7 ) >> 3;
262 */
Andres AG4623d832017-01-18 17:21:03 +0000263 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200264 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000265
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100266 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000267 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100268 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200269 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000270 }
271
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200272 equals = 0;
273 for( n = x = 0, p = dst; i > 0; i--, src++ )
274 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200275 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000276 continue;
277
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200278 x = x << 6;
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200279 if( *src == '=' )
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200280 ++equals;
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200281 else
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200282 x |= dec_value( *src );
Paul Bakker5121ce52009-01-03 21:22:43 +0000283
284 if( ++n == 4 )
285 {
286 n = 0;
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200287 *p++ = (unsigned char)( x >> 16 );
288 if( equals <= 1 ) *p++ = (unsigned char)( x >> 8 );
289 if( equals <= 0 ) *p++ = (unsigned char)( x );
Paul Bakker5121ce52009-01-03 21:22:43 +0000290 }
291 }
292
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100293 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000294
295 return( 0 );
296}
297
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200298#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000299
Paul Bakker5121ce52009-01-03 21:22:43 +0000300static const unsigned char base64_test_dec[64] =
301{
302 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
303 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
304 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
305 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
306 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
307 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
308 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
309 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
310};
311
312static const unsigned char base64_test_enc[] =
313 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
314 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
315
316/*
317 * Checkup routine
318 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200319int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000320{
Paul Bakker23986e52011-04-24 08:57:21 +0000321 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200322 const unsigned char *src;
323 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000324
325 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200326 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000327
Paul Bakker3c2122f2013-06-24 19:03:14 +0200328 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000329
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100330 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200331 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000332 {
333 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200334 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000335
336 return( 1 );
337 }
338
339 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200340 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000341
Paul Bakker3c2122f2013-06-24 19:03:14 +0200342 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000343
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100344 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000345 memcmp( base64_test_dec, buffer, 64 ) != 0 )
346 {
347 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200348 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000349
350 return( 1 );
351 }
352
353 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200354 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000355
356 return( 0 );
357}
358
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200359#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000360
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200361#endif /* MBEDTLS_BASE64_C */