blob: 5cb12cba754b299b69e50be79bd17f40b16f6f21 [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
Paul Bakker66d5d072014-06-17 16:39:18 +0200195 n = ( ( n * 6 ) + 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 */