1/* 2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please obtain 7 * a copy of the License at http://www.apple.com/publicsource and read it before 8 * using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 15 * specific language governing rights and limitations under the License. 16 */ 17 18 19/* 20 * BlockCryptor.cpp - common context for block-oriented encryption algorithms 21 * 22 */ 23 24#include "BlockCryptor.h" 25#include "BinaryKey.h" 26#include "AppleCSPSession.h" 27#include <security_utilities/alloc.h> 28#include <Security/cssmerr.h> 29#include <string.h> 30#include <security_utilities/debugging.h> 31#include <security_cdsa_utilities/cssmdata.h> 32 33#define BlockCryptDebug(args...) secdebug("blockCrypt", ## args) 34#define bprintf(args...) secdebug("blockCryptBuf", ## args) 35#define ioprintf(args...) secdebug("blockCryptIo", ## args) 36 37BlockCryptor::~BlockCryptor() 38{ 39 if(mInBuf) { 40 memset(mInBuf, 0, mInBlockSize); 41 session().free(mInBuf); 42 mInBuf = NULL; 43 } 44 if(mChainBuf) { 45 memset(mChainBuf, 0, mInBlockSize); 46 session().free(mChainBuf); 47 mChainBuf = NULL; 48 } 49 mInBufSize = 0; 50} 51 52/* 53 * Reusable setup functions called from subclass's init. 54 * This is the general purpose one.... 55 */ 56void BlockCryptor::setup( 57 size_t blockSizeIn, // block size of input 58 size_t blockSizeOut, // block size of output 59 bool pkcsPad, // this class performs PKCS{5,7} padding 60 bool needsFinal, // needs final update with valid data 61 BC_Mode mode, // ECB, CBC 62 const CssmData *iv) // init vector, required for CBC 63 //� must be at least blockSizeIn bytes 64{ 65 if(pkcsPad && needsFinal) { 66 BlockCryptDebug("BlockCryptor::setup pkcsPad && needsFinal"); 67 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); 68 } 69 mPkcsPadding = pkcsPad; 70 mMode = mode; 71 mNeedFinalData = needsFinal; 72 73 /* set up inBuf, all configurations */ 74 if(mInBuf != NULL) { 75 /* only reuse if same size */ 76 if(mInBlockSize != blockSizeIn) { 77 session().free(mInBuf); 78 mInBuf = NULL; 79 } 80 } 81 if(mInBuf == NULL) { 82 mInBuf = (uint8 *)session().malloc(blockSizeIn); 83 } 84 85 /* set up chain buf, decrypt/CBC only; skip if algorithm does its own chaining */ 86 if((mMode == BCM_CBC) && !encoding() && !mCbcCapable) { 87 if(mChainBuf != NULL) { 88 /* only reuse if same size */ 89 if(mInBlockSize != blockSizeIn) { 90 session().free(mChainBuf); 91 mChainBuf = NULL; 92 } 93 } 94 if(mChainBuf == NULL) { 95 mChainBuf = (uint8 *)session().malloc(blockSizeIn); 96 } 97 } 98 99 /* IV iff CBC mode, and ensure IV is big enough */ 100 switch(mMode) { 101 case BCM_ECB: 102 if(iv != NULL) { 103 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_INIT_VECTOR); 104 } 105 break; 106 case BCM_CBC: 107 if(iv == NULL) { 108 CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_INIT_VECTOR); 109 } 110 if(blockSizeIn != blockSizeOut) { 111 /* no can do, must be same block sizes */ 112 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_MODE); 113 } 114 if(iv->Length < blockSizeIn) { 115 /* not enough IV */ 116 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_INIT_VECTOR); 117 } 118 /* save IV as appropriate */ 119 if(!mCbcCapable) { 120 if(encoding()) { 121 memmove(mInBuf, iv->Data, blockSizeIn); 122 } 123 else { 124 assert(mChainBuf != NULL); 125 memmove(mChainBuf, iv->Data, blockSizeIn); 126 } 127 } 128 break; 129 } 130 131 mInBlockSize = blockSizeIn; 132 mInBufSize = 0; 133 mOutBlockSize = blockSizeOut; 134 mOpStarted = false; 135} 136 137/* 138 * This one is used by simple, well-behaved algorithms which don't do their own 139 * padding and which rely on us to do everything but one-block-at-a-time 140 * encrypt and decrypt. 141 */ 142void BlockCryptor::setup( 143 size_t blockSize, // block size of input and output 144 const Context &context) 145{ 146 bool padEnable = false; 147 bool chainEnable = false; 148 bool ivEnable = false; 149 CssmData *iv = NULL; 150 151 /* 152 * Validate context 153 * IV optional per mode 154 * pad optional per mode 155 * Currently we ignore extraneous attributes (e.g., it's OK to pass in 156 * an IV if the mode doesn't specify it), mainly for simplifying test routines. 157 */ 158 CSSM_ENCRYPT_MODE cssmMode = context.getInt(CSSM_ATTRIBUTE_MODE); 159 160 switch (cssmMode) { 161 /* no mode attr --> 0 == CSSM_ALGMODE_NONE, not currently supported */ 162 case CSSM_ALGMODE_CBCPadIV8: 163 padEnable = true; 164 ivEnable = true; 165 chainEnable = true; 166 break; 167 168 case CSSM_ALGMODE_CBC_IV8: 169 ivEnable = true; 170 chainEnable = true; 171 break; 172 173 case CSSM_ALGMODE_ECB: 174 break; 175 176 case CSSM_ALGMODE_ECBPad: 177 padEnable = true; 178 break; 179 180 default: 181 errorLog1("DESContext::init: illegal mode (%d)\n", (int)cssmMode); 182 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_MODE); 183 } 184 185 if(padEnable) { 186 /* validate padding type */ 187 uint32 padding = context.getInt(CSSM_ATTRIBUTE_PADDING); // 0 ==> PADDING_NONE 188 if(blockSize == 8) { 189 switch(padding) { 190 /* backwards compatibility - used to be PKCS1, should be PKCS5 or 7 */ 191 case CSSM_PADDING_PKCS7: 192 case CSSM_PADDING_PKCS5: 193 case CSSM_PADDING_PKCS1: //�this goes away soon 194 /* OK */ 195 break; 196 default: 197 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING); 198 } 199 } 200 else { 201 switch(padding) { 202 case CSSM_PADDING_PKCS5: // this goes away soon 203 case CSSM_PADDING_PKCS7: 204 /* OK */ 205 break; 206 default: 207 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING); 208 } 209 } 210 } 211 if(ivEnable) { 212 /* make sure there's an IV in the context of sufficient length */ 213 iv = context.get<CssmData>(CSSM_ATTRIBUTE_INIT_VECTOR); 214 if(iv == NULL) { 215 CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_INIT_VECTOR); 216 } 217 if(iv->Length < blockSize) { 218 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_INIT_VECTOR); 219 } 220 } 221 setup(blockSize, 222 blockSize, 223 padEnable, 224 false, // needsFinal 225 chainEnable ? BCM_CBC : BCM_ECB, 226 iv); 227} 228 229/* 230 * Update always leaves some data in mInBuf if: 231 * mNeedsFinalData is true, or 232 * decrypting and mPkcsPadding true. 233 * Also, we always process all of the input (except on error). 234 */ 235void BlockCryptor::update( 236 void *inp, 237 size_t &inSize, // in/out 238 void *outp, 239 size_t &outSize) // in/out 240{ 241 uint8 *uInp = (UInt8 *)inp; 242 uint8 *uOutp = (UInt8 *)outp; 243 size_t uInSize = inSize; // input bytes to go 244 size_t uOutSize = 0; // ouput bytes generated 245 size_t uOutLeft = outSize; // bytes remaining in outp 246 size_t toMove; 247 size_t actMoved; 248 unsigned i; 249 bool needLeftOver = mNeedFinalData || (!encoding() && mPkcsPadding); 250 bool doCbc = (mMode == BCM_CBC) && !mCbcCapable; 251 252 assert(mInBuf != NULL); 253 mOpStarted = true; 254 255 if(mInBufSize) { 256 /* attempt to fill mInBuf from inp */ 257 toMove = mInBlockSize - mInBufSize; 258 if(toMove > uInSize) { 259 toMove = uInSize; 260 } 261 if(encoding() && doCbc) { 262 /* xor into last cipherblock or IV */ 263 for(i=0; i<toMove; i++) { 264 mInBuf[mInBufSize + i] ^= *uInp++; 265 } 266 } 267 else { 268 /* use incoming data as is */ 269 memmove(mInBuf+mInBufSize, uInp, toMove); 270 uInp += toMove; 271 } 272 uInSize -= toMove; 273 mInBufSize += toMove; 274 /* 275 * Process inBuf if it's full, but skip if no more data in uInp and 276 * inBuf might be needed (by us for unpadding on decrypt, or by 277 * subclass for anything) for a final call 278 */ 279 if((mInBufSize == mInBlockSize) && !((uInSize == 0) && needLeftOver)) { 280 actMoved = uOutLeft; 281 if(encoding()) { 282 encryptBlock(mInBuf, mInBlockSize, uOutp, actMoved, false); 283 if(doCbc) { 284 /* save ciphertext for chaining next block */ 285 assert(mInBlockSize == actMoved); 286 memmove(mInBuf, uOutp, mInBlockSize); 287 } 288 } 289 else { 290 decryptBlock(mInBuf, mInBlockSize, uOutp, actMoved, false); 291 if(doCbc) { 292 /* xor in last ciphertext */ 293 assert(mInBlockSize == actMoved); 294 for(i=0; i<mInBlockSize; i++) { 295 uOutp[i] ^= mChainBuf[i]; 296 } 297 /* save this ciphertext for next chain */ 298 memmove(mChainBuf, mInBuf, mInBlockSize); 299 } 300 } 301 uOutSize += actMoved; 302 uOutp += actMoved; 303 uOutLeft -= actMoved; 304 mInBufSize = 0; 305 assert(uOutSize <= outSize); 306 } 307 } /* processing mInBuf */ 308 if(uInSize == 0) { 309 /* done */ 310 outSize = uOutSize; 311 ioprintf("=== BlockCryptor::update encrypt %d inSize 0x%lx outSize 0x%lx", 312 encoding() ? 1 : 0, inSize, outSize); 313 return; 314 } 315 316 317 /* 318 * en/decrypt even blocks in (remaining) inp. 319 */ 320 size_t leftOver = uInSize % mInBlockSize; 321 if((leftOver == 0) && needLeftOver) { 322 /* 323 * Even blocks coming in, but we really need to leave some data 324 * in the buffer (because the subclass asked for it, or we're decrypting 325 * with PKCS padding). Save one block for mInBuf. 326 */ 327 leftOver = mInBlockSize; 328 } 329 toMove = uInSize - leftOver; 330 size_t blocks = toMove / mInBlockSize; 331 if(mMultiBlockCapable && !doCbc && (blocks != 0)) { 332 /* 333 * Optimization for algorithms that are multi-block capable and that 334 * can do their own CBC (if necessary). 335 */ 336 size_t thisMove = blocks * mInBlockSize; 337 actMoved = uOutLeft; 338 if(encoding()) { 339 encryptBlock(uInp, thisMove, uOutp, actMoved, false); 340 } 341 else { 342 decryptBlock(uInp, thisMove, uOutp, actMoved, false); 343 } 344 uOutSize += actMoved; 345 uOutp += actMoved; 346 uInp += thisMove; 347 uOutLeft -= actMoved; 348 toMove -= thisMove; 349 assert(uOutSize <= outSize); 350 } 351 else if(encoding()) { 352 while(toMove) { 353 actMoved = uOutLeft; 354 if(!doCbc) { 355 /* encrypt directly from input to output */ 356 encryptBlock(uInp, mInBlockSize, uOutp, actMoved, false); 357 } 358 else { 359 /* xor into last ciphertext, encrypt the result */ 360 for(i=0; i<mInBlockSize; i++) { 361 mInBuf[i] ^= uInp[i]; 362 } 363 encryptBlock(mInBuf, mInBlockSize, uOutp, actMoved, false); 364 365 /* save new ciphertext for next chain */ 366 assert(actMoved == mInBlockSize); 367 memmove(mInBuf, uOutp, mInBlockSize); 368 } 369 uOutSize += actMoved; 370 uOutp += actMoved; 371 uInp += mInBlockSize; 372 uOutLeft -= actMoved; 373 toMove -= mInBlockSize; 374 assert(uOutSize <= outSize); 375 } /* main encrypt loop */ 376 377 } 378 else { 379 /* decrypting */ 380 while(toMove) { 381 actMoved = uOutLeft; 382 if(doCbc) { 383 /* save this ciphertext for chain; don't assume in != out */ 384 memmove(mInBuf, uInp, mInBlockSize); 385 decryptBlock(uInp, mInBlockSize, uOutp, actMoved, false); 386 387 /* chain in previous ciphertext */ 388 assert(mInBlockSize == actMoved); 389 for(i=0; i<mInBlockSize; i++) { 390 uOutp[i] ^= mChainBuf[i]; 391 } 392 393 /* save current ciphertext for next block */ 394 memmove(mChainBuf, mInBuf, mInBlockSize); 395 } 396 else { 397 /* ECB */ 398 decryptBlock(uInp, mInBlockSize, uOutp, actMoved, false); 399 } 400 uOutSize += actMoved; 401 uOutp += actMoved; 402 uInp += mInBlockSize; 403 uOutLeft -= actMoved; 404 toMove -= mInBlockSize; 405 assert(uOutSize <= outSize); 406 } /* main decrypt loop */ 407 408 } 409 410 /* leftover bytes from inp --> mInBuf */ 411 if(leftOver) { 412 if(encoding() && doCbc) { 413 /* xor into last cipherblock or IV */ 414 for(i=0; i<leftOver; i++) { 415 mInBuf[i] ^= *uInp++; 416 } 417 } 418 else { 419 if(mInBuf && uInp && leftOver) memmove(mInBuf, uInp, leftOver); 420 } 421 } 422 423 mInBufSize = leftOver; 424 outSize = uOutSize; 425 ioprintf("=== BlockCryptor::update encrypt %d inSize 0x%lx outSize 0x%lx", 426 encoding() ? 1 : 0, inSize, outSize); 427} 428 429void BlockCryptor::final( 430 CssmData &out) 431{ 432 size_t uOutSize = 0; // ouput bytes generated 433 size_t actMoved; 434 size_t uOutLeft = out.Length; // bytes remaining in out 435 unsigned i; 436 bool doCbc = (mMode == BCM_CBC) && !mCbcCapable; 437 438 assert(mInBuf != NULL); 439 mOpStarted = true; 440 if((mInBufSize == 0) && mNeedFinalData) { 441 /* only way this could happen: no update() called (at least not with 442 * non-zero input data sizes) */ 443 BlockCryptDebug("BlockCryptor::final with no mInBuf data"); 444 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR); 445 } 446 if(encoding()) { 447 uint8 *ctext = out.Data; 448 449 if(mPkcsPadding) { 450 /* 451 * PKCS5/7 padding: pad byte = size of padding. 452 * This assertion courtesy of the limitation on the mutual 453 * exclusivity of mPkcsPadding and mNeedFinalData. 454 */ 455 assert(mInBufSize < mInBlockSize); 456 size_t padSize = mInBlockSize - mInBufSize; 457 uint8 *padPtr = mInBuf + mInBufSize; 458 if(!doCbc) { 459 for(i=0; i<padSize; i++) { 460 *padPtr++ = padSize; 461 } 462 } 463 else { 464 for(i=0; i<padSize; i++) { 465 *padPtr++ ^= padSize; 466 } 467 } 468 mInBufSize = mInBlockSize; 469 } /* PKCS padding */ 470 471 /* 472 * Encrypt final mInBuf. If it's not full, the BlockCryptObject better know 473 * how to pad.... 474 */ 475 if(mInBufSize) { 476 actMoved = uOutLeft; 477 encryptBlock(mInBuf, mInBufSize, ctext, actMoved, true); 478 uOutSize += actMoved; 479 mInBufSize = 0; 480 assert(uOutSize <= out.length()); 481 } 482 out.length(uOutSize); 483 } /* encrypting */ 484 485 else { 486 if(mInBufSize == 0) { 487 if(mPkcsPadding) { 488 BlockCryptDebug("BlockCryptor::final decrypt/pad with no mInBuf data"); 489 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR); 490 } 491 else { 492 /* simple decrypt op complete */ 493 ioprintf("=== BlockCryptor::final encrypt 0 outSize 0"); 494 out.length(0); 495 return; 496 } 497 } 498 499 /* 500 * Decrypt - must have exactly one block of ciphertext. 501 * We trust CSPContext, and our own outputSize(), to have set up 502 * the current output buffer with enough space to handle the 503 * full size of the decrypt, even though - due to padding - we 504 * might actually pass less than that amount back to caller. 505 */ 506 if(mInBufSize != mInBlockSize) { 507 BlockCryptDebug("BlockCryptor::final unaligned ciphertext"); 508 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR); 509 } 510 511 uint8 *ptext = out.Data; 512 actMoved = uOutLeft; 513 decryptBlock(mInBuf, mInBlockSize, ptext, actMoved, true); 514 if(doCbc) { 515 /* chain in previous ciphertext one more time */ 516 assert(mInBlockSize == actMoved); 517 for(i=0; i<mInBlockSize; i++) { 518 ptext[i] ^= mChainBuf[i]; 519 } 520 } 521 if(mPkcsPadding) { 522 assert(actMoved == mOutBlockSize); 523 524 /* ensure integrity of padding byte(s) */ 525 unsigned padSize = ptext[mOutBlockSize - 1]; 526 if(padSize > mOutBlockSize) { 527 BlockCryptDebug("BlockCryptor::final malformed ciphertext (1)"); 528 CssmError::throwMe(CSSM_ERRCODE_INVALID_DATA); 529 } 530 uint8 *padPtr = ptext + mOutBlockSize - padSize; 531 for(unsigned i=0; i<padSize; i++) { 532 if(*padPtr++ != padSize) { 533 BlockCryptDebug("BlockCryptor::final malformed ciphertext " 534 "(2)"); 535 CssmError::throwMe(CSSM_ERRCODE_INVALID_DATA); 536 } 537 } 538 actMoved -= padSize; 539 } 540 assert(actMoved <= out.length()); 541 out.length(actMoved); 542 } /* decrypting */ 543 ioprintf("=== BlockCryptor::final encrypt %d outSize 0x%lx", 544 encoding() ? 1 : 0, out.Length); 545} 546 547/* 548 * These three are only valid for algorithms for which encrypting one block 549 * of plaintext always yields exactly one block of ciphertext, and vice versa 550 * for decrypt. The block sizes for plaintext and ciphertext do NOT have to be 551 * the same. Subclasses (e.g. FEED) which do not meet this criterion will have 552 * to override. 553 */ 554 555void BlockCryptor::minimumProgress( 556 size_t &inSize, 557 size_t &outSize) 558{ 559 /* each size = one block (including buffered input) */ 560 inSize = mInBlockSize - mInBufSize; 561 if(inSize == 0) { 562 /* i.e., we're holding a whole buffer */ 563 inSize++; 564 } 565 outSize = mOutBlockSize; 566 bprintf("--- BlockCryptor::minProgres inSize 0x%lx outSize 0x%lx mInBufSize 0x%lx", 567 inSize, outSize, mInBufSize); 568} 569 570size_t BlockCryptor::inputSize( 571 size_t outSize) // input for given output size 572{ 573 size_t inSize; 574 575 if(outSize < mOutBlockSize) { 576 /* 577 * Sometimes CSPFullPluginSession calls us like this....in this 578 * case the legal inSize is just the remainder of the input buffer, 579 * less one byte (in other words, the max we we gobble up without 580 * producing any output). 581 */ 582 inSize = mInBlockSize - mInBufSize; 583 if(inSize == 0) { 584 /* we have a full input buffer! How can this happen!? */ 585 BlockCryptDebug("BlockCryptor::inputSize: HELP! zero inSize and outSize!\n"); 586 } 587 } 588 else { 589 /* more-or-less normal case */ 590 size_t wholeBlocks = outSize / mOutBlockSize; 591 assert(wholeBlocks >= 1); 592 inSize = (wholeBlocks * mInBlockSize) - mInBufSize; 593 if(inSize == 0) { 594 /* i.e., we're holding a whole buffer */ 595 inSize++; 596 } 597 } 598 bprintf("--- BlockCryptor::inputSize inSize 0x%lx outSize 0x%lx mInBufSize 0x%lx", 599 inSize, outSize, mInBufSize); 600 return inSize; 601} 602 603size_t BlockCryptor::outputSize( 604 bool final, 605 size_t inSize /*= 0*/) // output for given input size 606{ 607 size_t rawBytes = inSize + mInBufSize; 608 // huh?�don't round this up! 609 //size_t rawBlocks = (rawBytes + mInBlockSize - 1) / mInBlockSize; 610 size_t rawBlocks = rawBytes / mInBlockSize; 611 612 /* 613 * encrypting: always get one additional block on final() if we're padding 614 * or (we presume) the subclass is padding. Note that we 615 * truncated when calculating rawBlocks; to finish out on the 616 * final block, we (or our subclass) will either have to pad 617 * out the current partial block, or cook up a full pad block if 618 * mInBufSize is currently zero. Subclasses which pad some other 619 * way need to override this method. 620 * 621 * decrypting: outsize always <= insize 622 */ 623 if(encoding() && final && (mPkcsPadding || mNeedFinalData)) { 624 rawBlocks++; 625 } 626 627 /* FIXME - optimize for needFinalData? (can squeak by with smaller outSize) */ 628 size_t rtn = rawBlocks * mOutBlockSize; 629 bprintf("--- BlockCryptor::outputSize inSize 0x%lx outSize 0x%lx final %d " 630 "inBufSize 0x%lx", inSize, rtn, final, mInBufSize); 631 return rtn; 632} 633 634 635 636