Back to index

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