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 for(i=0; i<srcLen; i++) { 226 int dBit = (i*8) % destBits; 227 dPos = (i*8) / destBits; 228 int shiftr = baseShift + dBit; 229 230 dest[dPos] |= (src[i] >> shiftr) & basemask(coderRef); 231 if(shiftr > destBits) { 232 shiftr = shiftr - destBits; 233 dPos++; 234 dest[dPos] |= (src[i] >> shiftr) & basemask(coderRef); 235 } 236 dest[dPos+1] |= (src[i] << (destBits - shiftr)) & basemask(coderRef); 237 } 238 dPos+=2; 239 240 for(i=0; i<dPos; i++) dest[i] = encodeToBase(coderRef, dest[i]); 241 242 for(; dPos < needed; dPos++) dest[dPos] = coderRef->coderFrame->encoderRef->padding; 243 dest[dPos] = 0; 244 return 0; 245} 246 247static void setReverseMap(CoderFrame frame) 248{ 249 int i; 250 CC_XMEMSET(frame->reverseMap, 0x80, 256); 251 for(i=0; i<frame->encoderRef->baseNum; i++) { 252 int idx; 253 idx = frame->encoderRef->charMap[i]; 254 frame->reverseMap[idx] = i; 255 } 256} 257 258static CoderFrame 259getCodeFrame(CNEncodings encoding) 260{ 261 cc_globals_t globals = _cc_globals(); 262 if(encoding > CN_STANDARD_BASE_ENCODERS) return NULL; 263 dispatch_once(&globals->basexx_init, ^{ 264 for(int i=0; i<CN_STANDARD_BASE_ENCODERS; i++) 265 globals->encoderTab[i].encoderRef = NULL; 266 globals->encoderTab[kCNEncodingBase64].encoderRef = &defaultBase64; 267 globals->encoderTab[kCNEncodingBase32].encoderRef = &defaultBase32; 268 globals->encoderTab[kCNEncodingBase32Recovery].encoderRef = &recoveryBase32; 269 globals->encoderTab[kCNEncodingBase32HEX].encoderRef = &hexBase32; 270 globals->encoderTab[kCNEncodingBase16].encoderRef = &defaultBase16; 271 }); 272 dispatch_once(&globals->encoderTab[encoding].encoderInit, ^{ 273 globals->encoderTab[encoding].reverseMap = CC_XMALLOC(256); 274 if(globals->encoderTab[encoding].reverseMap) setReverseMap(&globals->encoderTab[encoding]); 275 }); 276 if(NULL == globals->encoderTab[encoding].reverseMap) return NULL; 277 return &globals->encoderTab[encoding]; 278} 279 280/* 281 Interface functions 282 */ 283 284CNStatus CNEncoderCreate(CNEncodings encoding, 285 CNEncodingDirection direction, 286 CNEncoderRef *encoderRef) 287{ 288 if(direction != kCNEncode && direction != kCNDecode) return kCNParamError; 289 if(!encoderRef) return kCNParamError; 290 *encoderRef = NULL; 291 CoderFrame codeFrame = getCodeFrame (encoding); 292 if(!codeFrame) return kCNParamError; 293 294 CNEncoder *coderRef = CC_XMALLOC(sizeof(CNEncoder)); 295 if(!coderRef) return kCNMemoryFailure; 296 297 coderRef->direction = direction; 298 coderRef->coderFrame = codeFrame; 299 coderRef->base256buffer = NULL; 300 coderRef->baseXXbuffer = NULL; 301 coderRef->base256buffer = CNBufferCreate(inputBlocksize(coderRef)); 302 coderRef->baseXXbuffer = CNBufferCreate(outputBlocksize(coderRef)); 303 if(!coderRef->base256buffer || !coderRef->baseXXbuffer) { 304 if(coderRef->base256buffer) CNBufferRelease(&coderRef->base256buffer); 305 if(coderRef->baseXXbuffer) CNBufferRelease(&coderRef->baseXXbuffer); 306 CC_XFREE(coderRef, sizeof(CNEncoder)); 307 return kCNMemoryFailure; 308 } 309 *encoderRef = coderRef; 310 return kCNSuccess; 311} 312 313 314CNStatus CNEncoderCreateCustom( 315 const void *name, 316 const uint8_t baseNum, 317 const void *charMap, 318 const char padChar, 319 CNEncodingDirection direction, 320 CNEncoderRef *encoderRef) 321{ 322 if(direction != kCNEncode && direction != kCNDecode) return kCNParamError; 323 if(baseNum != 16 && baseNum != 32 && baseNum != 64) return kCNParamError; 324 if(!encoderRef || !charMap) return kCNParamError; 325 *encoderRef = NULL; 326 327 CoderFrame codeFrame = CC_XMALLOC(sizeof(BaseEncoderFrame)); 328 BaseEncoderRefCustom customEncoder = CC_XMALLOC(sizeof(BaseEncoder)); 329 CNEncoder *coderRef = CC_XMALLOC(sizeof(CNEncoder)); 330 if(codeFrame) codeFrame->reverseMap = CC_XMALLOC(256); 331 if(coderRef) { 332 coderRef->base256buffer = NULL; 333 coderRef->baseXXbuffer = NULL; 334 } 335 336 CNStatus retval = kCNMemoryFailure; 337 if(!codeFrame || !customEncoder || !coderRef) goto errOut; 338 if(!codeFrame->reverseMap) goto errOut; 339 340 customEncoder->baseNum = baseNum; 341 customEncoder->values = &encoderValue[baseNum/32]; 342 customEncoder->name = name; 343 customEncoder->charMap = charMap; 344 customEncoder->padding = padChar; 345 customEncoder->encoding = kCNEncodingCustom; 346 347 codeFrame->encoderRef = customEncoder; 348 setReverseMap(codeFrame); 349 350 coderRef->coderFrame = codeFrame; 351 coderRef->direction = direction; 352 coderRef->base256buffer = CNBufferCreate(inputBlocksize(coderRef)); 353 coderRef->baseXXbuffer = CNBufferCreate(outputBlocksize(coderRef)); 354 if(!coderRef->base256buffer || !coderRef->baseXXbuffer) goto errOut; 355 356 *encoderRef = coderRef; 357 return kCNSuccess; 358 359errOut: 360 if(codeFrame) { 361 if(codeFrame->reverseMap) CC_XFREE(codeFrame->reverseMap, 256); 362 CC_XFREE(codeFrame, sizeof(BaseEncoderFrame)); 363 } 364 365 if(customEncoder) { 366 CC_XFREE(customEncoder, sizeof(BaseEncoder)); 367 } 368 369 if(coderRef) { 370 if(coderRef->base256buffer) CNBufferRelease(&coderRef->base256buffer); 371 if(coderRef->baseXXbuffer) CNBufferRelease(&coderRef->baseXXbuffer); 372 CC_XFREE(coderRef, sizeof(CNEncoder)); 373 } 374 return retval; 375 376} 377 378CNStatus CNEncoderRelease(CNEncoderRef *encoderRef) 379{ 380 CNEncoder *coderRef = *encoderRef; 381 *encoderRef = NULL; 382 if(coderRef) { 383 CoderFrame codeFrame = coderRef->coderFrame; 384 if(codeFrame->encoderRef && kCNEncodingCustom == codeFrame->encoderRef->encoding) { 385 CC_XFREE(codeFrame->reverseMap, 256); 386 BaseEncoderRefCustom customRef = (BaseEncoderRefCustom) codeFrame->encoderRef; 387 CC_XFREE((void *) customRef, sizeof(BaseEncoder)); 388 } 389 if(coderRef->base256buffer) CNBufferRelease(&coderRef->base256buffer); 390 if(coderRef->baseXXbuffer) CNBufferRelease(&coderRef->baseXXbuffer); 391 CC_XFREE(coderRef, sizeof(CNEncoder)); 392 } 393 return kCNSuccess; 394} 395 396 397size_t 398CNEncoderGetOutputLength(CNEncoderRef encoderRef, const size_t inLen) 399{ 400 CNEncoder *coderRef = encoderRef; 401 size_t retval = 0; 402 403 __Require_Quiet(NULL != coderRef, errOut); 404 405 if(coderRef->direction == kCNEncode) { 406 retval = encodeLen(coderRef, inLen + coderRef->base256buffer->bufferPos) + 1; 407 } else if(coderRef->direction == kCNDecode) { 408 retval = decodeLen(coderRef, inLen + coderRef->baseXXbuffer->bufferPos); 409 } 410 411errOut: 412 return retval; 413} 414 415 416size_t 417CNEncoderGetOutputLengthFromEncoding(CNEncodings encoding, CNEncodingDirection direction, const size_t inLen) 418{ 419 size_t retval = 0; 420 CNEncoderRef coder; 421 CNStatus status; 422 423 if((status = CNEncoderCreate(encoding, direction, &coder))) return 0; 424 425 if(direction == kCNEncode) { 426 retval = encodeLen(coder, inLen) + 1; 427 } else if(direction == kCNDecode) { 428 retval = decodeLen(coder, inLen); 429 } 430 431 CNEncoderRelease(&coder); 432 433 return retval; 434} 435 436 437CNStatus 438CNEncoderUpdate(CNEncoderRef coderRef, const void *in, const size_t inLen, void *out, size_t *outLen) 439{ 440 CNStatus retval = kCNParamError; 441 CNEncoder *encoderRef = coderRef; 442// size_t outputLen, outputAvailable; 443 444 445 __Require_Quiet(NULL != coderRef, errOut); 446 __Require_Quiet(NULL != out, errOut); 447 __Require_Quiet(NULL != outLen, errOut); 448 449 if(NULL == in) { 450 if(0 == inLen) { 451 *outLen = 0; 452 return kCNSuccess; 453 } 454 return kCNParamError; 455 } 456 457// outputAvailable = outputLen = *outLen; 458 459 if(encoderRef->direction == kCNEncode) { 460 retval = CNBufferProcessData(coderRef->base256buffer, coderRef, in, inLen, out, outLen, enCode, encodeLen); 461 } else if(encoderRef->direction == kCNDecode) { 462 retval = CNBufferProcessData(coderRef->baseXXbuffer, coderRef, in, inLen, out, outLen, deCode, decodeLen); 463 } else { 464 retval = kCNParamError; 465 } 466 467errOut: 468 return retval; 469} 470 471CNStatus 472CNEncoderFinal(CNEncoderRef coderRef, void *out, size_t *outLen) 473{ 474 CNStatus retval = kCNParamError; 475 CNEncoder *encoderRef = coderRef; 476 477 __Require_Quiet(NULL != coderRef, errOut); 478 __Require_Quiet(NULL != out, errOut); 479 __Require_Quiet(NULL != outLen, errOut); 480 481 if(encoderRef->direction == kCNEncode) { 482 if((encodeLen(coderRef, coderRef->baseXXbuffer->bufferPos)+1) > *outLen) { 483 // We need room for the final '\0' on the encoded string. 484 retval = kCNBufferTooSmall; 485 goto errOut; 486 } 487 retval = CNBufferFlushData(coderRef->base256buffer, coderRef, out, outLen, enCode, encodeLen); 488 if(kCNSuccess == retval) { 489 ((uint8_t *)out)[*outLen] = 0; 490 } 491 } else if(encoderRef->direction == kCNDecode) { 492 retval = CNBufferFlushData(coderRef->baseXXbuffer, coderRef, out, outLen, deCode, decodeLen); 493 } else { 494 retval = kCNParamError; 495 } 496 497 498errOut: 499 return retval; 500 501} 502 503 504CNStatus 505CNEncoderBlocksize(CNEncodings encoding, size_t *inputSize, size_t *outputSize) 506{ 507 CNEncoderRef coder; 508 CNStatus status; 509 510 __Require_Quiet(NULL != inputSize, errOut); 511 __Require_Quiet(NULL != outputSize, errOut); 512 513 if((status = CNEncoderCreate(encoding, kCNEncode, &coder))) return status; 514 515 *inputSize = inputBlocksize(coder); 516 *outputSize = outputBlocksize(coder); 517 CNEncoderRelease(&coder); 518 519 return kCNSuccess; 520errOut: 521 return kCNParamError; 522} 523 524CNStatus 525CNEncoderBlocksizeFromRef(CNEncoderRef encoderRef, size_t *inputSize, size_t *outputSize) 526{ 527 __Require_Quiet(NULL != encoderRef, errOut); 528 __Require_Quiet(NULL != inputSize, errOut); 529 __Require_Quiet(NULL != outputSize, errOut); 530 531 *inputSize = inputBlocksize(encoderRef); 532 *outputSize = outputBlocksize(encoderRef); 533 return kCNSuccess; 534errOut: 535 return kCNParamError; 536} 537 538CNStatus CNEncode(CNEncodings encoding, 539 CNEncodingDirection direction, 540 const void *in, const size_t inLen, 541 void *out, size_t *outLen) 542{ 543 CNStatus retval; 544 size_t outAvailable, currentlyAvailable; 545 CNEncoderRef encoder; 546 uint8_t *outPtr = out; 547 548 retval = kCNParamError; 549 __Require_Quiet(NULL != out, outReturn); 550 __Require_Quiet(NULL != outLen, outReturn); 551 __Require_Quiet(NULL != in, outReturn); 552 553 retval = CNEncoderCreate(encoding, direction, &encoder); 554 __Require_Quiet(kCNSuccess == retval, outReturn); 555 556 currentlyAvailable = outAvailable = *outLen; 557 *outLen = 0; 558 559 retval = CNEncoderUpdate(encoder, in, inLen, outPtr, ¤tlyAvailable); 560 __Require_Quiet(kCNSuccess == retval, outReturn); 561 562 *outLen = currentlyAvailable; 563 outAvailable -= currentlyAvailable; 564 outPtr += currentlyAvailable; 565 currentlyAvailable = outAvailable; 566 567 retval = CNEncoderFinal(encoder, outPtr, ¤tlyAvailable); 568 __Require_Quiet(kCNSuccess == retval, outReturn); 569 570 *outLen += currentlyAvailable; 571 572 retval = CNEncoderRelease(&encoder); 573 574outReturn: 575 return retval; 576 577} 578 579