blob: a2358754b986d2118aac006d3879a886cf007ba2 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
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
11static 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 */
27int 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
68int 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 */
98static 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 */
127int 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}