blob: 139c5cc0707f3c29126fc9f37db41d449047cc6c [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é-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
80 n = (slen << 3) / 6;
81
82 switch( (slen << 3) - (n * 6) )
83 {
84 case 2: n += 3; break;
85 case 4: n += 2; break;
86 default: break;
87 }
88
89 if( *dlen < n + 1 )
90 {
91 *dlen = n + 1;
Paul Bakker40e46942009-01-03 21:51:57 +000092 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000093 }
94
95 n = (slen / 3) * 3;
96
97 for( i = 0, p = dst; i < n; i += 3 )
98 {
99 C1 = *src++;
100 C2 = *src++;
101 C3 = *src++;
102
103 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
104 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
105 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
106 *p++ = base64_enc_map[C3 & 0x3F];
107 }
108
109 if( i < slen )
110 {
111 C1 = *src++;
112 C2 = ((i + 1) < slen) ? *src++ : 0;
113
114 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
115 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
116
117 if( (i + 1) < slen )
118 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
119 else *p++ = '=';
120
121 *p++ = '=';
122 }
123
124 *dlen = p - dst;
125 *p = 0;
126
127 return( 0 );
128}
129
130/*
131 * Decode a base64-formatted buffer
132 */
Paul Bakker23986e52011-04-24 08:57:21 +0000133int base64_decode( unsigned char *dst, size_t *dlen,
134 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000135{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000136 size_t i, n;
137 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000138 unsigned char *p;
139
Manuel Pégourié-Gonnard0b12d5e2014-10-23 17:00:26 +0200140 /* First pass: check for validity and get output length */
141 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000142 {
Manuel Pégourié-Gonnard0b12d5e2014-10-23 17:00:26 +0200143 /* Skip spaces before checking for EOL */
144 x = 0;
145 while( i < slen && src[i] == ' ' )
146 {
147 ++i;
148 ++x;
149 }
150
151 /* Spaces at end of buffer are OK */
152 if( i == slen )
153 break;
154
Paul Bakker5121ce52009-01-03 21:22:43 +0000155 if( ( slen - i ) >= 2 &&
156 src[i] == '\r' && src[i + 1] == '\n' )
157 continue;
158
159 if( src[i] == '\n' )
160 continue;
161
Manuel Pégourié-Gonnard0b12d5e2014-10-23 17:00:26 +0200162 /* Space inside a line is an error */
163 if( x != 0 )
164 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
165
Paul Bakker5121ce52009-01-03 21:22:43 +0000166 if( src[i] == '=' && ++j > 2 )
Paul Bakker40e46942009-01-03 21:51:57 +0000167 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000168
169 if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
Paul Bakker40e46942009-01-03 21:51:57 +0000170 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000171
172 if( base64_dec_map[src[i]] < 64 && j != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000173 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000174
175 n++;
176 }
177
178 if( n == 0 )
179 return( 0 );
180
181 n = ((n * 6) + 7) >> 3;
Paul Bakkerbbc843f2014-07-08 18:18:38 +0200182 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000183
184 if( *dlen < n )
185 {
186 *dlen = n;
Paul Bakker40e46942009-01-03 21:51:57 +0000187 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000188 }
189
190 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
191 {
192 if( *src == '\r' || *src == '\n' )
193 continue;
194
195 j -= ( base64_dec_map[*src] == 64 );
196 x = (x << 6) | ( base64_dec_map[*src] & 0x3F );
197
198 if( ++n == 4 )
199 {
200 n = 0;
201 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
202 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
203 if( j > 2 ) *p++ = (unsigned char)( x );
204 }
205 }
206
207 *dlen = p - dst;
208
209 return( 0 );
210}
211
Paul Bakker40e46942009-01-03 21:51:57 +0000212#if defined(POLARSSL_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000213
214#include <string.h>
215#include <stdio.h>
216
217static const unsigned char base64_test_dec[64] =
218{
219 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
220 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
221 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
222 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
223 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
224 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
225 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
226 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
227};
228
229static const unsigned char base64_test_enc[] =
230 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
231 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
232
233/*
234 * Checkup routine
235 */
236int base64_self_test( int verbose )
237{
Paul Bakker23986e52011-04-24 08:57:21 +0000238 size_t len;
Paul Bakkereae09db2013-06-06 12:35:54 +0200239 const unsigned char *src;
240 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000241
242 if( verbose != 0 )
243 printf( " Base64 encoding test: " );
244
245 len = sizeof( buffer );
Paul Bakkereae09db2013-06-06 12:35:54 +0200246 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000247
248 if( base64_encode( buffer, &len, src, 64 ) != 0 ||
Paul Bakkereae09db2013-06-06 12:35:54 +0200249 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000250 {
251 if( verbose != 0 )
252 printf( "failed\n" );
253
254 return( 1 );
255 }
256
257 if( verbose != 0 )
258 printf( "passed\n Base64 decoding test: " );
259
260 len = sizeof( buffer );
Paul Bakkereae09db2013-06-06 12:35:54 +0200261 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000262
263 if( base64_decode( buffer, &len, src, 88 ) != 0 ||
264 memcmp( base64_test_dec, buffer, 64 ) != 0 )
265 {
266 if( verbose != 0 )
267 printf( "failed\n" );
268
269 return( 1 );
270 }
271
272 if( verbose != 0 )
273 printf( "passed\n\n" );
274
275 return( 0 );
276}
277
278#endif
279
280#endif