Skip to content

Commit 81b2092

Browse files
rustyrussellcdecker
authored andcommitted
CCAN: add base64 module.
Signed-off-by: Rusty Russell <[email protected]>
1 parent 9c254c8 commit 81b2092

File tree

7 files changed

+992
-0
lines changed

7 files changed

+992
-0
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ CCAN_HEADERS := \
146146
$(CCANDIR)/ccan/alignof/alignof.h \
147147
$(CCANDIR)/ccan/array_size/array_size.h \
148148
$(CCANDIR)/ccan/asort/asort.h \
149+
$(CCANDIR)/ccan/base64/base64.h \
149150
$(CCANDIR)/ccan/bitmap/bitmap.h \
150151
$(CCANDIR)/ccan/bitops/bitops.h \
151152
$(CCANDIR)/ccan/breakpoint/breakpoint.h \

ccan/ccan/base64/LICENSE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../licenses/BSD-MIT

ccan/ccan/base64/_info

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include "config.h"
2+
3+
/**
4+
* base64 - base64 encoding and decoding (rfc4648).
5+
*
6+
* base64 encoding is used to encode data in a 7-bit clean manner.
7+
* Commonly used for escaping data before encapsulation or transfer
8+
*
9+
* Example:
10+
* #include <stdio.h>
11+
* #include <string.h>
12+
* #include <ccan/base64/base64.h>
13+
*
14+
* int main(int argc, char *argv[])
15+
* {
16+
* char *base64_encoded_string;
17+
* int i;
18+
*
19+
* // print the base64-encoded form of the program arguments
20+
* for(i=1;i<argc;i++) {
21+
* size_t unencoded_length = strlen(argv[i]);
22+
* size_t encoded_length = base64_encoded_length(unencoded_length);
23+
* base64_encoded_string = malloc(encoded_length);
24+
* base64_encode(base64_encoded_string, encoded_length,
25+
* argv[i], unencoded_length);
26+
* printf("%s\n", base64_encoded_string);
27+
* free(base64_encoded_string);
28+
* }
29+
*
30+
* return 0;
31+
* }
32+
*
33+
* License: BSD-MIT
34+
*/
35+
int main(int argc, char *argv[])
36+
{
37+
if (argc != 2)
38+
return 1;
39+
40+
return 1;
41+
}

ccan/ccan/base64/base64.c

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/* Licensed under BSD-MIT - see LICENSE file for details */
2+
#include "base64.h"
3+
4+
#include <errno.h>
5+
#include <string.h>
6+
#include <assert.h>
7+
#include <stdint.h>
8+
9+
/**
10+
* sixbit_to_b64 - maps a 6-bit value to the base64 alphabet
11+
* @param map A base 64 map (see base64_init_map)
12+
* @param sixbit Six-bit value to map
13+
* @return a base 64 character
14+
*/
15+
static char sixbit_to_b64(const base64_maps_t *maps, const uint8_t sixbit)
16+
{
17+
assert(sixbit <= 63);
18+
19+
return maps->encode_map[(unsigned char)sixbit];
20+
}
21+
22+
/**
23+
* sixbit_from_b64 - maps a base64-alphabet character to its 6-bit value
24+
* @param maps A base 64 maps structure (see base64_init_maps)
25+
* @param sixbit Six-bit value to map
26+
* @return a six-bit value
27+
*/
28+
static int8_t sixbit_from_b64(const base64_maps_t *maps,
29+
const unsigned char b64letter)
30+
{
31+
int8_t ret;
32+
33+
ret = maps->decode_map[(unsigned char)b64letter];
34+
if (ret == (char)0xff) {
35+
errno = EDOM;
36+
return -1;
37+
}
38+
39+
return ret;
40+
}
41+
42+
bool base64_char_in_alphabet(const base64_maps_t *maps, const char b64char)
43+
{
44+
return (maps->decode_map[(const unsigned char)b64char] != (char)0xff);
45+
}
46+
47+
void base64_init_maps(base64_maps_t *dest, const char src[64])
48+
{
49+
unsigned char i;
50+
51+
memcpy(dest->encode_map,src,64);
52+
memset(dest->decode_map,0xff,256);
53+
for (i=0; i<64; i++) {
54+
dest->decode_map[(unsigned char)src[i]] = i;
55+
}
56+
}
57+
58+
size_t base64_encoded_length(size_t srclen)
59+
{
60+
return ((srclen + 2) / 3) * 4;
61+
}
62+
63+
void base64_encode_triplet_using_maps(const base64_maps_t *maps,
64+
char dest[4], const char src[3])
65+
{
66+
char a = src[0];
67+
char b = src[1];
68+
char c = src[2];
69+
70+
dest[0] = sixbit_to_b64(maps, (a & 0xfc) >> 2);
71+
dest[1] = sixbit_to_b64(maps, ((a & 0x3) << 4) | ((b & 0xf0) >> 4));
72+
dest[2] = sixbit_to_b64(maps, ((c & 0xc0) >> 6) | ((b & 0xf) << 2));
73+
dest[3] = sixbit_to_b64(maps, c & 0x3f);
74+
}
75+
76+
void base64_encode_tail_using_maps(const base64_maps_t *maps, char dest[4],
77+
const char *src, const size_t srclen)
78+
{
79+
char longsrc[3] = { 0 };
80+
81+
assert(srclen <= 3);
82+
83+
memcpy(longsrc, src, srclen);
84+
base64_encode_triplet_using_maps(maps, dest, longsrc);
85+
memset(dest+1+srclen, '=', 3-srclen);
86+
}
87+
88+
ssize_t base64_encode_using_maps(const base64_maps_t *maps,
89+
char *dest, const size_t destlen,
90+
const char *src, const size_t srclen)
91+
{
92+
size_t src_offset = 0;
93+
size_t dest_offset = 0;
94+
95+
if (destlen < base64_encoded_length(srclen)) {
96+
errno = EOVERFLOW;
97+
return -1;
98+
}
99+
100+
while (srclen - src_offset >= 3) {
101+
base64_encode_triplet_using_maps(maps, &dest[dest_offset], &src[src_offset]);
102+
src_offset += 3;
103+
dest_offset += 4;
104+
}
105+
106+
if (src_offset < srclen) {
107+
base64_encode_tail_using_maps(maps, &dest[dest_offset], &src[src_offset], srclen-src_offset);
108+
dest_offset += 4;
109+
}
110+
111+
memset(&dest[dest_offset], '\0', destlen-dest_offset);
112+
113+
return dest_offset;
114+
}
115+
116+
size_t base64_decoded_length(size_t srclen)
117+
{
118+
return ((srclen+3)/4*3);
119+
}
120+
121+
int base64_decode_quartet_using_maps(const base64_maps_t *maps, char dest[3],
122+
const char src[4])
123+
{
124+
signed char a;
125+
signed char b;
126+
signed char c;
127+
signed char d;
128+
129+
a = sixbit_from_b64(maps, src[0]);
130+
b = sixbit_from_b64(maps, src[1]);
131+
c = sixbit_from_b64(maps, src[2]);
132+
d = sixbit_from_b64(maps, src[3]);
133+
134+
if ((a == -1) || (b == -1) || (c == -1) || (d == -1)) {
135+
return -1;
136+
}
137+
138+
dest[0] = (a << 2) | (b >> 4);
139+
dest[1] = ((b & 0xf) << 4) | (c >> 2);
140+
dest[2] = ((c & 0x3) << 6) | d;
141+
142+
return 0;
143+
}
144+
145+
146+
int base64_decode_tail_using_maps(const base64_maps_t *maps, char dest[3],
147+
const char * src, const size_t srclen)
148+
{
149+
char longsrc[4];
150+
int quartet_result;
151+
size_t insize = srclen;
152+
153+
while (insize != 0 &&
154+
src[insize-1] == '=') { /* throw away padding symbols */
155+
insize--;
156+
}
157+
if (insize == 0) {
158+
return 0;
159+
}
160+
if (insize == 1) {
161+
/* the input is malformed.... */
162+
errno = EINVAL;
163+
return -1;
164+
}
165+
memcpy(longsrc, src, insize);
166+
memset(longsrc+insize, 'A', 4-insize);
167+
quartet_result = base64_decode_quartet_using_maps(maps, dest, longsrc);
168+
if (quartet_result == -1) {
169+
return -1;
170+
}
171+
172+
return insize - 1;
173+
}
174+
175+
ssize_t base64_decode_using_maps(const base64_maps_t *maps,
176+
char *dest, const size_t destlen,
177+
const char *src, const size_t srclen)
178+
{
179+
ssize_t dest_offset = 0;
180+
ssize_t i;
181+
size_t more;
182+
183+
if (destlen < base64_decoded_length(srclen)) {
184+
errno = EOVERFLOW;
185+
return -1;
186+
}
187+
188+
for(i=0; srclen - i > 4; i+=4) {
189+
if (base64_decode_quartet_using_maps(maps, &dest[dest_offset], &src[i]) == -1) {
190+
return -1;
191+
}
192+
dest_offset += 3;
193+
}
194+
195+
more = base64_decode_tail_using_maps(maps, &dest[dest_offset], &src[i], srclen - i);
196+
if (more == -1) {
197+
return -1;
198+
}
199+
dest_offset += more;
200+
201+
memset(&dest[dest_offset], '\0', destlen-dest_offset);
202+
203+
return dest_offset;
204+
}
205+
206+
207+
208+
209+
/**
210+
* base64_maps_rfc4648 - pregenerated maps struct for rfc4648
211+
*/
212+
const base64_maps_t base64_maps_rfc4648 = {
213+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
214+
215+
"\xff\xff\xff\xff\xff" /* 0 */ \
216+
"\xff\xff\xff\xff\xff" /* 5 */ \
217+
"\xff\xff\xff\xff\xff" /* 10 */ \
218+
"\xff\xff\xff\xff\xff" /* 15 */ \
219+
"\xff\xff\xff\xff\xff" /* 20 */ \
220+
"\xff\xff\xff\xff\xff" /* 25 */ \
221+
"\xff\xff\xff\xff\xff" /* 30 */ \
222+
"\xff\xff\xff\xff\xff" /* 35 */ \
223+
"\xff\xff\xff\x3e\xff" /* 40 */ \
224+
"\xff\xff\x3f\x34\x35" /* 45 */ \
225+
"\x36\x37\x38\x39\x3a" /* 50 */ \
226+
"\x3b\x3c\x3d\xff\xff" /* 55 */ \
227+
"\xff\xff\xff\xff\xff" /* 60 */ \
228+
"\x00\x01\x02\x03\x04" /* 65 A */ \
229+
"\x05\x06\x07\x08\x09" /* 70 */ \
230+
"\x0a\x0b\x0c\x0d\x0e" /* 75 */ \
231+
"\x0f\x10\x11\x12\x13" /* 80 */ \
232+
"\x14\x15\x16\x17\x18" /* 85 */ \
233+
"\x19\xff\xff\xff\xff" /* 90 */ \
234+
"\xff\xff\x1a\x1b\x1c" /* 95 */ \
235+
"\x1d\x1e\x1f\x20\x21" /* 100 */ \
236+
"\x22\x23\x24\x25\x26" /* 105 */ \
237+
"\x27\x28\x29\x2a\x2b" /* 110 */ \
238+
"\x2c\x2d\x2e\x2f\x30" /* 115 */ \
239+
"\x31\x32\x33\xff\xff" /* 120 */ \
240+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 125 */ \
241+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
242+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
243+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 155 */ \
244+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
245+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
246+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 185 */ \
247+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
248+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
249+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 215 */ \
250+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
251+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
252+
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 245 */
253+
};

0 commit comments

Comments
 (0)