1 /* ///////////////////////////////////////////////////////////////////////////// 
   4  * Purpose:     Implementation file for the b64 library 
   6  * Created:     18th October 2004 
   7  * Updated:     2nd August 2006 
   9  * Home:        http://synesis.com.au/software/ 
  11  * Copyright (c) 2004-2006, Matthew Wilson and Synesis Software 
  12  * All rights reserved. 
  14  * Redistribution and use in source and binary forms, with or without  
  15  * modification, are permitted provided that the following conditions are met: 
  17  * - Redistributions of source code must retain the above copyright notice, this 
  18  *   list of conditions and the following disclaimer.  
  19  * - Redistributions in binary form must reproduce the above copyright notice, 
  20  *   this list of conditions and the following disclaimer in the documentation 
  21  *   and/or other materials provided with the distribution. 
  22  * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of 
  23  *   any contributors may be used to endorse or promote products derived from 
  24  *   this software without specific prior written permission. 
  26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  36  * POSSIBILITY OF SUCH DAMAGE. 
  38  * ////////////////////////////////////////////////////////////////////////// */ 
  41 /** \file b64.c Implementation file for the b64 library 
  44 #include "SecBase64P.h" 
  49 /* ///////////////////////////////////////////////////////////////////////////// 
  50  * Constants and definitions 
  53 #ifndef B64_DOCUMENTATION_SKIP_SECTION 
  54 # define NUM_PLAIN_DATA_BYTES        (3) 
  55 # define NUM_ENCODED_DATA_BYTES      (4) 
  56 #endif /* !B64_DOCUMENTATION_SKIP_SECTION */ 
  58 /* ///////////////////////////////////////////////////////////////////////////// 
  62 #if defined(_MSC_VER) && \ 
  64 # pragma warning(disable : 4705) 
  65 #endif /* _MSC_VER < 1000 */ 
  67 /* ///////////////////////////////////////////////////////////////////////////// 
  71 static const char           b64_chars
[] =   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 
  73 static const signed char    b64_indexes
[]   =    
  75     /* 0 - 31 / 0x00 - 0x1f */ 
  76         -1, -1, -1, -1, -1, -1, -1, -1   
  77     ,   -1, -1, -1, -1, -1, -1, -1, -1   
  78     ,   -1, -1, -1, -1, -1, -1, -1, -1   
  79     ,   -1, -1, -1, -1, -1, -1, -1, -1 
  80     /* 32 - 63 / 0x20 - 0x3f */ 
  81     ,   -1, -1, -1, -1, -1, -1, -1, -1   
  82     ,   -1, -1, -1, 62, -1, -1, -1, 63  /* ... , '+', ... '/' */ 
  83     ,   52, 53, 54, 55, 56, 57, 58, 59  /* '0' - '7' */ 
  84     ,   60, 61, -1, -1, -1, -1, -1, -1  /* '8', '9', ... */ 
  85     /* 64 - 95 / 0x40 - 0x5f */ 
  86     ,   -1, 0,  1,  2,  3,  4,  5,  6   /* ..., 'A' - 'G' */ 
  87     ,   7,  8,  9,  10, 11, 12, 13, 14  /* 'H' - 'O' */ 
  88     ,   15, 16, 17, 18, 19, 20, 21, 22  /* 'P' - 'W' */ 
  89     ,   23, 24, 25, -1, -1, -1, -1, -1  /* 'X', 'Y', 'Z', ... */ 
  90     /* 96 - 127 / 0x60 - 0x7f */ 
  91     ,   -1, 26, 27, 28, 29, 30, 31, 32  /* ..., 'a' - 'g' */ 
  92     ,   33, 34, 35, 36, 37, 38, 39, 40  /* 'h' - 'o' */ 
  93     ,   41, 42, 43, 44, 45, 46, 47, 48  /* 'p' - 'w' */ 
  94     ,   49, 50, 51, -1, -1, -1, -1, -1  /* 'x', 'y', 'z', ... */ 
  96     ,   -1, -1, -1, -1, -1, -1, -1, -1   
  97     ,   -1, -1, -1, -1, -1, -1, -1, -1   
  98     ,   -1, -1, -1, -1, -1, -1, -1, -1   
  99     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 101     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 102     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 103     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 104     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 106     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 107     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 108     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 109     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 111     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 112     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 113     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 114     ,   -1, -1, -1, -1, -1, -1, -1, -1   
 117 /* ///////////////////////////////////////////////////////////////////////////// 
 121 /** This function reads in 3 bytes at a time, and translates them into 4 
 124 static size_t SecBase64Encode_(  unsigned char const *src
 
 129                         ,   SecBase64Result     
*rc
) 
 131     size_t  total   
=   ((srcSize 
+ (NUM_PLAIN_DATA_BYTES 
- 1)) / NUM_PLAIN_DATA_BYTES
) * NUM_ENCODED_DATA_BYTES
; 
 138         size_t    numLines    
=   (total 
+ (lineLen 
- 1)) / lineLen
; 
 140         total 
+= 2 * (numLines 
- 1); 
 147     else if(destLen 
< total
) 
 149         *rc 
= kSecB64_R_INSUFFICIENT_BUFFER
; 
 156         char    *end    
=   dest 
+ destLen
; 
 159         for(; NUM_PLAIN_DATA_BYTES 
<= srcSize
; srcSize 
-= NUM_PLAIN_DATA_BYTES
) 
 161             char    characters
[NUM_ENCODED_DATA_BYTES
]; 
 169              * |   |   |   |   |   |   |   |   |   |   |   |   | 
 170              * | | | | | | | | | | | | | | | | | | | | | | | | | 
 176             /* characters[0] is the 6 left-most bits of src[0] */ 
 177             characters
[0] = (char)((src
[0] & 0xfc) >> 2); 
 178             /* characters[0] is the right-most 2 bits of src[0] and the left-most 4 bits of src[1] */ 
 179             characters
[1] = (char)(((src
[0] & 0x03) << 4) + ((src
[1] & 0xf0) >> 4)); 
 180             /* characters[0] is the right-most 4 bits of src[1] and the 2 left-most bits of src[2] */ 
 181             characters
[2] = (char)(((src
[1] & 0x0f) << 2) + ((src
[2] & 0xc0) >> 6)); 
 182             /* characters[3] is the right-most 6 bits of src[2] */ 
 183             characters
[3] = (char)(src
[2] & 0x3f); 
 186             assert(characters
[0] >= 0 && characters
[0] < 64); 
 187             assert(characters
[1] >= 0 && characters
[1] < 64); 
 188             assert(characters
[2] >= 0 && characters
[2] < 64); 
 189             assert(characters
[3] >= 0 && characters
[3] < 64); 
 190 #endif /* __WATCOMC__ */ 
 192             src 
+= NUM_PLAIN_DATA_BYTES
; 
 193             *p
++ = b64_chars
[(unsigned char)characters
[0]]; 
 194             assert(NULL 
!= strchr(b64_chars
, *(p
-1))); 
 196             assert(len 
!= lineLen
); 
 198             *p
++ = b64_chars
[(unsigned char)characters
[1]]; 
 199             assert(NULL 
!= strchr(b64_chars
, *(p
-1))); 
 201             assert(len 
!= lineLen
); 
 203             *p
++ = b64_chars
[(unsigned char)characters
[2]]; 
 204             assert(NULL 
!= strchr(b64_chars
, *(p
-1))); 
 206             assert(len 
!= lineLen
); 
 208             *p
++ = b64_chars
[(unsigned char)characters
[3]]; 
 209             assert(NULL 
!= strchr(b64_chars
, *(p
-1))); 
 211             if( ++len 
== lineLen 
&& 
 222             /* Deal with the overspill, by boosting it up to three bytes (using 0s) 
 223              * and then appending '=' for any missing characters. 
 225              * This is done into a temporary buffer, so we can call ourselves and 
 226              * have the output continue to be written direct to the destination. 
 229             unsigned char   dummy
[NUM_PLAIN_DATA_BYTES
]; 
 232             for(i 
= 0; i 
< srcSize
; ++i
) 
 237             for(; i 
< NUM_PLAIN_DATA_BYTES
; ++i
) 
 242             SecBase64Encode_(&dummy
[0], NUM_PLAIN_DATA_BYTES
, p
, NUM_ENCODED_DATA_BYTES 
* (1 + 2), 0, rc
); 
 244             for(p 
+= 1 + srcSize
; srcSize
++ < NUM_PLAIN_DATA_BYTES
; ) 
 254 /** This function reads in a character string in 4-character chunks, and writes  
 255  * out the converted form in 3-byte chunks to the destination. 
 257 static size_t SecBase64Decode_(  char const      *src
 
 259                         ,   unsigned char   *dest
 
 262                         ,   char const      **badChar
 
 263                         ,   SecBase64Result 
*rc
) 
 265     const size_t    wholeChunks     
=   (srcLen 
/ NUM_ENCODED_DATA_BYTES
); 
 266     const size_t    remainderBytes  
=   (srcLen 
% NUM_ENCODED_DATA_BYTES
); 
 267     size_t          maxTotal        
=   (wholeChunks 
+ (0 != remainderBytes
)) * NUM_PLAIN_DATA_BYTES
; 
 268     unsigned char   *dest_          
=   dest
; 
 270     ((void)remainderBytes
); 
 272     assert(NULL 
!= badChar
); 
 282     else if(destSize 
< maxTotal
) 
 284         *rc 
= kSecB64_R_INSUFFICIENT_BUFFER
; 
 290         /* Now we iterate through the src, collecting together four characters 
 291          * at a time from the Base-64 alphabet, until the end-point is reached. 
 296         char const          *begin      
=   src
; 
 297         char const  *const  end         
=   begin 
+ srcLen
; 
 298         size_t              currIndex   
=   0; 
 300         signed char         indexes
[NUM_ENCODED_DATA_BYTES
];    /* 4 */ 
 302         for(; begin 
!= end
; ++begin
) 
 304             const char  ch  
=   *begin
; 
 308                 assert(currIndex 
< NUM_ENCODED_DATA_BYTES
); 
 310                 indexes
[currIndex
++] = '\0'; 
 316                 signed char ix   
=   b64_indexes
[(unsigned char)ch
]; 
 326                             if(kSecB64_F_STOP_ON_UNEXPECTED_WS 
& flags
) 
 328                                 *rc         
=   kSecB64_R_DATA_ERROR
; 
 340                             if(kSecB64_F_STOP_ON_UNKNOWN_CHAR 
& flags
) 
 342                                 *rc         
=   kSecB64_R_DATA_ERROR
; 
 356                     assert(currIndex 
< NUM_ENCODED_DATA_BYTES
); 
 358                     indexes
[currIndex
++] = ix
; 
 362             if(NUM_ENCODED_DATA_BYTES 
== currIndex
) 
 364                 unsigned char   bytes
[NUM_PLAIN_DATA_BYTES
];        /* 3 */ 
 366                 bytes
[0] = (unsigned char)((indexes
[0] << 2) + ((indexes
[1] & 0x30) >> 4)); 
 373                     bytes
[1] = (unsigned char)(((indexes
[1] & 0xf) << 4) + ((indexes
[2] & 0x3c) >> 2)); 
 379                         bytes
[2] = (unsigned char)(((indexes
[2] & 0x3) << 6) + indexes
[3]); 
 391         return (size_t)(dest 
- dest_
); 
 395 /* ///////////////////////////////////////////////////////////////////////////// 
 399 size_t SecBase64Encode(void const *src
, size_t srcSize
, char *dest
, size_t destLen
) 
 401     /* Use Null Object (Variable) here for rc, so do not need to check 
 406     return SecBase64Encode_((unsigned char const*)src
, srcSize
, dest
, destLen
, 0, &rc_
); 
 409 size_t SecBase64Encode2( void const *src
 
 414                 ,   int             lineLen 
/* = -1 */ 
 415                 ,   SecBase64Result 
*rc     
/* = NULL */) 
 417     /* Use Null Object (Variable) here for rc, so do not need to check 
 426     switch(kSecB64_F_LINE_LEN_MASK 
& flags
) 
 428         case    kSecB64_F_LINE_LEN_USE_PARAM
: 
 433             /* Fall through to 64 */ 
 434         case    kSecB64_F_LINE_LEN_64
: 
 437         case    kSecB64_F_LINE_LEN_76
: 
 441             assert(!"Bad line length flag specified to SecBase64Encode2()"); 
 442         case    kSecB64_F_LINE_LEN_INFINITE
: 
 447     assert(0 == (lineLen 
% 4)); 
 449     return SecBase64Encode_((unsigned char const*)src
, srcSize
, dest
, destLen
, (unsigned)lineLen
, rc
); 
 452 size_t SecBase64Decode(char const *src
, size_t srcLen
, void *dest
, size_t destSize
) 
 454     /* Use Null Object (Variable) here for rc and badChar, so do not need to 
 457     char const  *badChar_
; 
 460     return SecBase64Decode_(src
, srcLen
, (unsigned char*)dest
, destSize
, kSecB64_F_STOP_ON_NOTHING
, &badChar_
, &rc_
); 
 463 size_t SecBase64Decode2( char const  *src
 
 468                 ,   char const  **badChar   
/* = NULL */ 
 469                 ,   SecBase64Result      
*rc         
/* = NULL */) 
 471     char const      *badChar_
; 
 474     /* Use Null Object (Variable) here for rc and badChar, so do not need to 
 486     return SecBase64Decode_(src
, srcLen
, (unsigned char*)dest
, destSize
, flags
, badChar
, rc
); 
 489 /* ////////////////////////////////////////////////////////////////////////// */