blob: e1886082da0f96d72ca7f7a04b004d8064c76eaa [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * RFC 1521 base64 encoding/decoding
3 *
Manuel Pégourié-Gonnard0edee5e2015-01-26 15:29:40 +00004 * Copyright (C) 2006-2010, ARM Limited, All Rights Reserved
Paul Bakkerb96f1542010-07-18 20:36:00 +00005 *
Manuel Pégourié-Gonnard0edee5e2015-01-26 15:29:40 +00006 * This file is part of mbed TLS (https://www.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 )
75 return( 0 );
76
77 n = (slen << 3) / 6;
78
79 switch( (slen << 3) - (n * 6) )
80 {
81 case 2: n += 3; break;
82 case 4: n += 2; break;
83 default: break;
84 }
85
86 if( *dlen < n + 1 )
87 {
88 *dlen = n + 1;
Paul Bakker40e46942009-01-03 21:51:57 +000089 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000090 }
91
92 n = (slen / 3) * 3;
93
94 for( i = 0, p = dst; i < n; i += 3 )
95 {
96 C1 = *src++;
97 C2 = *src++;
98 C3 = *src++;
99
100 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
101 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
102 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
103 *p++ = base64_enc_map[C3 & 0x3F];
104 }
105
106 if( i < slen )
107 {
108 C1 = *src++;
109 C2 = ((i + 1) < slen) ? *src++ : 0;
110
111 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
112 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
113
114 if( (i + 1) < slen )
115 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
116 else *p++ = '=';
117
118 *p++ = '=';
119 }
120
121 *dlen = p - dst;
122 *p = 0;
123
124 return( 0 );
125}
126
127/*
128 * Decode a base64-formatted buffer
129 */
Paul Bakker23986e52011-04-24 08:57:21 +0000130int base64_decode( unsigned char *dst, size_t *dlen,
131 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000132{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000133 size_t i, n;
134 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000135 unsigned char *p;
136
Manuel Pégourié-Gonnard0b12d5e2014-10-23 17:00:26 +0200137 /* First pass: check for validity and get output length */
138 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000139 {
Manuel Pégourié-Gonnard0b12d5e2014-10-23 17:00:26 +0200140 /* Skip spaces before checking for EOL */
141 x = 0;
142 while( i < slen && src[i] == ' ' )
143 {
144 ++i;
145 ++x;
146 }
147
148 /* Spaces at end of buffer are OK */
149 if( i == slen )
150 break;
151
Paul Bakker5121ce52009-01-03 21:22:43 +0000152 if( ( slen - i ) >= 2 &&
153 src[i] == '\r' && src[i + 1] == '\n' )
154 continue;
155
156 if( src[i] == '\n' )
157 continue;
158
Manuel Pégourié-Gonnard0b12d5e2014-10-23 17:00:26 +0200159 /* Space inside a line is an error */
160 if( x != 0 )
161 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
162
Paul Bakker5121ce52009-01-03 21:22:43 +0000163 if( src[i] == '=' && ++j > 2 )
Paul Bakker40e46942009-01-03 21:51:57 +0000164 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000165
166 if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
Paul Bakker40e46942009-01-03 21:51:57 +0000167 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000168
169 if( base64_dec_map[src[i]] < 64 && j != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000170 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000171
172 n++;
173 }
174
175 if( n == 0 )
176 return( 0 );
177
178 n = ((n * 6) + 7) >> 3;
Paul Bakkerbbc843f2014-07-08 18:18:38 +0200179 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000180
181 if( *dlen < n )
182 {
183 *dlen = n;
Paul Bakker40e46942009-01-03 21:51:57 +0000184 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000185 }
186
187 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
188 {
189 if( *src == '\r' || *src == '\n' )
190 continue;
191
192 j -= ( base64_dec_map[*src] == 64 );
193 x = (x << 6) | ( base64_dec_map[*src] & 0x3F );
194
195 if( ++n == 4 )
196 {
197 n = 0;
198 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
199 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
200 if( j > 2 ) *p++ = (unsigned char)( x );
201 }
202 }
203
204 *dlen = p - dst;
205
206 return( 0 );
207}
208
Paul Bakker40e46942009-01-03 21:51:57 +0000209#if defined(POLARSSL_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000210
211#include <string.h>
212#include <stdio.h>
213
214static const unsigned char base64_test_dec[64] =
215{
216 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
217 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
218 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
219 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
220 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
221 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
222 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
223 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
224};
225
226static const unsigned char base64_test_enc[] =
227 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
228 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
229
230/*
231 * Checkup routine
232 */
233int base64_self_test( int verbose )
234{
Paul Bakker23986e52011-04-24 08:57:21 +0000235 size_t len;
Paul Bakkereae09db2013-06-06 12:35:54 +0200236 const unsigned char *src;
237 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000238
239 if( verbose != 0 )
240 printf( " Base64 encoding test: " );
241
242 len = sizeof( buffer );
Paul Bakkereae09db2013-06-06 12:35:54 +0200243 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000244
245 if( base64_encode( buffer, &len, src, 64 ) != 0 ||
Paul Bakkereae09db2013-06-06 12:35:54 +0200246 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000247 {
248 if( verbose != 0 )
249 printf( "failed\n" );
250
251 return( 1 );
252 }
253
254 if( verbose != 0 )
255 printf( "passed\n Base64 decoding test: " );
256
257 len = sizeof( buffer );
Paul Bakkereae09db2013-06-06 12:35:54 +0200258 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000259
260 if( base64_decode( buffer, &len, src, 88 ) != 0 ||
261 memcmp( base64_test_dec, buffer, 64 ) != 0 )
262 {
263 if( verbose != 0 )
264 printf( "failed\n" );
265
266 return( 1 );
267 }
268
269 if( verbose != 0 )
270 printf( "passed\n\n" );
271
272 return( 0 );
273}
274
275#endif
276
277#endif