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 "SecBase64.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 /* ////////////////////////////////////////////////////////////////////////// */