usock: implement usock_inet_timeout() with RFC6555 support
[project/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         int 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 tarindex, state, ch;
204         u_char nextbyte;
205         char *pos;
206
207         state = 0;
208         tarindex = 0;
209
210         while ((ch = (unsigned char)*src++) != '\0') {
211                 if (isspace(ch))        /* Skip whitespace anywhere. */
212                         continue;
213
214                 if (ch == Pad64)
215                         break;
216
217                 pos = strchr(Base64, ch);
218                 if (pos == 0)           /* A non-base64 character. */
219                         return (-1);
220
221                 switch (state) {
222                 case 0:
223                         if (target) {
224                                 if (tarindex >= targsize)
225                                         return (-1);
226                                 target[tarindex] = (pos - Base64) << 2;
227                         }
228                         state = 1;
229                         break;
230                 case 1:
231                         if (target) {
232                                 if (tarindex >= targsize)
233                                         return (-1);
234                                 target[tarindex]   |=  (pos - Base64) >> 4;
235                                 nextbyte = ((pos - Base64) & 0x0f) << 4;
236                                 if (tarindex + 1 < targsize)
237                                         target[tarindex+1] = nextbyte;
238                                 else if (nextbyte)
239                                         return (-1);
240                         }
241                         tarindex++;
242                         state = 2;
243                         break;
244                 case 2:
245                         if (target) {
246                                 if (tarindex >= targsize)
247                                         return (-1);
248                                 target[tarindex]   |=  (pos - Base64) >> 2;
249                                 nextbyte = ((pos - Base64) & 0x03) << 6;
250                                 if (tarindex + 1 < targsize)
251                                         target[tarindex+1] = nextbyte;
252                                 else if (nextbyte)
253                                         return (-1);
254                         }
255                         tarindex++;
256                         state = 3;
257                         break;
258                 case 3:
259                         if (target) {
260                                 if (tarindex >= targsize)
261                                         return (-1);
262                                 target[tarindex] |= (pos - Base64);
263                         }
264                         tarindex++;
265                         state = 0;
266                         break;
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 = (unsigned char)*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 (; ch != '\0'; ch = (unsigned char)*src++)
285                                 if (!isspace(ch))
286                                         break;
287                         /* Make sure there is another trailing = sign. */
288                         if (ch != Pad64)
289                                 return (-1);
290                         ch = (unsigned char)*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 (; ch != '\0'; ch = (unsigned char)*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 && tarindex < targsize &&
310                             target[tarindex] != 0)
311                                 return (-1);
312                 }
313         } else {
314                 /*
315                  * We ended by seeing the end of the string.  Make sure we
316                  * have no partial bytes lying around.
317                  */
318                 if (state != 0)
319                         return (-1);
320         }
321
322         /* Null-terminate if we have room left */
323         if (tarindex < targsize)
324                 target[tarindex] = 0;
325
326         return (tarindex);
327 }