base64.c revision 1.1.1.1.2.2 1 1.1.1.1.2.2 jym /* $NetBSD: base64.c,v 1.1.1.1.2.2 2009/05/13 18:52:12 jym Exp $ */
2 1.1.1.1.2.2 jym
3 1.1.1.1.2.2 jym /*
4 1.1.1.1.2.2 jym * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 1.1.1.1.2.2 jym * Copyright (c) 1996-1999 by Internet Software Consortium.
6 1.1.1.1.2.2 jym *
7 1.1.1.1.2.2 jym * Permission to use, copy, modify, and distribute this software for any
8 1.1.1.1.2.2 jym * purpose with or without fee is hereby granted, provided that the above
9 1.1.1.1.2.2 jym * copyright notice and this permission notice appear in all copies.
10 1.1.1.1.2.2 jym *
11 1.1.1.1.2.2 jym * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 1.1.1.1.2.2 jym * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 1.1.1.1.2.2 jym * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14 1.1.1.1.2.2 jym * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 1.1.1.1.2.2 jym * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 1.1.1.1.2.2 jym * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 1.1.1.1.2.2 jym * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 1.1.1.1.2.2 jym */
19 1.1.1.1.2.2 jym
20 1.1.1.1.2.2 jym /*
21 1.1.1.1.2.2 jym * Portions Copyright (c) 1995 by International Business Machines, Inc.
22 1.1.1.1.2.2 jym *
23 1.1.1.1.2.2 jym * International Business Machines, Inc. (hereinafter called IBM) grants
24 1.1.1.1.2.2 jym * permission under its copyrights to use, copy, modify, and distribute this
25 1.1.1.1.2.2 jym * Software with or without fee, provided that the above copyright notice and
26 1.1.1.1.2.2 jym * all paragraphs of this notice appear in all copies, and that the name of IBM
27 1.1.1.1.2.2 jym * not be used in connection with the marketing of any product incorporating
28 1.1.1.1.2.2 jym * the Software or modifications thereof, without specific, written prior
29 1.1.1.1.2.2 jym * permission.
30 1.1.1.1.2.2 jym *
31 1.1.1.1.2.2 jym * To the extent it has a right to do so, IBM grants an immunity from suit
32 1.1.1.1.2.2 jym * under its patents, if any, for the use, sale or manufacture of products to
33 1.1.1.1.2.2 jym * the extent that such products are used for performing Domain Name System
34 1.1.1.1.2.2 jym * dynamic updates in TCP/IP networks by means of the Software. No immunity is
35 1.1.1.1.2.2 jym * granted for any product per se or for any other function of any product.
36 1.1.1.1.2.2 jym *
37 1.1.1.1.2.2 jym * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
38 1.1.1.1.2.2 jym * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
39 1.1.1.1.2.2 jym * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
40 1.1.1.1.2.2 jym * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
41 1.1.1.1.2.2 jym * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
42 1.1.1.1.2.2 jym * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
43 1.1.1.1.2.2 jym */
44 1.1.1.1.2.2 jym
45 1.1.1.1.2.2 jym #if !defined(LINT) && !defined(CODECENTER)
46 1.1.1.1.2.2 jym static const char rcsid[] = "Id: base64.c,v 1.4 2005/04/27 04:56:34 sra Exp";
47 1.1.1.1.2.2 jym #endif /* not lint */
48 1.1.1.1.2.2 jym
49 1.1.1.1.2.2 jym #include "port_before.h"
50 1.1.1.1.2.2 jym
51 1.1.1.1.2.2 jym #include <sys/types.h>
52 1.1.1.1.2.2 jym #include <sys/param.h>
53 1.1.1.1.2.2 jym #include <sys/socket.h>
54 1.1.1.1.2.2 jym
55 1.1.1.1.2.2 jym #include <netinet/in.h>
56 1.1.1.1.2.2 jym #include <arpa/inet.h>
57 1.1.1.1.2.2 jym #include <arpa/nameser.h>
58 1.1.1.1.2.2 jym
59 1.1.1.1.2.2 jym #include <ctype.h>
60 1.1.1.1.2.2 jym #include <resolv.h>
61 1.1.1.1.2.2 jym #include <stdio.h>
62 1.1.1.1.2.2 jym #include <stdlib.h>
63 1.1.1.1.2.2 jym #include <string.h>
64 1.1.1.1.2.2 jym
65 1.1.1.1.2.2 jym #include "port_after.h"
66 1.1.1.1.2.2 jym
67 1.1.1.1.2.2 jym #define Assert(Cond) if (!(Cond)) abort()
68 1.1.1.1.2.2 jym
69 1.1.1.1.2.2 jym static const char Base64[] =
70 1.1.1.1.2.2 jym "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
71 1.1.1.1.2.2 jym static const char Pad64 = '=';
72 1.1.1.1.2.2 jym
73 1.1.1.1.2.2 jym /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
74 1.1.1.1.2.2 jym The following encoding technique is taken from RFC1521 by Borenstein
75 1.1.1.1.2.2 jym and Freed. It is reproduced here in a slightly edited form for
76 1.1.1.1.2.2 jym convenience.
77 1.1.1.1.2.2 jym
78 1.1.1.1.2.2 jym A 65-character subset of US-ASCII is used, enabling 6 bits to be
79 1.1.1.1.2.2 jym represented per printable character. (The extra 65th character, "=",
80 1.1.1.1.2.2 jym is used to signify a special processing function.)
81 1.1.1.1.2.2 jym
82 1.1.1.1.2.2 jym The encoding process represents 24-bit groups of input bits as output
83 1.1.1.1.2.2 jym strings of 4 encoded characters. Proceeding from left to right, a
84 1.1.1.1.2.2 jym 24-bit input group is formed by concatenating 3 8-bit input groups.
85 1.1.1.1.2.2 jym These 24 bits are then treated as 4 concatenated 6-bit groups, each
86 1.1.1.1.2.2 jym of which is translated into a single digit in the base64 alphabet.
87 1.1.1.1.2.2 jym
88 1.1.1.1.2.2 jym Each 6-bit group is used as an index into an array of 64 printable
89 1.1.1.1.2.2 jym characters. The character referenced by the index is placed in the
90 1.1.1.1.2.2 jym output string.
91 1.1.1.1.2.2 jym
92 1.1.1.1.2.2 jym Table 1: The Base64 Alphabet
93 1.1.1.1.2.2 jym
94 1.1.1.1.2.2 jym Value Encoding Value Encoding Value Encoding Value Encoding
95 1.1.1.1.2.2 jym 0 A 17 R 34 i 51 z
96 1.1.1.1.2.2 jym 1 B 18 S 35 j 52 0
97 1.1.1.1.2.2 jym 2 C 19 T 36 k 53 1
98 1.1.1.1.2.2 jym 3 D 20 U 37 l 54 2
99 1.1.1.1.2.2 jym 4 E 21 V 38 m 55 3
100 1.1.1.1.2.2 jym 5 F 22 W 39 n 56 4
101 1.1.1.1.2.2 jym 6 G 23 X 40 o 57 5
102 1.1.1.1.2.2 jym 7 H 24 Y 41 p 58 6
103 1.1.1.1.2.2 jym 8 I 25 Z 42 q 59 7
104 1.1.1.1.2.2 jym 9 J 26 a 43 r 60 8
105 1.1.1.1.2.2 jym 10 K 27 b 44 s 61 9
106 1.1.1.1.2.2 jym 11 L 28 c 45 t 62 +
107 1.1.1.1.2.2 jym 12 M 29 d 46 u 63 /
108 1.1.1.1.2.2 jym 13 N 30 e 47 v
109 1.1.1.1.2.2 jym 14 O 31 f 48 w (pad) =
110 1.1.1.1.2.2 jym 15 P 32 g 49 x
111 1.1.1.1.2.2 jym 16 Q 33 h 50 y
112 1.1.1.1.2.2 jym
113 1.1.1.1.2.2 jym Special processing is performed if fewer than 24 bits are available
114 1.1.1.1.2.2 jym at the end of the data being encoded. A full encoding quantum is
115 1.1.1.1.2.2 jym always completed at the end of a quantity. When fewer than 24 input
116 1.1.1.1.2.2 jym bits are available in an input group, zero bits are added (on the
117 1.1.1.1.2.2 jym right) to form an integral number of 6-bit groups. Padding at the
118 1.1.1.1.2.2 jym end of the data is performed using the '=' character.
119 1.1.1.1.2.2 jym
120 1.1.1.1.2.2 jym Since all base64 input is an integral number of octets, only the
121 1.1.1.1.2.2 jym -------------------------------------------------
122 1.1.1.1.2.2 jym following cases can arise:
123 1.1.1.1.2.2 jym
124 1.1.1.1.2.2 jym (1) the final quantum of encoding input is an integral
125 1.1.1.1.2.2 jym multiple of 24 bits; here, the final unit of encoded
126 1.1.1.1.2.2 jym output will be an integral multiple of 4 characters
127 1.1.1.1.2.2 jym with no "=" padding,
128 1.1.1.1.2.2 jym (2) the final quantum of encoding input is exactly 8 bits;
129 1.1.1.1.2.2 jym here, the final unit of encoded output will be two
130 1.1.1.1.2.2 jym characters followed by two "=" padding characters, or
131 1.1.1.1.2.2 jym (3) the final quantum of encoding input is exactly 16 bits;
132 1.1.1.1.2.2 jym here, the final unit of encoded output will be three
133 1.1.1.1.2.2 jym characters followed by one "=" padding character.
134 1.1.1.1.2.2 jym */
135 1.1.1.1.2.2 jym
136 1.1.1.1.2.2 jym int
137 1.1.1.1.2.2 jym b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
138 1.1.1.1.2.2 jym size_t datalength = 0;
139 1.1.1.1.2.2 jym u_char input[3];
140 1.1.1.1.2.2 jym u_char output[4];
141 1.1.1.1.2.2 jym size_t i;
142 1.1.1.1.2.2 jym
143 1.1.1.1.2.2 jym while (2U < srclength) {
144 1.1.1.1.2.2 jym input[0] = *src++;
145 1.1.1.1.2.2 jym input[1] = *src++;
146 1.1.1.1.2.2 jym input[2] = *src++;
147 1.1.1.1.2.2 jym srclength -= 3;
148 1.1.1.1.2.2 jym
149 1.1.1.1.2.2 jym output[0] = input[0] >> 2;
150 1.1.1.1.2.2 jym output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
151 1.1.1.1.2.2 jym output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
152 1.1.1.1.2.2 jym output[3] = input[2] & 0x3f;
153 1.1.1.1.2.2 jym Assert(output[0] < 64);
154 1.1.1.1.2.2 jym Assert(output[1] < 64);
155 1.1.1.1.2.2 jym Assert(output[2] < 64);
156 1.1.1.1.2.2 jym Assert(output[3] < 64);
157 1.1.1.1.2.2 jym
158 1.1.1.1.2.2 jym if (datalength + 4 > targsize)
159 1.1.1.1.2.2 jym return (-1);
160 1.1.1.1.2.2 jym target[datalength++] = Base64[output[0]];
161 1.1.1.1.2.2 jym target[datalength++] = Base64[output[1]];
162 1.1.1.1.2.2 jym target[datalength++] = Base64[output[2]];
163 1.1.1.1.2.2 jym target[datalength++] = Base64[output[3]];
164 1.1.1.1.2.2 jym }
165 1.1.1.1.2.2 jym
166 1.1.1.1.2.2 jym /* Now we worry about padding. */
167 1.1.1.1.2.2 jym if (0U != srclength) {
168 1.1.1.1.2.2 jym /* Get what's left. */
169 1.1.1.1.2.2 jym input[0] = input[1] = input[2] = '\0';
170 1.1.1.1.2.2 jym for (i = 0; i < srclength; i++)
171 1.1.1.1.2.2 jym input[i] = *src++;
172 1.1.1.1.2.2 jym
173 1.1.1.1.2.2 jym output[0] = input[0] >> 2;
174 1.1.1.1.2.2 jym output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
175 1.1.1.1.2.2 jym output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
176 1.1.1.1.2.2 jym Assert(output[0] < 64);
177 1.1.1.1.2.2 jym Assert(output[1] < 64);
178 1.1.1.1.2.2 jym Assert(output[2] < 64);
179 1.1.1.1.2.2 jym
180 1.1.1.1.2.2 jym if (datalength + 4 > targsize)
181 1.1.1.1.2.2 jym return (-1);
182 1.1.1.1.2.2 jym target[datalength++] = Base64[output[0]];
183 1.1.1.1.2.2 jym target[datalength++] = Base64[output[1]];
184 1.1.1.1.2.2 jym if (srclength == 1U)
185 1.1.1.1.2.2 jym target[datalength++] = Pad64;
186 1.1.1.1.2.2 jym else
187 1.1.1.1.2.2 jym target[datalength++] = Base64[output[2]];
188 1.1.1.1.2.2 jym target[datalength++] = Pad64;
189 1.1.1.1.2.2 jym }
190 1.1.1.1.2.2 jym if (datalength >= targsize)
191 1.1.1.1.2.2 jym return (-1);
192 1.1.1.1.2.2 jym target[datalength] = '\0'; /*%< Returned value doesn't count \\0. */
193 1.1.1.1.2.2 jym return (datalength);
194 1.1.1.1.2.2 jym }
195 1.1.1.1.2.2 jym
196 1.1.1.1.2.2 jym /* skips all whitespace anywhere.
197 1.1.1.1.2.2 jym converts characters, four at a time, starting at (or after)
198 1.1.1.1.2.2 jym src from base - 64 numbers into three 8 bit bytes in the target area.
199 1.1.1.1.2.2 jym it returns the number of data bytes stored at the target, or -1 on error.
200 1.1.1.1.2.2 jym */
201 1.1.1.1.2.2 jym
202 1.1.1.1.2.2 jym int
203 1.1.1.1.2.2 jym b64_pton(src, target, targsize)
204 1.1.1.1.2.2 jym char const *src;
205 1.1.1.1.2.2 jym u_char *target;
206 1.1.1.1.2.2 jym size_t targsize;
207 1.1.1.1.2.2 jym {
208 1.1.1.1.2.2 jym int tarindex, state, ch;
209 1.1.1.1.2.2 jym char *pos;
210 1.1.1.1.2.2 jym
211 1.1.1.1.2.2 jym state = 0;
212 1.1.1.1.2.2 jym tarindex = 0;
213 1.1.1.1.2.2 jym
214 1.1.1.1.2.2 jym while ((ch = *src++) != '\0') {
215 1.1.1.1.2.2 jym if (isspace(ch)) /*%< Skip whitespace anywhere. */
216 1.1.1.1.2.2 jym continue;
217 1.1.1.1.2.2 jym
218 1.1.1.1.2.2 jym if (ch == Pad64)
219 1.1.1.1.2.2 jym break;
220 1.1.1.1.2.2 jym
221 1.1.1.1.2.2 jym pos = strchr(Base64, ch);
222 1.1.1.1.2.2 jym if (pos == 0) /*%< A non-base64 character. */
223 1.1.1.1.2.2 jym return (-1);
224 1.1.1.1.2.2 jym
225 1.1.1.1.2.2 jym switch (state) {
226 1.1.1.1.2.2 jym case 0:
227 1.1.1.1.2.2 jym if (target) {
228 1.1.1.1.2.2 jym if ((size_t)tarindex >= targsize)
229 1.1.1.1.2.2 jym return (-1);
230 1.1.1.1.2.2 jym target[tarindex] = (pos - Base64) << 2;
231 1.1.1.1.2.2 jym }
232 1.1.1.1.2.2 jym state = 1;
233 1.1.1.1.2.2 jym break;
234 1.1.1.1.2.2 jym case 1:
235 1.1.1.1.2.2 jym if (target) {
236 1.1.1.1.2.2 jym if ((size_t)tarindex + 1 >= targsize)
237 1.1.1.1.2.2 jym return (-1);
238 1.1.1.1.2.2 jym target[tarindex] |= (pos - Base64) >> 4;
239 1.1.1.1.2.2 jym target[tarindex+1] = ((pos - Base64) & 0x0f)
240 1.1.1.1.2.2 jym << 4 ;
241 1.1.1.1.2.2 jym }
242 1.1.1.1.2.2 jym tarindex++;
243 1.1.1.1.2.2 jym state = 2;
244 1.1.1.1.2.2 jym break;
245 1.1.1.1.2.2 jym case 2:
246 1.1.1.1.2.2 jym if (target) {
247 1.1.1.1.2.2 jym if ((size_t)tarindex + 1 >= targsize)
248 1.1.1.1.2.2 jym return (-1);
249 1.1.1.1.2.2 jym target[tarindex] |= (pos - Base64) >> 2;
250 1.1.1.1.2.2 jym target[tarindex+1] = ((pos - Base64) & 0x03)
251 1.1.1.1.2.2 jym << 6;
252 1.1.1.1.2.2 jym }
253 1.1.1.1.2.2 jym tarindex++;
254 1.1.1.1.2.2 jym state = 3;
255 1.1.1.1.2.2 jym break;
256 1.1.1.1.2.2 jym case 3:
257 1.1.1.1.2.2 jym if (target) {
258 1.1.1.1.2.2 jym if ((size_t)tarindex >= targsize)
259 1.1.1.1.2.2 jym return (-1);
260 1.1.1.1.2.2 jym target[tarindex] |= (pos - Base64);
261 1.1.1.1.2.2 jym }
262 1.1.1.1.2.2 jym tarindex++;
263 1.1.1.1.2.2 jym state = 0;
264 1.1.1.1.2.2 jym break;
265 1.1.1.1.2.2 jym default:
266 1.1.1.1.2.2 jym abort();
267 1.1.1.1.2.2 jym }
268 1.1.1.1.2.2 jym }
269 1.1.1.1.2.2 jym
270 1.1.1.1.2.2 jym /*
271 1.1.1.1.2.2 jym * We are done decoding Base-64 chars. Let's see if we ended
272 1.1.1.1.2.2 jym * on a byte boundary, and/or with erroneous trailing characters.
273 1.1.1.1.2.2 jym */
274 1.1.1.1.2.2 jym
275 1.1.1.1.2.2 jym if (ch == Pad64) { /*%< We got a pad char. */
276 1.1.1.1.2.2 jym ch = *src++; /*%< Skip it, get next. */
277 1.1.1.1.2.2 jym switch (state) {
278 1.1.1.1.2.2 jym case 0: /*%< Invalid = in first position */
279 1.1.1.1.2.2 jym case 1: /*%< Invalid = in second position */
280 1.1.1.1.2.2 jym return (-1);
281 1.1.1.1.2.2 jym
282 1.1.1.1.2.2 jym case 2: /*%< Valid, means one byte of info */
283 1.1.1.1.2.2 jym /* Skip any number of spaces. */
284 1.1.1.1.2.2 jym for ((void)NULL; ch != '\0'; ch = *src++)
285 1.1.1.1.2.2 jym if (!isspace(ch))
286 1.1.1.1.2.2 jym break;
287 1.1.1.1.2.2 jym /* Make sure there is another trailing = sign. */
288 1.1.1.1.2.2 jym if (ch != Pad64)
289 1.1.1.1.2.2 jym return (-1);
290 1.1.1.1.2.2 jym ch = *src++; /*%< Skip the = */
291 1.1.1.1.2.2 jym /* Fall through to "single trailing =" case. */
292 1.1.1.1.2.2 jym /* FALLTHROUGH */
293 1.1.1.1.2.2 jym
294 1.1.1.1.2.2 jym case 3: /*%< Valid, means two bytes of info */
295 1.1.1.1.2.2 jym /*
296 1.1.1.1.2.2 jym * We know this char is an =. Is there anything but
297 1.1.1.1.2.2 jym * whitespace after it?
298 1.1.1.1.2.2 jym */
299 1.1.1.1.2.2 jym for ((void)NULL; ch != '\0'; ch = *src++)
300 1.1.1.1.2.2 jym if (!isspace(ch))
301 1.1.1.1.2.2 jym return (-1);
302 1.1.1.1.2.2 jym
303 1.1.1.1.2.2 jym /*
304 1.1.1.1.2.2 jym * Now make sure for cases 2 and 3 that the "extra"
305 1.1.1.1.2.2 jym * bits that slopped past the last full byte were
306 1.1.1.1.2.2 jym * zeros. If we don't check them, they become a
307 1.1.1.1.2.2 jym * subliminal channel.
308 1.1.1.1.2.2 jym */
309 1.1.1.1.2.2 jym if (target && target[tarindex] != 0)
310 1.1.1.1.2.2 jym return (-1);
311 1.1.1.1.2.2 jym }
312 1.1.1.1.2.2 jym } else {
313 1.1.1.1.2.2 jym /*
314 1.1.1.1.2.2 jym * We ended by seeing the end of the string. Make sure we
315 1.1.1.1.2.2 jym * have no partial bytes lying around.
316 1.1.1.1.2.2 jym */
317 1.1.1.1.2.2 jym if (state != 0)
318 1.1.1.1.2.2 jym return (-1);
319 1.1.1.1.2.2 jym }
320 1.1.1.1.2.2 jym
321 1.1.1.1.2.2 jym return (tarindex);
322 1.1.1.1.2.2 jym }
323 1.1.1.1.2.2 jym
324 1.1.1.1.2.2 jym /*! \file */
325