Line data Source code
1 : /*
2 : * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
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 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include <config.h>
35 :
36 : #include <errno.h>
37 : #include <stdlib.h>
38 : #include <string.h>
39 : #include <limits.h>
40 : #ifdef TEST
41 : #include <stdio.h>
42 : #include <getarg.h>
43 : #include <err.h>
44 : #endif
45 : #include "base64.h"
46 : #include "roken.h"
47 :
48 : static const char base64_chars[] =
49 : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
50 :
51 : static int
52 586466 : pos(char c)
53 : {
54 : const char *p;
55 17881602 : for (p = base64_chars; *p; p++)
56 17881602 : if (*p == c)
57 586466 : return p - base64_chars;
58 0 : return -1;
59 : }
60 :
61 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
62 0 : rk_base64_encode(const void *data, int size, char **str)
63 : {
64 : char *s, *p;
65 : int i;
66 : int c;
67 : const unsigned char *q;
68 :
69 0 : if (size > INT_MAX/4 || size < 0) {
70 0 : *str = NULL;
71 0 : errno = ERANGE;
72 0 : return -1;
73 : }
74 :
75 0 : p = s = (char *) malloc(size * 4 / 3 + 4);
76 0 : if (p == NULL) {
77 0 : *str = NULL;
78 0 : return -1;
79 : }
80 0 : q = (const unsigned char *) data;
81 :
82 0 : for (i = 0; i < size;) {
83 0 : c = q[i++];
84 0 : c *= 256;
85 0 : if (i < size)
86 0 : c += q[i];
87 0 : i++;
88 0 : c *= 256;
89 0 : if (i < size)
90 0 : c += q[i];
91 0 : i++;
92 0 : p[0] = base64_chars[(c & 0x00fc0000) >> 18];
93 0 : p[1] = base64_chars[(c & 0x0003f000) >> 12];
94 0 : p[2] = base64_chars[(c & 0x00000fc0) >> 6];
95 0 : p[3] = base64_chars[(c & 0x0000003f) >> 0];
96 0 : if (i > size)
97 0 : p[3] = '=';
98 0 : if (i > size + 1)
99 0 : p[2] = '=';
100 0 : p += 4;
101 : }
102 0 : *p = 0;
103 0 : *str = s;
104 0 : return (int) strlen(s);
105 : }
106 :
107 : #define DECODE_ERROR 0xffffffff
108 :
109 : static unsigned int
110 146651 : token_decode(const char *token)
111 : {
112 : int i;
113 146651 : unsigned int val = 0;
114 146651 : int marker = 0;
115 146651 : if (strlen(token) < 4)
116 0 : return DECODE_ERROR;
117 733255 : for (i = 0; i < 4; i++) {
118 586604 : val *= 64;
119 586604 : if (token[i] == '=')
120 138 : marker++;
121 586466 : else if (marker > 0)
122 0 : return DECODE_ERROR;
123 : else
124 586466 : val += pos(token[i]);
125 : }
126 146651 : if (marker > 2)
127 0 : return DECODE_ERROR;
128 146651 : return (marker << 24) | val;
129 : }
130 :
131 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
132 9211 : rk_base64_decode(const char *str, void *data)
133 : {
134 : const char *p;
135 : unsigned char *q;
136 :
137 9211 : q = data;
138 155862 : for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
139 146651 : unsigned int val = token_decode(p);
140 146651 : unsigned int marker = (val >> 24) & 0xff;
141 146651 : if (val == DECODE_ERROR) {
142 0 : errno = EINVAL;
143 0 : return -1;
144 : }
145 146651 : *q++ = (val >> 16) & 0xff;
146 146651 : if (marker < 2)
147 146613 : *q++ = (val >> 8) & 0xff;
148 146651 : if (marker < 1)
149 146551 : *q++ = val & 0xff;
150 : }
151 9211 : if (q - (unsigned char *) data > INT_MAX) {
152 0 : errno = EOVERFLOW;
153 0 : return -1;
154 : }
155 9211 : return q - (unsigned char *) data;
156 : }
157 :
158 : #ifdef TEST
159 : static int decode_flag;
160 : static int help_flag;
161 :
162 : /*
163 : * The short options are compatible with a subset of the FreeBSD contrib
164 : * vis(1). Heimdal additions have long option names only.
165 : */
166 : static struct getargs args[] = {
167 : { "decode", 'd', arg_flag, &decode_flag, "Decode", NULL },
168 : { "help", 'h', arg_flag, &help_flag, "Print help message", NULL },
169 : };
170 : static size_t num_args = sizeof(args)/sizeof(args[0]);
171 :
172 : int
173 : main(int argc, char **argv)
174 : {
175 : unsigned char *buf = NULL;
176 : size_t buflen = 0;
177 : size_t bufsz = 0;
178 : int goptind = 0;
179 : int ret;
180 :
181 : setprogname("rkbase64");
182 : if (getarg(args, num_args, argc, argv, &goptind) || help_flag) {
183 : arg_printusage(args, num_args, NULL, "FILE | -");
184 : return help_flag ? 0 : 1;
185 : }
186 :
187 : argc -= goptind;
188 : argv += goptind;
189 :
190 : if (help_flag)
191 : return arg_printusage(args, num_args, NULL, "FILE | -- -"), 0;
192 : if (argc != 1)
193 : return arg_printusage(args, num_args, NULL, "FILE | -- -"), 1;
194 :
195 : if (strcmp(argv[0], "-") == 0) {
196 : unsigned char *tmp;
197 : unsigned char d[4096];
198 : size_t bytes;
199 :
200 : while (!feof(stdin) && !ferror(stdin)) {
201 : bytes = fread(d, 1, sizeof(d), stdin);
202 : if (bytes == 0)
203 : continue;
204 : if (buflen + bytes > bufsz) {
205 : if ((tmp = realloc(buf, bufsz + (bufsz >> 2) + sizeof(d))) == NULL)
206 : err(1, "Could not read stdin");
207 : buf = tmp;
208 : bufsz = bufsz + (bufsz >> 2) + sizeof(d);
209 : }
210 : memcpy(buf + buflen, d, bytes);
211 : buflen += bytes;
212 : }
213 : if (ferror(stdin))
214 : err(1, "Could not read stdin");
215 : } else {
216 : void *d;
217 : if ((errno = rk_undumpdata(argv[0], &d, &bufsz)))
218 : err(1, "Could not read %s", argv[0]);
219 : buflen = bufsz;
220 : buf = d;
221 : }
222 :
223 : if (decode_flag) {
224 : unsigned char *d;
225 :
226 : if (buflen == bufsz) {
227 : unsigned char *tmp;
228 :
229 : if ((tmp = realloc(buf, bufsz + 1)) == NULL)
230 : err(1, "Could not decode data");
231 : buf = tmp;
232 : bufsz++;
233 : }
234 : buf[buflen] = '\0';
235 :
236 : if ((d = malloc(buflen * 3 / 4 + 4)) == NULL)
237 : err(1, "Could not decode data");
238 :
239 : if ((ret = rk_base64_decode((const char *)buf, d)) < 0)
240 : err(1, "Could not decode data");
241 : if (fwrite(d, ret, 1, stdout) != 1)
242 : err(1, "Could not write decoded data");
243 : free(d);
244 : } else if (buf) { /* buf can be NULL if we read from an empty file */
245 : char *e;
246 :
247 : if ((ret = rk_base64_encode(buf, buflen, &e)) < 0)
248 : err(1, "Could not encode data");
249 : if (fwrite(e, ret, 1, stdout) != 1)
250 : err(1, "Could not write decoded data");
251 : free(e);
252 : if (fwrite("\n", 1, 1, stdout) != 1)
253 : err(1, "Could not write decoded data");
254 : }
255 : free(buf);
256 : return 0;
257 : }
258 : #endif
|