• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/libubox/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 
 69 #include "assert.h"
 70 #include "utils.h"
 71 
 72 static const char Base64[] =
 73         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 74 static const char Pad64 = '=';
 75 
 76 /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
 77    The following encoding technique is taken from RFC 1521 by Borenstein
 78    and Freed.  It is reproduced here in a slightly edited form for
 79    convenience.
 80 
 81    A 65-character subset of US-ASCII is used, enabling 6 bits to be
 82    represented per printable character. (The extra 65th character, "=",
 83    is used to signify a special processing function.)
 84 
 85    The encoding process represents 24-bit groups of input bits as output
 86    strings of 4 encoded characters. Proceeding from left to right, a
 87    24-bit input group is formed by concatenating 3 8-bit input groups.
 88    These 24 bits are then treated as 4 concatenated 6-bit groups, each
 89    of which is translated into a single digit in the base64 alphabet.
 90 
 91    Each 6-bit group is used as an index into an array of 64 printable
 92    characters. The character referenced by the index is placed in the
 93    output string.
 94 
 95                          Table 1: The Base64 Alphabet
 96 
 97       Value Encoding  Value Encoding  Value Encoding  Value Encoding
 98           0 A            17 R            34 i            51 z
 99           1 B            18 S            35 j            52 0
100           2 C            19 T            36 k            53 1
101           3 D            20 U            37 l            54 2
102           4 E            21 V            38 m            55 3
103           5 F            22 W            39 n            56 4
104           6 G            23 X            40 o            57 5
105           7 H            24 Y            41 p            58 6
106           8 I            25 Z            42 q            59 7
107           9 J            26 a            43 r            60 8
108          10 K            27 b            44 s            61 9
109          11 L            28 c            45 t            62 +
110          12 M            29 d            46 u            63 /
111          13 N            30 e            47 v
112          14 O            31 f            48 w         (pad) =
113          15 P            32 g            49 x
114          16 Q            33 h            50 y
115 
116    Special processing is performed if fewer than 24 bits are available
117    at the end of the data being encoded.  A full encoding quantum is
118    always completed at the end of a quantity.  When fewer than 24 input
119    bits are available in an input group, zero bits are added (on the
120    right) to form an integral number of 6-bit groups.  Padding at the
121    end of the data is performed using the '=' character.
122 
123    Since all base64 input is an integral number of octets, only the
124          -------------------------------------------------
125    following cases can arise:
126 
127        (1) the final quantum of encoding input is an integral
128            multiple of 24 bits; here, the final unit of encoded
129            output will be an integral multiple of 4 characters
130            with no "=" padding,
131        (2) the final quantum of encoding input is exactly 8 bits;
132            here, the final unit of encoded output will be two
133            characters followed by two "=" padding characters, or
134        (3) the final quantum of encoding input is exactly 16 bits;
135            here, the final unit of encoded output will be three
136            characters followed by one "=" padding character.
137    */
138 
139 int b64_encode(const void *_src, size_t srclength,
140                void *dest, size_t targsize)
141 {
142         const unsigned char *src = _src;
143         char *target = dest;
144         size_t datalength = 0;
145         u_char input[3] = {0};
146         u_char output[4];
147         size_t i;
148 
149         assert(dest && targsize > 0);
150 
151         while (2 < srclength) {
152                 input[0] = *src++;
153                 input[1] = *src++;
154                 input[2] = *src++;
155                 srclength -= 3;
156 
157                 output[0] = input[0] >> 2;
158                 output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
159                 output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
160                 output[3] = input[2] & 0x3f;
161 
162                 if (datalength + 4 > targsize)
163                         return (-1);
164                 target[datalength++] = Base64[output[0]];
165                 target[datalength++] = Base64[output[1]];
166                 target[datalength++] = Base64[output[2]];
167                 target[datalength++] = Base64[output[3]];
168         }
169 
170         /* Now we worry about padding. */
171         if (0 != srclength) {
172                 /* Get what's left. */
173                 input[0] = input[1] = input[2] = '\0';
174                 for (i = 0; i < srclength; i++)
175                         input[i] = *src++;
176 
177                 output[0] = input[0] >> 2;
178                 output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
179                 output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
180 
181                 if (datalength + 4 > targsize)
182                         return (-1);
183                 target[datalength++] = Base64[output[0]];
184                 target[datalength++] = Base64[output[1]];
185                 if (srclength == 1)
186                         target[datalength++] = Pad64;
187                 else
188                         target[datalength++] = Base64[output[2]];
189                 target[datalength++] = Pad64;
190         }
191         if (datalength >= targsize)
192                 return (-1);
193         target[datalength] = '\0';      /* Returned value doesn't count \0. */
194         return (datalength);
195 }
196 
197 /* skips all whitespace anywhere.
198    converts characters, four at a time, starting at (or after)
199    src from base - 64 numbers into three 8 bit bytes in the target area.
200    it returns the number of data bytes stored at the target, or -1 on error.
201  */
202 
203 int b64_decode(const void *_src, void *dest, size_t targsize)
204 {
205         const char *src = _src;
206         unsigned char *target = dest;
207         int state, ch;
208         size_t tarindex;
209         u_char nextbyte;
210         char *pos;
211 
212         state = 0;
213         tarindex = 0;
214 
215         assert(dest && targsize > 0);
216 
217         while ((ch = (unsigned char)*src++) != '\0') {
218                 if (isspace(ch))        /* Skip whitespace anywhere. */
219                         continue;
220 
221                 if (ch == Pad64)
222                         break;
223 
224                 pos = strchr(Base64, ch);
225                 if (pos == 0)           /* A non-base64 character. */
226                         return (-1);
227 
228                 switch (state) {
229                 case 0:
230                         if (target) {
231                                 if (tarindex >= targsize)
232                                         return (-1);
233                                 target[tarindex] = (pos - Base64) << 2;
234                         }
235                         state = 1;
236                         break;
237                 case 1:
238                         if (target) {
239                                 if (tarindex >= targsize)
240                                         return (-1);
241                                 target[tarindex]   |=  (pos - Base64) >> 4;
242                                 nextbyte = ((pos - Base64) & 0x0f) << 4;
243                                 if (tarindex + 1 < targsize)
244                                         target[tarindex+1] = nextbyte;
245                                 else if (nextbyte)
246                                         return (-1);
247                         }
248                         tarindex++;
249                         state = 2;
250                         break;
251                 case 2:
252                         if (target) {
253                                 if (tarindex >= targsize)
254                                         return (-1);
255                                 target[tarindex]   |=  (pos - Base64) >> 2;
256                                 nextbyte = ((pos - Base64) & 0x03) << 6;
257                                 if (tarindex + 1 < targsize)
258                                         target[tarindex+1] = nextbyte;
259                                 else if (nextbyte)
260                                         return (-1);
261                         }
262                         tarindex++;
263                         state = 3;
264                         break;
265                 case 3:
266                         if (target) {
267                                 if (tarindex >= targsize)
268                                         return (-1);
269                                 target[tarindex] |= (pos - Base64);
270                         }
271                         tarindex++;
272                         state = 0;
273                         break;
274                 }
275         }
276 
277         /*
278          * We are done decoding Base-64 chars.  Let's see if we ended
279          * on a byte boundary, and/or with erroneous trailing characters.
280          */
281 
282         if (ch == Pad64) {                      /* We got a pad char. */
283                 ch = (unsigned char)*src++;     /* Skip it, get next. */
284                 switch (state) {
285                 case 0:         /* Invalid = in first position */
286                 case 1:         /* Invalid = in second position */
287                         return (-1);
288 
289                 case 2:         /* Valid, means one byte of info */
290                         /* Skip any number of spaces. */
291                         for (; ch != '\0'; ch = (unsigned char)*src++)
292                                 if (!isspace(ch))
293                                         break;
294                         /* Make sure there is another trailing = sign. */
295                         if (ch != Pad64)
296                                 return (-1);
297                         ch = (unsigned char)*src++;             /* Skip the = */
298                         /* Fall through to "single trailing =" case. */
299                         /* FALLTHROUGH */
300 
301                 case 3:         /* Valid, means two bytes of info */
302                         /*
303                          * We know this char is an =.  Is there anything but
304                          * whitespace after it?
305                          */
306                         for (; ch != '\0'; ch = (unsigned char)*src++)
307                                 if (!isspace(ch))
308                                         return (-1);
309 
310                         /*
311                          * Now make sure for cases 2 and 3 that the "extra"
312                          * bits that slopped past the last full byte were
313                          * zeros.  If we don't check them, they become a
314                          * subliminal channel.
315                          */
316                         if (target && tarindex < targsize &&
317                             target[tarindex] != 0)
318                                 return (-1);
319                 }
320         } else {
321                 /*
322                  * We ended by seeing the end of the string.  Make sure we
323                  * have no partial bytes lying around.
324                  */
325                 if (state != 0)
326                         return (-1);
327         }
328 
329         /* Null-terminate if we have room left */
330         if (tarindex < targsize)
331                 target[tarindex] = 0;
332 
333         return (tarindex);
334 }
335 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt