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