Back to index

glibc  2.9
base64.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1996-1999 by Internet Software Consortium.
00003  *
00004  * Permission to use, copy, modify, and distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
00009  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
00010  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
00011  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
00012  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00013  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00014  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00015  * SOFTWARE.
00016  */
00017 
00018 /*
00019  * Portions Copyright (c) 1995 by International Business Machines, Inc.
00020  *
00021  * International Business Machines, Inc. (hereinafter called IBM) grants
00022  * permission under its copyrights to use, copy, modify, and distribute this
00023  * Software with or without fee, provided that the above copyright notice and
00024  * all paragraphs of this notice appear in all copies, and that the name of IBM
00025  * not be used in connection with the marketing of any product incorporating
00026  * the Software or modifications thereof, without specific, written prior
00027  * permission.
00028  *
00029  * To the extent it has a right to do so, IBM grants an immunity from suit
00030  * under its patents, if any, for the use, sale or manufacture of products to
00031  * the extent that such products are used for performing Domain Name System
00032  * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
00033  * granted for any product per se or for any other function of any product.
00034  *
00035  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
00036  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00037  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
00038  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
00039  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
00040  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
00041  */
00042 
00043 #if !defined(LINT) && !defined(CODECENTER)
00044 static const char rcsid[] = "$BINDId: base64.c,v 8.7 1999/10/13 16:39:33 vixie Exp $";
00045 #endif /* not lint */
00046 
00047 #include <sys/types.h>
00048 #include <sys/param.h>
00049 #include <sys/socket.h>
00050 
00051 #include <netinet/in.h>
00052 #include <arpa/inet.h>
00053 #include <arpa/nameser.h>
00054 
00055 #include <ctype.h>
00056 #include <resolv.h>
00057 #include <stdio.h>
00058 #include <stdlib.h>
00059 #include <string.h>
00060 
00061 #define Assert(Cond) if (!(Cond)) abort()
00062 
00063 static const char Base64[] =
00064        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00065 static const char Pad64 = '=';
00066 
00067 /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
00068    The following encoding technique is taken from RFC 1521 by Borenstein
00069    and Freed.  It is reproduced here in a slightly edited form for
00070    convenience.
00071 
00072    A 65-character subset of US-ASCII is used, enabling 6 bits to be
00073    represented per printable character. (The extra 65th character, "=",
00074    is used to signify a special processing function.)
00075 
00076    The encoding process represents 24-bit groups of input bits as output
00077    strings of 4 encoded characters. Proceeding from left to right, a
00078    24-bit input group is formed by concatenating 3 8-bit input groups.
00079    These 24 bits are then treated as 4 concatenated 6-bit groups, each
00080    of which is translated into a single digit in the base64 alphabet.
00081 
00082    Each 6-bit group is used as an index into an array of 64 printable
00083    characters. The character referenced by the index is placed in the
00084    output string.
00085 
00086                          Table 1: The Base64 Alphabet
00087 
00088       Value Encoding  Value Encoding  Value Encoding  Value Encoding
00089           0 A            17 R            34 i            51 z
00090           1 B            18 S            35 j            52 0
00091           2 C            19 T            36 k            53 1
00092           3 D            20 U            37 l            54 2
00093           4 E            21 V            38 m            55 3
00094           5 F            22 W            39 n            56 4
00095           6 G            23 X            40 o            57 5
00096           7 H            24 Y            41 p            58 6
00097           8 I            25 Z            42 q            59 7
00098           9 J            26 a            43 r            60 8
00099          10 K            27 b            44 s            61 9
00100          11 L            28 c            45 t            62 +
00101          12 M            29 d            46 u            63 /
00102          13 N            30 e            47 v
00103          14 O            31 f            48 w         (pad) =
00104          15 P            32 g            49 x
00105          16 Q            33 h            50 y
00106 
00107    Special processing is performed if fewer than 24 bits are available
00108    at the end of the data being encoded.  A full encoding quantum is
00109    always completed at the end of a quantity.  When fewer than 24 input
00110    bits are available in an input group, zero bits are added (on the
00111    right) to form an integral number of 6-bit groups.  Padding at the
00112    end of the data is performed using the '=' character.
00113 
00114    Since all base64 input is an integral number of octets, only the
00115          -------------------------------------------------
00116    following cases can arise:
00117 
00118        (1) the final quantum of encoding input is an integral
00119            multiple of 24 bits; here, the final unit of encoded
00120           output will be an integral multiple of 4 characters
00121           with no "=" padding,
00122        (2) the final quantum of encoding input is exactly 8 bits;
00123            here, the final unit of encoded output will be two
00124           characters followed by two "=" padding characters, or
00125        (3) the final quantum of encoding input is exactly 16 bits;
00126            here, the final unit of encoded output will be three
00127           characters followed by one "=" padding character.
00128    */
00129 
00130 int
00131 b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
00132        size_t datalength = 0;
00133        u_char input[3];
00134        u_char output[4];
00135        size_t i;
00136 
00137        while (2 < srclength) {
00138               input[0] = *src++;
00139               input[1] = *src++;
00140               input[2] = *src++;
00141               srclength -= 3;
00142 
00143               output[0] = input[0] >> 2;
00144               output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
00145               output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
00146               output[3] = input[2] & 0x3f;
00147               Assert(output[0] < 64);
00148               Assert(output[1] < 64);
00149               Assert(output[2] < 64);
00150               Assert(output[3] < 64);
00151 
00152               if (datalength + 4 > targsize)
00153                      return (-1);
00154               target[datalength++] = Base64[output[0]];
00155               target[datalength++] = Base64[output[1]];
00156               target[datalength++] = Base64[output[2]];
00157               target[datalength++] = Base64[output[3]];
00158        }
00159 
00160        /* Now we worry about padding. */
00161        if (0 != srclength) {
00162               /* Get what's left. */
00163               input[0] = input[1] = input[2] = '\0';
00164               for (i = 0; i < srclength; i++)
00165                      input[i] = *src++;
00166 
00167               output[0] = input[0] >> 2;
00168               output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
00169               output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
00170               Assert(output[0] < 64);
00171               Assert(output[1] < 64);
00172               Assert(output[2] < 64);
00173 
00174               if (datalength + 4 > targsize)
00175                      return (-1);
00176               target[datalength++] = Base64[output[0]];
00177               target[datalength++] = Base64[output[1]];
00178               if (srclength == 1)
00179                      target[datalength++] = Pad64;
00180               else
00181                      target[datalength++] = Base64[output[2]];
00182               target[datalength++] = Pad64;
00183        }
00184        if (datalength >= targsize)
00185               return (-1);
00186        target[datalength] = '\0';  /* Returned value doesn't count \0. */
00187        return (datalength);
00188 }
00189 libresolv_hidden_def (b64_ntop)
00190 
00191 /* skips all whitespace anywhere.
00192    converts characters, four at a time, starting at (or after)
00193    src from base - 64 numbers into three 8 bit bytes in the target area.
00194    it returns the number of data bytes stored at the target, or -1 on error.
00195  */
00196 
00197 int
00198 b64_pton(src, target, targsize)
00199        char const *src;
00200        u_char *target;
00201        size_t targsize;
00202 {
00203        int tarindex, state, ch;
00204        char *pos;
00205 
00206        state = 0;
00207        tarindex = 0;
00208 
00209        while ((ch = *src++) != '\0') {
00210               if (isspace(ch))     /* Skip whitespace anywhere. */
00211                      continue;
00212 
00213               if (ch == Pad64)
00214                      break;
00215 
00216               pos = strchr(Base64, ch);
00217               if (pos == 0)               /* A non-base64 character. */
00218                      return (-1);
00219 
00220               switch (state) {
00221               case 0:
00222                      if (target) {
00223                             if ((size_t)tarindex >= targsize)
00224                                    return (-1);
00225                             target[tarindex] = (pos - Base64) << 2;
00226                      }
00227                      state = 1;
00228                      break;
00229               case 1:
00230                      if (target) {
00231                             if ((size_t)tarindex + 1 >= targsize)
00232                                    return (-1);
00233                             target[tarindex]   |=  (pos - Base64) >> 4;
00234                             target[tarindex+1]  = ((pos - Base64) & 0x0f)
00235                                                  << 4 ;
00236                      }
00237                      tarindex++;
00238                      state = 2;
00239                      break;
00240               case 2:
00241                      if (target) {
00242                             if ((size_t)tarindex + 1 >= targsize)
00243                                    return (-1);
00244                             target[tarindex]   |=  (pos - Base64) >> 2;
00245                             target[tarindex+1]  = ((pos - Base64) & 0x03)
00246                                                  << 6;
00247                      }
00248                      tarindex++;
00249                      state = 3;
00250                      break;
00251               case 3:
00252                      if (target) {
00253                             if ((size_t)tarindex >= targsize)
00254                                    return (-1);
00255                             target[tarindex] |= (pos - Base64);
00256                      }
00257                      tarindex++;
00258                      state = 0;
00259                      break;
00260               default:
00261                      abort();
00262               }
00263        }
00264 
00265        /*
00266         * We are done decoding Base-64 chars.  Let's see if we ended
00267         * on a byte boundary, and/or with erroneous trailing characters.
00268         */
00269 
00270        if (ch == Pad64) {          /* We got a pad char. */
00271               ch = *src++;         /* Skip it, get next. */
00272               switch (state) {
00273               case 0:              /* Invalid = in first position */
00274               case 1:              /* Invalid = in second position */
00275                      return (-1);
00276 
00277               case 2:              /* Valid, means one byte of info */
00278                      /* Skip any number of spaces. */
00279                      for ((void)NULL; ch != '\0'; ch = *src++)
00280                             if (!isspace(ch))
00281                                    break;
00282                      /* Make sure there is another trailing = sign. */
00283                      if (ch != Pad64)
00284                             return (-1);
00285                      ch = *src++;         /* Skip the = */
00286                      /* Fall through to "single trailing =" case. */
00287                      /* FALLTHROUGH */
00288 
00289               case 3:              /* Valid, means two bytes of info */
00290                      /*
00291                       * We know this char is an =.  Is there anything but
00292                       * whitespace after it?
00293                       */
00294                      for ((void)NULL; ch != '\0'; ch = *src++)
00295                             if (!isspace(ch))
00296                                    return (-1);
00297 
00298                      /*
00299                       * Now make sure for cases 2 and 3 that the "extra"
00300                       * bits that slopped past the last full byte were
00301                       * zeros.  If we don't check them, they become a
00302                       * subliminal channel.
00303                       */
00304                      if (target && target[tarindex] != 0)
00305                             return (-1);
00306               }
00307        } else {
00308               /*
00309                * We ended by seeing the end of the string.  Make sure we
00310                * have no partial bytes lying around.
00311                */
00312               if (state != 0)
00313                      return (-1);
00314        }
00315 
00316        return (tarindex);
00317 }