/* ***************************************************************** *
 * Copyright 1998 International Business Machines Corporation. All   *
 * Rights Reserved.                                                  *
 *                                                                   *
 * Please read this carefully.  Your use of this reference           *
 * implementation of certain of the IETF public-key infrastructure   *
 * specifications ("Software") indicates your acceptance of the      *
 * following.  If you do not agree to the following, do not install  *
 * or use any of the Software.                                       *
 *                                                                   *
 * Permission to use, reproduce, distribute and create derivative    *
 * works from the Software ("Software Derivative Works"), and to     *
 * distribute such Software Derivative Works is hereby granted to    *
 * you by International Business Machines Corporation ("IBM").  This *
 * permission includes a license under the patents of IBM that are   *
 * necessarily infringed by your use of the Software as provided by  *
 * IBM.                                                              *
 *                                                                   *
 * IBM licenses the Software to you on an "AS IS" basis, without     *
 * warranty of any kind.  IBM HEREBY EXPRESSLY DISCLAIMS ALL         *
 * WARRANTIES OR CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING,   *
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF       *
 * MERCHANTABILITY, NON INFRINGEMENT AND FITNESS FOR A PARTICULAR    *
 * PURPOSE.  You are solely responsible for determining the          *
 * appropriateness of using this Software and assume all risks       *
 * associated with the use of this Software, including but not       *
 * limited to the risks of program errors, damage to or loss of      *
 * data, programs or equipment, and unavailability or interruption   *
 * of operations.                                                    *
 *                                                                   *
 * IBM WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, *
 * INCIDENTAL, OR  INDIRECT DAMAGES OR FOR ANY ECONOMIC              *
 * CONSEQUENTIAL DAMAGES (INCLUDING LOST PROFITS OR SAVINGS), EVEN   *
 * IF IBM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  IBM  *
 * will not be liable for the loss of, or damage to, your records or *
 * data, or any damages claimed by you based on a third party claim. *
 *                                                                   *
 * IBM wishes to obtain your feedback to assist in improving the     *
 * Software.  You grant IBM a world-wide, royalty-free right to use, *
 * copy, distribute, sublicense and prepare derivative works based   *
 * upon any feedback, including materials, error corrections,        *
 * Software Derivatives, enhancements, suggestions and the like that *
 * you provide to IBM relating to the Software (this does not        *
 * include products for which you charge a royalty and distribute to *
 * IBM under other terms and conditions).                            *
 *                                                                   *
 * You agree to distribute the Software and any Software Derivatives *
 * under a license agreement that: 1) is sufficient to notify all    *
 * licensees of the Software and Software Derivatives that IBM       *
 * assumes no liability for any claim that may arise regarding the   *
 * Software or Software Derivatives, and 2) that disclaims all       *
 * warranties, both express and implied, from IBM regarding the      *
 * Software and Software Derivatives.  (If you include this          *
 * Agreement with any distribution of the Software or Software       *
 * Derivatives you will have met this requirement.)  You agree that  *
 * you will not delete any copyright notices in the Software.        *
 *                                                                   *
 * This Agreement is the exclusive statement of your rights in the   *
 * Software as provided by IBM.   Except for the rights granted to   *
 * you in the second paragraph above, You are not granted any other  *
 * patent rights, including but not limited to the right to make     *
 * combinations of the Software with products that infringe IBM      *
 * patents. You agree to comply with all applicable laws and         *
 * regulations, including all export and import laws and regulation. *
 * This Agreement is governed by the laws of the State of New York.  *
 * This Agreement supersedes all other communications,               *
 * understandings or agreements we may have had prior to this        *
 * Agreement.                                                        *
 * ***************************************************************** */

#include "exception.hpp"
#include "cssmerr.h"
#include "misc.hpp"
#include "bytearraykey.hpp"
#include "symblockcipher.hpp"

/**********************************************************
 *
 *	SymBlockCipherEngine class
 *
 **********************************************************/
SymBlockCipherEngine::SymBlockCipherEngine(uint32 algId, uint32 mode, uint32 _blockSize) 
:CipherEngine(algId, mode)
{
	switch (mode) {
	case CSSM_ALGMODE_CBCPadIV8:
	case CSSM_ALGMODE_CFBPadIV8:
	case CSSM_ALGMODE_OFBPadIV8:
	case CSSM_ALGMODE_CBC_IV8:
	case CSSM_ALGMODE_CFB_IV8:
	case CSSM_ALGMODE_OFB_IV8:
	case CSSM_ALGMODE_ECBPad:
	case CSSM_ALGMODE_ECB:
	case CSSM_ALGMODE_ECB64:
	case CSSM_ALGMODE_CBC:
	case CSSM_ALGMODE_CBC64:
	case CSSM_ALGMODE_CFB:
	case CSSM_ALGMODE_CFB64:
	case CSSM_ALGMODE_CFB8:
	case CSSM_ALGMODE_OFB:
	case CSSM_ALGMODE_OFB64:
		break;
	default:
		//mode not supported
		throw InputException(CSSM_MODE_UNSUPPORTED);
		break;
	}
	remData.setDestroy(CSSM_TRUE);
	IV.setDestroy(CSSM_TRUE);
	IV.setLength(_blockSize);
	blockSize = _blockSize;
}

SymBlockCipherEngine::~SymBlockCipherEngine() {
	cleanUp();
}

void SymBlockCipherEngine::storeIV(CSSM_DATA *cssmIV, CSSM_BOOL encrypt) {
	switch (mode) {
	case CSSM_ALGMODE_CBCPadIV8:
	case CSSM_ALGMODE_CFBPadIV8:
	case CSSM_ALGMODE_OFBPadIV8:
	case CSSM_ALGMODE_CBC_IV8:
	case CSSM_ALGMODE_CFB_IV8:
	case CSSM_ALGMODE_OFB_IV8:
		if ((cssmIV == NULL) || 
			((cssmIV->Length == 0) && (cssmIV->Data == NULL))) 
		{
			//no IV provided
			memset(IV.getData(),'\0', blockSize);
			break;
		}

		if ((cssmIV->Length < blockSize) || (cssmIV->Data == NULL))
			throw InputException(encrypt ? CSSM_CSP_ENC_IV_ERROR : CSSM_CSP_DEC_IV_ERROR);

		IV.setData(blockSize, cssmIV->Data);
		break;
	case CSSM_ALGMODE_ECBPad:
	case CSSM_ALGMODE_ECB:
	case CSSM_ALGMODE_ECB64:
		//doesn't need IV
		memset(IV.getData(),'\0', blockSize);
		break;
	case CSSM_ALGMODE_CBC:
	case CSSM_ALGMODE_CBC64:
	case CSSM_ALGMODE_CFB:
	case CSSM_ALGMODE_CFB64:
	case CSSM_ALGMODE_CFB8:
	case CSSM_ALGMODE_OFB:
	case CSSM_ALGMODE_OFB64:
		//no IV provided, set the IV to zero
		//memcpy(IV, (uchar*)"NeedNoIV", blockSize);
		memset(IV.getData(),'\0', blockSize);
		break;
	default:
		throw InputException(encrypt ? CSSM_CSP_ENC_UNKNOWN_MODE : CSSM_CSP_ENC_UNKNOWN_MODE);
		break;
	}
}

void SymBlockCipherEngine::encryptInit(Key *key, void *params) {
	if (key == NULL) 
		throw InputException(CSSM_CSP_INVALID_KEY_POINTER);

	if (key->getAlgId() != this->algId) 
		throw InputException(CSSM_CSP_KEY_ALGID_NOTMATCH);

	//check if it is expired
	/*{
		throw InputException(CSSM_CSP_INVALID_KEY);
	}*/

	//check the usage
	if ((!(key->getUsage() & CSSM_KEYUSE_ENCRYPT)) && (key->getUsage() != CSSM_KEYUSE_ANY))
		throw InputException(CSSM_CSP_KEY_USAGE_INCORRECT);

	//store the IV
	storeIV((CSSM_DATA*)params, CSSM_TRUE);
}

CSSM_BOOL SymBlockCipherEngine::isModeWithPadding() {
	switch (mode) {
	case CSSM_ALGMODE_CBCPadIV8:
	case CSSM_ALGMODE_CFBPadIV8:
	case CSSM_ALGMODE_OFBPadIV8:
	case CSSM_ALGMODE_ECBPad:
		return(CSSM_TRUE);	
	case CSSM_ALGMODE_CBC_IV8:
	case CSSM_ALGMODE_CFB_IV8:
	case CSSM_ALGMODE_OFB_IV8:
	case CSSM_ALGMODE_ECB:
	case CSSM_ALGMODE_ECB64:
	case CSSM_ALGMODE_CBC:
	case CSSM_ALGMODE_CBC64:
	case CSSM_ALGMODE_CFB:
	case CSSM_ALGMODE_CFB64:
	case CSSM_ALGMODE_CFB8:
	case CSSM_ALGMODE_OFB:
	case CSSM_ALGMODE_OFB64:
		return(CSSM_FALSE);
	default:
		//mode not supported
		throw InputException(CSSM_MODE_UNSUPPORTED);
	}
	return(CSSM_FALSE);
}

void SymBlockCipherEngine::pad(CssmData &dataIn, CssmData &paddedData) {
	uint32	dataInLength;
	char	c;

	dataInLength = dataIn.getLength();
	//length of paddedData is going o be up to blockSize longer than that
	//of the input data
	paddedData.setLength(((dataInLength / blockSize) + 1) * blockSize);
	if (dataInLength != 0) {
		memcpy(paddedData.getData(), dataIn.getData(), dataInLength);
	}

	//c is set to the number of pad bytes added
	c = blockSize - (dataInLength % blockSize);
	memset(paddedData.getData() + dataInLength,	c,
		blockSize - (dataInLength % blockSize));
}

void SymBlockCipherEngine::encryptUpdate(CssmData &clearBuff,
		CssmData &cipherBuff, uint32 *bytesEncrypted) 
{
	uint32		blocks;
	CssmData	data;

	data.setDestroy(CSSM_TRUE);

	//if there is any leftover data from previous updates concatenate it with the new data
	if(remData.getLength() != 0) {
		//It has to be multiple of the block size!
		blocks = (remData.getLength() + clearBuff.getLength()) / blockSize;
		data.setLength(blocks * blockSize);

		if (blocks != 0) {
			//copy data from the leftover buffer and clear text buffer into the input buffer
			memcpy(data.getData(), remData.getData(), remData.getLength());
			memcpy(data.getData() + remData.getLength(), clearBuff.getData(), data.getLength() - remData.getLength());

			//copy whatever is left out from the cleartext buffer into the leftover buffer
			remData.setData(clearBuff.getLength() - (data.getLength() - remData.getLength()),
							clearBuff.getData()  +  (data.getLength() - remData.getLength()));
		}
		else { //no data is encrypted
			//save remData
			CssmData tmpBuff = CssmData(remData.getLength(), remData.getData());

			//increase the length of remData to accomodate the additional input data
			remData.setLength(remData.getLength() + clearBuff.getLength());

			//copy back to remData its old contents plus the input data
			memcpy(remData.getData(), tmpBuff.getData(), tmpBuff.getLength());
			memcpy(remData.getData() + tmpBuff.getLength(), clearBuff.getData(), clearBuff.getLength());

			//return;
		}
	}
	else { //remData.Length == 0
		//It has to be multiple of the block size!
		blocks = clearBuff.getLength() / blockSize;
		data.setData(blocks * blockSize, clearBuff.getData());

		//this is the leftover
		remData.setData(clearBuff.getLength() % blockSize, clearBuff.getData() + data.getLength());
	}
	encryptBlock(data, cipherBuff, bytesEncrypted);
}

uint32 SymBlockCipherEngine::getCylinkMode(uint32 mode) {
	uint32 cMode;

	switch (mode) {
	case CSSM_ALGMODE_ECBPad:
	case CSSM_ALGMODE_ECB:
	case CSSM_ALGMODE_ECB64:
		cMode = ECB_MODE;
		break;
	case CSSM_ALGMODE_CBCPadIV8:
	case CSSM_ALGMODE_CBC_IV8:
	case CSSM_ALGMODE_CBC64:
	case CSSM_ALGMODE_CBC:
		cMode = CBC_MODE;
		break;
	case CSSM_ALGMODE_CFBPadIV8:
	case CSSM_ALGMODE_CFB_IV8:
	case CSSM_ALGMODE_CFB64:
	case CSSM_ALGMODE_CFB:
		cMode = CFB64_MODE;
		break;
	case CSSM_ALGMODE_CFB8:
		cMode = CFB8_MODE;
		break;
	case CSSM_ALGMODE_OFBPadIV8:
	case CSSM_ALGMODE_OFB_IV8:
	case CSSM_ALGMODE_OFB64:
	case CSSM_ALGMODE_OFB:
		cMode = OFB64_MODE;
		break;
	default: 
		throw InputException(CSSM_CSP_ENC_UNKNOWN_MODE);
		break;
	}

	return(cMode);
}

void SymBlockCipherEngine::encryptFinal(CssmData &_remData) {
	CssmData	data;

	if (isModeWithPadding() == CSSM_FALSE) {
		//there should be nothing left in remData
		if (remData.getLength() != 0) {
			remData.setLength(0);
			throw InternalException(CSSM_CSP_INVALID_PADDING);
		}

		_remData.setLength(0);
		return;
	}

	//for modes that require padding, in remData there should be 
	//less than blockSize bytes
	if (remData.getLength() >= blockSize) {
		//remData length should be less than blockSize
		throw InternalException(CSSM_CSP_INVALID_PADDING);
	}

	pad(remData, data);

	//check for sufficient output buffer length
	if (data.getLength() < _remData.getLength())
		throw InputException(CSSM_CSP_NOT_ENOUGH_BUFFER);

	uint32 bytesEncrypted;
	encryptBlock(data, _remData, &bytesEncrypted);

	//cleanUp();
	remData.setLength(0);
}

void SymBlockCipherEngine::decryptInit(Key *key, void *params) {
	if (key == NULL)
		throw InputException(CSSM_CSP_INVALID_KEY_POINTER);

	//Check if it is the proper key
	if (key->getAlgId() != this->algId) {
		throw InputException(CSSM_CSP_KEY_ALGID_NOTMATCH);
	}

	//check the usage
	if ((!(key->getUsage() & CSSM_KEYUSE_DECRYPT)) && (key->getUsage() != CSSM_KEYUSE_ANY))
		throw InputException(CSSM_CSP_KEY_USAGE_INCORRECT);

	//check if it is expired
	/*{
		throw InputException(CSSM_CSP_INVALID_KEY);
	}*/
	
	storeIV((CSSM_DATA*)params, CSSM_FALSE);
}

void SymBlockCipherEngine::decryptUpdate(CssmData &cipherBuff,
		CssmData &clearBuff, uint32 *bytesDecrypted) 
{
	CssmData	tmpData;
	uint32		blocks;

	tmpData.setDestroy(CSSM_TRUE);

	//if there is any leftover data from previous updates concatenate that with the new data
	if(remData.getLength() != 0) {
		//we need multiples of block size, but we need to save the last block if data was padded
		blocks = (remData.getLength() + cipherBuff.getLength()) / blockSize;

		if ((isModeWithPadding() == CSSM_TRUE) && 
			(((remData.getLength() + cipherBuff.getLength()) % blockSize) == 0)) {
			//in this case, even if the input data plus the rem data make up a multiple of the
			//block size, the last block needs to be saved, for use in DecryptFinal
			tmpData.setLength((blocks - 1) * blockSize);
		}
		else {
			tmpData.setLength(blocks * blockSize);
		}

		//copy data from the leftover buffer and cipher text buffer into the input buffer
		if (tmpData.getLength() != 0) {
			memcpy(tmpData.getData(), remData.getData(), remData.getLength());
			memcpy(tmpData.getData() + remData.getLength(), cipherBuff.getData(), tmpData.getLength() - remData.getLength());

			//copy whatever is left out from the ciphertext buffer into the leftover buffer
			remData.setData(cipherBuff.getLength() - (tmpData.getLength() - remData.getLength()),
							cipherBuff.getData()  +  (tmpData.getLength() - remData.getLength()));
		}
		else { // no decryption is performed
			//save remData
			CssmData buff = CssmData(remData.getLength(), remData.getData());

			//increase the length of remData to accomodate the additional input data
			remData.setLength(remData.getLength() + cipherBuff.getLength());

			//copy back to remData its old contents plus the input data
			memcpy(remData.getData(), buff.getData(), buff.getLength());
			memcpy(remData.getData() + buff.getLength(), cipherBuff.getData(), cipherBuff.getLength());

			//return;
		}
	}
	else { //remData.getLength() == 0
		//we need multiples of block size
		blocks = cipherBuff.getLength() / blockSize;		

		if ((isModeWithPadding() == CSSM_TRUE) &&
			((cipherBuff.getLength() % blockSize) == 0)) {
			//in this case, even if the input data plus the rem data make up a multiple of the
			//block size, the last block needs to be saved, for use in DecryptFinal
			tmpData.setData((blocks - 1) * blockSize, cipherBuff.getData());
			//put the leftover in remData
			remData.setData(blockSize, cipherBuff.getData() + tmpData.getLength());
		}
		else {
			tmpData.setData(blocks * blockSize, cipherBuff.getData());
			//put the leftover in remData
			remData.setData(cipherBuff.getLength() % blockSize, cipherBuff.getData() + tmpData.getLength());
		}
	}
	decryptBlock(tmpData, clearBuff, bytesDecrypted);
}

void SymBlockCipherEngine::decryptFinal(CssmData &_remData) {
	CssmData	clearData;
	uint32		bytesDecrypted;
	uint8		paddingBytes;

	if (isModeWithPadding() == CSSM_FALSE) {
		//there should be nothing left in remData
		if (remData.getLength() != 0)
			throw InternalException(CSSM_CSP_INVALID_PADDING);

		_remData.setLength(0);
		return;
	}

	//for modes that require padding, in remData there should be 
	//exactly one block left
	if (remData.getLength() != blockSize)
		throw InternalException(CSSM_CSP_INVALID_PADDING);

	decryptBlock(remData, clearData, &bytesDecrypted);
	//cleanUp();
	remData.setLength(0);
	
	paddingBytes = *(uint8*)(clearData.getData() + clearData.getLength() - 1);
	//no. of padding bytes has to be between 1 and blockSize
	if ((paddingBytes > blockSize) || (paddingBytes == 0)) {
		throw InternalException(CSSM_CSP_INVALID_PADDING);
	}

	//copy out only the bytes of the original message, not including
	//the padding bytes
	_remData.setData(clearData.getLength() - paddingBytes, clearData.getData());
}

uint32 SymBlockCipherEngine::getCipherTextLength(uint32 ClearTextLength) {
	if (isModeWithPadding() == CSSM_TRUE)
		return(((ClearTextLength + remData.getLength()) / blockSize) * blockSize);
	else
		return(((ClearTextLength + remData.getLength()) / blockSize) * blockSize);

	switch (mode) {
	case CSSM_ALGMODE_ECBPad:
	case CSSM_ALGMODE_CBCPadIV8:
	case CSSM_ALGMODE_CFBPadIV8:
	case CSSM_ALGMODE_OFBPadIV8:
		return((ClearTextLength + remData.getLength() / blockSize) * blockSize);
		//the remData will contain another blockSize ALWAYS!
		break;
	case CSSM_ALGMODE_ECB:
	case CSSM_ALGMODE_ECB64:
	case CSSM_ALGMODE_CBC_IV8:
	case CSSM_ALGMODE_CBC:
	case CSSM_ALGMODE_CBC64:
	case CSSM_ALGMODE_CFB_IV8:
	case CSSM_ALGMODE_CFB:
	case CSSM_ALGMODE_CFB64:
	case CSSM_ALGMODE_OFB_IV8:
	case CSSM_ALGMODE_OFB:
	case CSSM_ALGMODE_OFB64:
	case CSSM_ALGMODE_CFB8:
		if (((ClearTextLength/* + remData.getLength()*/) % blockSize) == 0) {
			return (ClearTextLength + remData.getLength());
		}
		else {
			//not multiple of blockSize
			//return(0);
			throw InputException(CSSM_CSP_INPUT_LENGTH_ERROR);
		}
		break;
	default:
		//mode not supported
		//return(0);
		throw InputException(CSSM_CSP_ENC_UNKNOWN_MODE);
		break;
	}
	return(0);
}

uint32 SymBlockCipherEngine::getCipherRemLength(uint32 ClearTextLength) {
	if (isModeWithPadding() == CSSM_TRUE)
		return(blockSize);
	else
		return(0);

/*	switch (mode) {
	case CSSM_ALGMODE_ECBPad:
	case CSSM_ALGMODE_CBCPadIV8:
	case CSSM_ALGMODE_CFBPadIV8:
	case CSSM_ALGMODE_OFBPadIV8:
		return(blockSize);
		break;
	case CSSM_ALGMODE_ECB:
	case CSSM_ALGMODE_ECB64:
	case CSSM_ALGMODE_CBC_IV8:
	case CSSM_ALGMODE_CBC:
	case CSSM_ALGMODE_CBC64:
	case CSSM_ALGMODE_CFB_IV8:
	case CSSM_ALGMODE_CFB:
	case CSSM_ALGMODE_CFB64:
	case CSSM_ALGMODE_OFB_IV8:
	case CSSM_ALGMODE_OFB:
	case CSSM_ALGMODE_OFB64:
	case CSSM_ALGMODE_CFB8:
		return (0);
		break;
	default:
		//mode unsupported
		//return (0);
		throw InputException(CSSM_CSP_ENC_UNKNOWN_MODE);
		break;
	}
	return(0);
	*/
}

uint32 SymBlockCipherEngine::getCipherMaxRemLength() {
	return(blockSize);
}

uint32 SymBlockCipherEngine::getClearTextLength(uint32 CipherTextLength) {
	uint32	leftOverData = (CipherTextLength + remData.getLength()) % blockSize;

	/* For decryption, the remData is concatenated with the input data */
	if (isModeWithPadding() == CSSM_TRUE) {
		/* In padding modes, the last ciphertext block is always saved for DecryptFinal
		 * The cleartext length is the total number of blocks (remData + input data) less
		 * the remainder of the division to blockSize, if this remainder is non-zero, or 
		 * less an entire block, if this division has a zero remainder. */
		if ((leftOverData) == 0)
			/* A full block is saved in the remData */
			return(CipherTextLength + remData.getLength()  - blockSize);
		else
			return(CipherTextLength + remData.getLength()  - leftOverData);
	}
	else {
		/* In non-padding modes, from the total processed data (input + remData) a number
		 * of bytes equal to the remainder of the division total_data_length / blockSize
		 * is saved in remData, even if that number is zero. For the final stage no block
		 * needs to be saved. */
		return(CipherTextLength + remData.getLength()  - leftOverData);
	}
		
			/* The remainder o the division is saved into remData */
/*	if ((CipherTextLength % blockSize) != 0)
		//cipher text HAS to be multiple of blockSize
		//return(0);
		throw InputException(CSSM_CSP_INPUT_LENGTH_ERROR);

	switch (mode) {
	case CSSM_ALGMODE_ECBPad:
	case CSSM_ALGMODE_CBCPadIV8:
	case CSSM_ALGMODE_CFBPadIV8:
	case CSSM_ALGMODE_OFBPadIV8:
		return(CipherTextLength - blockSize);
		//the last block is part of the remData, and contains the padding
		break;
	case CSSM_ALGMODE_ECB:
	case CSSM_ALGMODE_ECB64:
	case CSSM_ALGMODE_CBC_IV8:
	case CSSM_ALGMODE_CBC:
	case CSSM_ALGMODE_CBC64:
	case CSSM_ALGMODE_CFB_IV8:
	case CSSM_ALGMODE_CFB:
	case CSSM_ALGMODE_CFB64:
	case CSSM_ALGMODE_OFB_IV8:
	case CSSM_ALGMODE_OFB:
	case CSSM_ALGMODE_OFB64:
	case CSSM_ALGMODE_CFB8:
		return(CipherTextLength);
		break;
	default:
		//unknown mode -> should I throw an exception ?
		//return (0);
		throw InputException(CSSM_CSP_DEC_UNKNOWN_MODE);
		break;
	}
	return(0);
	*/
}

uint32 SymBlockCipherEngine::getClearRemLength(uint32 CipherTextLength) {
	if (isModeWithPadding() == CSSM_TRUE)
		return(blockSize);
	else
		return(0);

/*	if ((CipherTextLength % blockSize) != 0)
		//cipher text HAS to be multiple of blockSize
		//return(0);
		throw InputException(CSSM_CSP_INPUT_LENGTH_ERROR);

	switch (mode) {
	case CSSM_ALGMODE_ECBPad:
	case CSSM_ALGMODE_CBCPadIV8:
	case CSSM_ALGMODE_CFBPadIV8:
	case CSSM_ALGMODE_OFBPadIV8:
		return (blockSize);
		break;
	case CSSM_ALGMODE_ECB:
	case CSSM_ALGMODE_ECB64:
	case CSSM_ALGMODE_CBC_IV8:
	case CSSM_ALGMODE_CBC:
	case CSSM_ALGMODE_CBC64:
	case CSSM_ALGMODE_CFB_IV8:
	case CSSM_ALGMODE_CFB:
	case CSSM_ALGMODE_CFB64:
	case CSSM_ALGMODE_OFB_IV8:
	case CSSM_ALGMODE_OFB:
	case CSSM_ALGMODE_OFB64:
	case CSSM_ALGMODE_CFB8:
		return(0);		
		break;
	default:
		//unknown mode -> should I throw an exception ?
		throw InputException(CSSM_CSP_DEC_UNKNOWN_MODE);
		//return (0);
		break;
	}
	return(0);
	*/
}

uint32 SymBlockCipherEngine::getClearMaxRemLength() {
	return(blockSize);
}

void SymBlockCipherEngine::cleanUp() {
	mode = 0;
	IV.setLength(0);
	remData.setLength(0);
}
