1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #include "sdp_base64.h"
6 
7 /*
8  * Local definitions for Base64 to Raw table entries.
9  */
10 #define INVALID_CHAR 0xFF /* Character not in supported Base64 set */
11 #define WHITE_SPACE  0xFE /* Space, tab, newline, etc character */
12 #define PADDING      0xFD /* The character '=' */
13 
14 #define PAD_CHAR     '=' /* The character '=' */
15 
16 /* Maximum length of a base64 encoded line */
17 #define MAX_BASE64_LINE_LENGTH 76
18 
19 /*
20  * base64_result_table
21  *  String table for translating base64 error codes into human
22  *  understanable strings.
23  */
24 char *base64_result_table[BASE64_RESULT_MAX] =
25 {
26     "Base64 successful",
27     "Base64 Buffer Overrun",
28     "Base64 Bad Data",
29     "Base64 Bad Padding",
30     "Base64 Bad Block Size"
31 };
32 
33 /*
34  * base64_to_raw_table
35  *  Heart of the Base64 decoding algorithm. Lookup table to convert
36  *  the Base64 characters into their specified representative values.
37  *  Invalid characters are marked with 0xFF, white space characters
38  *  are marked with 0xFE, and the special pading character is marked
39  *  with 0xFD.
40  */
41 unsigned char base64_to_raw_table[128] =
42 {
43     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, /* 0-9 */
44     0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 10-19 */
45     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 20-29 */
46     0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 30-39 */
47     0xFF, 0xFF, 0xFF,   62, 0xFF, 0xFF, 0xFF,   63,   52,   53, /* 40-49 */
48       54,   55,   56,   57,   58,   59,   60,   61, 0xFF, 0xFF, /* 50-59 */
49     0xFF, 0xFD, 0xFF, 0xFF, 0xFF,    0,    1,    2,    3,    4, /* 60-69 */
50        5,    6,    7,    8,    9,   10,   11,   12,   13,   14, /* 70-79 */
51       15,   16,   17,   18,   19,   20,   21,   22,   23,   24, /* 80-89 */
52       25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   26,   27,   28, /* 90-99 */
53       29,   30,   31,   32,   33,   34,   35,   36,   37,   38, /* 100-109 */
54       39,   40,   41,   42,   43,   44,   45,   46,   47,   48, /* 110-119 */
55       49,   50,   51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF              /* 120-127 */
56 };
57 
58 unsigned char raw_to_base64_table[64] =
59 {
60     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0-9 */
61     'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10-19 */
62     'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20-29 */
63     'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 30-39 */
64     'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 40-49 */
65     'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 50-59 */
66     '8', '9', '+', '/'				      /* 60-63 */
67 };
68 
69 /*
70  * base64_encode_size_bytes
71  *
72  * DESCRIPTION
73  *  Estimates the size of buffer required for holding the result of
74  *  encoding data of size raw_size_bytes.
75  *
76  * PARAMETERS
77  *  raw_size_bytes = Estimated size of the un-encoded data in bytes.
78  *
79  * RETURN VALUE
80  *  The size of destination buffer to use for encoding in bytes.
81  */
base64_est_encode_size_bytes(int raw_size_bytes)82 int base64_est_encode_size_bytes (int raw_size_bytes)
83 {
84     int length;
85 
86     /*
87      * Find the number of bytes needed to represent the data
88      * using a 4/3 expansion ratio. That result must be
89      * rounded to the next higher multiple of four to account
90      * for padding. Then add in a term to account for any '\n's
91      * added.
92      */
93     length = ((((raw_size_bytes * 4 + 2)/ 3) + 3) & ~(0x3)) +
94 	raw_size_bytes / MAX_BASE64_LINE_LENGTH;
95 
96     return length;
97 }
98 
99 /*
100  * base64_decode_size_bytes
101  *
102  * DESCRIPTION
103  *  Estimates the size of buffer required for holding the result of
104  *  decoding data of size base64_size_bytes.
105  *
106  * PARAMETERS
107  *  base64_size_bytes = Estimated size of the Base64 data in bytes.
108  *
109  * RETURN VALUE
110  *  The size of destination buffer to use for decoding in bytes.
111  */
base64_est_decode_size_bytes(int base64_size_bytes)112 int base64_est_decode_size_bytes (int base64_size_bytes)
113 {
114     int length;
115 
116     length = (base64_size_bytes * 3 + 3) / 4;
117     return length;
118 }
119 
120 /*
121  * base64_encode
122  *
123  * DESCRIPTION
124  *  Encode data pointed to by src into the buffer pointer to by dest
125  *  using the Base64 algorithm.
126  *
127  *  NOTE: No trailing '\n' character will be added.
128  *
129  *  NOTE: As per specification, '\n' will be placed every 76 chars.
130  *
131  * PARAMETERS
132  *  src = Pointer to the raw data to base64 encode.
133  *  src_bytes = The number of bytes in the src buffer to encode.
134  *  dest = Pointer to the destination buffer where the converted data
135  *	will reside when complete.
136  *  dest_bytes = Initially holds the size of the destination buffer
137  *	but at completion holds the number of bytes converted.
138  *
139  * RETURN VALUE
140  *  base64_success if the buffer was successfully converted, the
141  *  appropriate error code otherwise.
142  *
143  *  The dest parameter holds the converted data.
144  *
145  *  The dest_bytes parameter holds the actual number of bytes converted.
146  */
base64_encode(unsigned char * src,int src_bytes,unsigned char * dest,int * dest_bytes)147 base64_result_t base64_encode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes)
148 {
149     int i, j=0;
150     int line_count = 0;
151     unsigned char index; /* index into base64 lookup table */
152     int smax = src_bytes-2; /* only do full multiples of 3 */
153     int dmax = *dest_bytes; /* destination maximum */
154 
155     *dest_bytes = 0;
156 
157     /* Do full groups. Base64 must be done in blocks of 3 src bytes */
158     for (i=0; i<smax; i+=3) {
159 	/* Check to see if newline should be injected */
160 	if (line_count>=MAX_BASE64_LINE_LENGTH) {
161 	    if (j<dmax){
162 		dest[j++] = '\n';
163 	    } else {
164 		return BASE64_BUFFER_OVERRUN;
165 	    }
166 	    line_count = 0;
167 	}
168 
169 	line_count += 4;
170 
171 	if ((j+3) < dmax) {
172 
173 	    /* Find mapping of upper 6 bits */
174 	    index = (src[i] >> 2) & 0x3F;
175 	    dest[j++] = raw_to_base64_table[index];
176 
177 	    /* bottom 2 bits of first word, high 4 bits of second word */
178 	    index = ((src[i] << 4) & 0x30) | ((src[i+1] >> 4) & 0x0F);
179 	    dest[j++] = raw_to_base64_table[index];
180 
181 	    /* bottom 4 bits of second word, high 2 bits of third word */
182 	    index = ((src[i+1] << 2) & 0x3C) | ((src[i+2] >> 6) & 0x03);
183 	    dest[j++] = raw_to_base64_table[index];
184 
185 	    /* bottom 6 bits of third word */
186 	    index = src[i+2] & 0x3F;
187 	    dest[j++] = raw_to_base64_table[index];
188 	} else {
189 	    return BASE64_BUFFER_OVERRUN;
190 	}
191     }
192 
193     /* Check to see if any more work must be done */
194     if (i<src_bytes) {
195 
196 	/* Check to see if a newline should be output */
197 	if (line_count>=MAX_BASE64_LINE_LENGTH) {
198 	    if (j<dmax){
199 		dest[j++] = '\n';
200 	    } else {
201 		return BASE64_BUFFER_OVERRUN;
202 	    }
203 	    line_count = 0;
204 	}
205 
206 	line_count += 4;
207 
208 	/* Must fill another quantum */
209 	if (j+4>dmax) {
210 	    /* No room left in output buffer! */
211 	    return BASE64_BUFFER_OVERRUN;
212 	}
213 
214 	/* Find mapping of upper 6 bits */
215 	index = (src[i] >> 2) & 0x3F;
216 	dest[j++] = raw_to_base64_table[index];
217 
218 	/* check for another stragler */
219 	if ((i+1)<src_bytes) {
220 	    /* bottom 2 bits of first word, high 4 bits of second word */
221 	    index = ((src[i] << 4) & 0x30) | ((src[i+1] >> 4) & 0x0F);
222 	    dest[j++] = raw_to_base64_table[index];
223 
224 	    /* bottom 4 bits of second word */
225 	    index = (src[i+1] << 2) & 0x3C;
226 	    dest[j++] = raw_to_base64_table[index];
227 	    dest[j++] = PAD_CHAR;
228 	} else {
229 	    /* bottom 2 bits of first word */
230 	    index = (src[i] << 4) & 0x30;
231 	    dest[j++] = raw_to_base64_table[index];
232 	    dest[j++] = PAD_CHAR;
233 	    dest[j++] = PAD_CHAR;
234 	}
235     }
236 
237     *dest_bytes = j;
238 
239     return BASE64_SUCCESS;
240 }
241 
base64_decode_get_raw(unsigned char index)242 unsigned char base64_decode_get_raw(unsigned char index)
243 {
244     /* only have 128 values, MSB must not be set! */
245     if (index >= 128) {
246       return INVALID_CHAR;
247     }
248     return base64_to_raw_table[index];
249 }
250 
251 /*
252  * base64_decode
253  *
254  * DESCRIPTION
255  *  Decode data pointed to by src into the buffer pointer to by dest
256  *  using the Base64 algorithm.
257  *
258  * PARAMETERS
259  *  src = Pointer to the Base64 data to decode.
260  *  src_bytes = The number of bytes in the src buffer to decode.
261  *  dest = Pointer to the destination buffer where the converted data
262  *	will reside when complete.
263  *  dest_bytes = Initially holds the size of the destination buffer
264  *	but at completion holds the number of bytes converted.
265  *
266  * RETURN VALUE
267  *  base64_success if the buffer was successfully converted, the
268  *  appropriate error code otherwise.
269  *
270  *  The dest parameter holds the converted data.
271  *
272  *  The dest_bytes parameter holds the actual number of bytes converted.
273  */
base64_decode(unsigned char * src,int src_bytes,unsigned char * dest,int * dest_bytes)274 base64_result_t base64_decode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes)
275 {
276     int i, j = 0;
277     int sindex = 0;			/* Current NON-whitespace source
278 					 * index */
279     int pad_count=0;			/* Number of padding characters
280 					 * encountered */
281     int dest_size_bytes = *dest_bytes;	/* Save size of destination buffer */
282     unsigned char cindex;		/* The current Base64 character to
283 					 * process */
284     unsigned char val;			/* The value of the current Base64
285 					 * character */
286 
287     *dest_bytes = 0;
288 
289     for (i=0; i<src_bytes; i++) {
290 	cindex = src[i];
291 
292 	val = base64_decode_get_raw(cindex);
293 	if (val  == INVALID_CHAR) {
294 	    /* Invalid base64 character */
295 	    return BASE64_BAD_DATA;
296 	}
297 
298 	if (val == WHITE_SPACE) {
299 	    /* Ignore white space */
300 	    continue;
301 	}
302 
303 	if (val == PADDING) {
304 	    /* we must be at the end-finish up */
305 	    pad_count++;
306 	    if (++i<src_bytes) {
307 		/* can have up to 2 pad chars */
308                 if (base64_decode_get_raw(src[i]) != PADDING) {
309 		    return BASE64_BAD_PADDING;
310 		}
311 
312 		if (++i<src_bytes) {
313 		    /* should not have any more padding! */
314 		    return BASE64_BAD_PADDING;
315 		}
316 
317 		pad_count++;
318 	    }
319 
320 	    /* DONE! */
321 	    break;
322 	}
323 
324 	/* Determine which portion of the 3 bytes this data will fill */
325 	switch (sindex & 0x3) {
326 	case 0:
327 	    /* Fill upper 6 bits */
328 	    if (j<dest_size_bytes) {
329 		dest[j] = val << 2;
330 	    } else {
331 		return BASE64_BUFFER_OVERRUN;
332 	    }
333 	    break;
334 	case 1:
335 	    /* Fill Bottom 2 bits */
336 	    dest[j++] |= val >> 4;
337 
338 	    if (j<dest_size_bytes) {
339 		/* Fill Top 4 bits */
340 		dest[j] = (val << 4) & 0xF0;
341 	    } else {
342 		/*
343 		 * Check to see if there is any more data present.
344 		 * Next base64 character MUST be a pad character and
345 		 * the rest of this data MUST be zero.
346 		 *
347 		 * If this is not the end of data then a buffer overrun
348 		 * has occurred
349 		 */
350 		if ((val & 0x0F) ||
351 		    (i+1>=src_bytes) ||
352 		    (base64_decode_get_raw(src[i+1]) != PADDING)) {
353 		    return BASE64_BUFFER_OVERRUN;
354 		}
355 	    }
356 	    break;
357 	case 2:
358 	    /* Fill Bottom 4 bits */
359 	    dest[j++] |= val >> 2;
360 
361 	    if (j<dest_size_bytes) {
362 		/* Fill Top 2 bits */
363 		dest[j] = (val << 6) & 0xC0;
364 	    } else {
365 		/*
366 		 * Check to see if there is any more data present.
367 		 * Next base64 character MUST be a pad character and
368 		 * the rest of this data MUST be zero.
369 		 *
370 		 * If this is not the end of data then a buffer overrun
371 		 * has occurred
372 		 */
373 		if ((val & 0x03) ||
374 		    (i+1>=src_bytes) ||
375 		    (base64_decode_get_raw(src[i+1]) != PADDING)) {
376 		    return BASE64_BUFFER_OVERRUN;
377 		}
378 	    }
379 	    break;
380 	case 3:
381 	    /*
382 	     *  No need to check for overrun here since the
383 	     *  previous case was already checked. If another
384 	     *  group is present then case 0 will check again.
385 	     */
386 
387 	    /* Fill Bottom 6 bits */
388 	    dest[j++] |= val;
389 	    break;
390 	}
391 	sindex++;
392     }
393 
394     /* Check length for multiple of 3 bytes */
395     if (((j + pad_count)% 3) != 0) {
396 	return BASE64_BAD_BLOCK_SIZE;
397     }
398 
399     /* Save off the number of bytes converted */
400     *dest_bytes = j;
401 
402     return BASE64_SUCCESS;
403 }
404