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