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