blob: f06b57b31fcd321c2747c38dc0745b4e5afe7ba0 [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
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020022#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000023#include "mbedtls/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020024#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020025#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020026#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000027
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020028#if defined(MBEDTLS_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000029
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000030#include "mbedtls/base64.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000031
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020032#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000033
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020034#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000035#include <string.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020036#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000037#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010038#else
Rich Evans00ab4702015-02-06 13:43:58 +000039#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020040#define mbedtls_printf printf
41#endif /* MBEDTLS_PLATFORM_C */
42#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010043
Paul Bakker5121ce52009-01-03 21:22:43 +000044static const unsigned char base64_enc_map[64] =
45{
46 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
47 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
48 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
49 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
50 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
51 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
52 '8', '9', '+', '/'
53};
54
55static const unsigned char base64_dec_map[128] =
56{
57 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
58 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
59 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
60 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
61 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
62 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
63 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
64 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
65 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
66 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
67 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
68 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
69 49, 50, 51, 127, 127, 127, 127, 127
70};
71
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010072#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
73
Paul Bakker5121ce52009-01-03 21:22:43 +000074/*
75 * Encode a buffer into base64 format
76 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010077int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +000078 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000079{
Paul Bakker23986e52011-04-24 08:57:21 +000080 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000081 int C1, C2, C3;
82 unsigned char *p;
83
84 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000085 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010086 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000087 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000088 }
Paul Bakker5121ce52009-01-03 21:22:43 +000089
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020090 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000091
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010092 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000093 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010094 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020095 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000096 }
97
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020098 n *= 4;
99
Janos Follath98e28a72016-05-31 14:03:54 +0100100 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +0000101 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100102 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200103 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000104 }
105
Paul Bakker66d5d072014-06-17 16:39:18 +0200106 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000107
108 for( i = 0, p = dst; i < n; i += 3 )
109 {
110 C1 = *src++;
111 C2 = *src++;
112 C3 = *src++;
113
114 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
115 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
116 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
117 *p++ = base64_enc_map[C3 & 0x3F];
118 }
119
120 if( i < slen )
121 {
122 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200123 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000124
125 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
126 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
127
Paul Bakker66d5d072014-06-17 16:39:18 +0200128 if( ( i + 1 ) < slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000129 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
130 else *p++ = '=';
131
132 *p++ = '=';
133 }
134
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100135 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000136 *p = 0;
137
138 return( 0 );
139}
140
141/*
142 * Decode a base64-formatted buffer
143 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100144int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000145 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000146{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000147 size_t i, n;
148 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000149 unsigned char *p;
150
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200151 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200152 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000153 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200154 /* Skip spaces before checking for EOL */
155 x = 0;
156 while( i < slen && src[i] == ' ' )
157 {
158 ++i;
159 ++x;
160 }
161
162 /* Spaces at end of buffer are OK */
163 if( i == slen )
164 break;
165
Paul Bakker5121ce52009-01-03 21:22:43 +0000166 if( ( slen - i ) >= 2 &&
167 src[i] == '\r' && src[i + 1] == '\n' )
168 continue;
169
170 if( src[i] == '\n' )
171 continue;
172
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200173 /* Space inside a line is an error */
174 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200175 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200176
Paul Bakker5121ce52009-01-03 21:22:43 +0000177 if( src[i] == '=' && ++j > 2 )
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 if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200181 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000182
183 if( base64_dec_map[src[i]] < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200184 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000185
186 n++;
187 }
188
189 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100190 {
191 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000192 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100193 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000194
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000195 /* The following expression is to calculate the following formula without
196 * risk of integer overflow in n:
197 * n = ( ( n * 6 ) + 7 ) >> 3;
198 */
Andres AG4623d832017-01-18 17:21:03 +0000199 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Paul Bakkerd5983182014-07-04 13:50:31 +0200200 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000201
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100202 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000203 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100204 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200205 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000206 }
207
208 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
209 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200210 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000211 continue;
212
213 j -= ( base64_dec_map[*src] == 64 );
Paul Bakker66d5d072014-06-17 16:39:18 +0200214 x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000215
216 if( ++n == 4 )
217 {
218 n = 0;
219 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
220 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
221 if( j > 2 ) *p++ = (unsigned char)( x );
222 }
223 }
224
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100225 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000226
227 return( 0 );
228}
229
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200230#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000231
Paul Bakker5121ce52009-01-03 21:22:43 +0000232static const unsigned char base64_test_dec[64] =
233{
234 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
235 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
236 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
237 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
238 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
239 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
240 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
241 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
242};
243
244static const unsigned char base64_test_enc[] =
245 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
246 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
247
248/*
249 * Checkup routine
250 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200251int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000252{
Paul Bakker23986e52011-04-24 08:57:21 +0000253 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200254 const unsigned char *src;
255 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000256
257 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200258 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000259
Paul Bakker3c2122f2013-06-24 19:03:14 +0200260 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000261
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100262 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200263 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000264 {
265 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200266 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000267
268 return( 1 );
269 }
270
271 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200272 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000273
Paul Bakker3c2122f2013-06-24 19:03:14 +0200274 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000275
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100276 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000277 memcmp( base64_test_dec, buffer, 64 ) != 0 )
278 {
279 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200280 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000281
282 return( 1 );
283 }
284
285 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200286 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000287
288 return( 0 );
289}
290
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200291#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000292
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200293#endif /* MBEDTLS_BASE64_C */