1 #include <libcper/base64.h> 2 #include <libcper/BaseTypes.h> 3 4 #include <stdlib.h> 5 #include <string.h> 6 #include <stdio.h> 7 #include <assert.h> 8 9 static const UINT8 encode_table[65] = 10 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 11 12 /** 13 * 14 * Caller is responsible for freeing the returned buffer. 15 */ 16 CHAR8 *base64_encode(const UINT8 *src, INT32 len, INT32 *out_len) 17 { 18 CHAR8 *out; 19 CHAR8 *out_pos; 20 const UINT8 *src_end; 21 const UINT8 *in_pos; 22 23 if (len <= 0) { 24 return NULL; 25 } 26 27 if (!out_len) { 28 return NULL; 29 } 30 31 // 3 byte blocks to 4 byte blocks plus up to 2 bytes of padding 32 *out_len = 4 * ((len + 2) / 3); 33 34 // Handle overflows 35 if (*out_len < len) { 36 return NULL; 37 } 38 39 out = malloc(*out_len); 40 if (out == NULL) { 41 return NULL; 42 } 43 44 src_end = src + len; 45 in_pos = src; 46 out_pos = out; 47 while (src_end - in_pos >= 3) { 48 *out_pos++ = encode_table[in_pos[0] >> 2]; 49 *out_pos++ = encode_table[((in_pos[0] & 0x03) << 4) | 50 (in_pos[1] >> 4)]; 51 *out_pos++ = encode_table[((in_pos[1] & 0x0f) << 2) | 52 (in_pos[2] >> 6)]; 53 *out_pos++ = encode_table[in_pos[2] & 0x3f]; 54 in_pos += 3; 55 } 56 57 if (src_end - in_pos) { 58 *out_pos++ = encode_table[in_pos[0] >> 2]; 59 if (src_end - in_pos == 1) { 60 *out_pos++ = encode_table[(in_pos[0] & 0x03) << 4]; 61 *out_pos++ = '='; 62 } else { 63 *out_pos++ = encode_table[((in_pos[0] & 0x03) << 4) | 64 (in_pos[1] >> 4)]; 65 *out_pos++ = encode_table[(in_pos[1] & 0x0f) << 2]; 66 } 67 *out_pos++ = '='; 68 } 69 70 return out; 71 } 72 73 // Base64 decode table. Invalid values are specified with 0x80. 74 UINT8 decode_table[256] = 75 "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 76 "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 77 "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x3e\x80\x80\x80\x3f" 78 "\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x80\x80\x80\x00\x80\x80" 79 "\x80\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e" 80 "\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x80\x80\x80\x80\x80" 81 "\x80\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28" 82 "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x80\x80\x80\x80\x80" 83 "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 84 "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 85 "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 86 "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 87 "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 88 "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 89 "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 90 "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"; 91 92 /** 93 * 94 * Caller is responsible for freeing the returned buffer. 95 */ 96 UINT8 *base64_decode(const CHAR8 *src, INT32 len, INT32 *out_len) 97 { 98 UINT8 *out = NULL; 99 UINT8 *pos = NULL; 100 UINT8 block[4]; 101 INT32 block_index = 0; 102 INT32 src_index = 0; 103 104 if (!out_len) { 105 goto error; 106 } 107 108 // Malloc might be up to 2 larger dependent on padding 109 *out_len = len / 4 * 3 + 2; 110 pos = out = malloc(*out_len); 111 if (out == NULL) { 112 goto error; 113 } 114 115 block_index = 0; 116 for (src_index = 0; src_index < len; src_index++) { 117 char current_char = src[src_index]; 118 if (current_char == '=') { 119 break; 120 } 121 // If the final character is a newline, as can occur in many editors 122 // then ignore it. 123 if (src_index + 1 == len && current_char == '\n') { 124 printf("Ignoring trailing newline.\n"); 125 break; 126 } 127 128 block[block_index] = decode_table[(UINT8)current_char]; 129 if (block[block_index] == 0x80) { 130 printf("Invalid character \"%c\".\n", current_char); 131 goto error; 132 } 133 134 block_index++; 135 if (block_index == 4) { 136 *pos++ = (block[0] << 2) | (block[1] >> 4); 137 *pos++ = (block[1] << 4) | (block[2] >> 2); 138 *pos++ = (block[2] << 6) | block[3]; 139 block_index = 0; 140 } 141 } 142 if (block_index == 0) { 143 // mod 4 Even number of characters, no padding. 144 } else if (block_index == 1) { 145 printf("Invalid base64 input length. Last character truncated.\n"); 146 goto error; 147 } else if (block_index == 2) { 148 *pos++ = (block[0] << 2) | (block[1] >> 4); 149 } else if (block_index == 3) { 150 *pos++ = (block[0] << 2) | (block[1] >> 4); 151 *pos++ = (block[1] << 4) | (block[2] >> 2); 152 } else { 153 /* Invalid pad_counting */ 154 printf("Invalid base64 input length %d.\n", block_index); 155 goto error; 156 } 157 158 *out_len = pos - out; 159 return out; 160 161 error: 162 free(out); 163 return NULL; 164 } 165