xref: /openbmc/libcper/base64.c (revision a7d2cddd)
1 #include "base64.h"
2 #include "edk/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  */
base64_encode(const UINT8 * src,INT32 len,INT32 * out_len)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  */
base64_decode(const CHAR8 * src,INT32 len,INT32 * out_len)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 }
150