PolarSSL v1.2.12
base64.c
Go to the documentation of this file.
1 /*
2  * RFC 1521 base64 encoding/decoding
3  *
4  * Copyright (C) 2006-2010, Brainspark B.V.
5  *
6  * This file is part of PolarSSL (http://www.polarssl.org)
7  * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8  *
9  * All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25 
26 #include "polarssl/config.h"
27 
28 #if defined(POLARSSL_BASE64_C)
29 
30 #include "polarssl/base64.h"
31 
32 #ifdef _MSC_VER
33 #include <basetsd.h>
34 typedef UINT32 uint32_t;
35 #else
36 #include <inttypes.h>
37 #endif
38 
39 static const unsigned char base64_enc_map[64] =
40 {
41  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
42  'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
43  'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
44  'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
45  'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
46  'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
47  '8', '9', '+', '/'
48 };
49 
50 static const unsigned char base64_dec_map[128] =
51 {
52  127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
53  127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
54  127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
55  127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
56  127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
57  54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
58  127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
59  5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
60  15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
61  25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
62  29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
63  39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
64  49, 50, 51, 127, 127, 127, 127, 127
65 };
66 
67 /*
68  * Encode a buffer into base64 format
69  */
70 int base64_encode( unsigned char *dst, size_t *dlen,
71  const unsigned char *src, size_t slen )
72 {
73  size_t i, n;
74  int C1, C2, C3;
75  unsigned char *p;
76 
77  if( slen == 0 )
78  return( 0 );
79 
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;
93  }
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  */
133 int base64_decode( unsigned char *dst, size_t *dlen,
134  const unsigned char *src, size_t slen )
135 {
136  size_t i, n;
137  uint32_t j, x;
138  unsigned char *p;
139 
140  /* First pass: check for validity and get output length */
141  for( i = n = j = 0; i < slen; i++ )
142  {
143  /* 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 
155  if( ( slen - i ) >= 2 &&
156  src[i] == '\r' && src[i + 1] == '\n' )
157  continue;
158 
159  if( src[i] == '\n' )
160  continue;
161 
162  /* Space inside a line is an error */
163  if( x != 0 )
165 
166  if( src[i] == '=' && ++j > 2 )
168 
169  if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
171 
172  if( base64_dec_map[src[i]] < 64 && j != 0 )
174 
175  n++;
176  }
177 
178  if( n == 0 )
179  return( 0 );
180 
181  n = ((n * 6) + 7) >> 3;
182  n -= j;
183 
184  if( *dlen < n )
185  {
186  *dlen = n;
188  }
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 
212 #if defined(POLARSSL_SELF_TEST)
213 
214 #include <string.h>
215 #include <stdio.h>
216 
217 static 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 
229 static const unsigned char base64_test_enc[] =
230  "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
231  "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
232 
233 /*
234  * Checkup routine
235  */
236 int base64_self_test( int verbose )
237 {
238  size_t len;
239  const unsigned char *src;
240  unsigned char buffer[128];
241 
242  if( verbose != 0 )
243  printf( " Base64 encoding test: " );
244 
245  len = sizeof( buffer );
246  src = base64_test_dec;
247 
248  if( base64_encode( buffer, &len, src, 64 ) != 0 ||
249  memcmp( base64_test_enc, buffer, 88 ) != 0 )
250  {
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 );
261  src = base64_test_enc;
262 
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