1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * Generic base 64 input and output routines
21 *
22 * Written by Kern E. Sibbald, March MM.
23 */
24
25
26 #include "bacula.h"
27
28
29 #ifdef TEST_MODE
30 #include <glob.h>
31 #endif
32
33
34 static uint8_t const base64_digits[64] =
35 {
36 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
37 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
38 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
39 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
40 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
41 };
42
43 static int base64_inited = 0;
44 static uint8_t base64_map[256];
45
46
47 /* Initialize the Base 64 conversion routines */
48 void
base64_init(void)49 base64_init(void)
50 {
51 int i;
52 memset(base64_map, 0, sizeof(base64_map));
53 for (i=0; i<64; i++)
54 base64_map[(uint8_t)base64_digits[i]] = i;
55 base64_inited = 1;
56 }
57
58 /* Convert a value to base64 characters.
59 * The result is stored in where, which
60 * must be at least 8 characters long.
61 *
62 * Returns the number of characters
63 * stored (not including the EOS).
64 */
65 int
to_base64(int64_t value,char * where)66 to_base64(int64_t value, char *where)
67 {
68 uint64_t val;
69 int i = 0;
70 int n;
71
72 /* Handle negative values */
73 if (value < 0) {
74 where[i++] = '-';
75 value = -value;
76 }
77
78 /* Determine output size */
79 val = value;
80 do {
81 val >>= 6;
82 i++;
83 } while (val);
84 n = i;
85
86 /* Output characters */
87 val = value;
88 where[i] = 0;
89 do {
90 where[--i] = base64_digits[val & (uint64_t)0x3F];
91 val >>= 6;
92 } while (val);
93 return n;
94 }
95
96 /*
97 * Convert the Base 64 characters in where to
98 * a value. No checking is done on the validity
99 * of the characters!!
100 *
101 * Returns the value.
102 */
103 int
from_base64(int64_t * value,char * where)104 from_base64(int64_t *value, char *where)
105 {
106 uint64_t val = 0;
107 int i, neg;
108
109 if (!base64_inited)
110 base64_init();
111 /* Check if it is negative */
112 i = neg = 0;
113 if (where[i] == '-') {
114 i++;
115 neg = 1;
116 }
117 /* Construct value */
118 while (where[i] != 0 && where[i] != ' ') {
119 val <<= 6;
120 val += base64_map[(uint8_t)where[i++]];
121 }
122
123 *value = neg ? -(int64_t)val : (int64_t)val;
124 return i;
125 }
126
127
128 /*
129 * Encode binary data in bin of len bytes into
130 * buf as base64 characters.
131 *
132 * If compatible is true, the bin_to_base64 routine will be compatible
133 * with what the rest of the world uses.
134 *
135 * Returns: the number of characters stored not
136 * including the EOS
137 */
138 int
bin_to_base64(char * buf,int buflen,char * bin,int binlen,int compatible)139 bin_to_base64(char *buf, int buflen, char *bin, int binlen, int compatible)
140 {
141 uint32_t reg, save, mask;
142 int rem, i;
143 int j = 0;
144
145 reg = 0;
146 rem = 0;
147 buflen--; /* allow for storing EOS */
148 for (i=0; i < binlen; ) {
149 if (rem < 6) {
150 reg <<= 8;
151 if (compatible) {
152 reg |= (uint8_t)bin[i++];
153 } else {
154 reg |= (int8_t)bin[i++];
155 }
156 rem += 8;
157 }
158 save = reg;
159 reg >>= (rem - 6);
160 if (j < buflen) {
161 buf[j++] = base64_digits[reg & 0x3F];
162 }
163 reg = save;
164 rem -= 6;
165 }
166 if (rem && j < buflen) {
167 mask = (1 << rem) - 1;
168 if (compatible) {
169 buf[j++] = base64_digits[(reg & mask) << (6 - rem)];
170 } else {
171 buf[j++] = base64_digits[reg & mask];
172 }
173 }
174 buf[j] = 0;
175 return j;
176 }
177
178 /*
179 * Decode base64 data in bin of len bytes into
180 * buf as binary characters.
181 *
182 * the base64_to_bin routine is compatible with what the rest of the world
183 * uses.
184 *
185 * 'dest_size' must be big enough! Giving the right size here could fail as
186 * we consider 'srclen' as an unpadded size, even if 'src' is padded
187 * we suggest to use dest_size=srclen for easiness or at least
188 * dest_size=((srclen + 3) / 4) * 3) for optimization lovers
189 *
190 * Returns: the number of characters stored not
191 * including the EOS
192 */
base64_to_bin(char * dest,int dest_size,char * src,int srclen)193 int base64_to_bin(char *dest, int dest_size, char *src, int srclen)
194 {
195 int nprbytes;
196 uint8_t *bufout;
197 uint8_t *bufplain = (uint8_t*) dest;
198 const uint8_t *bufin;
199
200 if (!base64_inited)
201 base64_init();
202
203 if (dest_size < (((srclen + 3) / 4) * 3)) {
204 /* dest buffer too small */
205 *dest = 0;
206 return 0;
207 }
208
209 bufin = (const uint8_t *) src;
210 while ((*bufin != ' ') && (srclen != 0)) {
211 bufin++;
212 srclen--;
213 }
214
215 nprbytes = bufin - (const uint8_t *) src;
216 bufin = (const uint8_t *) src;
217 bufout = (uint8_t *) bufplain;
218
219 while (nprbytes > 4)
220 {
221 *(bufout++) = (base64_map[bufin[0]] << 2 | base64_map[bufin[1]] >> 4);
222 *(bufout++) = (base64_map[bufin[1]] << 4 | base64_map[bufin[2]] >> 2);
223 *(bufout++) = (base64_map[bufin[2]] << 6 | base64_map[bufin[3]]);
224 bufin += 4;
225 nprbytes -= 4;
226 }
227
228 /* Bacula base64 strings are not always padded with = */
229 if (nprbytes > 1) {
230 *(bufout++) = (base64_map[bufin[0]] << 2 | base64_map[bufin[1]] >> 4);
231 }
232 if (nprbytes > 2) {
233 *(bufout++) = (base64_map[bufin[1]] << 4 | base64_map[bufin[2]] >> 2);
234 }
235 if (nprbytes > 3) {
236 *(bufout++) = (base64_map[bufin[2]] << 6 | base64_map[bufin[3]]);
237 }
238 *bufout = 0;
239
240 return (bufout - (uint8_t *) dest);
241 }
242
243 #ifdef BIN_TEST
main(int argc,char * argv[])244 int main(int argc, char *argv[])
245 {
246 int len;
247 char buf[100];
248 char junk[100];
249 int i;
250
251 #ifdef xxxx
252 int xx = 0;
253 for (i=0; i < 1000; i++) {
254 bin_to_base64(buf, sizeof(buf), (char *)&xx, 4, true);
255 printf("xx=%s\n", buf);
256 xx++;
257 }
258 #endif
259 junk[0] = 0xFF;
260 for (i=1; i<100; i++) {
261 junk[i] = junk[i-1]-1;
262 }
263 len = bin_to_base64(buf, sizeof(buf), junk, 16, true);
264 printf("len=%d junk=%s\n", len, buf);
265
266 strcpy(junk, "This is a sample stringa");
267 len = bin_to_base64(buf, sizeof(buf), junk, strlen(junk), true);
268 buf[len] = 0;
269 base64_to_bin(junk, sizeof(junk), buf, len);
270 printf("buf=<%s>\n", junk);
271 return 0;
272 }
273 #endif
274
275 #ifdef TEST_MODE
errfunc(const char * epath,int eernoo)276 static int errfunc(const char *epath, int eernoo)
277 {
278 printf("in errfunc\n");
279 return 1;
280 }
281
282
283 /*
284 * Test the base64 routines by encoding and decoding
285 * lstat() packets.
286 */
main(int argc,char * argv[])287 int main(int argc, char *argv[])
288 {
289 char where[500];
290 int i;
291 glob_t my_glob;
292 char *fname;
293 struct stat statp;
294 struct stat statn;
295 int debug_level = 0;
296 char *p;
297 int32_t j;
298 time_t t = 1028712799;
299
300 if (argc > 1 && strcmp(argv[1], "-v") == 0)
301 debug_level++;
302
303 base64_init();
304
305 my_glob.gl_offs = 0;
306 glob("/etc/grub.conf", GLOB_MARK, errfunc, &my_glob);
307
308 for (i=0; my_glob.gl_pathv[i]; i++) {
309 fname = my_glob.gl_pathv[i];
310 if (lstat(fname, &statp) < 0) {
311 berrno be;
312 printf("Cannot stat %s: %s\n", fname, be.bstrerror(errno));
313 continue;
314 }
315 encode_stat(where, &statp, sizeof(statp), 0, 0);
316
317 printf("Encoded stat=%s\n", where);
318
319 #ifdef xxx
320 p = where;
321 p += to_base64((int64_t)(statp.st_atime), p);
322 *p++ = ' ';
323 p += to_base64((int64_t)t, p);
324 printf("%s %s\n", fname, where);
325
326 printf("%s %lld\n", "st_dev", (int64_t)statp.st_dev);
327 printf("%s %lld\n", "st_ino", (int64_t)statp.st_ino);
328 printf("%s %lld\n", "st_mode", (int64_t)statp.st_mode);
329 printf("%s %lld\n", "st_nlink", (int64_t)statp.st_nlink);
330 printf("%s %lld\n", "st_uid", (int64_t)statp.st_uid);
331 printf("%s %lld\n", "st_gid", (int64_t)statp.st_gid);
332 printf("%s %lld\n", "st_rdev", (int64_t)statp.st_rdev);
333 printf("%s %lld\n", "st_size", (int64_t)statp.st_size);
334 printf("%s %lld\n", "st_blksize", (int64_t)statp.st_blksize);
335 printf("%s %lld\n", "st_blocks", (int64_t)statp.st_blocks);
336 printf("%s %lld\n", "st_atime", (int64_t)statp.st_atime);
337 printf("%s %lld\n", "st_mtime", (int64_t)statp.st_mtime);
338 printf("%s %lld\n", "st_ctime", (int64_t)statp.st_ctime);
339 #endif
340
341 if (debug_level)
342 printf("%s: len=%d val=%s\n", fname, strlen(where), where);
343
344 decode_stat(where, &statn, sizeof(statn), &j);
345
346 if (statp.st_dev != statn.st_dev ||
347 statp.st_ino != statn.st_ino ||
348 statp.st_mode != statn.st_mode ||
349 statp.st_nlink != statn.st_nlink ||
350 statp.st_uid != statn.st_uid ||
351 statp.st_gid != statn.st_gid ||
352 statp.st_rdev != statn.st_rdev ||
353 statp.st_size != statn.st_size ||
354 statp.st_blksize != statn.st_blksize ||
355 statp.st_blocks != statn.st_blocks ||
356 statp.st_atime != statn.st_atime ||
357 statp.st_mtime != statn.st_mtime ||
358 statp.st_ctime != statn.st_ctime) {
359
360 printf("%s: %s\n", fname, where);
361 encode_stat(where, &statn, sizeof(statn), 0, 0);
362 printf("%s: %s\n", fname, where);
363 printf("NOT EQAL\n");
364 }
365
366 }
367 globfree(&my_glob);
368
369 printf("%d files examined\n", i);
370
371 to_base64(UINT32_MAX, where);
372 printf("UINT32_MAX=%s\n", where);
373
374 return 0;
375 }
376 #endif
377
378 #ifndef TEST_PROGRAM
379 #define TEST_PROGRAM_A
380 #endif
381
382 #ifdef TEST_PROGRAM
383 #include "unittests.h"
384
385 static const unsigned char rnddata[16] = {
386 0xa5, 0x7d, 0xa3, 0xc4, 0x2c, 0xa0, 0x08, 0xe9, 0x32, 0xb9, 0xc7, 0x84, 0xf6, 0xd3, 0xdf, 0x4f
387 };
388 static const char *resb16 = "pX2jxCygCOkyuceE9tPfTw";
389 static const char *resb8 = "q83v7c";
390 #define VARREF 0xABCDEFEDC
391
main()392 int main()
393 {
394 Unittests base64_test("base64_test");
395 char buf[30];
396 char binbuf[30];
397 uint len;
398 bool check_cont;
399 int64_t var;
400
401 base64_init();
402 /*
403 for (int a=0; a < 16; a++){
404 fprintf(stderr, "%c", rnddata[a]);
405 }
406 */
407 /* encode reference binary data to base64 */
408 len = bin_to_base64(buf, 30, (char*)rnddata, 16, true);
409 ok(len == strlen(resb16), "Checking bin_to_base64 encoded length");
410 ok(strcmp(resb16, buf) == 0, "Checking bin_to_base64 encoded data");
411 /* decode reference base64 data to bin*/
412 len = base64_to_bin(binbuf, 30, (char*)resb16, strlen(resb16));
413 ok(len == 16, "Checking base64_to_bin decoded length");
414 check_cont = true;
415 for (uint a = 0; a < len; a++){
416 if ((unsigned char)binbuf[a] != rnddata[a]){
417 check_cont = false;
418 }
419 }
420 ok(check_cont, "Checking base64_to_bin decoded data");
421 /* decode the encoded base64 data to bin */
422 len = base64_to_bin(binbuf, 30, buf, strlen(buf));
423 ok(len == 16, "Checking base64_to_bin decoded length - encoded");
424 check_cont = true;
425 for (uint a = 0; a < len; a++){
426 if ((unsigned char)binbuf[a] != rnddata[a]){
427 check_cont = false;
428 }
429 }
430 ok(check_cont, "Checking base64_to_bin decoded data - encoded");
431 /* encode reference variable to base64 */
432 len = to_base64(VARREF, buf);
433 ok(len == 6, "Checking to_base64 encode length");
434 ok(strcmp(resb8, buf) == 0, "Checking to_base64 encoded data");
435 /* decode reference data to bin */
436 len = from_base64(&var, (char*)resb8);
437 ok(var == VARREF, "Checking from_base64 decoded data");
438 ok(len == 6, "Checking from_base64 decoded length");
439 /* decode encoded data to bin */
440 len = from_base64(&var, buf);
441 ok(var == VARREF, "Checking from_base64 decoded data - encoded");
442 ok(len == 6, "Checking from_base64 decoded length - encoded");
443 return report();
444 };
445 #endif /* TEST_PROGRAM */
446