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