blob: 3921c4611aed9de38a45300234eb6c89309c5290 [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
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 Bakkerb96f1542010-07-18 20:36:00 +000018 *
Manuel Pégourié-Gonnardfe446432015-03-06 13:17:10 +000019 * This file is part of mbed TLS (https://tls.mbed.org)
Paul Bakker5121ce52009-01-03 21:22:43 +000020 */
21
Gilles Peskinedb09ef62020-06-03 01:43:33 +020022#include "common.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000023
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020024#if defined(MBEDTLS_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000025
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000026#include "mbedtls/base64.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000027
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020028#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000029
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020030#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000031#include <string.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020032#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000033#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010034#else
Rich Evans00ab4702015-02-06 13:43:58 +000035#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020036#define mbedtls_printf printf
37#endif /* MBEDTLS_PLATFORM_C */
38#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010039
Paul Bakker5121ce52009-01-03 21:22:43 +000040static const unsigned char base64_enc_map[64] =
41{
42 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
43 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
44 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
45 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
46 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
47 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
48 '8', '9', '+', '/'
49};
50
51static const unsigned char base64_dec_map[128] =
52{
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, 127, 127, 127, 127, 127, 127, 127,
56 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
57 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
58 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
59 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
60 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
61 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
62 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
63 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
64 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
65 49, 50, 51, 127, 127, 127, 127, 127
66};
67
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010068#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
69
Paul Bakker5121ce52009-01-03 21:22:43 +000070/*
71 * Encode a buffer into base64 format
72 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010073int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +000074 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000075{
Paul Bakker23986e52011-04-24 08:57:21 +000076 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000077 int C1, C2, C3;
78 unsigned char *p;
79
80 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000081 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010082 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000083 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000084 }
Paul Bakker5121ce52009-01-03 21:22:43 +000085
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020086 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000087
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010088 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000089 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010090 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020091 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000092 }
93
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020094 n *= 4;
95
Janos Follath98e28a72016-05-31 14:03:54 +010096 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +000097 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010098 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020099 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000100 }
101
Paul Bakker66d5d072014-06-17 16:39:18 +0200102 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000103
104 for( i = 0, p = dst; i < n; i += 3 )
105 {
106 C1 = *src++;
107 C2 = *src++;
108 C3 = *src++;
109
110 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
111 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
112 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
113 *p++ = base64_enc_map[C3 & 0x3F];
114 }
115
116 if( i < slen )
117 {
118 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200119 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000120
121 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
122 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
123
Paul Bakker66d5d072014-06-17 16:39:18 +0200124 if( ( i + 1 ) < slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000125 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
126 else *p++ = '=';
127
128 *p++ = '=';
129 }
130
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100131 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000132 *p = 0;
133
134 return( 0 );
135}
136
137/*
138 * Decode a base64-formatted buffer
139 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100140int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000141 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000142{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000143 size_t i, n;
144 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000145 unsigned char *p;
146
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200147 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200148 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000149 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200150 /* Skip spaces before checking for EOL */
151 x = 0;
152 while( i < slen && src[i] == ' ' )
153 {
154 ++i;
155 ++x;
156 }
157
158 /* Spaces at end of buffer are OK */
159 if( i == slen )
160 break;
161
Paul Bakker5121ce52009-01-03 21:22:43 +0000162 if( ( slen - i ) >= 2 &&
163 src[i] == '\r' && src[i + 1] == '\n' )
164 continue;
165
166 if( src[i] == '\n' )
167 continue;
168
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200169 /* Space inside a line is an error */
170 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200171 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200172
Paul Bakker5121ce52009-01-03 21:22:43 +0000173 if( src[i] == '=' && ++j > 2 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200174 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000175
176 if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200177 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000178
179 if( base64_dec_map[src[i]] < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200180 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000181
182 n++;
183 }
184
185 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100186 {
187 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000188 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100189 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000190
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000191 /* The following expression is to calculate the following formula without
192 * risk of integer overflow in n:
193 * n = ( ( n * 6 ) + 7 ) >> 3;
194 */
Andres AG4623d832017-01-18 17:21:03 +0000195 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Paul Bakkerd5983182014-07-04 13:50:31 +0200196 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000197
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100198 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000199 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100200 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200201 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000202 }
203
204 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
205 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200206 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000207 continue;
208
209 j -= ( base64_dec_map[*src] == 64 );
Paul Bakker66d5d072014-06-17 16:39:18 +0200210 x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000211
212 if( ++n == 4 )
213 {
214 n = 0;
215 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
216 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
217 if( j > 2 ) *p++ = (unsigned char)( x );
218 }
219 }
220
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100221 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000222
223 return( 0 );
224}
225
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200226#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000227
Paul Bakker5121ce52009-01-03 21:22:43 +0000228static const unsigned char base64_test_dec[64] =
229{
230 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
231 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
232 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
233 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
234 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
235 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
236 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
237 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
238};
239
240static const unsigned char base64_test_enc[] =
241 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
242 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
243
244/*
245 * Checkup routine
246 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200247int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000248{
Paul Bakker23986e52011-04-24 08:57:21 +0000249 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200250 const unsigned char *src;
251 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000252
253 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200254 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000255
Paul Bakker3c2122f2013-06-24 19:03:14 +0200256 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000257
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100258 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200259 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000260 {
261 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200262 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000263
264 return( 1 );
265 }
266
267 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200268 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000269
Paul Bakker3c2122f2013-06-24 19:03:14 +0200270 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000271
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100272 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000273 memcmp( base64_test_dec, buffer, 64 ) != 0 )
274 {
275 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200276 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000277
278 return( 1 );
279 }
280
281 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200282 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000283
284 return( 0 );
285}
286
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200287#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000288
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200289#endif /* MBEDTLS_BASE64_C */