blob: 38ea0ab8f472f13939c98cf6ae673de821bb25fe [file] [log] [blame]
Thu Nguyene42fb482024-10-15 14:43:11 +00001#include <libcper/base64.h>
2#include <libcper/BaseTypes.h>
Ed Tanousa7d2cdd2024-07-15 11:07:27 -07003
4#include <stdlib.h>
5#include <string.h>
6#include <stdio.h>
7#include <assert.h>
8
9static const UINT8 encode_table[65] =
10 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
11
12/**
13 *
14 * Caller is responsible for freeing the returned buffer.
15 */
16CHAR8 *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.
70UINT8 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 */
92UINT8 *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}