1 /*
2  * Redistribution and use in source and binary forms, with or
3  * without modification, are permitted provided that the following
4  * conditions are met:
5  *
6  * 1. Redistributions of source code must retain the above
7  *    copyright notice, this list of conditions and the
8  *    following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above
11  *    copyright notice, this list of conditions and the following
12  *    disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19  * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 #include "base64.h"
30 /*
31  * This is part of the libb64 project, and has been placed in the
32  * public domain. For details, see
33  * http://sourceforge.net/projects/libb64
34  */
35 
36 /* {{{ encode */
37 
38 enum base64_encodestep { step_A, step_B, step_C };
39 
40 struct base64_encodestate {
41 	enum base64_encodestep step;
42 	char result;
43 	int stepcount;
44 };
45 
46 static inline void
base64_encodestate_init(struct base64_encodestate * state)47 base64_encodestate_init(struct base64_encodestate *state)
48 {
49 	state->step = step_A;
50 	state->result = 0;
51 	state->stepcount = 0;
52 }
53 
54 static inline char
base64_encode_value(char value)55 base64_encode_value(char value)
56 {
57 	static const char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
58 	unsigned codepos = (unsigned) value;
59 	if (codepos > sizeof(encoding) - 1)
60 		return '=';
61 	return encoding[codepos];
62 }
63 
64 static int
base64_encode_block(const char * in_bin,int in_len,char * out_base64,int out_len,struct base64_encodestate * state)65 base64_encode_block(const char *in_bin, int in_len,
66 		    char *out_base64, int out_len,
67 		    struct base64_encodestate *state)
68 {
69 	const char *const in_end = in_bin + in_len;
70 	const char *in_pos = in_bin;
71 	char *out_pos = out_base64;
72 	char *out_end = out_base64  + out_len;
73 	char result;
74 	char fragment;
75 
76 	result = state->result;
77 
78 	switch (state->step)
79 	{
80 		while (1)
81 		{
82 	case step_A:
83 			if (in_pos == in_end || out_pos >= out_end) {
84 				state->result = result;
85 				state->step = step_A;
86 				return out_pos - out_base64;
87 			}
88 			fragment = *in_pos++;
89 			result = (fragment & 0x0fc) >> 2;
90 			*out_pos++ = base64_encode_value(result);
91 			result = (fragment & 0x003) << 4;
92 			/* fallthrough */
93 	case step_B:
94 			if (in_pos == in_end || out_pos >= out_end) {
95 				state->result = result;
96 				state->step = step_B;
97 				return out_pos - out_base64;
98 			}
99 			fragment = *in_pos++;
100 			result |= (fragment & 0x0f0) >> 4;
101 			*out_pos++ = base64_encode_value(result);
102 			result = (fragment & 0x00f) << 2;
103 			/* fallthrough */
104 	case step_C:
105 			if (in_pos == in_end || out_pos + 2 >= out_end) {
106 				state->result = result;
107 				state->step = step_C;
108 				return out_pos - out_base64;
109 			}
110 			fragment = *in_pos++;
111 			result |= (fragment & 0x0c0) >> 6;
112 			*out_pos++ = base64_encode_value(result);
113 			result  = (fragment & 0x03f) >> 0;
114 			*out_pos++ = base64_encode_value(result);
115 
116 			/*
117 			 * Each full step (A->B->C) yields
118 			 * 4 characters.
119 			 */
120 			if (++state->stepcount * 4 == BASE64_CHARS_PER_LINE) {
121 				if (out_pos >= out_end)
122 					return out_pos - out_base64;
123 				*out_pos++ = '\n';
124 				state->stepcount = 0;
125 			}
126 		}
127 	}
128 	/* control should not reach here */
129 	return out_pos - out_base64;
130 }
131 
132 static int
base64_encode_blockend(char * out_base64,int out_len,struct base64_encodestate * state)133 base64_encode_blockend(char *out_base64, int out_len,
134 		       struct base64_encodestate *state)
135 {
136 	char *out_pos = out_base64;
137 	char *out_end = out_base64 + out_len;
138 
139 	switch (state->step) {
140 	case step_B:
141 		if (out_pos + 2 >= out_end)
142 			return out_pos - out_base64;
143 		*out_pos++ = base64_encode_value(state->result);
144 		*out_pos++ = '=';
145 		*out_pos++ = '=';
146 		break;
147 	case step_C:
148 		if (out_pos + 1 >= out_end)
149 			return out_pos - out_base64;
150 		*out_pos++ = base64_encode_value(state->result);
151 		*out_pos++ = '=';
152 		break;
153 	case step_A:
154 		break;
155 	}
156 	if (out_pos >= out_end)
157 		return out_pos - out_base64;
158 #if 0
159 	/* Sometimes the output is useful without a newline. */
160 	*out_pos++ = '\n';
161 	if (out_pos >= out_end)
162 		return out_pos - out_base64;
163 #endif
164 	*out_pos = '\0';
165 	return out_pos - out_base64;
166 }
167 
168 int
base64_encode(const char * in_bin,int in_len,char * out_base64,int out_len)169 base64_encode(const char *in_bin, int in_len,
170 	      char *out_base64, int out_len)
171 {
172 	struct base64_encodestate state;
173 	base64_encodestate_init(&state);
174 	int res = base64_encode_block(in_bin, in_len, out_base64,
175 				      out_len, &state);
176 	return res + base64_encode_blockend(out_base64 + res, out_len - res,
177 					    &state);
178 }
179 
180 /* }}} */
181 
182 /* {{{ decode */
183 
184 enum base64_decodestep { step_a, step_b, step_c, step_d };
185 
186 struct base64_decodestate
187 {
188 	enum base64_decodestep step;
189 	char result;
190 };
191 
192 static char
base64_decode_value(char value)193 base64_decode_value(char value)
194 {
195 	static const char decoding[] = {
196 		62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58,
197 		59, 60, 61, -1, -1, -1, -2, -1, -1, -1,  0,  1,
198 		2,   3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13,
199 		14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
200 		-1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
201 		32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
202 		44, 45, 46, 47, 48, 49, 50, 51
203 	};
204 	static const char decoding_size = sizeof(decoding);
205 	int codepos = (signed char) value;
206 	codepos -= 43;
207 	if (codepos < 0 || codepos > decoding_size)
208 		return -1;
209 	return decoding[codepos];
210 }
211 
212 static inline void
base64_decodestate_init(struct base64_decodestate * state)213 base64_decodestate_init(struct base64_decodestate *state)
214 {
215 	state->step = step_a;
216 	state->result = 0;
217 }
218 
219 static int
base64_decode_block(const char * in_base64,int in_len,char * out_bin,int out_len,struct base64_decodestate * state)220 base64_decode_block(const char *in_base64, int in_len,
221 		    char *out_bin, int out_len,
222 		    struct base64_decodestate *state)
223 {
224 	const char *in_pos = in_base64;
225 	const char *in_end = in_base64 + in_len;
226 	char *out_pos = out_bin;
227 	char *out_end = out_bin + out_len;
228 	char fragment;
229 
230 	*out_pos = state->result;
231 
232 	switch (state->step)
233 	{
234 		while (1)
235 		{
236 	case step_a:
237 			do {
238 				if (in_pos == in_end || out_pos >= out_end)
239 				{
240 					state->step = step_a;
241 					state->result = *out_pos;
242 					return out_pos - out_bin;
243 				}
244 				fragment = base64_decode_value(*in_pos++);
245 			} while (fragment < 0);
246 			*out_pos    = (fragment & 0x03f) << 2;
247 			/* fallthrough */
248 	case step_b:
249 			do {
250 				if (in_pos == in_end || out_pos >= out_end)
251 				{
252 					state->step = step_b;
253 					state->result = *out_pos;
254 					return out_pos - out_bin;
255 				}
256 				fragment = base64_decode_value(*in_pos++);
257 			} while (fragment < 0);
258 			*out_pos++ |= (fragment & 0x030) >> 4;
259 			if (out_pos < out_end)
260 				*out_pos = (fragment & 0x00f) << 4;
261 			/* fallthrough */
262 	case step_c:
263 			do {
264 				if (in_pos == in_end || out_pos >= out_end)
265 				{
266 					state->step = step_c;
267 					state->result = *out_pos;
268 					return out_pos - out_bin;
269 				}
270 				fragment = base64_decode_value(*in_pos++);
271 			} while (fragment < 0);
272 			*out_pos++ |= (fragment & 0x03c) >> 2;
273 			if (out_pos < out_end)
274 				*out_pos = (fragment & 0x003) << 6;
275 			/* fallthrough */
276 	case step_d:
277 			do {
278 				if (in_pos == in_end || out_pos >= out_end)
279 				{
280 					state->step = step_d;
281 					state->result = *out_pos;
282 					return out_pos - out_bin;
283 				}
284 				fragment = base64_decode_value(*in_pos++);
285 			} while (fragment < 0);
286 			*out_pos++   |= (fragment & 0x03f);
287 		}
288 	}
289 	/* control should not reach here */
290 	return out_pos - out_bin;
291 }
292 
293 
294 
295 int
base64_decode(const char * in_base64,int in_len,char * out_bin,int out_len)296 base64_decode(const char *in_base64, int in_len,
297 	      char *out_bin, int out_len)
298 {
299 	struct base64_decodestate state;
300 	base64_decodestate_init(&state);
301 	return base64_decode_block(in_base64, in_len,
302 				   out_bin, out_len, &state);
303 }
304 
305 /* }}} */
306