blob: b7c2d16a5f8806444e3101fa5226e2f20aaed119 [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 */
Gilles Peskine231b67a2021-07-30 12:56:21 +0200205 unsigned accumulated_digits = 0;
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200206 unsigned equals = 0;
207 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000208 unsigned char *p;
209
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200210 /* First pass: check for validity and get output length */
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200211 for( i = n = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000212 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200213 /* Skip spaces before checking for EOL */
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200214 spaces_present = 0;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200215 while( i < slen && src[i] == ' ' )
216 {
217 ++i;
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200218 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200219 }
220
221 /* Spaces at end of buffer are OK */
222 if( i == slen )
223 break;
224
Paul Bakker5121ce52009-01-03 21:22:43 +0000225 if( ( slen - i ) >= 2 &&
226 src[i] == '\r' && src[i + 1] == '\n' )
227 continue;
228
229 if( src[i] == '\n' )
230 continue;
231
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200232 /* Space inside a line is an error */
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200233 if( spaces_present )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200234 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200235
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200236 if( src[i] > 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200237 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000238
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200239 if( src[i] == '=' )
240 {
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200241 if( ++equals > 2 )
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200242 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
243 }
244 else
245 {
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200246 if( equals != 0 )
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200247 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Gilles Peskinef4a0a272021-07-28 13:54:02 +0200248 if( dec_value( src[i] ) < 0 )
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200249 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
250 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000251 n++;
252 }
253
254 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100255 {
256 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000257 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100258 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000259
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000260 /* The following expression is to calculate the following formula without
261 * risk of integer overflow in n:
262 * n = ( ( n * 6 ) + 7 ) >> 3;
263 */
Andres AG4623d832017-01-18 17:21:03 +0000264 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200265 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000266
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100267 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000268 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100269 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200270 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000271 }
272
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200273 equals = 0;
Gilles Peskine231b67a2021-07-30 12:56:21 +0200274 for( x = 0, p = dst; i > 0; i--, src++ )
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200275 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200276 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000277 continue;
278
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200279 x = x << 6;
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200280 if( *src == '=' )
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200281 ++equals;
Gilles Peskinea47fdcf2021-07-28 11:33:04 +0200282 else
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200283 x |= dec_value( *src );
Paul Bakker5121ce52009-01-03 21:22:43 +0000284
Gilles Peskine231b67a2021-07-30 12:56:21 +0200285 if( ++accumulated_digits == 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000286 {
Gilles Peskine231b67a2021-07-30 12:56:21 +0200287 accumulated_digits = 0;
Gilles Peskineea96b3a2021-07-28 14:20:06 +0200288 *p++ = (unsigned char)( x >> 16 );
289 if( equals <= 1 ) *p++ = (unsigned char)( x >> 8 );
290 if( equals <= 0 ) *p++ = (unsigned char)( x );
Paul Bakker5121ce52009-01-03 21:22:43 +0000291 }
292 }
293
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100294 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000295
296 return( 0 );
297}
298
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200299#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000300
Paul Bakker5121ce52009-01-03 21:22:43 +0000301static const unsigned char base64_test_dec[64] =
302{
303 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
304 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
305 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
306 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
307 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
308 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
309 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
310 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
311};
312
313static const unsigned char base64_test_enc[] =
314 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
315 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
316
317/*
318 * Checkup routine
319 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200320int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000321{
Paul Bakker23986e52011-04-24 08:57:21 +0000322 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200323 const unsigned char *src;
324 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000325
326 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200327 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000328
Paul Bakker3c2122f2013-06-24 19:03:14 +0200329 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000330
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100331 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200332 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000333 {
334 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200335 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000336
337 return( 1 );
338 }
339
340 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200341 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000342
Paul Bakker3c2122f2013-06-24 19:03:14 +0200343 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000344
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100345 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000346 memcmp( base64_test_dec, buffer, 64 ) != 0 )
347 {
348 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200349 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000350
351 return( 1 );
352 }
353
354 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200355 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000356
357 return( 0 );
358}
359
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200360#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000361
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200362#endif /* MBEDTLS_BASE64_C */