blob: d39474a0849f1d2ab1ddbe1b05b3a5704a5aba12 [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"
Paul Bakker5121ce52009-01-03 21:22:43 +000025
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020026#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000027
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020028#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000029#include <string.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020030#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000031#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010032#else
Rich Evans00ab4702015-02-06 13:43:58 +000033#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020034#define mbedtls_printf printf
35#endif /* MBEDTLS_PLATFORM_C */
36#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010037
Paul Bakker5121ce52009-01-03 21:22:43 +000038static const unsigned char base64_enc_map[64] =
39{
40 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
41 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
42 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
43 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
44 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
45 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
46 '8', '9', '+', '/'
47};
48
49static const unsigned char base64_dec_map[128] =
50{
51 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
52 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
53 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
54 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
55 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
56 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
57 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
58 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
59 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
60 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
61 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
62 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
63 49, 50, 51, 127, 127, 127, 127, 127
64};
65
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010066#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
67
Paul Bakker5121ce52009-01-03 21:22:43 +000068/*
69 * Encode a buffer into base64 format
70 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010071int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +000072 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000073{
Paul Bakker23986e52011-04-24 08:57:21 +000074 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000075 int C1, C2, C3;
76 unsigned char *p;
77
78 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000079 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010080 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000081 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000082 }
Paul Bakker5121ce52009-01-03 21:22:43 +000083
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020084 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000085
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010086 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000087 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010088 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020089 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000090 }
91
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020092 n *= 4;
93
Janos Follath98e28a72016-05-31 14:03:54 +010094 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +000095 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010096 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020097 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000098 }
99
Paul Bakker66d5d072014-06-17 16:39:18 +0200100 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000101
102 for( i = 0, p = dst; i < n; i += 3 )
103 {
104 C1 = *src++;
105 C2 = *src++;
106 C3 = *src++;
107
108 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
109 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
110 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
111 *p++ = base64_enc_map[C3 & 0x3F];
112 }
113
114 if( i < slen )
115 {
116 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200117 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000118
119 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
120 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
121
Paul Bakker66d5d072014-06-17 16:39:18 +0200122 if( ( i + 1 ) < slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000123 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
124 else *p++ = '=';
125
126 *p++ = '=';
127 }
128
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100129 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000130 *p = 0;
131
132 return( 0 );
133}
134
135/*
136 * Decode a base64-formatted buffer
137 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100138int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000139 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000140{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000141 size_t i, n;
142 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000143 unsigned char *p;
144
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200145 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200146 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000147 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200148 /* Skip spaces before checking for EOL */
149 x = 0;
150 while( i < slen && src[i] == ' ' )
151 {
152 ++i;
153 ++x;
154 }
155
156 /* Spaces at end of buffer are OK */
157 if( i == slen )
158 break;
159
Paul Bakker5121ce52009-01-03 21:22:43 +0000160 if( ( slen - i ) >= 2 &&
161 src[i] == '\r' && src[i + 1] == '\n' )
162 continue;
163
164 if( src[i] == '\n' )
165 continue;
166
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200167 /* Space inside a line is an error */
168 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200169 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200170
Paul Bakker5121ce52009-01-03 21:22:43 +0000171 if( src[i] == '=' && ++j > 2 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200172 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000173
174 if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200175 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000176
177 if( base64_dec_map[src[i]] < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200178 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000179
180 n++;
181 }
182
183 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100184 {
185 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000186 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100187 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000188
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000189 /* The following expression is to calculate the following formula without
190 * risk of integer overflow in n:
191 * n = ( ( n * 6 ) + 7 ) >> 3;
192 */
Andres AG4623d832017-01-18 17:21:03 +0000193 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Paul Bakkerd5983182014-07-04 13:50:31 +0200194 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000195
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100196 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000197 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100198 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200199 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000200 }
201
202 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
203 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200204 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000205 continue;
206
207 j -= ( base64_dec_map[*src] == 64 );
Paul Bakker66d5d072014-06-17 16:39:18 +0200208 x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000209
210 if( ++n == 4 )
211 {
212 n = 0;
213 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
214 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
215 if( j > 2 ) *p++ = (unsigned char)( x );
216 }
217 }
218
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100219 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000220
221 return( 0 );
222}
223
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200224#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000225
Paul Bakker5121ce52009-01-03 21:22:43 +0000226static const unsigned char base64_test_dec[64] =
227{
228 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
229 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
230 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
231 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
232 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
233 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
234 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
235 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
236};
237
238static const unsigned char base64_test_enc[] =
239 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
240 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
241
242/*
243 * Checkup routine
244 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200245int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000246{
Paul Bakker23986e52011-04-24 08:57:21 +0000247 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200248 const unsigned char *src;
249 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000250
251 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200252 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000253
Paul Bakker3c2122f2013-06-24 19:03:14 +0200254 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000255
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100256 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200257 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000258 {
259 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200260 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000261
262 return( 1 );
263 }
264
265 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200266 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000267
Paul Bakker3c2122f2013-06-24 19:03:14 +0200268 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000269
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100270 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000271 memcmp( base64_test_dec, buffer, 64 ) != 0 )
272 {
273 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200274 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000275
276 return( 1 );
277 }
278
279 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200280 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000281
282 return( 0 );
283}
284
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200285#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000286
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200287#endif /* MBEDTLS_BASE64_C */