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