blob: dba4c231cfd9c128ae17a6941af6f8e46acce367 [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
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 )
Manuel Pégourié-Gonnardb73ce452015-09-28 18:27:15 +0200179 {
180 *dlen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000181 return( 0 );
Manuel Pégourié-Gonnardb73ce452015-09-28 18:27:15 +0200182 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000183
184 n = ((n * 6) + 7) >> 3;
Paul Bakkerbbc843f2014-07-08 18:18:38 +0200185 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000186
187 if( *dlen < n )
188 {
189 *dlen = n;
Paul Bakker40e46942009-01-03 21:51:57 +0000190 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000191 }
192
193 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
194 {
195 if( *src == '\r' || *src == '\n' )
196 continue;
197
198 j -= ( base64_dec_map[*src] == 64 );
199 x = (x << 6) | ( base64_dec_map[*src] & 0x3F );
200
201 if( ++n == 4 )
202 {
203 n = 0;
204 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
205 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
206 if( j > 2 ) *p++ = (unsigned char)( x );
207 }
208 }
209
210 *dlen = p - dst;
211
212 return( 0 );
213}
214
Paul Bakker40e46942009-01-03 21:51:57 +0000215#if defined(POLARSSL_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000216
217#include <string.h>
218#include <stdio.h>
219
220static const unsigned char base64_test_dec[64] =
221{
222 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
223 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
224 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
225 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
226 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
227 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
228 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
229 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
230};
231
232static const unsigned char base64_test_enc[] =
233 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
234 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
235
236/*
237 * Checkup routine
238 */
239int base64_self_test( int verbose )
240{
Paul Bakker23986e52011-04-24 08:57:21 +0000241 size_t len;
Paul Bakkereae09db2013-06-06 12:35:54 +0200242 const unsigned char *src;
243 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000244
245 if( verbose != 0 )
246 printf( " Base64 encoding test: " );
247
248 len = sizeof( buffer );
Paul Bakkereae09db2013-06-06 12:35:54 +0200249 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000250
251 if( base64_encode( buffer, &len, src, 64 ) != 0 ||
Paul Bakkereae09db2013-06-06 12:35:54 +0200252 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000253 {
254 if( verbose != 0 )
255 printf( "failed\n" );
256
257 return( 1 );
258 }
259
260 if( verbose != 0 )
261 printf( "passed\n Base64 decoding test: " );
262
263 len = sizeof( buffer );
Paul Bakkereae09db2013-06-06 12:35:54 +0200264 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000265
266 if( base64_decode( buffer, &len, src, 88 ) != 0 ||
267 memcmp( base64_test_dec, buffer, 64 ) != 0 )
268 {
269 if( verbose != 0 )
270 printf( "failed\n" );
271
272 return( 1 );
273 }
274
275 if( verbose != 0 )
276 printf( "passed\n\n" );
277
278 return( 0 );
279}
280
281#endif
282
283#endif