1 /* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 Without limiting anything contained in the foregoing, this file,
15 which is part of C Driver for MySQL (Connector/C), is also subject to the
16 Universal FOSS Exception, version 1.0, a copy of which can be found at
17 http://oss.oracle.com/licenses/universal-foss-exception.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License, version 2.0, for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
27
28 #include <my_global.h>
29 #include <m_string.h> /* strchr() */
30 #include <m_ctype.h> /* my_isspace() */
31 #include <base64.h>
32
33 #ifndef MAIN
34
35 static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
36 "abcdefghijklmnopqrstuvwxyz"
37 "0123456789+/";
38
39 /**
40 * Maximum length base64_needed_encoded_length()
41 * can handle without overflow.
42 */
43 uint64
base64_encode_max_arg_length()44 base64_encode_max_arg_length()
45 {
46 #if (SIZEOF_VOIDP == 8)
47 /*
48 6827690988321067803 -> 9223372036854775805
49 6827690988321067804 -> -9223372036854775807
50 */
51 return 0x5EC0D4C77B03531BLL;
52 #else
53 /*
54 1589695686 -> 2147483646
55 1589695687 -> -2147483645
56 */
57 return 0x5EC0D4C6;
58 #endif
59 }
60
61
62 uint64
base64_needed_encoded_length(uint64 length_of_data)63 base64_needed_encoded_length(uint64 length_of_data)
64 {
65 uint64 nb_base64_chars;
66 if (length_of_data == 0) return 1;
67 nb_base64_chars= (length_of_data + 2) / 3 * 4;
68
69 return
70 nb_base64_chars + /* base64 char incl padding */
71 (nb_base64_chars - 1)/ 76 + /* newlines */
72 1; /* NUL termination of string */
73 }
74
75
76 /**
77 * Maximum length base64_needed_decoded_length()
78 * can handle without overflow.
79 */
80 uint64
base64_decode_max_arg_length()81 base64_decode_max_arg_length()
82 {
83 #if (SIZEOF_VOIDP == 8)
84 return 0x2AAAAAAAAAAAAAAALL;
85 #else
86 return 0x2AAAAAAA;
87 #endif
88 }
89
90
91 uint64
base64_needed_decoded_length(uint64 length_of_encoded_data)92 base64_needed_decoded_length(uint64 length_of_encoded_data)
93 {
94 return (uint64) ceil(length_of_encoded_data * 3 / 4);
95 }
96
97
98 /*
99 Encode a data as base64.
100
101 Note: We require that dst is pre-allocated to correct size.
102 See base64_needed_encoded_length().
103 */
104
105 int
base64_encode(const void * src,size_t src_len,char * dst)106 base64_encode(const void *src, size_t src_len, char *dst)
107 {
108 const unsigned char *s= (const unsigned char*)src;
109 size_t i= 0;
110 size_t len= 0;
111
112 for (; i < src_len; len += 4)
113 {
114 unsigned c;
115
116 if (len == 76)
117 {
118 len= 0;
119 *dst++= '\n';
120 }
121
122 c= s[i++];
123 c <<= 8;
124
125 if (i < src_len)
126 c += s[i];
127 c <<= 8;
128 i++;
129
130 if (i < src_len)
131 c += s[i];
132 i++;
133
134 *dst++= base64_table[(c >> 18) & 0x3f];
135 *dst++= base64_table[(c >> 12) & 0x3f];
136
137 if (i > (src_len + 1))
138 *dst++= '=';
139 else
140 *dst++= base64_table[(c >> 6) & 0x3f];
141
142 if (i > src_len)
143 *dst++= '=';
144 else
145 *dst++= base64_table[(c >> 0) & 0x3f];
146 }
147 *dst= '\0';
148
149 return 0;
150 }
151
152
153 /*
154 Base64 decoder stream
155 */
156 typedef struct my_base64_decoder_t
157 {
158 const char *src; /* Pointer to the current input position */
159 const char *end; /* Pointer to the end of input buffer */
160 uint c; /* Collect bits into this number */
161 int error; /* Error code */
162 uchar state; /* Character number in the current group of 4 */
163 uchar mark; /* Number of padding marks in the current group */
164 } MY_BASE64_DECODER;
165
166
167 /*
168 Helper table for decoder.
169 -2 means "space character"
170 -1 means "bad character"
171 Non-negative values mean valid base64 encoding character.
172 */
173 static int8
174 from_base64_table[]=
175 {
176 /*00*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-1,-1,
177 /*10*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
178 /*20*/ -2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* !"#$%&'()*+,-./ */
179 /*30*/ 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 0123456789:;<=>? */
180 /*40*/ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* @ABCDEFGHIJKLMNO */
181 /*50*/ 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* PQRSTUVWXYZ[\]^_ */
182 /*60*/ -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* `abcdefghijklmno */
183 /*70*/ 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* pqrstuvwxyz{|}~ */
184 /*80*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
185 /*90*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
186 /*A0*/ -2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
187 /*B0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
188 /*C0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
189 /*D0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
190 /*E0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
191 /*F0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
192 };
193
194
195 /**
196 * Skip leading spaces in a base64 encoded stream
197 * and stop on the first non-space character.
198 * decoder->src will point to the first non-space character,
199 * or to the end of the input string.
200 * In case when end-of-input met on unexpected position,
201 * decoder->error is also set to 1.
202 *
203 * @param decoder Pointer to MY_BASE64_DECODER
204 *
205 * @return
206 * FALSE on success (there are some more non-space input characters)
207 * TRUE on error (end-of-input found)
208 */
209 static inline my_bool
my_base64_decoder_skip_spaces(MY_BASE64_DECODER * decoder)210 my_base64_decoder_skip_spaces(MY_BASE64_DECODER *decoder)
211 {
212 for ( ; decoder->src < decoder->end; decoder->src++)
213 {
214 if (from_base64_table[(uchar) *decoder->src] != -2)
215 return FALSE;
216 }
217 if (decoder->state > 0)
218 decoder->error= 1; /* Unexpected end-of-input found */
219 return TRUE;
220 }
221
222
223 /**
224 * Convert the next character in a base64 encoded stream
225 * to a number in the range [0..63]
226 * and mix it with the previously collected value in decoder->c.
227 *
228 * @param decode base64 decoding stream
229 *
230 * @return
231 * FALSE on success
232 * TRUE on error (invalid base64 character found)
233 */
234 static inline my_bool
my_base64_add(MY_BASE64_DECODER * decoder)235 my_base64_add(MY_BASE64_DECODER *decoder)
236 {
237 int res;
238 decoder->c <<= 6;
239 if ((res= from_base64_table[(uchar) *decoder->src++]) < 0)
240 return (decoder->error= TRUE);
241 decoder->c+= (uint) res;
242 return FALSE;
243 }
244
245
246 /**
247 * Get the next character from a base64 encoded stream.
248 * Skip spaces, then scan the next base64 character or a pad character
249 * and collect bits into decoder->c.
250 *
251 * @param decoder Pointer to MY_BASE64_DECODER
252 * @return
253 * FALSE on success (a valid base64 encoding character found)
254 * TRUE on error (unexpected character or unexpected end-of-input found)
255 */
256 static inline my_bool
my_base64_decoder_getch(MY_BASE64_DECODER * decoder)257 my_base64_decoder_getch(MY_BASE64_DECODER *decoder)
258 {
259 if (my_base64_decoder_skip_spaces(decoder))
260 return TRUE; /* End-of-input */
261
262 if (!my_base64_add(decoder)) /* Valid base64 character found */
263 {
264 if (decoder->mark)
265 {
266 /* If we have scanned '=' already, then only '=' is valid */
267 DBUG_ASSERT(decoder->state == 3);
268 decoder->error= 1;
269 decoder->src--;
270 return TRUE; /* expected '=', but encoding character found */
271 }
272 decoder->state++;
273 return FALSE;
274 }
275
276 /* Process error */
277 switch (decoder->state)
278 {
279 case 0:
280 case 1:
281 decoder->src--;
282 return TRUE; /* base64 character expected */
283 break;
284
285 case 2:
286 case 3:
287 if (decoder->src[-1] == '=')
288 {
289 decoder->error= 0; /* Not an error - it's a pad character */
290 decoder->mark++;
291 }
292 else
293 {
294 decoder->src--;
295 return TRUE; /* base64 character or '=' expected */
296 }
297 break;
298
299 default:
300 DBUG_ASSERT(0);
301 return TRUE; /* Wrong state, should not happen */
302 }
303
304 decoder->state++;
305 return FALSE;
306 }
307
308
309 /**
310 * Decode a base64 string
311 * The base64-encoded data in the range ['src','*end_ptr') will be
312 * decoded and stored starting at 'dst'. The decoding will stop
313 * after 'len' characters have been read from 'src', or when padding
314 * occurs in the base64-encoded data. In either case: if 'end_ptr' is
315 * non-null, '*end_ptr' will be set to point to the character after
316 * the last read character, even in the presence of error.
317 *
318 * Note: We require that 'dst' is pre-allocated to correct size.
319 *
320 * @param src Pointer to base64-encoded string
321 * @param len Length of string at 'src'
322 * @param dst Pointer to location where decoded data will be stored
323 * @param end_ptr Pointer to variable that will refer to the character
324 * after the end of the encoded data that were decoded.
325 * Can be NULL.
326 * @flags flags e.g. allow multiple chunks
327 * @return Number of bytes written at 'dst', or -1 in case of failure
328 */
329 int64
base64_decode(const char * src_base,size_t len,void * dst,const char ** end_ptr,int flags)330 base64_decode(const char *src_base, size_t len,
331 void *dst, const char **end_ptr, int flags)
332 {
333 char *d= (char*) dst;
334 MY_BASE64_DECODER decoder;
335
336 decoder.src= src_base;
337 decoder.end= src_base + len;
338 decoder.error= 0;
339 decoder.mark= 0;
340
341 for ( ; ; )
342 {
343 decoder.c= 0;
344 decoder.state= 0;
345
346 if (my_base64_decoder_getch(&decoder) ||
347 my_base64_decoder_getch(&decoder) ||
348 my_base64_decoder_getch(&decoder) ||
349 my_base64_decoder_getch(&decoder))
350 break;
351
352 *d++= (decoder.c >> 16) & 0xff;
353 *d++= (decoder.c >> 8) & 0xff;
354 *d++= (decoder.c >> 0) & 0xff;
355
356 if (decoder.mark)
357 {
358 d-= decoder.mark;
359 if (!(flags & MY_BASE64_DECODE_ALLOW_MULTIPLE_CHUNKS))
360 break;
361 decoder.mark= 0;
362 }
363 }
364
365 /* Return error if there are more non-space characters */
366 decoder.state= 0;
367 if (!my_base64_decoder_skip_spaces(&decoder))
368 decoder.error= 1;
369
370 if (end_ptr != NULL)
371 *end_ptr= decoder.src;
372
373 return decoder.error ? -1 : (int) (d - (char*) dst);
374 }
375
376
377 #else /* MAIN */
378
379 #define require(b) { \
380 if (!(b)) { \
381 printf("Require failed at %s:%d\n", __FILE__, __LINE__); \
382 abort(); \
383 } \
384 }
385
386
387 int
main(void)388 main(void)
389 {
390 int i;
391 size_t j;
392 size_t k, l;
393 size_t dst_len;
394 size_t needed_length;
395 char * src;
396 char * s;
397 char * str;
398 char * dst;
399 const char *end_ptr;
400 size_t src_len;
401
402 for (i= 0; i <= 500; i++)
403 {
404 /* Create source data */
405 if (i == 500)
406 {
407 #if (SIZEOF_VOIDP == 8)
408 printf("Test case for base64 max event length: 2119594243\n");
409 src_len= 2119594243;
410 #else
411 printf("Test case for base64 max event length: 536870912\n");
412 src_len= 536870912;
413 #endif
414 }
415 else
416 src_len= rand() % 1000 + 1;
417
418 src= (char *) malloc(src_len);
419 s= src;
420
421 require(src);
422 for (j= 0; j<src_len; j++)
423 {
424 char c= rand();
425 *s++= c;
426 }
427
428 /* Encode */
429 needed_length= base64_needed_encoded_length(src_len);
430 str= (char *) malloc(needed_length);
431 require(str);
432 for (k= 0; k < needed_length; k++)
433 str[k]= 0xff; /* Fill memory to check correct NUL termination */
434 require(base64_encode(src, src_len, str) == 0);
435 require(needed_length == strlen(str) + 1);
436
437 /* Decode */
438 dst= (char *) malloc(base64_needed_decoded_length(strlen(str)));
439 require(dst);
440 dst_len= base64_decode(str, strlen(str), dst, &end_ptr, 0);
441 require(dst_len == src_len);
442
443 if (memcmp(src, dst, src_len) != 0)
444 {
445 printf(" --------- src --------- --------- dst ---------\n");
446 for (k= 0; k<src_len; k+=8)
447 {
448 printf("%.4x ", (uint) k);
449 for (l=0; l<8 && k+l<src_len; l++)
450 {
451 unsigned char c= src[k+l];
452 printf("%.2x ", (unsigned)c);
453 }
454
455 printf(" ");
456
457 for (l=0; l<8 && k+l<dst_len; l++)
458 {
459 unsigned char c= dst[k+l];
460 printf("%.2x ", (unsigned)c);
461 }
462 printf("\n");
463 }
464 printf("src length: %.8x, dst length: %.8x\n",
465 (uint) src_len, (uint) dst_len);
466 require(0);
467 }
468 free(src);
469 free(str);
470 free(dst);
471 }
472 printf("Test succeeded.\n");
473 return 0;
474 }
475
476 #endif
477