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