| Thu Nguyen | e42fb48 | 2024-10-15 14:43:11 +0000 | [diff] [blame] | 1 | #include <libcper/base64.h> | 
|  | 2 | #include <libcper/BaseTypes.h> | 
| Ed Tanous | a7d2cdd | 2024-07-15 11:07:27 -0700 | [diff] [blame] | 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 (!out_len) { | 
|  | 24 | return NULL; | 
|  | 25 | } | 
|  | 26 |  | 
|  | 27 | // 3 byte blocks to 4 byte blocks plus up to 2 bytes of padding | 
|  | 28 | *out_len = 4 * ((len + 2) / 3); | 
|  | 29 |  | 
|  | 30 | // Handle overflows | 
|  | 31 | if (*out_len < len) { | 
|  | 32 | return NULL; | 
|  | 33 | } | 
|  | 34 |  | 
|  | 35 | out = malloc(*out_len); | 
|  | 36 | if (out == NULL) { | 
|  | 37 | return NULL; | 
|  | 38 | } | 
|  | 39 |  | 
|  | 40 | src_end = src + len; | 
|  | 41 | in_pos = src; | 
|  | 42 | out_pos = out; | 
|  | 43 | while (src_end - in_pos >= 3) { | 
|  | 44 | *out_pos++ = encode_table[in_pos[0] >> 2]; | 
|  | 45 | *out_pos++ = encode_table[((in_pos[0] & 0x03) << 4) | | 
|  | 46 | (in_pos[1] >> 4)]; | 
|  | 47 | *out_pos++ = encode_table[((in_pos[1] & 0x0f) << 2) | | 
|  | 48 | (in_pos[2] >> 6)]; | 
|  | 49 | *out_pos++ = encode_table[in_pos[2] & 0x3f]; | 
|  | 50 | in_pos += 3; | 
|  | 51 | } | 
|  | 52 |  | 
|  | 53 | if (src_end - in_pos) { | 
|  | 54 | *out_pos++ = encode_table[in_pos[0] >> 2]; | 
|  | 55 | if (src_end - in_pos == 1) { | 
|  | 56 | *out_pos++ = encode_table[(in_pos[0] & 0x03) << 4]; | 
|  | 57 | *out_pos++ = '='; | 
|  | 58 | } else { | 
|  | 59 | *out_pos++ = encode_table[((in_pos[0] & 0x03) << 4) | | 
|  | 60 | (in_pos[1] >> 4)]; | 
|  | 61 | *out_pos++ = encode_table[(in_pos[1] & 0x0f) << 2]; | 
|  | 62 | } | 
|  | 63 | *out_pos++ = '='; | 
|  | 64 | } | 
|  | 65 |  | 
|  | 66 | return out; | 
|  | 67 | } | 
|  | 68 |  | 
|  | 69 | // Base64 decode table.  Invalid values are specified with 0x80. | 
|  | 70 | UINT8 decode_table[256] = | 
|  | 71 | "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" | 
|  | 72 | "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" | 
|  | 73 | "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x3e\x80\x80\x80\x3f" | 
|  | 74 | "\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x80\x80\x80\x00\x80\x80" | 
|  | 75 | "\x80\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e" | 
|  | 76 | "\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x80\x80\x80\x80\x80" | 
|  | 77 | "\x80\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28" | 
|  | 78 | "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x80\x80\x80\x80\x80" | 
|  | 79 | "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" | 
|  | 80 | "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" | 
|  | 81 | "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" | 
|  | 82 | "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\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 |  | 
|  | 88 | /** | 
|  | 89 | * | 
|  | 90 | * Caller is responsible for freeing the returned buffer. | 
|  | 91 | */ | 
|  | 92 | UINT8 *base64_decode(const CHAR8 *src, INT32 len, INT32 *out_len) | 
|  | 93 | { | 
|  | 94 | UINT8 *out; | 
|  | 95 | UINT8 *pos; | 
|  | 96 | UINT8 block[4]; | 
|  | 97 | UINT8 tmp; | 
|  | 98 | INT32 block_index; | 
|  | 99 | INT32 src_index; | 
|  | 100 | UINT32 pad_count = 0; | 
|  | 101 |  | 
|  | 102 | if (!out_len) { | 
|  | 103 | return NULL; | 
|  | 104 | } | 
|  | 105 |  | 
|  | 106 | // Malloc might be up to 2 larger dependent on padding | 
|  | 107 | *out_len = len / 4 * 3; | 
|  | 108 | pos = out = malloc(*out_len); | 
|  | 109 | if (out == NULL) { | 
|  | 110 | return NULL; | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | block_index = 0; | 
|  | 114 | for (src_index = 0; src_index < len; src_index++) { | 
|  | 115 | tmp = decode_table[(UINT8)src[src_index]]; | 
|  | 116 | if (tmp == 0x80) { | 
|  | 117 | free(out); | 
|  | 118 | return NULL; | 
|  | 119 | } | 
|  | 120 |  | 
|  | 121 | if (src[src_index] == '=') { | 
|  | 122 | pad_count++; | 
|  | 123 | } | 
|  | 124 |  | 
|  | 125 | block[block_index] = tmp; | 
|  | 126 | block_index++; | 
|  | 127 | if (block_index == 4) { | 
|  | 128 | *pos++ = (block[0] << 2) | (block[1] >> 4); | 
|  | 129 | *pos++ = (block[1] << 4) | (block[2] >> 2); | 
|  | 130 | *pos++ = (block[2] << 6) | block[3]; | 
|  | 131 | if (pad_count > 0) { | 
|  | 132 | if (pad_count == 1) { | 
|  | 133 | pos--; | 
|  | 134 | } else if (pad_count == 2) { | 
|  | 135 | pos -= 2; | 
|  | 136 | } else { | 
|  | 137 | /* Invalid pad_counting */ | 
|  | 138 | free(out); | 
|  | 139 | return NULL; | 
|  | 140 | } | 
|  | 141 | break; | 
|  | 142 | } | 
|  | 143 | block_index = 0; | 
|  | 144 | } | 
|  | 145 | } | 
|  | 146 |  | 
|  | 147 | *out_len = pos - out; | 
|  | 148 | return out; | 
|  | 149 | } |