/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "sdp_base64.h" /* * Local definitions for Base64 to Raw table entries. */ #define INVALID_CHAR 0xFF /* Character not in supported Base64 set */ #define WHITE_SPACE 0xFE /* Space, tab, newline, etc character */ #define PADDING 0xFD /* The character '=' */ #define PAD_CHAR '=' /* The character '=' */ /* Maximum length of a base64 encoded line */ #define MAX_BASE64_LINE_LENGTH 76 /* * base64_result_table * String table for translating base64 error codes into human * understanable strings. */ char *base64_result_table[BASE64_RESULT_MAX] = { "Base64 successful", "Base64 Buffer Overrun", "Base64 Bad Data", "Base64 Bad Padding", "Base64 Bad Block Size" }; /* * base64_to_raw_table * Heart of the Base64 decoding algorithm. Lookup table to convert * the Base64 characters into their specified representative values. * Invalid characters are marked with 0xFF, white space characters * are marked with 0xFE, and the special pading character is marked * with 0xFD. */ unsigned char base64_to_raw_table[128] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, /* 0-9 */ 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 10-19 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 20-29 */ 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 30-39 */ 0xFF, 0xFF, 0xFF, 62, 0xFF, 0xFF, 0xFF, 63, 52, 53, /* 40-49 */ 54, 55, 56, 57, 58, 59, 60, 61, 0xFF, 0xFF, /* 50-59 */ 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, /* 60-69 */ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 70-79 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /* 80-89 */ 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 26, 27, 28, /* 90-99 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 100-109 */ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, /* 110-119 */ 49, 50, 51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /* 120-127 */ }; unsigned char raw_to_base64_table[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0-9 */ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10-19 */ 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20-29 */ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 30-39 */ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 40-49 */ 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 50-59 */ '8', '9', '+', '/' /* 60-63 */ }; /* * base64_encode_size_bytes * * DESCRIPTION * Estimates the size of buffer required for holding the result of * encoding data of size raw_size_bytes. * * PARAMETERS * raw_size_bytes = Estimated size of the un-encoded data in bytes. * * RETURN VALUE * The size of destination buffer to use for encoding in bytes. */ int base64_est_encode_size_bytes (int raw_size_bytes) { int length; /* * Find the number of bytes needed to represent the data * using a 4/3 expansion ratio. That result must be * rounded to the next higher multiple of four to account * for padding. Then add in a term to account for any '\n's * added. */ length = ((((raw_size_bytes * 4 + 2)/ 3) + 3) & ~(0x3)) + raw_size_bytes / MAX_BASE64_LINE_LENGTH; return length; } /* * base64_decode_size_bytes * * DESCRIPTION * Estimates the size of buffer required for holding the result of * decoding data of size base64_size_bytes. * * PARAMETERS * base64_size_bytes = Estimated size of the Base64 data in bytes. * * RETURN VALUE * The size of destination buffer to use for decoding in bytes. */ int base64_est_decode_size_bytes (int base64_size_bytes) { int length; length = (base64_size_bytes * 3 + 3) / 4; return length; } /* * base64_encode * * DESCRIPTION * Encode data pointed to by src into the buffer pointer to by dest * using the Base64 algorithm. * * NOTE: No trailing '\n' character will be added. * * NOTE: As per specification, '\n' will be placed every 76 chars. * * PARAMETERS * src = Pointer to the raw data to base64 encode. * src_bytes = The number of bytes in the src buffer to encode. * dest = Pointer to the destination buffer where the converted data * will reside when complete. * dest_bytes = Initially holds the size of the destination buffer * but at completion holds the number of bytes converted. * * RETURN VALUE * base64_success if the buffer was successfully converted, the * appropriate error code otherwise. * * The dest parameter holds the converted data. * * The dest_bytes parameter holds the actual number of bytes converted. */ base64_result_t base64_encode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes) { int i, j=0; int line_count = 0; unsigned char index; /* index into base64 lookup table */ int smax = src_bytes-2; /* only do full multiples of 3 */ int dmax = *dest_bytes; /* destination maximum */ *dest_bytes = 0; /* Do full groups. Base64 must be done in blocks of 3 src bytes */ for (i=0; i=MAX_BASE64_LINE_LENGTH) { if (j> 2) & 0x3F; dest[j++] = raw_to_base64_table[index]; /* bottom 2 bits of first word, high 4 bits of second word */ index = ((src[i] << 4) & 0x30) | ((src[i+1] >> 4) & 0x0F); dest[j++] = raw_to_base64_table[index]; /* bottom 4 bits of second word, high 2 bits of third word */ index = ((src[i+1] << 2) & 0x3C) | ((src[i+2] >> 6) & 0x03); dest[j++] = raw_to_base64_table[index]; /* bottom 6 bits of third word */ index = src[i+2] & 0x3F; dest[j++] = raw_to_base64_table[index]; } else { return BASE64_BUFFER_OVERRUN; } } /* Check to see if any more work must be done */ if (i=MAX_BASE64_LINE_LENGTH) { if (jdmax) { /* No room left in output buffer! */ return BASE64_BUFFER_OVERRUN; } /* Find mapping of upper 6 bits */ index = (src[i] >> 2) & 0x3F; dest[j++] = raw_to_base64_table[index]; /* check for another stragler */ if ((i+1)> 4) & 0x0F); dest[j++] = raw_to_base64_table[index]; /* bottom 4 bits of second word */ index = (src[i+1] << 2) & 0x3C; dest[j++] = raw_to_base64_table[index]; dest[j++] = PAD_CHAR; } else { /* bottom 2 bits of first word */ index = (src[i] << 4) & 0x30; dest[j++] = raw_to_base64_table[index]; dest[j++] = PAD_CHAR; dest[j++] = PAD_CHAR; } } *dest_bytes = j; return BASE64_SUCCESS; } unsigned char base64_decode_get_raw(unsigned char index) { /* only have 128 values, MSB must not be set! */ if (index >= 128) { return INVALID_CHAR; } return base64_to_raw_table[index]; } /* * base64_decode * * DESCRIPTION * Decode data pointed to by src into the buffer pointer to by dest * using the Base64 algorithm. * * PARAMETERS * src = Pointer to the Base64 data to decode. * src_bytes = The number of bytes in the src buffer to decode. * dest = Pointer to the destination buffer where the converted data * will reside when complete. * dest_bytes = Initially holds the size of the destination buffer * but at completion holds the number of bytes converted. * * RETURN VALUE * base64_success if the buffer was successfully converted, the * appropriate error code otherwise. * * The dest parameter holds the converted data. * * The dest_bytes parameter holds the actual number of bytes converted. */ base64_result_t base64_decode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes) { int i, j = 0; int sindex = 0; /* Current NON-whitespace source * index */ int pad_count=0; /* Number of padding characters * encountered */ int dest_size_bytes = *dest_bytes; /* Save size of destination buffer */ unsigned char cindex; /* The current Base64 character to * process */ unsigned char val; /* The value of the current Base64 * character */ *dest_bytes = 0; for (i=0; i> 4; if (j=src_bytes) || (base64_decode_get_raw(src[i+1]) != PADDING)) { return BASE64_BUFFER_OVERRUN; } } break; case 2: /* Fill Bottom 4 bits */ dest[j++] |= val >> 2; if (j=src_bytes) || (base64_decode_get_raw(src[i+1]) != PADDING)) { return BASE64_BUFFER_OVERRUN; } } break; case 3: /* * No need to check for overrun here since the * previous case was already checked. If another * group is present then case 0 will check again. */ /* Fill Bottom 6 bits */ dest[j++] |= val; break; } sindex++; } /* Check length for multiple of 3 bytes */ if (((j + pad_count)% 3) != 0) { return BASE64_BAD_BLOCK_SIZE; } /* Save off the number of bytes converted */ *dest_bytes = j; return BASE64_SUCCESS; }