/ OSX / libsecurity_apple_csp / lib / BlockCryptor.cpp
BlockCryptor.cpp
  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...)	secinfo("blockCrypt", ## args)
 34  #define bprintf(args...)			secinfo("blockCryptBuf", ## args)
 35  #define ioprintf(args...)			secinfo("blockCryptIo", ## args)
 36  
 37  BlockCryptor::~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   */
 56  void 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   */
142  void 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   */
235  void 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 = (mInBlockSize > 0) ? uInSize % mInBlockSize : 0;
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 = (mInBlockSize > 0) ? toMove / mInBlockSize : 0;
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  	
429  void 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   
555  void 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  
570  size_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  
603  size_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