1 /**
2  * @file b64.c  Base64 encoding/decoding functions
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #include <re_types.h>
7 #include <re_fmt.h>
8 #include <re_base64.h>
9 
10 
11 static const char b64_table[65] =
12 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
13 	"abcdefghijklmnopqrstuvwxyz"
14 	"0123456789+/";
15 
16 
17 /**
18  * Base-64 encode a buffer
19  *
20  * @param in   Input buffer
21  * @param ilen Length of input buffer
22  * @param out  Output buffer
23  * @param olen Size of output buffer, actual written on return
24  *
25  * @return 0 if success, otherwise errorcode
26  */
base64_encode(const uint8_t * in,size_t ilen,char * out,size_t * olen)27 int base64_encode(const uint8_t *in, size_t ilen, char *out, size_t *olen)
28 {
29 	const uint8_t *in_end = in + ilen;
30 	const char *o = out;
31 
32 	if (!in || !out || !olen)
33 		return EINVAL;
34 
35 	if (*olen < 4 * ((ilen+2)/3))
36 		return EOVERFLOW;
37 
38 	for (; in < in_end; ) {
39 		uint32_t v;
40 		int pad = 0;
41 
42 		v  = *in++ << 16;
43 		if (in < in_end) {
44 			v |= *in++ << 8;
45 		}
46 		else {
47 			++pad;
48 		}
49 		if (in < in_end) {
50 			v |= *in++ << 0;
51 		}
52 		else {
53 			++pad;
54 		}
55 
56 		*out++ = b64_table[v>>18 & 0x3f];
57 		*out++ = b64_table[v>>12 & 0x3f];
58 		*out++ = (pad >= 2) ? '=' : b64_table[v>>6  & 0x3f];
59 		*out++ = (pad >= 1) ? '=' : b64_table[v>>0  & 0x3f];
60 	}
61 
62 	*olen = out - o;
63 
64 	return 0;
65 }
66 
67 
base64_print(struct re_printf * pf,const uint8_t * ptr,size_t len)68 int base64_print(struct re_printf *pf, const uint8_t *ptr, size_t len)
69 {
70 	char buf[256];
71 
72 	if (!pf || !ptr)
73 		return EINVAL;
74 
75 	while (len > 0) {
76 		size_t l, sz = sizeof(buf);
77 		int err;
78 
79 		l = min(len, 3 * (sizeof(buf)/4));
80 
81 		err = base64_encode(ptr, l, buf, &sz);
82 		if (err)
83 			return err;
84 
85 		err = pf->vph(buf, sz, pf->arg);
86 		if (err)
87 			return err;
88 
89 		ptr += l;
90 		len -= l;
91 	}
92 
93 	return 0;
94 }
95 
96 
97 /* convert char -> 6-bit value */
b64val(char c)98 static inline uint32_t b64val(char c)
99 {
100 	if ('A' <= c && c <= 'Z')
101 		return c - 'A' + 0;
102 	else if ('a' <= c && c <= 'z')
103 		return c - 'a' + 26;
104 	else if ('0' <= c && c <= '9')
105 		return c - '0' + 52;
106 	else if ('+' == c)
107 		return 62;
108 	else if ('/' == c)
109 		return 63;
110 	else if ('=' == c)
111 		return 1<<24; /* special trick */
112 	else
113 		return 0;
114 }
115 
116 
117 /**
118  * Decode a Base-64 encoded string
119  *
120  * @param in   Input buffer
121  * @param ilen Length of input buffer
122  * @param out  Output buffer
123  * @param olen Size of output buffer, actual written on return
124  *
125  * @return 0 if success, otherwise errorcode
126  */
base64_decode(const char * in,size_t ilen,uint8_t * out,size_t * olen)127 int base64_decode(const char *in, size_t ilen, uint8_t *out, size_t *olen)
128 {
129 	const char *in_end = in + ilen;
130 	const uint8_t *o = out;
131 
132 	if (!in || !out || !olen)
133 		return EINVAL;
134 
135 	if (*olen < 3 * (ilen/4))
136 		return EOVERFLOW;
137 
138 	for (;in+3 < in_end; ) {
139 		uint32_t v;
140 
141 		v  = b64val(*in++) << 18;
142 		v |= b64val(*in++) << 12;
143 		v |= b64val(*in++) << 6;
144 		v |= b64val(*in++) << 0;
145 
146 		*out++ = v>>16;
147 		if (!(v & (1<<30)))
148 			*out++ = (v>>8) & 0xff;
149 		if (!(v & (1<<24)))
150 			*out++ = (v>>0) & 0xff;
151 	}
152 
153 	*olen = out - o;
154 
155 	return 0;
156 }
157