1 /* $Id: base64.c 20800 2012-01-19 05:13:45Z m-oki $ */
2
3 /*
4 * Copyright (c) 2012, Internet Initiative Japan, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "config.h"
31
32 #include <inttypes.h>
33 #include <string.h>
34
35 #include <time.h>
36 #include <libarms.h>
37 #include <libarms_log.h>
38
39 #include <libarms/base64.h>
40
41 /*
42 * base64 implementation from xmpp_util.cpp by ebisawa@.
43 */
44 static char Base64Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
45
46 int
arms_base64_encode(char * dest,int destmax,const char * buf,int buflen)47 arms_base64_encode(char *dest, int destmax, const char *buf, int buflen)
48 {
49 int idx, rlen = 0;
50
51 while (buflen >= 3) {
52 if (destmax < 4)
53 return -1;
54
55 /* (1) */
56 idx = (buf[0] & 0xfc) >> 2;
57 *dest++ = Base64Table[idx];
58
59 /* (2) */
60 idx = ((buf[0] & 0x03) << 4) | ((buf[1] & 0xf0) >> 4);
61 *dest++ = Base64Table[idx];
62
63 /* (3) */
64 idx = ((buf[1] & 0x0f) << 2) | ((buf[2] & 0xc0) >> 6);
65 *dest++ = Base64Table[idx];
66
67 /* (4) */
68 idx = (buf[2] & 0x3f);
69 *dest++ = Base64Table[idx];
70
71 rlen += 4;
72 destmax -= 4;
73 buflen -= 3;
74 buf += 3;
75 }
76
77 /* the final quantum */
78 if (buflen >= 2) {
79 if (destmax < 4)
80 return -1;
81
82 /* (1) */
83 idx = (buf[0] & 0xfc) >> 2;
84 *dest++ = Base64Table[idx];
85
86 /* (2) */
87 idx = ((buf[0] & 0x03) << 4) | ((buf[1] & 0xf0) >> 4);
88 *dest++ = Base64Table[idx];
89
90 /* (3) */
91 idx = ((buf[1] & 0x0f) << 2);
92 *dest++ = Base64Table[idx];
93
94 *dest++ = '=';
95
96 rlen += 4;
97 } else if (buflen >= 1) {
98 if (destmax < 4)
99 return -1;
100
101 /* (1) */
102 idx = (buf[0] & 0xfc) >> 2;
103 *dest++ = Base64Table[idx];
104
105 /* (2) */
106 idx = ((buf[0] & 0x03) << 4);
107 *dest++ = Base64Table[idx];
108
109 *dest++ = '=';
110 *dest++ = '=';
111
112 rlen += 4;
113 }
114
115 return rlen;
116 }
117
118 static char modbuf[4];
119 static int modlen;
120
121 static void
arms_base64_reset_state(void)122 arms_base64_reset_state(void)
123 {
124 /* note: need to keep modbuf. */
125 modlen = 0;
126 }
127
128 int
arms_base64_decode_stream(arms_base64_stream_t * obj,char * dest,int destmax,const char * buf,int buflen)129 arms_base64_decode_stream(arms_base64_stream_t *obj, char *dest, int destmax,
130 const char *buf, int buflen)
131 {
132 int len, rlen = 0;
133
134 /* using like streaming. decode previous modulo and current buf */
135 while (obj->modlen > 0) {
136 int cplen;
137
138 /* to decode, at least need to read 4 byte data. */
139 if (obj->modlen + buflen < sizeof(obj->modbuf)) {
140 memcpy(&obj->modbuf[obj->modlen], buf, buflen);
141 obj->modlen += buflen;
142 return 0;
143 }
144 /* fill modbuf */
145 cplen = sizeof(obj->modbuf) - obj->modlen;
146 memcpy(&obj->modbuf[obj->modlen], buf, cplen);
147 buf += cplen;
148 buflen -= cplen;
149 /* decode 4 bytes */
150 len = arms_base64_decode(dest, destmax, obj->modbuf, 4);
151 if (len < 0) {
152 arms_base64_reset_state();
153 return -1;
154 }
155 /*
156 * 1: len == 0 and modlen > 0
157 * 2: len > 0 and modlen == 0
158 */
159 if (len > 0) {
160 rlen += len;
161 dest += len;
162 destmax -= len;
163 break;
164 }
165 memcpy(obj->modbuf, modbuf, sizeof(obj->modbuf));
166 obj->modlen = modlen;
167 }
168
169 len = arms_base64_decode(dest, destmax, buf, buflen);
170 if (len < 0) {
171 arms_base64_reset_state();
172 return -1;
173 }
174 memcpy(obj->modbuf, modbuf, sizeof(obj->modbuf));
175 obj->modlen = modlen;
176
177 return rlen + len;
178 }
179
180 int
arms_base64_decode(char * dest,int destmax,const char * buf,int buflen)181 arms_base64_decode(char *dest, int destmax, const char *buf, int buflen)
182 {
183 char *p;
184 int idx, rlen = 0;
185
186 arms_base64_reset_state();
187
188 while (buflen >= 4) {
189 if (destmax < 3) {
190 libarms_log(ARMS_LOG_DEBUG,
191 "base64: no space available");
192 return -1;
193 }
194
195 if (buf[0] == '\r' || buf[0] == '\n') {
196 buf++;
197 buflen--;
198 continue;
199 }
200 /* (1) */
201 if ((p = strchr(Base64Table, buf[0])) == NULL) {
202 libarms_log(ARMS_LOG_DEBUG,
203 "base64: invalid char 0x%x", buf[0]);
204 return -1;
205 }
206
207 idx = (int) (p - Base64Table);
208 dest[0] = idx << 2;
209
210 /* (2) */
211 while (buf[1] == '\r' || buf[1] == '\n') {
212 buf++;
213 buflen--;
214 if (buflen < 4) {
215 libarms_log(ARMS_LOG_DEBUG,
216 "base64: invalid input data");
217 return -1;
218 }
219 }
220 if ((p = strchr(Base64Table, buf[1])) == NULL) {
221 libarms_log(ARMS_LOG_DEBUG,
222 "base64: invalid char 0x%x", buf[1]);
223 return -1;
224 }
225
226 idx = (int) (p - Base64Table);
227 dest[0] |= idx >> 4;
228 dest[1] = (idx << 4) & 0xf0;
229
230 /* (3) */
231 while (buf[2] == '\r' || buf[2] == '\n') {
232 buf++;
233 buflen--;
234 if (buflen < 4) {
235 libarms_log(ARMS_LOG_DEBUG,
236 "base64: invalid input data");
237 return -1;
238 }
239 }
240 if (buf[2] != '=') {
241 if ((p = strchr(Base64Table, buf[2])) == NULL) {
242 libarms_log(ARMS_LOG_DEBUG,
243 "base64: invalid char 0x%x", buf[2]);
244 return -1;
245 }
246
247 idx = (int) (p - Base64Table);
248 dest[1] |= idx >> 2;
249 dest[2] = (idx << 6) & 0xc0;
250 } else {
251 rlen += 1;
252 buflen = 0;
253 break;
254 }
255
256 /* (4) */
257 while (buf[3] == '\r' || buf[3] == '\n') {
258 buf++;
259 buflen--;
260 if (buflen < 4) {
261 libarms_log(ARMS_LOG_DEBUG,
262 "base64: invalid input data");
263 return -1;
264 }
265 }
266 if (buf[3] != '=') {
267 if ((p = strchr(Base64Table, buf[3])) == NULL) {
268 libarms_log(ARMS_LOG_DEBUG,
269 "base64: invalid char 0x%x", buf[3]);
270 return -1;
271 }
272
273 idx = (int) (p - Base64Table);
274 dest[2] |= idx & 0x3f;
275 } else {
276 rlen += 2;
277 buflen = 0;
278 break;
279 }
280
281 rlen += 3;
282 buflen -= 4;
283 buf += 4;
284 destmax -= 3;
285 dest += 3;
286 }
287
288 /* modulo data is copied to static buffer */
289 modlen = buflen;
290 memcpy(modbuf, buf, modlen);
291
292 return rlen;
293 }
294