blob: bfafb05353cbc02402a726c9bfa60ca3a02dc86d [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
Paul Bakker5121ce52009-01-03 21:22:43 +000069static const unsigned char base64_enc_map[64] =
70{
71 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
72 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
73 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
74 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
75 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
76 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
77 '8', '9', '+', '/'
78};
79
80static const unsigned char base64_dec_map[128] =
81{
82 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
83 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
84 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
85 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
86 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
87 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
88 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
89 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
90 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
91 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
92 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
93 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
94 49, 50, 51, 127, 127, 127, 127, 127
95};
96
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010097#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
98
Paul Bakker5121ce52009-01-03 21:22:43 +000099/*
100 * Encode a buffer into base64 format
101 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100102int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000103 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000104{
Paul Bakker23986e52011-04-24 08:57:21 +0000105 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000106 int C1, C2, C3;
107 unsigned char *p;
108
109 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +0000110 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100111 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000112 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +0000113 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000114
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200115 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +0000116
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +0100117 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000118 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +0100119 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200120 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000121 }
122
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +0200123 n *= 4;
124
Janos Follath98e28a72016-05-31 14:03:54 +0100125 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +0000126 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100127 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200128 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000129 }
130
Paul Bakker66d5d072014-06-17 16:39:18 +0200131 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000132
133 for( i = 0, p = dst; i < n; i += 3 )
134 {
135 C1 = *src++;
136 C2 = *src++;
137 C3 = *src++;
138
139 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
140 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
141 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
142 *p++ = base64_enc_map[C3 & 0x3F];
143 }
144
145 if( i < slen )
146 {
147 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200148 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000149
150 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
151 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
152
Paul Bakker66d5d072014-06-17 16:39:18 +0200153 if( ( i + 1 ) < slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000154 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
155 else *p++ = '=';
156
157 *p++ = '=';
158 }
159
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100160 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000161 *p = 0;
162
163 return( 0 );
164}
165
166/*
167 * Decode a base64-formatted buffer
168 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100169int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000170 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000171{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000172 size_t i, n;
173 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000174 unsigned char *p;
175
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200176 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200177 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000178 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200179 /* Skip spaces before checking for EOL */
180 x = 0;
181 while( i < slen && src[i] == ' ' )
182 {
183 ++i;
184 ++x;
185 }
186
187 /* Spaces at end of buffer are OK */
188 if( i == slen )
189 break;
190
Paul Bakker5121ce52009-01-03 21:22:43 +0000191 if( ( slen - i ) >= 2 &&
192 src[i] == '\r' && src[i + 1] == '\n' )
193 continue;
194
195 if( src[i] == '\n' )
196 continue;
197
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200198 /* Space inside a line is an error */
199 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200200 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200201
Paul Bakker5121ce52009-01-03 21:22:43 +0000202 if( src[i] == '=' && ++j > 2 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200203 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000204
205 if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200206 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000207
208 if( base64_dec_map[src[i]] < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200209 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000210
211 n++;
212 }
213
214 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100215 {
216 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000217 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100218 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000219
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000220 /* The following expression is to calculate the following formula without
221 * risk of integer overflow in n:
222 * n = ( ( n * 6 ) + 7 ) >> 3;
223 */
Andres AG4623d832017-01-18 17:21:03 +0000224 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Paul Bakkerd5983182014-07-04 13:50:31 +0200225 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000226
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100227 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000228 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100229 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200230 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000231 }
232
233 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
234 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200235 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000236 continue;
237
238 j -= ( base64_dec_map[*src] == 64 );
Paul Bakker66d5d072014-06-17 16:39:18 +0200239 x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000240
241 if( ++n == 4 )
242 {
243 n = 0;
244 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
245 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
246 if( j > 2 ) *p++ = (unsigned char)( x );
247 }
248 }
249
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100250 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000251
252 return( 0 );
253}
254
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200255#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000256
Paul Bakker5121ce52009-01-03 21:22:43 +0000257static const unsigned char base64_test_dec[64] =
258{
259 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
260 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
261 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
262 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
263 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
264 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
265 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
266 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
267};
268
269static const unsigned char base64_test_enc[] =
270 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
271 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
272
273/*
274 * Checkup routine
275 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200276int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000277{
Paul Bakker23986e52011-04-24 08:57:21 +0000278 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200279 const unsigned char *src;
280 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000281
282 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200283 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000284
Paul Bakker3c2122f2013-06-24 19:03:14 +0200285 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000286
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100287 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200288 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000289 {
290 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200291 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000292
293 return( 1 );
294 }
295
296 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200297 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000298
Paul Bakker3c2122f2013-06-24 19:03:14 +0200299 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000300
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100301 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000302 memcmp( base64_test_dec, buffer, 64 ) != 0 )
303 {
304 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200305 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000306
307 return( 1 );
308 }
309
310 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200311 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000312
313 return( 0 );
314}
315
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200316#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000317
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200318#endif /* MBEDTLS_BASE64_C */