]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecBase64P.c
Security-58286.20.16.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecBase64P.c
1 /* /////////////////////////////////////////////////////////////////////////////
2 * File: b64.c
3 *
4 * Purpose: Implementation file for the b64 library
5 *
6 * Created: 18th October 2004
7 * Updated: 2nd August 2006
8 *
9 * Home: http://synesis.com.au/software/
10 *
11 * Copyright (c) 2004-2006, Matthew Wilson and Synesis Software
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are met:
16 *
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.
25 *
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.
37 *
38 * ////////////////////////////////////////////////////////////////////////// */
39
40
41 /** \file b64.c Implementation file for the b64 library
42 */
43
44 #include "SecBase64P.h"
45
46 #include <assert.h>
47 #include <string.h>
48
49 /* /////////////////////////////////////////////////////////////////////////////
50 * Constants and definitions
51 */
52
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 */
57
58 /* /////////////////////////////////////////////////////////////////////////////
59 * Warnings
60 */
61
62 #if defined(_MSC_VER) && \
63 _MSC_VER < 1000
64 # pragma warning(disable : 4705)
65 #endif /* _MSC_VER < 1000 */
66
67 /* /////////////////////////////////////////////////////////////////////////////
68 * Data
69 */
70
71 static const char b64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
72
73 static const signed char b64_indexes[] =
74 {
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', ... */
95
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
100
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
105
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
110
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
115 };
116
117 /* /////////////////////////////////////////////////////////////////////////////
118 * Helper functions
119 */
120
121 /** This function reads in 3 bytes at a time, and translates them into 4
122 * characters.
123 */
124 static size_t SecBase64Encode_( unsigned char const *src
125 , size_t srcSize
126 , char *const dest
127 , size_t destLen
128 , unsigned lineLen
129 , SecBase64Result *rc)
130 {
131 size_t total = ((srcSize + (NUM_PLAIN_DATA_BYTES - 1)) / NUM_PLAIN_DATA_BYTES) * NUM_ENCODED_DATA_BYTES;
132
133 assert(NULL != rc);
134 *rc = kSecB64_R_OK;
135
136 if(lineLen > 0)
137 {
138 size_t numLines = (total + (lineLen - 1)) / lineLen;
139
140 total += 2 * (numLines - 1);
141 }
142
143 if(NULL == dest)
144 {
145 return total;
146 }
147 else if(destLen < total)
148 {
149 *rc = kSecB64_R_INSUFFICIENT_BUFFER;
150
151 return 0;
152 }
153 else
154 {
155 char *p = dest;
156 char *end = dest + destLen;
157 size_t len = 0;
158
159 for(; NUM_PLAIN_DATA_BYTES <= srcSize; srcSize -= NUM_PLAIN_DATA_BYTES)
160 {
161 char characters[NUM_ENCODED_DATA_BYTES];
162
163 /*
164 *
165 * | 0 | 1 | 2 |
166 *
167 * | | | |
168 * | | | | | | |
169 * | | | | | | | | | | | | |
170 * | | | | | | | | | | | | | | | | | | | | | | | | |
171 *
172 * | 0 | 1 | 2 | 3 |
173 *
174 */
175
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);
184
185 #ifndef __WATCOMC__
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__ */
191
192 src += NUM_PLAIN_DATA_BYTES;
193 *p++ = b64_chars[(unsigned char)characters[0]];
194 assert(NULL != strchr(b64_chars, *(p-1)));
195 ++len;
196 assert(len != lineLen);
197
198 *p++ = b64_chars[(unsigned char)characters[1]];
199 assert(NULL != strchr(b64_chars, *(p-1)));
200 ++len;
201 assert(len != lineLen);
202
203 *p++ = b64_chars[(unsigned char)characters[2]];
204 assert(NULL != strchr(b64_chars, *(p-1)));
205 ++len;
206 assert(len != lineLen);
207
208 *p++ = b64_chars[(unsigned char)characters[3]];
209 assert(NULL != strchr(b64_chars, *(p-1)));
210
211 if( ++len == lineLen &&
212 p != end)
213 {
214 *p++ = '\r';
215 *p++ = '\n';
216 len = 0;
217 }
218 }
219
220 if(0 != srcSize)
221 {
222 /* Deal with the overspill, by boosting it up to three bytes (using 0s)
223 * and then appending '=' for any missing characters.
224 *
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.
227 */
228
229 unsigned char dummy[NUM_PLAIN_DATA_BYTES];
230 size_t i;
231
232 for(i = 0; i < srcSize; ++i)
233 {
234 dummy[i] = *src++;
235 }
236
237 for(; i < NUM_PLAIN_DATA_BYTES; ++i)
238 {
239 dummy[i] = '\0';
240 }
241
242 SecBase64Encode_(&dummy[0], NUM_PLAIN_DATA_BYTES, p, NUM_ENCODED_DATA_BYTES * (1 + 2), 0, rc);
243
244 for(p += 1 + srcSize; srcSize++ < NUM_PLAIN_DATA_BYTES; )
245 {
246 *p++ = '=';
247 }
248 }
249
250 return total;
251 }
252 }
253
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.
256 */
257 static size_t SecBase64Decode_( char const *src
258 , size_t srcLen
259 , unsigned char *dest
260 , size_t destSize
261 , unsigned flags
262 , char const **badChar
263 , SecBase64Result *rc)
264 {
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;
269
270 ((void)remainderBytes);
271
272 assert(NULL != badChar);
273 assert(NULL != rc);
274
275 *badChar = NULL;
276 *rc = kSecB64_R_OK;
277
278 if(NULL == dest)
279 {
280 return maxTotal;
281 }
282 else if(destSize < maxTotal)
283 {
284 *rc = kSecB64_R_INSUFFICIENT_BUFFER;
285
286 return 0;
287 }
288 else
289 {
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.
292 *
293 *
294 */
295
296 char const *begin = src;
297 char const *const end = begin + srcLen;
298 size_t currIndex = 0;
299 size_t numPads = 0;
300 signed char indexes[NUM_ENCODED_DATA_BYTES]; /* 4 */
301
302 for(; begin != end; ++begin)
303 {
304 const char ch = *begin;
305
306 if('=' == ch)
307 {
308 assert(currIndex < NUM_ENCODED_DATA_BYTES);
309
310 indexes[currIndex++] = '\0';
311
312 ++numPads;
313 }
314 else
315 {
316 signed char ix = b64_indexes[(unsigned char)ch];
317
318 if(-1 == ix)
319 {
320 switch(ch)
321 {
322 case ' ':
323 case '\t':
324 case '\b':
325 case '\v':
326 if(kSecB64_F_STOP_ON_UNEXPECTED_WS & flags)
327 {
328 *rc = kSecB64_R_DATA_ERROR;
329 *badChar = begin;
330 return 0;
331 }
332 else
333 {
334 /* Fall through */
335 }
336 case '\r':
337 case '\n':
338 continue;
339 default:
340 if(kSecB64_F_STOP_ON_UNKNOWN_CHAR & flags)
341 {
342 *rc = kSecB64_R_DATA_ERROR;
343 *badChar = begin;
344 return 0;
345 }
346 else
347 {
348 continue;
349 }
350 }
351 }
352 else
353 {
354 numPads = 0;
355
356 assert(currIndex < NUM_ENCODED_DATA_BYTES);
357
358 indexes[currIndex++] = ix;
359 }
360 }
361
362 if(NUM_ENCODED_DATA_BYTES == currIndex)
363 {
364 unsigned char bytes[NUM_PLAIN_DATA_BYTES]; /* 3 */
365
366 bytes[0] = (unsigned char)((indexes[0] << 2) + ((indexes[1] & 0x30) >> 4));
367
368 currIndex = 0;
369
370 *dest++ = bytes[0];
371 if(2 != numPads)
372 {
373 bytes[1] = (unsigned char)(((indexes[1] & 0xf) << 4) + ((indexes[2] & 0x3c) >> 2));
374
375 *dest++ = bytes[1];
376
377 if(1 != numPads)
378 {
379 bytes[2] = (unsigned char)(((indexes[2] & 0x3) << 6) + indexes[3]);
380
381 *dest++ = bytes[2];
382 }
383 }
384 if(0 != numPads)
385 {
386 break;
387 }
388 }
389 }
390
391 return (size_t)(dest - dest_);
392 }
393 }
394
395 /* /////////////////////////////////////////////////////////////////////////////
396 * API functions
397 */
398
399 size_t SecBase64Encode(void const *src, size_t srcSize, char *dest, size_t destLen)
400 {
401 /* Use Null Object (Variable) here for rc, so do not need to check
402 * elsewhere.
403 */
404 SecBase64Result rc_;
405
406 return SecBase64Encode_((unsigned char const*)src, srcSize, dest, destLen, 0, &rc_);
407 }
408
409 size_t SecBase64Encode2( void const *src
410 , size_t srcSize
411 , char *dest
412 , size_t destLen
413 , unsigned flags
414 , int lineLen /* = -1 */
415 , SecBase64Result *rc /* = NULL */)
416 {
417 /* Use Null Object (Variable) here for rc, so do not need to check
418 * elsewhere
419 */
420 SecBase64Result rc_;
421 if(NULL == rc)
422 {
423 rc = &rc_;
424 }
425
426 switch(kSecB64_F_LINE_LEN_MASK & flags)
427 {
428 case kSecB64_F_LINE_LEN_USE_PARAM:
429 if(lineLen >= 0)
430 {
431 break;
432 }
433 /* Fall through to 64 */
434 case kSecB64_F_LINE_LEN_64:
435 lineLen = 64;
436 break;
437 case kSecB64_F_LINE_LEN_76:
438 lineLen = 76;
439 break;
440 default:
441 assert(!"Bad line length flag specified to SecBase64Encode2()");
442 case kSecB64_F_LINE_LEN_INFINITE:
443 lineLen = 0;
444 break;
445 }
446
447 assert(0 == (lineLen % 4));
448
449 return SecBase64Encode_((unsigned char const*)src, srcSize, dest, destLen, (unsigned)lineLen, rc);
450 }
451
452 size_t SecBase64Decode(char const *src, size_t srcLen, void *dest, size_t destSize)
453 {
454 /* Use Null Object (Variable) here for rc and badChar, so do not need to
455 * check elsewhere.
456 */
457 char const *badChar_;
458 SecBase64Result rc_;
459
460 return SecBase64Decode_(src, srcLen, (unsigned char*)dest, destSize, kSecB64_F_STOP_ON_NOTHING, &badChar_, &rc_);
461 }
462
463 size_t SecBase64Decode2( char const *src
464 , size_t srcLen
465 , void *dest
466 , size_t destSize
467 , unsigned flags
468 , char const **badChar /* = NULL */
469 , SecBase64Result *rc /* = NULL */)
470 {
471 char const *badChar_;
472 SecBase64Result rc_;
473
474 /* Use Null Object (Variable) here for rc and badChar, so do not need to
475 * check elsewhere.
476 */
477 if(NULL == badChar)
478 {
479 badChar = &badChar_;
480 }
481 if(NULL == rc)
482 {
483 rc = &rc_;
484 }
485
486 return SecBase64Decode_(src, srcLen, (unsigned char*)dest, destSize, flags, badChar, rc);
487 }
488
489 /* ////////////////////////////////////////////////////////////////////////// */