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"
50 /* /////////////////////////////////////////////////////////////////////////////
51 * Constants and definitions
54 #ifndef B64_DOCUMENTATION_SKIP_SECTION
55 # define NUM_PLAIN_DATA_BYTES (3)
56 # define NUM_ENCODED_DATA_BYTES (4)
57 #endif /* !B64_DOCUMENTATION_SKIP_SECTION */
59 /* /////////////////////////////////////////////////////////////////////////////
63 #if defined(_MSC_VER) && \
65 # pragma warning(disable : 4705)
66 #endif /* _MSC_VER < 1000 */
68 /* /////////////////////////////////////////////////////////////////////////////
72 static const char b64_chars
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
74 static const signed char b64_indexes
[] =
76 /* 0 - 31 / 0x00 - 0x1f */
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 , -1, -1, -1, -1, -1, -1, -1, -1
81 /* 32 - 63 / 0x20 - 0x3f */
82 , -1, -1, -1, -1, -1, -1, -1, -1
83 , -1, -1, -1, 62, -1, -1, -1, 63 /* ... , '+', ... '/' */
84 , 52, 53, 54, 55, 56, 57, 58, 59 /* '0' - '7' */
85 , 60, 61, -1, -1, -1, -1, -1, -1 /* '8', '9', ... */
86 /* 64 - 95 / 0x40 - 0x5f */
87 , -1, 0, 1, 2, 3, 4, 5, 6 /* ..., 'A' - 'G' */
88 , 7, 8, 9, 10, 11, 12, 13, 14 /* 'H' - 'O' */
89 , 15, 16, 17, 18, 19, 20, 21, 22 /* 'P' - 'W' */
90 , 23, 24, 25, -1, -1, -1, -1, -1 /* 'X', 'Y', 'Z', ... */
91 /* 96 - 127 / 0x60 - 0x7f */
92 , -1, 26, 27, 28, 29, 30, 31, 32 /* ..., 'a' - 'g' */
93 , 33, 34, 35, 36, 37, 38, 39, 40 /* 'h' - 'o' */
94 , 41, 42, 43, 44, 45, 46, 47, 48 /* 'p' - 'w' */
95 , 49, 50, 51, -1, -1, -1, -1, -1 /* 'x', 'y', 'z', ... */
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
100 , -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
105 , -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
110 , -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
115 , -1, -1, -1, -1, -1, -1, -1, -1
118 /* /////////////////////////////////////////////////////////////////////////////
122 /** This function reads in 3 bytes at a time, and translates them into 4
125 static size_t SecBase64Encode_( unsigned char const *src
130 , SecBase64Result
*rc
)
132 size_t total
= ((srcSize
+ (NUM_PLAIN_DATA_BYTES
- 1)) / NUM_PLAIN_DATA_BYTES
) * NUM_ENCODED_DATA_BYTES
;
139 size_t numLines
= (total
+ (lineLen
- 1)) / lineLen
;
141 total
+= 2 * (numLines
- 1);
148 else if(destLen
< total
)
150 *rc
= kSecB64_R_INSUFFICIENT_BUFFER
;
157 char *end
= dest
+ destLen
;
160 for(; NUM_PLAIN_DATA_BYTES
<= srcSize
; srcSize
-= NUM_PLAIN_DATA_BYTES
)
162 char characters
[NUM_ENCODED_DATA_BYTES
];
170 * | | | | | | | | | | | | |
171 * | | | | | | | | | | | | | | | | | | | | | | | | |
177 /* characters[0] is the 6 left-most bits of src[0] */
178 characters
[0] = (char)((src
[0] & 0xfc) >> 2);
179 /* characters[0] is the right-most 2 bits of src[0] and the left-most 4 bits of src[1] */
180 characters
[1] = (char)(((src
[0] & 0x03) << 4) + ((src
[1] & 0xf0) >> 4));
181 /* characters[0] is the right-most 4 bits of src[1] and the 2 left-most bits of src[2] */
182 characters
[2] = (char)(((src
[1] & 0x0f) << 2) + ((src
[2] & 0xc0) >> 6));
183 /* characters[3] is the right-most 6 bits of src[2] */
184 characters
[3] = (char)(src
[2] & 0x3f);
187 assert(characters
[0] >= 0 && characters
[0] < 64);
188 assert(characters
[1] >= 0 && characters
[1] < 64);
189 assert(characters
[2] >= 0 && characters
[2] < 64);
190 assert(characters
[3] >= 0 && characters
[3] < 64);
191 #endif /* __WATCOMC__ */
193 src
+= NUM_PLAIN_DATA_BYTES
;
194 *p
++ = b64_chars
[(unsigned char)characters
[0]];
195 assert(NULL
!= strchr(b64_chars
, *(p
-1)));
197 assert(len
!= lineLen
);
199 *p
++ = b64_chars
[(unsigned char)characters
[1]];
200 assert(NULL
!= strchr(b64_chars
, *(p
-1)));
202 assert(len
!= lineLen
);
204 *p
++ = b64_chars
[(unsigned char)characters
[2]];
205 assert(NULL
!= strchr(b64_chars
, *(p
-1)));
207 assert(len
!= lineLen
);
209 *p
++ = b64_chars
[(unsigned char)characters
[3]];
210 assert(NULL
!= strchr(b64_chars
, *(p
-1)));
212 if( ++len
== lineLen
&&
223 /* Deal with the overspill, by boosting it up to three bytes (using 0s)
224 * and then appending '=' for any missing characters.
226 * This is done into a temporary buffer, so we can call ourselves and
227 * have the output continue to be written direct to the destination.
230 unsigned char dummy
[NUM_PLAIN_DATA_BYTES
];
233 for(i
= 0; i
< srcSize
; ++i
)
238 for(; i
< NUM_PLAIN_DATA_BYTES
; ++i
)
243 SecBase64Encode_(&dummy
[0], NUM_PLAIN_DATA_BYTES
, p
, NUM_ENCODED_DATA_BYTES
* (1 + 2), 0, rc
);
245 for(p
+= 1 + srcSize
; srcSize
++ < NUM_PLAIN_DATA_BYTES
; )
255 /** This function reads in a character string in 4-character chunks, and writes
256 * out the converted form in 3-byte chunks to the destination.
258 static size_t SecBase64Decode_( char const *src
260 , unsigned char *dest
263 , char const **badChar
264 , SecBase64Result
*rc
)
266 const size_t wholeChunks
= (srcLen
/ NUM_ENCODED_DATA_BYTES
);
267 const size_t remainderBytes
= (srcLen
% NUM_ENCODED_DATA_BYTES
);
268 size_t maxTotal
= (wholeChunks
+ (0 != remainderBytes
)) * NUM_PLAIN_DATA_BYTES
;
269 unsigned char *dest_
= dest
;
271 ((void)remainderBytes
);
273 assert(NULL
!= badChar
);
283 else if(destSize
< maxTotal
)
285 *rc
= kSecB64_R_INSUFFICIENT_BUFFER
;
291 /* Now we iterate through the src, collecting together four characters
292 * at a time from the Base-64 alphabet, until the end-point is reached.
297 char const *begin
= src
;
298 char const *const end
= begin
+ srcLen
;
299 size_t currIndex
= 0;
301 signed char indexes
[NUM_ENCODED_DATA_BYTES
]; /* 4 */
303 for(; begin
!= end
; ++begin
)
305 const char ch
= *begin
;
309 assert(currIndex
< NUM_ENCODED_DATA_BYTES
);
311 indexes
[currIndex
++] = '\0';
317 signed char ix
= b64_indexes
[(unsigned char)ch
];
327 if(kSecB64_F_STOP_ON_UNEXPECTED_WS
& flags
)
329 *rc
= kSecB64_R_DATA_ERROR
;
341 if(kSecB64_F_STOP_ON_UNKNOWN_CHAR
& flags
)
343 *rc
= kSecB64_R_DATA_ERROR
;
357 assert(currIndex
< NUM_ENCODED_DATA_BYTES
);
359 indexes
[currIndex
++] = ix
;
363 if(NUM_ENCODED_DATA_BYTES
== currIndex
)
365 unsigned char bytes
[NUM_PLAIN_DATA_BYTES
]; /* 3 */
367 bytes
[0] = (unsigned char)((indexes
[0] << 2) + ((indexes
[1] & 0x30) >> 4));
374 bytes
[1] = (unsigned char)(((indexes
[1] & 0xf) << 4) + ((indexes
[2] & 0x3c) >> 2));
380 bytes
[2] = (unsigned char)(((indexes
[2] & 0x3) << 6) + indexes
[3]);
392 return (size_t)(dest
- dest_
);
396 /* /////////////////////////////////////////////////////////////////////////////
400 size_t SecBase64Encode(void const *src
, size_t srcSize
, char *dest
, size_t destLen
)
402 /* Use Null Object (Variable) here for rc, so do not need to check
407 return SecBase64Encode_((unsigned char const*)src
, srcSize
, dest
, destLen
, 0, &rc_
);
410 size_t SecBase64Encode2( void const *src
415 , int lineLen
/* = -1 */
416 , SecBase64Result
*rc
/* = NULL */)
418 /* Use Null Object (Variable) here for rc, so do not need to check
427 switch(kSecB64_F_LINE_LEN_MASK
& flags
)
429 case kSecB64_F_LINE_LEN_USE_PARAM
:
434 /* Fall through to 64 */
435 case kSecB64_F_LINE_LEN_64
:
438 case kSecB64_F_LINE_LEN_76
:
442 assert(false); // "Bad line length flag specified to SecBase64Encode2()"
443 case kSecB64_F_LINE_LEN_INFINITE
:
448 assert(0 == (lineLen
% 4));
450 return SecBase64Encode_((unsigned char const*)src
, srcSize
, dest
, destLen
, (unsigned)lineLen
, rc
);
453 size_t SecBase64Decode(char const *src
, size_t srcLen
, void *dest
, size_t destSize
)
455 /* Use Null Object (Variable) here for rc and badChar, so do not need to
458 char const *badChar_
;
461 return SecBase64Decode_(src
, srcLen
, (unsigned char*)dest
, destSize
, kSecB64_F_STOP_ON_NOTHING
, &badChar_
, &rc_
);
464 size_t SecBase64Decode2( char const *src
469 , char const **badChar
/* = NULL */
470 , SecBase64Result
*rc
/* = NULL */)
472 char const *badChar_
;
475 /* Use Null Object (Variable) here for rc and badChar, so do not need to
487 return SecBase64Decode_(src
, srcLen
, (unsigned char*)dest
, destSize
, flags
, badChar
, rc
);
490 /* ////////////////////////////////////////////////////////////////////////// */