1/* 2 * Copyright (c) 2011 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include "basexx.h" 25#include "CommonBaseXX.h" 26#include "ccMemory.h" 27#include "CommonBufferingPriv.h" 28#include "ccGlobals.h" 29#include <AssertMacros.h> 30 31const static encoderConstants encoderValue[] = { 32 { 16, 4, 1, 2, 0x0f }, // Base16 33 { 32, 5, 5, 8, 0x1f }, // Base32 34 { 64, 6, 3, 4, 0x3f }, // Base64 35}; 36 37typedef struct _CNEncoder { 38 CoderFrame coderFrame; 39 CNEncodingDirection direction; 40 CNBufferRef base256buffer; 41 CNBufferRef baseXXbuffer; 42} CNEncoder; 43 44/* 45 * Pre-defined encoders. 46 */ 47 48#define DEFAULTPAD '=' 49 50const static BaseEncoder defaultBase64 = { 51 .name = "Base64", 52 .encoding = kCNEncodingBase64, 53 .baseNum = 64, 54 .charMap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 55 .padding = DEFAULTPAD, 56 .values = &encoderValue[2] 57}; 58 59// RFC 4678 Base32Alphabet 60const static BaseEncoder defaultBase32 = { 61 .name = "Base32", 62 .encoding = kCNEncodingBase32, 63 .baseNum = 32, 64 .charMap = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", 65 .padding = DEFAULTPAD, 66 .values = &encoderValue[1] 67}; 68 69const static BaseEncoder recoveryBase32 = { 70 .name = "RecoveryBase32", 71 .encoding = kCNEncodingBase32Recovery, 72 .baseNum = 32, 73 .charMap = "ABCDEFGH8JKLMNOPQR9TUVWXYZ234567", 74 .padding = DEFAULTPAD, 75 .values = &encoderValue[1] 76}; 77 78const static BaseEncoder hexBase32 = { 79 .name = "Base32Hex", 80 .encoding = kCNEncodingBase32HEX, 81 .baseNum = 32, 82 .charMap = "0123456789ABCDEFGHIJKLMNOPQRSTUV", 83 .padding = DEFAULTPAD, 84 .values = &encoderValue[1] 85}; 86 87 88const static BaseEncoder defaultBase16 = { 89 .name = "Base16", 90 .encoding = kCNEncodingBase16, 91 .baseNum = 16, 92 .charMap = "0123456789ABCDEF", 93 .padding = DEFAULTPAD, 94 .values = &encoderValue[0] 95}; 96 97 98/* 99 Utility functions 100 */ 101 102 103static inline uint32_t baselog(CNEncoder *coderRef) 104{ 105 if(coderRef && coderRef->coderFrame && coderRef->coderFrame->encoderRef && coderRef->coderFrame->encoderRef->values) 106 return coderRef->coderFrame->encoderRef->values->log; 107 else return 0; 108} 109 110static inline uint32_t basemask(CNEncoder *coderRef) 111{ 112 return coderRef->coderFrame->encoderRef->values->basemask; 113} 114 115static inline uint32_t inputBlocksize(CNEncoder *coderRef) 116{ 117 if(coderRef && coderRef->coderFrame && coderRef->coderFrame->encoderRef && coderRef->coderFrame->encoderRef->values) 118 return coderRef->coderFrame->encoderRef->values->inputBlocksize; 119 else return 0; 120} 121 122static inline uint32_t outputBlocksize(CNEncoder *coderRef) 123{ 124 if(coderRef && coderRef->coderFrame && coderRef->coderFrame->encoderRef && coderRef->coderFrame->encoderRef->values) 125 return coderRef->coderFrame->encoderRef->values->outputBlocksize; 126 else return 0; 127} 128 129static inline uint8_t encodeToBase(CNEncoder *coderRef, uint8_t inByte) 130{ 131 if(inByte < coderRef->coderFrame->encoderRef->baseNum) return coderRef->coderFrame->encoderRef->charMap[inByte]; 132 return 0x80; 133} 134 135static inline uint8_t decodeFromBase(CNEncoder *coderRef, uint8_t inByte) 136{ 137 return coderRef->coderFrame->reverseMap[inByte]; 138} 139 140static inline size_t decodeLen(void *ctx, size_t len) 141{ 142 CNEncoder *coderRef = (CNEncoder *) ctx; 143 if(0 == len) return 0; 144 return (baselog(coderRef) * len + 8 ) / 8; 145} 146 147static inline size_t encodeLen(void *ctx, size_t len) 148{ 149 CNEncoder *coderRef = (CNEncoder *) ctx; 150 if(0 == len || 0 == inputBlocksize(coderRef) || 0 == outputBlocksize(coderRef)) return 0; 151 return ((len + inputBlocksize(coderRef) - 1) / inputBlocksize(coderRef)) * outputBlocksize(coderRef); 152} 153 154 155/* 156 * This takes raw data from base XX (where XX is "base") and puts it into base256 form. 157 */ 158 159static int 160deCode(void *ctx, const void *in, size_t srcLen, void *out, size_t *destLen) 161{ 162 uint8_t *src = (uint8_t *) in, *dest = (uint8_t *) out; 163 CNEncoder *coderRef = (CNEncoder *) ctx; 164 size_t i; 165 size_t dPos = 0; 166 int sourceBits = baselog(coderRef); 167 168 if(coderRef == NULL || coderRef->coderFrame == NULL || coderRef->coderFrame->encoderRef == NULL) return 0; 169 if((*destLen = decodeLen(coderRef, srcLen)) == 0) { 170 *dest = 0; 171 return 0; 172 } 173 174 CC_XZEROMEM(dest, *destLen); 175 176 for(i=0; i<srcLen; i++) { 177 if(src[i] != coderRef->coderFrame->encoderRef->padding) { 178 uint8_t srcByte = decodeFromBase(coderRef, src[i]); 179 int dBit = (i*sourceBits) % 8; // destination position of Leftmost Bit of source byte 180 int shiftl = (8-sourceBits) - dBit; // amount needed to shift left to get bits positioned 181 dPos = (i*sourceBits) / 8; // destination byte of leftmost bit of source byte 182 183 if(shiftl >= 0) { 184 dest[dPos] |= srcByte << shiftl; 185 } else if(shiftl < 0) { 186 int shiftr = shiftl * (-1); 187 dest[dPos] |= srcByte >> shiftr; 188 dest[dPos+1] |= srcByte << (8-shiftr); 189 } 190 } 191 } 192 *destLen = (dest[dPos+1]) ? dPos+2: dPos+1; 193 return 0; 194} 195 196/* 197 * This takes "normal" base256 encoding and puts it into baseXX (where XX is "base") raw data. 198 */ 199 200static int 201enCode(void *ctx, const void *in, size_t srcLen, void *out, size_t *destLen) 202{ 203 uint8_t *src = (uint8_t *) in, *dest = (uint8_t *) out; 204 CNEncoder *coderRef = (CNEncoder *) ctx; 205 size_t i; 206 int destBits = baselog(coderRef); 207 int baseShift = 8 - destBits; 208 size_t needed, dPos; 209 210 if((needed = encodeLen(coderRef, srcLen)) == 0) { 211 *destLen = 0; 212 *dest = 0; 213 return 0; 214 } 215 216 if(*destLen < needed) { 217 *destLen = needed; 218 return -1; 219 } 220 221 *destLen = needed; 222 223 CC_XZEROMEM(dest, needed); 224 225 dPos = 0; 226 for(i=0; i<srcLen; i++) { 227 int dBit = (i*8) % destBits; 228 dPos = (i*8) / destBits; 229 int shiftr = baseShift + dBit; 230 231 dest[dPos] |= (src[i] >> shiftr) & basemask(coderRef); 232 if(shiftr > destBits) { 233 shiftr = shiftr - destBits; 234 dPos++; 235 dest[dPos] |= (src[i] >> shiftr) & basemask(coderRef); 236 } 237 dest[dPos+1] |= (src[i] << (destBits - shiftr)) & basemask(coderRef); 238 } 239 dPos+=2; 240 241 for(i=0; i<dPos; i++) dest[i] = encodeToBase(coderRef, dest[i]); 242 243 for(; dPos < needed; dPos++) dest[dPos] = coderRef->coderFrame->encoderRef->padding; 244 dest[dPos] = 0; 245 return 0; 246} 247 248static void setReverseMap(CoderFrame frame) 249{ 250 int i; 251 CC_XMEMSET(frame->reverseMap, 0x80, 256); 252 for(i=0; i<frame->encoderRef->baseNum; i++) { 253 int idx; 254 idx = frame->encoderRef->charMap[i]; 255 frame->reverseMap[idx] = i; 256 } 257} 258 259static CoderFrame 260getCodeFrame(CNEncodings encoding) 261{ 262 cc_globals_t globals = _cc_globals(); 263 if(encoding > CN_STANDARD_BASE_ENCODERS) return NULL; 264 dispatch_once(&globals->basexx_init, ^{ 265 for(int i=0; i<CN_STANDARD_BASE_ENCODERS; i++) 266 globals->encoderTab[i].encoderRef = NULL; 267 globals->encoderTab[kCNEncodingBase64].encoderRef = &defaultBase64; 268 globals->encoderTab[kCNEncodingBase32].encoderRef = &defaultBase32; 269 globals->encoderTab[kCNEncodingBase32Recovery].encoderRef = &recoveryBase32; 270 globals->encoderTab[kCNEncodingBase32HEX].encoderRef = &hexBase32; 271 globals->encoderTab[kCNEncodingBase16].encoderRef = &defaultBase16; 272 }); 273 dispatch_once(&globals->encoderTab[encoding].encoderInit, ^{ 274 globals->encoderTab[encoding].reverseMap = CC_XMALLOC(256); 275 if(globals->encoderTab[encoding].reverseMap) setReverseMap(&globals->encoderTab[encoding]); 276 }); 277 if(NULL == globals->encoderTab[encoding].reverseMap) return NULL; 278 return &globals->encoderTab[encoding]; 279} 280 281/* 282 Interface functions 283 */ 284 285CNStatus CNEncoderCreate(CNEncodings encoding, 286 CNEncodingDirection direction, 287 CNEncoderRef *encoderRef) 288{ 289 if(direction != kCNEncode && direction != kCNDecode) return kCNParamError; 290 if(!encoderRef) return kCNParamError; 291 *encoderRef = NULL; 292 CoderFrame codeFrame = getCodeFrame (encoding); 293 if(!codeFrame) return kCNParamError; 294 295 CNEncoder *coderRef = CC_XMALLOC(sizeof(CNEncoder)); 296 if(!coderRef) return kCNMemoryFailure; 297 298 coderRef->direction = direction; 299 coderRef->coderFrame = codeFrame; 300 coderRef->base256buffer = NULL; 301 coderRef->baseXXbuffer = NULL; 302 coderRef->base256buffer = CNBufferCreate(inputBlocksize(coderRef)); 303 coderRef->baseXXbuffer = CNBufferCreate(outputBlocksize(coderRef)); 304 if(!coderRef->base256buffer || !coderRef->baseXXbuffer) { 305 if(coderRef->base256buffer) CNBufferRelease(&coderRef->base256buffer); 306 if(coderRef->baseXXbuffer) CNBufferRelease(&coderRef->baseXXbuffer); 307 CC_XFREE(coderRef, sizeof(CNEncoder)); 308 return kCNMemoryFailure; 309 } 310 *encoderRef = coderRef; 311 return kCNSuccess; 312} 313 314 315CNStatus CNEncoderCreateCustom( 316 const void *name, 317 const uint8_t baseNum, 318 const void *charMap, 319 const char padChar, 320 CNEncodingDirection direction, 321 CNEncoderRef *encoderRef) 322{ 323 if(direction != kCNEncode && direction != kCNDecode) return kCNParamError; 324 if(baseNum != 16 && baseNum != 32 && baseNum != 64) return kCNParamError; 325 if(!encoderRef || !charMap) return kCNParamError; 326 *encoderRef = NULL; 327 328 CoderFrame codeFrame = CC_XMALLOC(sizeof(BaseEncoderFrame)); 329 BaseEncoderRefCustom customEncoder = CC_XMALLOC(sizeof(BaseEncoder)); 330 CNEncoder *coderRef = CC_XMALLOC(sizeof(CNEncoder)); 331 if(codeFrame) codeFrame->reverseMap = CC_XMALLOC(256); 332 if(coderRef) { 333 coderRef->base256buffer = NULL; 334 coderRef->baseXXbuffer = NULL; 335 } 336 337 CNStatus retval = kCNMemoryFailure; 338 if(!codeFrame || !customEncoder || !coderRef) goto errOut; 339 if(!codeFrame->reverseMap) goto errOut; 340 341 customEncoder->baseNum = baseNum; 342 customEncoder->values = &encoderValue[baseNum/32]; 343 customEncoder->name = name; 344 customEncoder->charMap = charMap; 345 customEncoder->padding = padChar; 346 customEncoder->encoding = kCNEncodingCustom; 347 348 codeFrame->encoderRef = customEncoder; 349 setReverseMap(codeFrame); 350 351 coderRef->coderFrame = codeFrame; 352 coderRef->direction = direction; 353 coderRef->base256buffer = CNBufferCreate(inputBlocksize(coderRef)); 354 coderRef->baseXXbuffer = CNBufferCreate(outputBlocksize(coderRef)); 355 if(!coderRef->base256buffer || !coderRef->baseXXbuffer) goto errOut; 356 357 *encoderRef = coderRef; 358 return kCNSuccess; 359 360errOut: 361 if(codeFrame) { 362 if(codeFrame->reverseMap) CC_XFREE(codeFrame->reverseMap, 256); 363 CC_XFREE(codeFrame, sizeof(BaseEncoderFrame)); 364 } 365 366 if(customEncoder) { 367 CC_XFREE(customEncoder, sizeof(BaseEncoder)); 368 } 369 370 if(coderRef) { 371 if(coderRef->base256buffer) CNBufferRelease(&coderRef->base256buffer); 372 if(coderRef->baseXXbuffer) CNBufferRelease(&coderRef->baseXXbuffer); 373 CC_XFREE(coderRef, sizeof(CNEncoder)); 374 } 375 return retval; 376 377} 378 379CNStatus CNEncoderRelease(CNEncoderRef *encoderRef) 380{ 381 CNEncoder *coderRef = *encoderRef; 382 *encoderRef = NULL; 383 if(coderRef) { 384 CoderFrame codeFrame = coderRef->coderFrame; 385 if(codeFrame->encoderRef && kCNEncodingCustom == codeFrame->encoderRef->encoding) { 386 CC_XFREE(codeFrame->reverseMap, 256); 387 BaseEncoderRefCustom customRef = (BaseEncoderRefCustom) codeFrame->encoderRef; 388 CC_XFREE((void *) customRef, sizeof(BaseEncoder)); 389 } 390 if(coderRef->base256buffer) CNBufferRelease(&coderRef->base256buffer); 391 if(coderRef->baseXXbuffer) CNBufferRelease(&coderRef->baseXXbuffer); 392 CC_XFREE(coderRef, sizeof(CNEncoder)); 393 } 394 return kCNSuccess; 395} 396 397 398size_t 399CNEncoderGetOutputLength(CNEncoderRef encoderRef, const size_t inLen) 400{ 401 CNEncoder *coderRef = encoderRef; 402 size_t retval = 0; 403 404 __Require_Quiet(NULL != coderRef, errOut); 405 406 if(coderRef->direction == kCNEncode) { 407 retval = encodeLen(coderRef, inLen + coderRef->base256buffer->bufferPos) + 1; 408 } else if(coderRef->direction == kCNDecode) { 409 retval = decodeLen(coderRef, inLen + coderRef->baseXXbuffer->bufferPos); 410 } 411 412errOut: 413 return retval; 414} 415 416 417size_t 418CNEncoderGetOutputLengthFromEncoding(CNEncodings encoding, CNEncodingDirection direction, const size_t inLen) 419{ 420 size_t retval = 0; 421 CNEncoderRef coder; 422 CNStatus status; 423 424 if((status = CNEncoderCreate(encoding, direction, &coder))) return 0; 425 426 if(direction == kCNEncode) { 427 retval = encodeLen(coder, inLen) + 1; 428 } else if(direction == kCNDecode) { 429 retval = decodeLen(coder, inLen); 430 } 431 432 CNEncoderRelease(&coder); 433 434 return retval; 435} 436 437 438CNStatus 439CNEncoderUpdate(CNEncoderRef coderRef, const void *in, const size_t inLen, void *out, size_t *outLen) 440{ 441 CNStatus retval = kCNParamError; 442 CNEncoder *encoderRef = coderRef; 443// size_t outputLen, outputAvailable; 444 445 446 __Require_Quiet(NULL != coderRef, errOut); 447 __Require_Quiet(NULL != out, errOut); 448 __Require_Quiet(NULL != outLen, errOut); 449 450 if(NULL == in) { 451 if(0 == inLen) { 452 *outLen = 0; 453 return kCNSuccess; 454 } 455 return kCNParamError; 456 } 457 458// outputAvailable = outputLen = *outLen; 459 460 if(encoderRef->direction == kCNEncode) { 461 retval = CNBufferProcessData(coderRef->base256buffer, coderRef, in, inLen, out, outLen, enCode, encodeLen); 462 } else if(encoderRef->direction == kCNDecode) { 463 retval = CNBufferProcessData(coderRef->baseXXbuffer, coderRef, in, inLen, out, outLen, deCode, decodeLen); 464 } else { 465 retval = kCNParamError; 466 } 467 468errOut: 469 return retval; 470} 471 472CNStatus 473CNEncoderFinal(CNEncoderRef coderRef, void *out, size_t *outLen) 474{ 475 CNStatus retval = kCNParamError; 476 CNEncoder *encoderRef = coderRef; 477 478 __Require_Quiet(NULL != coderRef, errOut); 479 __Require_Quiet(NULL != out, errOut); 480 __Require_Quiet(NULL != outLen, errOut); 481 482 if(encoderRef->direction == kCNEncode) { 483 if((encodeLen(coderRef, coderRef->baseXXbuffer->bufferPos)+1) > *outLen) { 484 // We need room for the final '\0' on the encoded string. 485 retval = kCNBufferTooSmall; 486 goto errOut; 487 } 488 retval = CNBufferFlushData(coderRef->base256buffer, coderRef, out, outLen, enCode, encodeLen); 489 if(kCNSuccess == retval) { 490 ((uint8_t *)out)[*outLen] = 0; 491 } 492 } else if(encoderRef->direction == kCNDecode) { 493 retval = CNBufferFlushData(coderRef->baseXXbuffer, coderRef, out, outLen, deCode, decodeLen); 494 } else { 495 retval = kCNParamError; 496 } 497 498 499errOut: 500 return retval; 501 502} 503 504 505CNStatus 506CNEncoderBlocksize(CNEncodings encoding, size_t *inputSize, size_t *outputSize) 507{ 508 CNEncoderRef coder; 509 CNStatus status; 510 511 __Require_Quiet(NULL != inputSize, errOut); 512 __Require_Quiet(NULL != outputSize, errOut); 513 514 if((status = CNEncoderCreate(encoding, kCNEncode, &coder))) return status; 515 516 *inputSize = inputBlocksize(coder); 517 *outputSize = outputBlocksize(coder); 518 CNEncoderRelease(&coder); 519 520 return kCNSuccess; 521errOut: 522 return kCNParamError; 523} 524 525CNStatus 526CNEncoderBlocksizeFromRef(CNEncoderRef encoderRef, size_t *inputSize, size_t *outputSize) 527{ 528 __Require_Quiet(NULL != encoderRef, errOut); 529 __Require_Quiet(NULL != inputSize, errOut); 530 __Require_Quiet(NULL != outputSize, errOut); 531 532 *inputSize = inputBlocksize(encoderRef); 533 *outputSize = outputBlocksize(encoderRef); 534 return kCNSuccess; 535errOut: 536 return kCNParamError; 537} 538 539CNStatus CNEncode(CNEncodings encoding, 540 CNEncodingDirection direction, 541 const void *in, const size_t inLen, 542 void *out, size_t *outLen) 543{ 544 CNStatus retval; 545 size_t outAvailable, currentlyAvailable; 546 CNEncoderRef encoder; 547 uint8_t *outPtr = out; 548 549 retval = kCNParamError; 550 __Require_Quiet(NULL != out, outReturn); 551 __Require_Quiet(NULL != outLen, outReturn); 552 __Require_Quiet(NULL != in, outReturn); 553 554 retval = CNEncoderCreate(encoding, direction, &encoder); 555 __Require_Quiet(kCNSuccess == retval, outReturn); 556 557 currentlyAvailable = outAvailable = *outLen; 558 *outLen = 0; 559 560 retval = CNEncoderUpdate(encoder, in, inLen, outPtr, ¤tlyAvailable); 561 __Require_Quiet(kCNSuccess == retval, outReturn); 562 563 *outLen = currentlyAvailable; 564 outAvailable -= currentlyAvailable; 565 outPtr += currentlyAvailable; 566 currentlyAvailable = outAvailable; 567 568 retval = CNEncoderFinal(encoder, outPtr, ¤tlyAvailable); 569 __Require_Quiet(kCNSuccess == retval, outReturn); 570 571 *outLen += currentlyAvailable; 572 573 retval = CNEncoderRelease(&encoder); 574 575outReturn: 576 return retval; 577 578} 579 580