/*
 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
 * 
 * The contents of this file constitute Original Code as defined in and are
 * subject to the Apple Public Source License Version 1.2 (the 'License').
 * You may not use this file except in compliance with the License. Please obtain
 * a copy of the License at http://www.apple.com/publicsource and read it before
 * using this file.
 * 
 * This Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
 * specific language governing rights and limitations under the License.
 */


/*
 * BlockCryptor.h - common context for block-oriented encryption algorithms
 *
 * Created March 5 2001 by dmitch
 */

#ifndef	_BLOCK_CRYPTOR_H_
#define _BLOCK_CRYPTOR_H_

#include "AppleCSPContext.h"
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>

/*
 * Base class for AppleCSPContexts associated with BlockCryptObjects. 
 * The main purpose of this class is to abstract out the very common work
 * of buffering incoming data (per CSSM-style update, ..., final) and 
 * doing single-block ops on the underlying encrypt/decrypt algorithm
 * objects. Standard PKSC5 padding is handled here. All other chaining,
 * padding, IV, et al, logic is handled by subclasses.
 */
class BlockCryptor : public AppleCSPContext
{
public:
	BlockCryptor(
		AppleCSPSession &session) : 
			AppleCSPContext(session), 
			mOpStarted(false),
			mInBuf(NULL),
			mChainBuf(NULL) { }
	virtual ~BlockCryptor();
	
	/* 
	 * Note standard init(const Context &context, bool encoding) is totally 
	 * subclass-specific. 
	 *
	 * These are implemented here using the subclass's {en,de}cryptBlock functions.
	 * Note PKCS5 padding is implemented here if mPkcs5Padding is true. PKCS5
	 * padding can only be accomplished if the result of decrypting 
	 * cipherBlockSize() bytes of ciphertext yields exactly plainBlockSize()
	 * bytes of plaintext. (Sound odd? FEED does not meet that restriction...)
	 */
	void update(
		void 			*inp, 
		size_t 			&inSize, 			// in/out
		void 			*outp, 
		size_t 			&outSize);			// in/out
		
	void final(
		CssmData 		&out);

	/* 
	 * Our implementation of these three query functions are only valid 
	 * for algorithms for which encrypting one block of plaintext always 
	 * yields exactly one block of ciphertext, and vice versa for decrypt.
	 * The block sizes for plaintext and ciphertext do NOT have to be the same. 
	 * Subclasses (e.g. FEED) which do not meet this criterion will have to override.
	 */
 	virtual size_t inputSize(
		size_t 			outSize);			// input for given output size
	virtual size_t outputSize(
		bool 			final = false, 
		size_t 			inSize = 0); 		// output for given input size
	virtual void minimumProgress(
		size_t 			&in, 
		size_t 			&out); 				// minimum progress chunks

protected:
	typedef enum {
		BCM_ECB,			// no chaining
		BCM_CBC				// requires inBlockSize == outBlockSize
	} BC_Mode;
	
	/* accessors (see comments below re: the member variables) */
	bool	pkcs5Padding()		{ return mPkcsPadding; }
	bool	needFinalData()		{ return mNeedFinalData; }
	void	*inBuf()			{ return mInBuf; }
	size_t	inBufSize()			{ return mInBufSize; }
	void	*chainBuf()			{ return mChainBuf; }
	size_t	inBlockSize()		{ return mInBlockSize; }
	size_t	outBlockSize()		{ return mOutBlockSize; }
	BC_Mode	mode()				{ return mMode; }
	bool	opStarted()			{ return mOpStarted; }
	
	/* 
	 * Reusable setup functions called from subclass's init.
	 * This is the general purpose one....
	 */
	void	setup(
		size_t			blockSizeIn,	// block size of input in bytes
		size_t			blockSizeOut,	// block size of output in bytes
		bool			pkcsPad,		// this class performs PKCS{5,7} padding
		bool			needsFinal,		// needs final update with valid data
		BC_Mode			mode,			// ECB, CBC
		const CssmData	*iv);			// init vector, required for CBC
										//Ê  must be at least blockSizeIn bytes
		
	/*
	 * This one is used by simple, well-behaved algorithms which don't do their own
	 * padding and which rely on us to do everything but one-block-at-a-time
	 * encrypt and decrypt.
	 */
	void BlockCryptor::setup(
		size_t			blockSize,		// block size of input and output
		const Context 	&context);

	/***
	 *** Routines to be implemented by subclass.
	 ***/
	 
	/*
	virtual void init(const Context &context, bool encoding = true);
	*/

	/* 
	 * encrypt/decrypt exactly one block. Output buffers mallocd by caller.
	 * On encrypt, it may be acceptable for plainTextLen to be less than
	 * one plainBlockSize() if:
	 *   -- final is true, and
	 *   -- the subclass permits this. That is generally only true
	 *      when the subclass implements some padding other than our
	 *      standard PKCS5.
	 *
	 * The subclass throws CSSMERR_CSP_INPUT_LENGTH_ERROR if the above
	 * conditions are not met.  
	 */
	virtual void encryptBlock(
		const void		*plainText,			// length implied (one block)
		size_t			plainTextLen,
		void			*cipherText,	
		size_t			&cipherTextLen,		// in/out, subclass throws on overflow
		bool			final) = 0;
		
	/*
	 * Decrypt one block. Incoming cipherText length is ALWAYS cipherBlockSize(). 
	 */
	virtual void decryptBlock(
		const void		*cipherText,		// length implied (one cipher block)
		void			*plainText,	
		size_t			&plainTextLen,		// in/out, subclass throws on overflow
		bool			final) = 0;

private:
	bool				mOpStarted;			// for optional use by subclasses when 
											//   resuing context after encrypt/decrypt 
											//   ops occur

	/* these are all init'd via setup(), called from subclass-specific init */
	bool				mPkcsPadding;		// PKCS{5,7} padding enabled
	bool				mNeedFinalData;		// subclass needs an update(final) with
											//   valid data; if true we always keep
											//   some data in mInBuf after an update.
											//   Mutually exclusive with mPkcsPadding. 
	uint8 				*mInBuf;			// for buffering input
	size_t				mInBufSize;			// valid bytes in mInBuf
	uint8				*mChainBuf;			// for CBC, decrypting only
	size_t				mInBlockSize;		// block size of input in bytes; also
											//    mallocd size of mInBuf
	size_t				mOutBlockSize;		// block size of output in bytes
	BC_Mode				mMode;				// ECB, CBC
		
};

#endif	/* _BLOCK_CRYPTOR_H_ */
