blob: 3de67f09053189ccdd8cd3c3ccf2a466e5239680 [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é-Gonnardcef4ad22014-04-29 12:39:06 +020023#if !defined(POLARSSL_CONFIG_FILE)
Paul Bakker40e46942009-01-03 21:51:57 +000024#include "polarssl/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020025#else
26#include POLARSSL_CONFIG_FILE
27#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000028
Paul Bakker40e46942009-01-03 21:51:57 +000029#if defined(POLARSSL_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000030
Paul Bakker40e46942009-01-03 21:51:57 +000031#include "polarssl/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
Rich Evans00ab4702015-02-06 13:43:58 +000040#if defined(POLARSSL_SELF_TEST)
41#include <string.h>
Paul Bakker7dc4c442014-02-01 22:50:26 +010042#if defined(POLARSSL_PLATFORM_C)
43#include "polarssl/platform.h"
44#else
Rich Evans00ab4702015-02-06 13:43:58 +000045#include <stdio.h>
Paul Bakker7dc4c442014-02-01 22:50:26 +010046#define polarssl_printf printf
Rich Evans00ab4702015-02-06 13:43:58 +000047#endif /* POLARSSL_PLATFORM_C */
48#endif /* POLARSSL_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
Manuel Pégourié-Gonnardfa647a72015-10-05 15:23:11 +010078#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
79
Paul Bakker5121ce52009-01-03 21:22:43 +000080/*
81 * Encode a buffer into base64 format
82 */
Paul Bakker23986e52011-04-24 08:57:21 +000083int base64_encode( unsigned char *dst, size_t *dlen,
84 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000085{
Paul Bakker23986e52011-04-24 08:57:21 +000086 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000087 int C1, C2, C3;
88 unsigned char *p;
89
90 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000091 {
92 *dlen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000093 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000094 }
Paul Bakker5121ce52009-01-03 21:22:43 +000095
Manuel Pégourié-Gonnard48ec2c72015-09-30 16:30:28 +020096 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000097
Manuel Pégourié-Gonnardfa647a72015-10-05 15:23:11 +010098 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000099 {
Manuel Pégourié-Gonnardfa647a72015-10-05 15:23:11 +0100100 *dlen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard48ec2c72015-09-30 16:30:28 +0200101 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000102 }
103
Manuel Pégourié-Gonnard48ec2c72015-09-30 16:30:28 +0200104 n *= 4;
105
Paul Bakker5121ce52009-01-03 21:22:43 +0000106 if( *dlen < n + 1 )
107 {
108 *dlen = n + 1;
Paul Bakker40e46942009-01-03 21:51:57 +0000109 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000110 }
111
Paul Bakker66d5d072014-06-17 16:39:18 +0200112 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000113
114 for( i = 0, p = dst; i < n; i += 3 )
115 {
116 C1 = *src++;
117 C2 = *src++;
118 C3 = *src++;
119
120 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
121 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
122 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
123 *p++ = base64_enc_map[C3 & 0x3F];
124 }
125
126 if( i < slen )
127 {
128 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200129 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000130
131 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
132 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
133
Paul Bakker66d5d072014-06-17 16:39:18 +0200134 if( ( i + 1 ) < slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000135 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
136 else *p++ = '=';
137
138 *p++ = '=';
139 }
140
141 *dlen = p - dst;
142 *p = 0;
143
144 return( 0 );
145}
146
147/*
148 * Decode a base64-formatted buffer
149 */
Paul Bakker23986e52011-04-24 08:57:21 +0000150int base64_decode( unsigned char *dst, size_t *dlen,
151 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000152{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000153 size_t i, n;
154 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000155 unsigned char *p;
156
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200157 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200158 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000159 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200160 /* Skip spaces before checking for EOL */
161 x = 0;
162 while( i < slen && src[i] == ' ' )
163 {
164 ++i;
165 ++x;
166 }
167
168 /* Spaces at end of buffer are OK */
169 if( i == slen )
170 break;
171
Paul Bakker5121ce52009-01-03 21:22:43 +0000172 if( ( slen - i ) >= 2 &&
173 src[i] == '\r' && src[i + 1] == '\n' )
174 continue;
175
176 if( src[i] == '\n' )
177 continue;
178
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200179 /* Space inside a line is an error */
180 if( x != 0 )
181 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
182
Paul Bakker5121ce52009-01-03 21:22:43 +0000183 if( src[i] == '=' && ++j > 2 )
Paul Bakker40e46942009-01-03 21:51:57 +0000184 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000185
186 if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
Paul Bakker40e46942009-01-03 21:51:57 +0000187 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000188
189 if( base64_dec_map[src[i]] < 64 && j != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000190 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000191
192 n++;
193 }
194
195 if( n == 0 )
Manuel Pégourié-Gonnard9bf29be2015-09-28 18:27:15 +0200196 {
197 *dlen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000198 return( 0 );
Manuel Pégourié-Gonnard9bf29be2015-09-28 18:27:15 +0200199 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000200
Andres AG59abd302017-01-18 17:21:03 +0000201 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Paul Bakkerd5983182014-07-04 13:50:31 +0200202 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000203
Paul Bakkerf4a14272013-07-05 10:29:12 +0200204 if( dst == NULL || *dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000205 {
206 *dlen = n;
Paul Bakker40e46942009-01-03 21:51:57 +0000207 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000208 }
209
210 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
211 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200212 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000213 continue;
214
215 j -= ( base64_dec_map[*src] == 64 );
Paul Bakker66d5d072014-06-17 16:39:18 +0200216 x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000217
218 if( ++n == 4 )
219 {
220 n = 0;
221 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
222 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
223 if( j > 2 ) *p++ = (unsigned char)( x );
224 }
225 }
226
227 *dlen = p - dst;
228
229 return( 0 );
230}
231
Paul Bakker40e46942009-01-03 21:51:57 +0000232#if defined(POLARSSL_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000233
Paul Bakker5121ce52009-01-03 21:22:43 +0000234static const unsigned char base64_test_dec[64] =
235{
236 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
237 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
238 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
239 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
240 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
241 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
242 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
243 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
244};
245
246static const unsigned char base64_test_enc[] =
247 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
248 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
249
250/*
251 * Checkup routine
252 */
253int base64_self_test( int verbose )
254{
Paul Bakker23986e52011-04-24 08:57:21 +0000255 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200256 const unsigned char *src;
257 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000258
259 if( verbose != 0 )
Paul Bakker7dc4c442014-02-01 22:50:26 +0100260 polarssl_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000261
262 len = sizeof( buffer );
Paul Bakker3c2122f2013-06-24 19:03:14 +0200263 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000264
265 if( base64_encode( buffer, &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200266 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000267 {
268 if( verbose != 0 )
Paul Bakker7dc4c442014-02-01 22:50:26 +0100269 polarssl_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000270
271 return( 1 );
272 }
273
274 if( verbose != 0 )
Paul Bakker7dc4c442014-02-01 22:50:26 +0100275 polarssl_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000276
277 len = sizeof( buffer );
Paul Bakker3c2122f2013-06-24 19:03:14 +0200278 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000279
280 if( base64_decode( buffer, &len, src, 88 ) != 0 ||
281 memcmp( base64_test_dec, buffer, 64 ) != 0 )
282 {
283 if( verbose != 0 )
Paul Bakker7dc4c442014-02-01 22:50:26 +0100284 polarssl_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000285
286 return( 1 );
287 }
288
289 if( verbose != 0 )
Paul Bakker7dc4c442014-02-01 22:50:26 +0100290 polarssl_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000291
292 return( 0 );
293}
294
Paul Bakker9af723c2014-05-01 13:03:14 +0200295#endif /* POLARSSL_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000296
Paul Bakker9af723c2014-05-01 13:03:14 +0200297#endif /* POLARSSL_BASE64_C */