1 /*
2 * Copyright (c) 2013, Joyent, Inc.
3 * See LICENSE file for copyright and license details.
4 *
5 * Portions based on Public Domain work obtained from:
6 * https://shell.franken.de/svn/sky/xmlstorage/trunk/c++/xmlrpc/base64.cpp
7 */
8
9 #include "stdlib.h"
10 #include "stdio.h"
11 #include "dynstr.h"
12 #include "stdint.h"
13
14 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
15 "abcdefghijklmnopqrstuvwxyz0123456789+/";
16
17 void
base64_encode(uint8_t * input,size_t len,string_t * output)18 base64_encode(uint8_t *input, size_t len, string_t *output)
19 {
20 char tmp[5];
21 unsigned int i = 0;
22
23 tmp[4] = '\0';
24 dynstr_append(output, "");
25
26 while (i < len) {
27 uint32_t c = input[i++] << 16;
28 if (i < len)
29 c |= input[i] << 8;
30 i++;
31 if (i < len)
32 c |= input[i];
33 i++;
34
35 tmp[0] = base64[(c & 0x00fc0000) >> 18];
36 tmp[1] = base64[(c & 0x0003f000) >> 12];
37 tmp[2] = i > len + 1 ? '=' : base64[(c & 0x00000fc0) >> 6];
38 tmp[3] = i > len ? '=' : base64[c & 0x0000003f];
39
40 dynstr_append(output, tmp);
41 }
42 }
43
44 static int
decode_one(char c)45 decode_one(char c)
46 {
47 if (c >= 'A' && c <= 'Z')
48 return (c - 'A');
49 if (c >= 'a' && c <= 'z')
50 return (c - 'a' + 26);
51 if (c >= '0' && c <= '9')
52 return (c - '0' + 52);
53 if (c == '+')
54 return (62);
55 if (c == '/')
56 return (63);
57 if (c == '=')
58 return (-1);
59
60 return (-2);
61 }
62
63 int
base64_decode(const char * input,size_t len,string_t * output)64 base64_decode(const char *input, size_t len, string_t *output)
65 {
66 int typ[4];
67 uint8_t buf[4];
68 unsigned int i, j;
69
70 buf[3] = '\0';
71 dynstr_append(output, "");
72
73 /*
74 * Valid encoded strings are a multiple of 4 characters long:
75 */
76 if (len % 4 != 0)
77 return (-1);
78
79 for (i = 0; i < len; i += 4) {
80 for (j = 0; j < 4; j++)
81 typ[j] = decode_one(input[i + j]);
82
83 /*
84 * Filler must be contiguous on the right of the input
85 * string, and at most two bytes:
86 */
87 if (typ[0] == -1 || typ[1] == -1)
88 return (-1);
89 if (typ[2] == -1 && typ[3] != -1)
90 return (-1);
91
92 buf[0] = (typ[0] << 2) | (typ[1] >> 4);
93 if (typ[2] != -1)
94 buf[1] = ((typ[1] & 0x0f) << 4) | (typ[2] >>2);
95 else
96 buf[1] = '\0';
97 if (typ[3] != -1)
98 buf[2] = ((typ[2] & 0x03) << 6) | typ[3];
99 else
100 buf[2] = '\0';
101
102 dynstr_append(output, (const char *) buf);
103 }
104
105 return (0);
106 }
107