1 /*
2  * Copyright (c) 2000, 2001, 2002 X-Way Rights BV
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  */
19 
20 /*!\file base64.c
21  * \brief Base64 encoding and decoding.
22  * \author Bob Deblier <bob.deblier@telenet.be>
23  */
24 
25 #define BEECRYPT_DLL_EXPORT
26 
27 #if HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 
31 #include "beecrypt/base64.h"
32 
33 #if HAVE_ENDIAN_H && HAVE_ASM_BYTEORDER_H
34 # include <endian.h>
35 #endif
36 
37 #include "beecrypt/endianness.h"
38 
39 #if HAVE_CTYPE_H
40 # include <ctype.h>
41 #endif
42 
43 static const char* to_b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
44 
45 /* encode 64 characters per line */
46 #define CHARS_PER_LINE	64
47 
b64enc(const memchunk * chunk)48 char* b64enc(const memchunk* chunk)
49 {
50 	int div = chunk->size / 3;
51 	int rem = chunk->size % 3;
52 	int chars = div*4 + rem + 1;
53 	int newlines = (chars + CHARS_PER_LINE - 1) / CHARS_PER_LINE;
54 
55 	const byte* data = chunk->data;
56 	char* string = (char*) malloc(chars + newlines + 1);
57 
58 	if (string)
59 	{
60 		register char* buf = string;
61 
62 		chars = 0;
63 
64 		while (div > 0)
65 		{
66 			buf[0] = to_b64[ (data[0] >> 2) & 0x3f];
67 			buf[1] = to_b64[((data[0] << 4) & 0x30) | ((data[1] >> 4) & 0xf)];
68 			buf[2] = to_b64[((data[1] << 2) & 0x3c) | ((data[2] >> 6) & 0x3)];
69 			buf[3] = to_b64[  data[2] & 0x3f];
70 			data += 3;
71 			buf += 4;
72 			div--;
73 			chars += 4;
74 			if (chars == CHARS_PER_LINE)
75 			{
76 				chars = 0;
77 				*(buf++) = '\n';
78 			}
79 		}
80 
81 		switch (rem)
82 		{
83 		case 2:
84 			buf[0] = to_b64[ (data[0] >> 2) & 0x3f];
85 			buf[1] = to_b64[((data[0] << 4) & 0x30) + ((data[1] >> 4) & 0xf)];
86 			buf[2] = to_b64[ (data[1] << 2) & 0x3c];
87 			buf[3] = '=';
88 			buf += 4;
89 			chars += 4;
90 			break;
91 		case 1:
92 			buf[0] = to_b64[ (data[0] >> 2) & 0x3f];
93 			buf[1] = to_b64[ (data[0] << 4) & 0x30];
94 			buf[2] = '=';
95 			buf[3] = '=';
96 			buf += 4;
97 			chars += 4;
98 			break;
99 		}
100 
101 	/* 	*(buf++) = '\n'; This would result in a buffer overrun */
102 		*buf = '\0';
103 	}
104 
105 	return string;
106 }
107 
b64dec(const char * string)108 memchunk* b64dec(const char* string)
109 {
110 	/* return a decoded memchunk, or a null pointer in case of failure */
111 
112 	memchunk* rc = 0;
113 
114 	if (string)
115 	{
116 		register int length = strlen(string);
117 
118 		/* do a format verification first */
119 		if (length > 0)
120 		{
121 			register int count = 0, rem = 0;
122 			register const char* tmp = string;
123 
124 			while (length > 0)
125 			{
126 				register int skip = strspn(tmp, to_b64);
127 				count += skip;
128 				length -= skip;
129 				tmp += skip;
130 				if (length > 0)
131 				{
132 					register int i, vrfy = strcspn(tmp, to_b64);
133 
134 					for (i = 0; i < vrfy; i++)
135 					{
136 						if (isspace(tmp[i]))
137 							continue;
138 
139 						if (tmp[i] == '=')
140 						{
141 							/* we should check if we're close to the end of the string */
142 							rem = count % 4;
143 
144 							/* rem must be either 2 or 3, otherwise no '=' should be here */
145 							if (rem < 2)
146 								return 0;
147 
148 							/* end-of-message recognized */
149 							break;
150 						}
151 						else
152 						{
153 							/* Transmission error; RFC tells us to ignore this, but:
154 							 *  - the rest of the message is going to even more corrupt since we're sliding bits out of place
155 							 * If a message is corrupt, it should be dropped. Period.
156 							 */
157 
158 							return 0;
159 						}
160 					}
161 
162 					length -= vrfy;
163 					tmp += vrfy;
164 				}
165 			}
166 
167 			rc = memchunkAlloc((count / 4) * 3 + (rem ? (rem - 1) : 0));
168 
169 			if (rc)
170 			{
171 				if (count > 0)
172 				{
173 					register int i, qw = 0, tw = 0;
174 					register byte* data = rc->data;
175 
176 					length = strlen(tmp = string);
177 
178 					for (i = 0; i < length; i++)
179 					{
180 						register char ch = string[i];
181 						register byte bits = 0;
182 
183 						if (isspace(ch))
184 							continue;
185 
186 						if ((ch >= 'A') && (ch <= 'Z'))
187 						{
188 							bits = (byte) (ch - 'A');
189 						}
190 						else if ((ch >= 'a') && (ch <= 'z'))
191 						{
192 							bits = (byte) (ch - 'a' + 26);
193 						}
194 						else if ((ch >= '0') && (ch <= '9'))
195 						{
196 							bits = (byte) (ch - '0' + 52);
197 						}
198 						else if (ch == '+')
199 						{
200 							bits = 62;
201 						}
202 						else if (ch == '/')
203 						{
204 							bits = 63;
205 						}
206 						else if (ch == '=')
207 							break;
208 
209 						switch (qw++)
210 						{
211 						case 0:
212 							data[tw+0] = (bits << 2) & 0xfc;
213 							break;
214 						case 1:
215 							data[tw+0] |= (bits >> 4) & 0x03;
216 							data[tw+1] = (bits << 4) & 0xf0;
217 							break;
218 						case 2:
219 							data[tw+1] |= (bits >> 2) & 0x0f;
220 							data[tw+2] = (bits << 6) & 0xc0;
221 							break;
222 						case 3:
223 							data[tw+2] |= bits & 0x3f;
224 							break;
225 						}
226 
227 						if (qw == 4)
228 						{
229 							qw = 0;
230 							tw += 3;
231 						}
232 					}
233 				}
234 			}
235 		}
236 	}
237 
238 	return rc;
239 }
240 
241 int b64encode_chars_per_line = B64ENCODE_CHARS_PER_LINE;
242 
243 const char * b64encode_eolstr = B64ENCODE_EOLSTR;
244 
b64encode(const void * data,size_t ns)245 char* b64encode(const void* data, size_t ns)
246 {
247 	static char b64enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
248 	const char *e;
249 	const unsigned char *s = data;
250 	unsigned char *t, *te;
251 	int nt;
252 	int lc;
253 	unsigned c;
254 
255 	if (s == NULL) return NULL;
256 
257 	if (ns == 0) ns = strlen((const char*) s);
258 	nt = ((ns + 2) / 3) * 4;
259 
260 	/* Add additional bytes necessary for eol string(s). */
261 	if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL)
262 	{
263 		lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line;
264 		if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0)
265 			++lc;
266 		nt += lc * strlen(b64encode_eolstr);
267 	}
268 
269 	t = te = malloc(nt + 1);
270 
271 	lc = 0;
272 	if (te)
273 	{
274 		while (ns > 0)
275 		{
276 			c = *s++;
277 			*te++ = b64enc[ (c >> 2) ], lc++;
278 			*te++ = b64enc[ ((c & 0x3) << 4) | (((ns-1) > 0 ? *s : 0) >> 4) ], lc++;
279 			if (--ns == 0)
280 			{
281 				*te++ = '=';
282 				*te++ = '=';
283 				continue;
284 			}
285 			c = *s++;
286 			*te++ = b64enc[ ((c & 0xf) << 2) | (((ns-1) > 0 ? *s : 0) >> 6) ], lc++;
287 			if (--ns == 0)
288 			{
289 				*te++ = '=';
290 				continue;
291 			}
292 			*te++ = b64enc[ (int)(*s & 0x3f) ], lc++;
293 
294 			/* Append eol string if desired. */
295 			if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL)
296 			{
297 				if (lc >= b64encode_chars_per_line)
298 				{
299 					for (e = b64encode_eolstr; *e != '\0'; e++)
300 						*te++ = *e;
301 					lc = 0;
302 				}
303 			}
304 			s++;
305 			--ns;
306 		}
307 
308 		/* Append eol string if desired. */
309 		if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL)
310 		{
311 			if (lc != 0)
312 			{
313 				for (e = b64encode_eolstr; *e != '\0'; e++)
314 					*te++ = *e;
315 			}
316 		}
317 		*te = '\0';
318 	}
319 
320 	return (char*) t;
321 }
322 
323 #define CRC24_INIT 0xb704ceL
324 #define CRC24_POLY 0x1864cfbL
325 
b64crc(const unsigned char * data,size_t ns)326 char* b64crc (const unsigned char* data, size_t ns)
327 {
328 	const unsigned char *s = data;
329 	uint32_t crc = CRC24_INIT;
330 
331 	while (ns-- > 0)
332 	{
333 		int i;
334 		crc ^= (*s++) << 16;
335 		for (i = 0; i < 8; i++)
336 		{
337 			crc <<= 1;
338 			if (crc & 0x1000000)
339 			crc ^= CRC24_POLY;
340 		}
341 	}
342 	crc &= 0xffffff;
343 	#if !WORDS_BIGENDIAN
344 	crc = swapu32(crc);
345 	#endif
346 	data = (byte *)&crc;
347 	data++;
348 	ns = 3;
349 
350 	return b64encode(data, ns);
351 }
352 
353 const char* b64decode_whitespace = B64DECODE_WHITESPACE;
354 
b64decode(const char * s,void ** datap,size_t * lenp)355 int b64decode(const char* s, void** datap, size_t* lenp)
356 {
357 	unsigned char b64dec[256];
358 	const unsigned char *t;
359 	unsigned char *te;
360 	int ns, nt;
361 	unsigned a, b, c, d;
362 
363 	if (s == NULL)	return 1;
364 
365 	/* Setup character lookup tables. */
366 	memset(b64dec, 0x80, sizeof(b64dec));
367 	for (c = 'A'; c <= 'Z'; c++)
368 		b64dec[ c ] = 0 + (c - 'A');
369 	for (c = 'a'; c <= 'z'; c++)
370 		b64dec[ c ] = 26 + (c - 'a');
371 	for (c = '0'; c <= '9'; c++)
372 		b64dec[ c ] = 52 + (c - '0');
373 	b64dec[(unsigned)'+'] = 62;
374 	b64dec[(unsigned)'/'] = 63;
375 	b64dec[(unsigned)'='] = 0;
376 
377 	/* Mark whitespace characters. */
378 	if (b64decode_whitespace)
379 	{
380 		const char *e;
381 		for (e = b64decode_whitespace; *e != '\0'; e++)
382 		{
383 			if (b64dec[ (unsigned)*e ] == 0x80)
384 				b64dec[ (unsigned)*e ] = 0x81;
385 		}
386 	}
387 
388 	/* Validate input buffer */
389 	ns = 0;
390 	for (t = (unsigned char*) s; *t != '\0'; t++)
391 	{
392 		switch (b64dec[(unsigned) *t])
393 		{
394 		case 0x80:	/* invalid chararcter */
395 			return 3;
396 		case 0x81:	/* white space */
397 			break;
398 		default:
399 			ns++;
400 			break;
401 		}
402 	}
403 
404 	if (((unsigned) ns) & 0x3)	return 2;
405 
406 	nt = (ns / 4) * 3;
407 	t = te = malloc(nt + 1);
408 
409 	while (ns > 0)
410 	{
411 		/* Get next 4 characters, ignoring whitespace. */
412 		while ((a = b64dec[ (unsigned)*s++ ]) == 0x81)
413 			;
414 		while ((b = b64dec[ (unsigned)*s++ ]) == 0x81)
415 			;
416 		while ((c = b64dec[ (unsigned)*s++ ]) == 0x81)
417 			;
418 		while ((d = b64dec[ (unsigned)*s++ ]) == 0x81)
419 			;
420 
421 		ns -= 4;
422 		*te++ = (a << 2) | (b >> 4);
423 		if (s[-2] == '=') break;
424 		*te++ = (b << 4) | (c >> 2);
425 		if (s[-1] == '=') break;
426 		*te++ = (c << 6) | d;
427 	}
428 
429 	if (ns != 0)
430 	{	/* XXX can't happen, just in case */
431 		if (t) free((void *)t);
432 		return 1;
433 	}
434 	if (lenp)
435 		*lenp = (te - t);
436 
437 	if (datap)
438 		*datap = (void *)t;
439 	else
440 		if (t) free((void *)t);
441 
442 	return 0;
443 }
444