1 /*
2  * Copyright (c) 2013, Joyent, Inc.
3  * See LICENSE file for copyright and license details.
4  *
5  * Portions based on Public Domain work obtained from:
6  *  https://shell.franken.de/svn/sky/xmlstorage/trunk/c++/xmlrpc/base64.cpp
7  */
8 
9 #include "stdlib.h"
10 #include "stdio.h"
11 #include "dynstr.h"
12 #include "stdint.h"
13 
14 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
15     "abcdefghijklmnopqrstuvwxyz0123456789+/";
16 
17 void
base64_encode(uint8_t * input,size_t len,string_t * output)18 base64_encode(uint8_t *input, size_t len, string_t *output)
19 {
20 	char tmp[5];
21 	unsigned int i = 0;
22 
23 	tmp[4] = '\0';
24 	dynstr_append(output, "");
25 
26 	while (i < len) {
27 		uint32_t c = input[i++] << 16;
28 		if (i < len)
29 			c |= input[i] << 8;
30 		i++;
31 		if (i < len)
32 			c |= input[i];
33 		i++;
34 
35 		tmp[0] = base64[(c & 0x00fc0000) >> 18];
36 		tmp[1] = base64[(c & 0x0003f000) >> 12];
37 		tmp[2] = i > len + 1 ? '=' : base64[(c & 0x00000fc0) >> 6];
38 		tmp[3] = i > len ? '=' : base64[c & 0x0000003f];
39 
40 		dynstr_append(output, tmp);
41 	}
42 }
43 
44 static int
decode_one(char c)45 decode_one(char c)
46 {
47 	if (c >= 'A' && c <= 'Z')
48 		return (c - 'A');
49 	if (c >= 'a' && c <= 'z')
50 		return (c - 'a' + 26);
51 	if (c >= '0' && c <= '9')
52 		return (c - '0' + 52);
53 	if (c == '+')
54 		return (62);
55 	if (c == '/')
56 		return (63);
57 	if (c == '=')
58 		return (-1);
59 
60 	return (-2);
61 }
62 
63 int
base64_decode(const char * input,size_t len,string_t * output)64 base64_decode(const char *input, size_t len, string_t *output)
65 {
66 	int typ[4];
67 	uint8_t buf[4];
68 	unsigned int i, j;
69 
70 	buf[3] = '\0';
71 	dynstr_append(output, "");
72 
73 	/*
74 	 * Valid encoded strings are a multiple of 4 characters long:
75 	 */
76 	if (len % 4 != 0)
77 		return (-1);
78 
79 	for (i = 0; i < len; i += 4) {
80 		for (j = 0; j < 4; j++)
81 			typ[j] = decode_one(input[i + j]);
82 
83 		/*
84 		 * Filler must be contiguous on the right of the input
85 		 * string, and at most two bytes:
86 		 */
87 		if (typ[0] == -1 || typ[1] == -1)
88 			return (-1);
89 		if (typ[2] == -1 && typ[3] != -1)
90 			return (-1);
91 
92 		buf[0] = (typ[0] << 2) | (typ[1] >> 4);
93 		if (typ[2] != -1)
94 			buf[1] = ((typ[1] & 0x0f) << 4) | (typ[2] >>2);
95 		else
96 			buf[1] = '\0';
97 		if (typ[3] != -1)
98 			buf[2] = ((typ[2] & 0x03) << 6) | typ[3];
99 		else
100 			buf[2] = '\0';
101 
102 		dynstr_append(output, (const char *) buf);
103 	}
104 
105 	return (0);
106 }
107