blob: 75849d1214d047e5ab0f461e97c0ebb6829eaa54 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * RFC 1521 base64 encoding/decoding
3 *
Manuel Pégourié-Gonnard6fb81872015-07-27 11:11:48 +02004 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
Bence Szépkúti4e9f7122020-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úti4e9f7122020-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 * **********
45 *
Manuel Pégourié-Gonnardfe446432015-03-06 13:17:10 +000046 * This file is part of mbed TLS (https://tls.mbed.org)
Paul Bakker5121ce52009-01-03 21:22:43 +000047 */
48
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020049#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000050#include "mbedtls/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020051#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020052#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020053#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000054
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020055#if defined(MBEDTLS_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000056
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000057#include "mbedtls/base64.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000058
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020059#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000060
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020061#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000062#include <string.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020063#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000064#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010065#else
Rich Evans00ab4702015-02-06 13:43:58 +000066#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020067#define mbedtls_printf printf
68#endif /* MBEDTLS_PLATFORM_C */
69#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010070
Paul Bakker5121ce52009-01-03 21:22:43 +000071static const unsigned char base64_enc_map[64] =
72{
73 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
74 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
75 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
76 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
77 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
78 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
79 '8', '9', '+', '/'
80};
81
82static const unsigned char base64_dec_map[128] =
83{
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, 127, 127, 127, 127, 127, 127, 127,
87 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
88 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
89 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
90 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
91 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
92 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
93 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
94 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
95 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
96 49, 50, 51, 127, 127, 127, 127, 127
97};
98
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010099#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
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
141 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
142 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
143 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
144 *p++ = base64_enc_map[C3 & 0x3F];
145 }
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
152 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
153 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
154
Paul Bakker66d5d072014-06-17 16:39:18 +0200155 if( ( i + 1 ) < slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000156 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
157 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
168/*
169 * Decode a base64-formatted buffer
170 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100171int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000172 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000173{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000174 size_t i, n;
175 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000176 unsigned char *p;
177
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200178 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200179 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000180 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200181 /* Skip spaces before checking for EOL */
182 x = 0;
183 while( i < slen && src[i] == ' ' )
184 {
185 ++i;
186 ++x;
187 }
188
189 /* Spaces at end of buffer are OK */
190 if( i == slen )
191 break;
192
Paul Bakker5121ce52009-01-03 21:22:43 +0000193 if( ( slen - i ) >= 2 &&
194 src[i] == '\r' && src[i + 1] == '\n' )
195 continue;
196
197 if( src[i] == '\n' )
198 continue;
199
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200200 /* Space inside a line is an error */
201 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200202 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200203
Paul Bakker5121ce52009-01-03 21:22:43 +0000204 if( src[i] == '=' && ++j > 2 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200205 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000206
207 if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200208 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000209
210 if( base64_dec_map[src[i]] < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200211 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000212
213 n++;
214 }
215
216 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100217 {
218 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000219 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100220 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000221
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000222 /* The following expression is to calculate the following formula without
223 * risk of integer overflow in n:
224 * n = ( ( n * 6 ) + 7 ) >> 3;
225 */
Andres AG4623d832017-01-18 17:21:03 +0000226 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Paul Bakkerd5983182014-07-04 13:50:31 +0200227 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000228
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100229 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000230 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100231 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200232 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000233 }
234
235 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
236 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200237 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000238 continue;
239
240 j -= ( base64_dec_map[*src] == 64 );
Paul Bakker66d5d072014-06-17 16:39:18 +0200241 x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000242
243 if( ++n == 4 )
244 {
245 n = 0;
246 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
247 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
248 if( j > 2 ) *p++ = (unsigned char)( x );
249 }
250 }
251
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100252 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000253
254 return( 0 );
255}
256
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200257#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000258
Paul Bakker5121ce52009-01-03 21:22:43 +0000259static const unsigned char base64_test_dec[64] =
260{
261 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
262 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
263 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
264 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
265 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
266 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
267 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
268 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
269};
270
271static const unsigned char base64_test_enc[] =
272 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
273 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
274
275/*
276 * Checkup routine
277 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200278int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000279{
Paul Bakker23986e52011-04-24 08:57:21 +0000280 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200281 const unsigned char *src;
282 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000283
284 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200285 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000286
Paul Bakker3c2122f2013-06-24 19:03:14 +0200287 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000288
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100289 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200290 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000291 {
292 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200293 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000294
295 return( 1 );
296 }
297
298 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200299 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000300
Paul Bakker3c2122f2013-06-24 19:03:14 +0200301 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000302
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100303 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000304 memcmp( base64_test_dec, buffer, 64 ) != 0 )
305 {
306 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200307 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000308
309 return( 1 );
310 }
311
312 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200313 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000314
315 return( 0 );
316}
317
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200318#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000319
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200320#endif /* MBEDTLS_BASE64_C */