blob: c492cc0c703ee3a96bbfc397ceda44ac840499f3 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * RFC 1521 base64 encoding/decoding
3 *
Paul Bakker530927b2015-02-13 14:24:10 +01004 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
Paul Bakkerb96f1542010-07-18 20:36:00 +00005 *
Manuel Pégourié-Gonnarde12abf92015-01-28 17:13:45 +00006 * This file is part of mbed TLS (https://polarssl.org)
Paul Bakkere0ccd0a2009-01-04 16:27:10 +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
Paul Bakker40e46942009-01-03 21:51:57 +000023#include "polarssl/config.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000024
Paul Bakker40e46942009-01-03 21:51:57 +000025#if defined(POLARSSL_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000026
Paul Bakker40e46942009-01-03 21:51:57 +000027#include "polarssl/base64.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000028
Paul Bakker5c2364c2012-10-01 14:41:15 +000029#ifdef _MSC_VER
30#include <basetsd.h>
31typedef UINT32 uint32_t;
32#else
33#include <inttypes.h>
34#endif
35
Paul Bakker5121ce52009-01-03 21:22:43 +000036static const unsigned char base64_enc_map[64] =
37{
38 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
39 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
40 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
41 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
42 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
43 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
44 '8', '9', '+', '/'
45};
46
47static const unsigned char base64_dec_map[128] =
48{
49 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
50 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
51 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
52 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
53 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
54 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
55 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
56 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
57 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
58 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
59 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
60 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
61 49, 50, 51, 127, 127, 127, 127, 127
62};
63
64/*
65 * Encode a buffer into base64 format
66 */
Paul Bakker23986e52011-04-24 08:57:21 +000067int base64_encode( unsigned char *dst, size_t *dlen,
68 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000069{
Paul Bakker23986e52011-04-24 08:57:21 +000070 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000071 int C1, C2, C3;
72 unsigned char *p;
73
74 if( slen == 0 )
Manuel Pégourié-Gonnardf0974002015-01-28 16:49:26 +000075 {
76 *dlen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000077 return( 0 );
Manuel Pégourié-Gonnardf0974002015-01-28 16:49:26 +000078 }
Paul Bakker5121ce52009-01-03 21:22:43 +000079
Manuel Pégourié-Gonnarde4e4be72015-09-30 16:30:28 +020080 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000081
Manuel Pégourié-Gonnarde4e4be72015-09-30 16:30:28 +020082 if( n > ( SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000083 {
Manuel Pégourié-Gonnarde4e4be72015-09-30 16:30:28 +020084 *dlen = SIZE_T_MAX;
85 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000086 }
87
Manuel Pégourié-Gonnarde4e4be72015-09-30 16:30:28 +020088 n *= 4;
89
Paul Bakker5121ce52009-01-03 21:22:43 +000090 if( *dlen < n + 1 )
91 {
92 *dlen = n + 1;
Paul Bakker40e46942009-01-03 21:51:57 +000093 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000094 }
95
96 n = (slen / 3) * 3;
97
98 for( i = 0, p = dst; i < n; i += 3 )
99 {
100 C1 = *src++;
101 C2 = *src++;
102 C3 = *src++;
103
104 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
105 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
106 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
107 *p++ = base64_enc_map[C3 & 0x3F];
108 }
109
110 if( i < slen )
111 {
112 C1 = *src++;
113 C2 = ((i + 1) < slen) ? *src++ : 0;
114
115 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
116 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
117
118 if( (i + 1) < slen )
119 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
120 else *p++ = '=';
121
122 *p++ = '=';
123 }
124
125 *dlen = p - dst;
126 *p = 0;
127
128 return( 0 );
129}
130
131/*
132 * Decode a base64-formatted buffer
133 */
Paul Bakker23986e52011-04-24 08:57:21 +0000134int base64_decode( unsigned char *dst, size_t *dlen,
135 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000136{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000137 size_t i, n;
138 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000139 unsigned char *p;
140
Manuel Pégourié-Gonnard0b12d5e2014-10-23 17:00:26 +0200141 /* First pass: check for validity and get output length */
142 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000143 {
Manuel Pégourié-Gonnard0b12d5e2014-10-23 17:00:26 +0200144 /* Skip spaces before checking for EOL */
145 x = 0;
146 while( i < slen && src[i] == ' ' )
147 {
148 ++i;
149 ++x;
150 }
151
152 /* Spaces at end of buffer are OK */
153 if( i == slen )
154 break;
155
Paul Bakker5121ce52009-01-03 21:22:43 +0000156 if( ( slen - i ) >= 2 &&
157 src[i] == '\r' && src[i + 1] == '\n' )
158 continue;
159
160 if( src[i] == '\n' )
161 continue;
162
Manuel Pégourié-Gonnard0b12d5e2014-10-23 17:00:26 +0200163 /* Space inside a line is an error */
164 if( x != 0 )
165 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
166
Paul Bakker5121ce52009-01-03 21:22:43 +0000167 if( src[i] == '=' && ++j > 2 )
Paul Bakker40e46942009-01-03 21:51:57 +0000168 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000169
170 if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
Paul Bakker40e46942009-01-03 21:51:57 +0000171 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000172
173 if( base64_dec_map[src[i]] < 64 && j != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000174 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000175
176 n++;
177 }
178
179 if( n == 0 )
Manuel Pégourié-Gonnardb73ce452015-09-28 18:27:15 +0200180 {
181 *dlen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000182 return( 0 );
Manuel Pégourié-Gonnardb73ce452015-09-28 18:27:15 +0200183 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000184
185 n = ((n * 6) + 7) >> 3;
Paul Bakkerbbc843f2014-07-08 18:18:38 +0200186 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000187
188 if( *dlen < n )
189 {
190 *dlen = n;
Paul Bakker40e46942009-01-03 21:51:57 +0000191 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000192 }
193
194 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
195 {
196 if( *src == '\r' || *src == '\n' )
197 continue;
198
199 j -= ( base64_dec_map[*src] == 64 );
200 x = (x << 6) | ( base64_dec_map[*src] & 0x3F );
201
202 if( ++n == 4 )
203 {
204 n = 0;
205 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
206 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
207 if( j > 2 ) *p++ = (unsigned char)( x );
208 }
209 }
210
211 *dlen = p - dst;
212
213 return( 0 );
214}
215
Paul Bakker40e46942009-01-03 21:51:57 +0000216#if defined(POLARSSL_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000217
218#include <string.h>
219#include <stdio.h>
220
221static const unsigned char base64_test_dec[64] =
222{
223 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
224 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
225 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
226 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
227 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
228 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
229 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
230 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
231};
232
233static const unsigned char base64_test_enc[] =
234 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
235 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
236
237/*
238 * Checkup routine
239 */
240int base64_self_test( int verbose )
241{
Paul Bakker23986e52011-04-24 08:57:21 +0000242 size_t len;
Paul Bakkereae09db2013-06-06 12:35:54 +0200243 const unsigned char *src;
244 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000245
246 if( verbose != 0 )
247 printf( " Base64 encoding test: " );
248
249 len = sizeof( buffer );
Paul Bakkereae09db2013-06-06 12:35:54 +0200250 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000251
252 if( base64_encode( buffer, &len, src, 64 ) != 0 ||
Paul Bakkereae09db2013-06-06 12:35:54 +0200253 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000254 {
255 if( verbose != 0 )
256 printf( "failed\n" );
257
258 return( 1 );
259 }
260
261 if( verbose != 0 )
262 printf( "passed\n Base64 decoding test: " );
263
264 len = sizeof( buffer );
Paul Bakkereae09db2013-06-06 12:35:54 +0200265 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000266
267 if( base64_decode( buffer, &len, src, 88 ) != 0 ||
268 memcmp( base64_test_dec, buffer, 64 ) != 0 )
269 {
270 if( verbose != 0 )
271 printf( "failed\n" );
272
273 return( 1 );
274 }
275
276 if( verbose != 0 )
277 printf( "passed\n\n" );
278
279 return( 0 );
280}
281
282#endif
283
284#endif