blob: e0a6f188fe2603f4ef7807a495743b90d4b897b4 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * RFC 1521 base64 encoding/decoding
3 *
Manuel Pégourié-Gonnarda658a402015-01-23 09:45:19 +00004 * Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
Paul Bakkerb96f1542010-07-18 20:36:00 +00005 *
Manuel Pégourié-Gonnardfe446432015-03-06 13:17:10 +00006 * This file is part of mbed TLS (https://tls.mbed.org)
Paul Bakkerb96f1542010-07-18 20:36:00 +00007 *
Paul Bakker5121ce52009-01-03 21:22:43 +00008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020023#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000024#include "mbedtls/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020025#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020026#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020027#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000028
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020029#if defined(MBEDTLS_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000030
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000031#include "mbedtls/base64.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000032
Paul Bakkerfa6a6202013-10-28 18:48:30 +010033#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5c2364c2012-10-01 14:41:15 +000034#include <basetsd.h>
35typedef UINT32 uint32_t;
36#else
37#include <inttypes.h>
38#endif
39
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020040#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000041#include <string.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020042#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000043#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010044#else
Rich Evans00ab4702015-02-06 13:43:58 +000045#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020046#define mbedtls_printf printf
47#endif /* MBEDTLS_PLATFORM_C */
48#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010049
Paul Bakker5121ce52009-01-03 21:22:43 +000050static const unsigned char base64_enc_map[64] =
51{
52 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
53 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
54 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
55 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
56 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
57 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
58 '8', '9', '+', '/'
59};
60
61static const unsigned char base64_dec_map[128] =
62{
63 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
64 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
65 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
66 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
67 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
68 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
69 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
70 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
71 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
72 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
73 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
74 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
75 49, 50, 51, 127, 127, 127, 127, 127
76};
77
78/*
79 * Encode a buffer into base64 format
80 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020081int mbedtls_base64_encode( unsigned char *dst, size_t *dlen,
Paul Bakker23986e52011-04-24 08:57:21 +000082 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000083{
Paul Bakker23986e52011-04-24 08:57:21 +000084 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000085 int C1, C2, C3;
86 unsigned char *p;
87
88 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000089 {
90 *dlen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000091 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000092 }
Paul Bakker5121ce52009-01-03 21:22:43 +000093
Paul Bakker66d5d072014-06-17 16:39:18 +020094 n = ( slen << 3 ) / 6;
Paul Bakker5121ce52009-01-03 21:22:43 +000095
Paul Bakker66d5d072014-06-17 16:39:18 +020096 switch( ( slen << 3 ) - ( n * 6 ) )
Paul Bakker5121ce52009-01-03 21:22:43 +000097 {
98 case 2: n += 3; break;
99 case 4: n += 2; break;
100 default: break;
101 }
102
103 if( *dlen < n + 1 )
104 {
105 *dlen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200106 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000107 }
108
Paul Bakker66d5d072014-06-17 16:39:18 +0200109 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000110
111 for( i = 0, p = dst; i < n; i += 3 )
112 {
113 C1 = *src++;
114 C2 = *src++;
115 C3 = *src++;
116
117 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
118 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
119 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
120 *p++ = base64_enc_map[C3 & 0x3F];
121 }
122
123 if( i < slen )
124 {
125 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200126 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000127
128 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
129 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
130
Paul Bakker66d5d072014-06-17 16:39:18 +0200131 if( ( i + 1 ) < slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000132 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
133 else *p++ = '=';
134
135 *p++ = '=';
136 }
137
138 *dlen = p - dst;
139 *p = 0;
140
141 return( 0 );
142}
143
144/*
145 * Decode a base64-formatted buffer
146 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200147int mbedtls_base64_decode( unsigned char *dst, size_t *dlen,
Paul Bakker23986e52011-04-24 08:57:21 +0000148 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000149{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000150 size_t i, n;
151 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000152 unsigned char *p;
153
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200154 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200155 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000156 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200157 /* Skip spaces before checking for EOL */
158 x = 0;
159 while( i < slen && src[i] == ' ' )
160 {
161 ++i;
162 ++x;
163 }
164
165 /* Spaces at end of buffer are OK */
166 if( i == slen )
167 break;
168
Paul Bakker5121ce52009-01-03 21:22:43 +0000169 if( ( slen - i ) >= 2 &&
170 src[i] == '\r' && src[i + 1] == '\n' )
171 continue;
172
173 if( src[i] == '\n' )
174 continue;
175
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200176 /* Space inside a line is an error */
177 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200178 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200179
Paul Bakker5121ce52009-01-03 21:22:43 +0000180 if( src[i] == '=' && ++j > 2 )
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( src[i] > 127 || base64_dec_map[src[i]] == 127 )
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 if( base64_dec_map[src[i]] < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200187 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000188
189 n++;
190 }
191
192 if( n == 0 )
193 return( 0 );
194
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
Paul Bakkerf4a14272013-07-05 10:29:12 +0200198 if( dst == NULL || *dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000199 {
200 *dlen = 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
221 *dlen = p - dst;
222
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
256 len = sizeof( buffer );
Paul Bakker3c2122f2013-06-24 19:03:14 +0200257 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000258
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200259 if( mbedtls_base64_encode( buffer, &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200260 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000261 {
262 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200263 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000264
265 return( 1 );
266 }
267
268 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200269 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000270
271 len = sizeof( buffer );
Paul Bakker3c2122f2013-06-24 19:03:14 +0200272 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000273
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200274 if( mbedtls_base64_decode( buffer, &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000275 memcmp( base64_test_dec, buffer, 64 ) != 0 )
276 {
277 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200278 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000279
280 return( 1 );
281 }
282
283 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200284 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000285
286 return( 0 );
287}
288
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200289#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000290
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200291#endif /* MBEDTLS_BASE64_C */