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