#include <stdio.h>
#include <stdint.h>
#include "drStd.h"
#include "DrApi/DrApiMm.h"
#if TBASE_API_LEVEL >= 5
#include "DrApi/DrApiMmExt.h"
#include "DrApi/DrApiError.h"
#endif
#include "TlApiDrTimaError.h"
#include "debug_log.h"
#include "TlApiMarshalDrTima.h"
#include "sc_api.h"

#include "process_scrypto.h"

#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
#include "openssl/crypto.h"
#endif

#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
#include "openssl/fipssyms.h"
#endif
#include "openssl/fips.h"
#include "openssl/des.h"
#include "openssl/aes.h"
#include "openssl/rsa.h"
#include "openssl/ossl_typ.h"
#include "openssl/evp.h"
#include "openssl/obj_mac.h"
#include "openssl/objects.h"


/* util functions */

#define CHECK_IN_LEN(IN_LEN, EXPECTED_LEN)	((IN_LEN)!=(EXPECTED_LEN))
#define PRINT_BOUND_OUT(IN_LEN, EXPECTED_LEN)\
	if(CHECK_IN_LEN(IN_LEN, EXPECTED_LEN)){\
		TTY_LOG("%s in_len(%d) does not match expected len (%d)", __FUNCTION__, IN_LEN, EXPECTED_LEN);\
	}

drApiResult_t drRet = DRAPI_OK;

uint32_t set_rsa_pub_key(
	RSA *rsa,
	uint8_t *n,
	uint32_t n_len,
	uint8_t *e,
	uint32_t e_len
)
{
	if (!rsa) {
		TTY_LOG("rsa is NULL");
		return SC_NULL_POINTER;
	}

	rsa->e = BN_bin2bn(e, e_len, rsa->e);
	if(NULL == rsa->e)
	{
		TTY_LOG("%s BN_bin2bn() for rsa->e returned NULL!", __FUNCTION__);
		return SC_NULL_POINTER;
	}

	rsa->n = BN_bin2bn(n, n_len, rsa->n);
	if(NULL == rsa->n)
	{
		TTY_LOG("%s BN_bin2bn() for rsa->n returned NULL!", __FUNCTION__);
		return SC_NULL_POINTER;
	}

	return SC_OK;
}

uint32_t set_rsa_priv_key(
	RSA *rsa,
	uint8_t *n,
	uint32_t n_len,
	uint8_t *e,
	uint32_t e_len,
	uint8_t *d,
	uint32_t d_len
)
{
	uint32_t ret = SC_UNKNOWN_ERROR;

	ret = set_rsa_pub_key(rsa, n, n_len, e, e_len);
	if (ret != SC_OK)
		return ret;

	rsa->d = BN_bin2bn(d, d_len, rsa->d);
	if(NULL == rsa->d)
	{
		TTY_LOG("%s BN_bin2bn() for rsa->d returned NULL!", __FUNCTION__);
		return SC_NULL_POINTER;
	}
	return SC_OK;
}

uint32_t set_rsa_priv_key2(
	RSA *rsa,
	uint8_t *n,
	uint32_t n_len,
	uint8_t *e,
	uint32_t e_len,
	uint8_t *d,
	uint32_t d_len,
	uint8_t *p,
	uint32_t p_len,
	uint8_t *q,
	uint32_t q_len,
	uint8_t *dp,
	uint32_t dp_len,
	uint8_t *dq,
	uint32_t dq_len,
	uint8_t *qp,
	uint32_t qp_len
)
{
	uint32_t ret = SC_UNKNOWN_ERROR;

	ret = set_rsa_pub_key(rsa, n, n_len, e, e_len);
	if (ret != SC_OK)
		return ret;

	if (d_len != 0 && d != NULL) {
		rsa->d = BN_bin2bn(d, d_len, rsa->d);
		if(NULL == rsa->d)
		{
			TTY_LOG("%s BN_bin2bn() for rsa->d returned NULL!", __FUNCTION__);
			return SC_NULL_POINTER;
		}
	}

	if (p_len != 0 && p != NULL
			&& q_len != 0 && q != NULL
			&& dp_len != 0 && dp != NULL
			&& dq_len != 0 && dq != NULL
			&& qp_len != 0 && qp != NULL) {
		rsa->p = BN_bin2bn(p, p_len, rsa->p);
		if(NULL == rsa->p)
		{
			TTY_LOG("%s BN_bin2bn() for rsa->p returned NULL!", __FUNCTION__);
			return SC_NULL_POINTER;
		}

		rsa->q = BN_bin2bn(q, q_len, rsa->q);
		if(NULL == rsa->q)
		{
			TTY_LOG("%s BN_bin2bn() for rsa->q returned NULL!", __FUNCTION__);
			return SC_NULL_POINTER;
		}

		rsa->dmp1 = BN_bin2bn(dp, dp_len, rsa->dmp1);
		if(NULL == rsa->dmp1)
		{
			TTY_LOG("%s BN_bin2bn() for rsa->dmp1 returned NULL!", __FUNCTION__);
			return SC_NULL_POINTER;
		}

		rsa->dmq1 = BN_bin2bn(dq, dq_len, rsa->dmq1);
		if(NULL == rsa->dmq1)
		{
			TTY_LOG("%s BN_bin2bn() for rsa->dmq1 returned NULL!", __FUNCTION__);
			return SC_NULL_POINTER;
		}

		rsa->iqmp = BN_bin2bn(qp, qp_len, rsa->iqmp);
		if(NULL == rsa->iqmp)
		{
			TTY_LOG("%s BN_bin2bn() for rsa->iqmp returned NULL!", __FUNCTION__);
			return SC_NULL_POINTER;
		}
	}
	return SC_OK;
}

uint32_t get_md(uint32_t masked_cmd, const EVP_MD **md)
{
	switch (masked_cmd) {
	case SC_MD_SHA1:
	case SC_SIG_MD_SHA1:
		*md = EVP_sha1();
		break;
	case SC_MD_SHA224:
	case SC_SIG_MD_SHA224:
		*md = EVP_sha224();
		break;
	case SC_MD_SHA256:
	case SC_SIG_MD_SHA256:
		*md = EVP_sha256();
		break;
	case SC_MD_SHA384:
	case SC_SIG_MD_SHA384:
		*md = EVP_sha384();
		break;
	case SC_MD_SHA512:
	case SC_SIG_MD_SHA512:
		*md = EVP_sha512();
		break;
	default:
		TTY_LOG("%s unsupported hash alg", __FUNCTION__);
		return SC_INVALID_INPUT_PARAM;
	}
	return SC_OK;
}

#if TBASE_API_LEVEL >= 5
uint32_t process_scrypto(struct scrypto_t *pSCrypto, threadid_t ipcClient) {
#else
uint32_t process_scrypto(struct scrypto_t *pSCrypto) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;
	uint32_t cmd = pSCrypto->cmd;
	void * in;
	uint32_t in_len = pSCrypto->in_len;
#if TBASE_API_LEVEL >= 5
	drRet = drApiMapTaskBuffer(
			THREADID_TO_TASKID(ipcClient),
			pSCrypto->in_addr,
			in_len,
			MAP_READABLE | MAP_WRITABLE,
			(void **)&in);
	if (drRet != DRAPI_OK) {
		TTY_LOG("in_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}
#else
	if (NULL ==
			(in =
			 drApiAddrTranslateAndCheckBuffer(pSCrypto->in_addr, in_len))) {
		TTY_LOG("ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}
#endif
	switch (cmd & SC_MASK_TYPE) {
		case SC_CIPHER:
			ret = process_cipher(cmd, in, in_len);
			break;
		case SC_SIG:
			ret = process_sig(cmd, in, in_len);
			break;
		case SC_MD:
			ret = process_md(cmd, in, in_len);
			break;
		case SC_RNG:
			ret = process_rng(cmd, in, in_len);
			break;
#if TBASE_API_LEVEL >= 5
		case SC2_CIPHER:
			ret = process_cipher2(cmd, in, in_len, ipcClient);
			break;
		case SC2_SIG:
			ret = process_sig2(cmd, in, in_len, ipcClient);
			break;
		case SC2_MD:
			ret = process_md2(cmd, in, in_len, ipcClient);
			break;
#else
		case SC2_CIPHER:
			ret = process_cipher2(cmd, in, in_len);
			break;
		case SC2_SIG:
			ret = process_sig2(cmd, in, in_len);
			break;
		case SC2_MD:
			ret = process_md2(cmd, in, in_len);
			break;
#endif
		case SC2_RNG:
			//ret = process_rng2(cmd, in, in_len);
			break;
		case SC2_VER:
			ret = process_version(cmd, in, in_len);
			break;

	default:
			TTY_LOG("unsupported SC TYPE");
			ret = SC_INVALID_INPUT_PARAM;
			break;
	}

exit:
	return ret;
}

uint32_t process_version(uint32_t cmd, void *in, uint32_t in_len)
{
	uint32_t ret = SC_UNKNOWN_ERROR;

	sc_version_t *param = (sc_version_t *)in;

	PRINT_BOUND_OUT(in_len, sizeof(sc_version_t))
	if(CHECK_IN_LEN(in_len, sizeof(sc_version_t)))
		goto exit;

	param->version = SC_VERSION_NUMBER;

	ret = SC_OK;
exit:
	return ret;

}

uint32_t process_cipher(uint32_t cmd, void *in, uint32_t in_len)
{
	uint32_t ret = SC_UNKNOWN_ERROR;

	switch (cmd & SC_MASK_ALG) {
	case SC_CIPHER_AES:
		ret = process_cipher_aes(cmd, in, in_len);
		break;
	case SC_CIPHER_TDEA:
		ret = process_cipher_tdea(cmd, in, in_len);
		break;
	case SC_CIPHER_RSA:
		ret = process_cipher_rsa(cmd, in, in_len);
		break;
	default:
		TTY_LOG("Unsupported SC_CIPHER algorithm");
		ret = SC_INVALID_INPUT_PARAM;
		break;
	}

	return ret;
}

uint32_t process_cipher_tdea(uint32_t cmd, void *in, uint32_t in_len)
{
	uint32_t ret = SC_UNKNOWN_ERROR;
	int sc_ret = -1;
	sc_tdea_t *param = (sc_tdea_t *)in;
	uint32_t cmd_TABK = cmd & (SC_MASK_TYPE | SC_MASK_ALG | SC_MASK_BLOCK_MODE | SC_MASK_KEYSIZE);
	uint32_t cmd_O = cmd & SC_MASK_OP;
	int enc = -1;
	EVP_CIPHER_CTX ctx;
	const EVP_CIPHER *cipher = NULL;
	uint8_t des3_keys[3*DES_KEY_SIZE] = { 0 };
	uint8_t iv_buf[DES_BLOCK_SIZE] = { 0 };
	uint8_t key_cnt = 0;
	uint8_t *iv_ptr = NULL;
	uint8_t iv_len = param->iv_len;

	PRINT_BOUND_OUT(in_len, sizeof(sc_tdea_t))
	if(CHECK_IN_LEN(in_len, sizeof(sc_tdea_t)))
		return ret;

	if (param->key_len == 0
			|| param->input_len == 0
			|| param->input_len > INPUT_MAX_SIZE) {
		TTY_LOG("key_len: %d, input_len: %d", param->key_len, param->input_len);
		return SC_INVALID_INPUT_PARAM;
	}

	EVP_CIPHER_CTX_init(&ctx);

#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	switch(cmd_TABK) {
	case SC_ALG_TDEA_2KEY_ECB:
		
	case SC_ALG_TDEA_3KEY_ECB:
		
	case SC_ALG_TDEA_2KEY_CFB:
		
	case SC_ALG_TDEA_3KEY_CFB:
		
	case SC_ALG_TDEA_2KEY_OFB:
		
	case SC_ALG_TDEA_3KEY_OFB:
		
	case SC_ALG_TDEA_2KEY_CBC:
		cipher = EVP_des_ede_cbc();
		break;
	case SC_ALG_TDEA_3KEY_CBC:
		cipher = EVP_des_ede3_cbc();
		break;
	default:
		TTY_LOG("Unsupported 3DES algorithm");
		ret = SC_UNSUPPORTED_ALG;
		goto exit;
	}
#else
	switch(cmd_TABK) {
	case SC_ALG_TDEA_2KEY_ECB:
		cipher = EVP_des_ede_ecb();
		break;
	case SC_ALG_TDEA_3KEY_ECB:
		cipher = EVP_des_ede3_ecb();
		break;
	case SC_ALG_TDEA_2KEY_CFB:
		cipher = EVP_des_ede_cfb();
		break;
	case SC_ALG_TDEA_3KEY_CFB:
		cipher = EVP_des_ede3_cfb();
		break;
	case SC_ALG_TDEA_2KEY_OFB:
		cipher = EVP_des_ede_ofb();
		break;
	case SC_ALG_TDEA_3KEY_OFB:
		cipher = EVP_des_ede3_ofb();
		break;
	case SC_ALG_TDEA_2KEY_CBC:
		cipher = EVP_des_ede_cbc();
		break;
	case SC_ALG_TDEA_3KEY_CBC:
		cipher = EVP_des_ede3_cbc();
		break;
	default:
		TTY_LOG("Unsupported 3DES algorithm");
		ret = SC_UNSUPPORTED_ALG;
		goto exit;
	}
#endif
	key_cnt = param->key_len / DES_KEY_SIZE;
	switch(key_cnt) {
		case 1:
			memcpy(des3_keys, param->key, DES_KEY_SIZE);
			memcpy(des3_keys + DES_KEY_SIZE, param->key, DES_KEY_SIZE);
			memcpy(des3_keys + 2*DES_KEY_SIZE, param->key, DES_KEY_SIZE);
			break;
		case 2:
			memcpy(des3_keys, param->key, DES_KEY_SIZE);
			memcpy(des3_keys + DES_KEY_SIZE, param->key + DES_KEY_SIZE, DES_KEY_SIZE);
			memcpy(des3_keys + 2*DES_KEY_SIZE, param->key, DES_KEY_SIZE);
			break;
		case 3:
			memcpy(des3_keys, param->key, DES_KEY_SIZE);
			memcpy(des3_keys + DES_KEY_SIZE, param->key + DES_KEY_SIZE, DES_KEY_SIZE);
			memcpy(des3_keys + 2*DES_KEY_SIZE, param->key + 2*DES_KEY_SIZE, DES_KEY_SIZE);
			break;
		default:
			TTY_LOG("invalid TDEA key size");
			ret = SC_INVALID_INPUT_PARAM;
			goto exit;
	}

	/* setup iv, default is NULL */
	memset(iv_buf, 0, sizeof(iv_buf));
	if (iv_len == DES_BLOCK_SIZE) {
		memcpy(iv_buf, param->iv, iv_len);
		iv_ptr = iv_buf;
	}

	if (cmd_O == SC_OP_ENC) {
		enc = DES_ENCRYPT;
	} else if (cmd_O == SC_OP_DEC) {
		enc = DES_DECRYPT;
	} else {
		 TTY_LOG("unsupported OP for TDEA");
		 ret = SC_INVALID_INPUT_PARAM;
		 goto exit;
	}
	/* instantiate cipher context */
	sc_ret = EVP_CipherInit_ex(&ctx, cipher, NULL, des3_keys, iv_ptr, enc);
	if (sc_ret <= 0) {
		TTY_LOG("init error, %d", ret);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	/* do cipher */
	sc_ret = EVP_Cipher(&ctx, param->output, param->input, param->input_len);
	param->output_len = param->input_len;
	if (sc_ret <= 0) {
		TTY_LOG("EVP_CipherUpdate error %d", ret);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	ret = SC_OK;

exit:
	/* clean up cipher context */
	EVP_CIPHER_CTX_cleanup(&ctx);
	return ret;
}

uint32_t process_cipher_aes(uint32_t cmd, void *in, uint32_t in_len)
{
	uint32_t ret = SC_UNKNOWN_ERROR;
	sc_aes_t *param = (sc_aes_t *)in;
	uint8_t aes_key_size = param->key_len;
	uint8_t aes_key[AES_KEY_MAX_SIZE] = {0};
	uint32_t cmd_TAB = cmd & (SC_MASK_TYPE | SC_MASK_ALG | SC_MASK_BLOCK_MODE);
	EVP_CIPHER_CTX ctx;
	const EVP_CIPHER *cipher = NULL;
	uint8_t iv_buf[AES_BLOCK_SIZE] = {0};
	uint8_t *iv_ptr = NULL;
	int dir = 1; /* encrypt by default */
	uint32_t pad_len = 0;
	uint32_t i = 0;
	uint32_t input_len = param->input_len;
	uint8_t iv_len = param->iv_len;

	PRINT_BOUND_OUT(in_len, sizeof(sc_aes_t))
	if(CHECK_IN_LEN(in_len, sizeof(sc_aes_t)))
		return ret;

	if (input_len == 0 || input_len >= INPUT_MAX_SIZE
			|| (aes_key_size != AES_128_KEY_SIZE
				&& aes_key_size != AES_192_KEY_SIZE
				&& aes_key_size != AES_256_KEY_SIZE)) {
		TTY_LOG("key_len: %d, input_len: %d", aes_key_size, input_len);
		return SC_INVALID_INPUT_PARAM;
	}
	memcpy(aes_key, param->key, aes_key_size);

	/* setup iv, default is NULL */
	memset(iv_buf, 0, sizeof(iv_buf));
	if (iv_len == AES_BLOCK_SIZE) {
		memcpy(iv_buf, param->iv, iv_len);
		iv_ptr = iv_buf;
	}

	/* op = enc/dec */
	switch (cmd & SC_MASK_OP) {
		case SC_OP_ENC:
			dir = 1;
			break;
		case SC_OP_DEC:
			dir = 0;
			break;
		default:
			TTY_LOG("unsupported AES OP");
			return SC_INVALID_INPUT_PARAM;
	}

	/* check padding */
	if (dir) { /* for encryption */
		if ((cmd & SC_MASK_PADDING) == SC_PAD_NOPAD) {
			if (input_len % AES_BLOCK_SIZE != 0) {
				TTY_LOG("%s invalid input length %d", __FUNCTION__, input_len);
				return SC_INVALID_INPUT_PARAM;
			}
			pad_len = 0;
		} else { /* by default we use PKCS 5 padding */
			if (input_len % AES_BLOCK_SIZE == 0) {
				pad_len = AES_BLOCK_SIZE;
			} else {
				pad_len = AES_BLOCK_SIZE - (input_len % AES_BLOCK_SIZE);
			}
			if (input_len + pad_len > INPUT_MAX_SIZE
					|| input_len + pad_len > OUTPUT_MAX_SIZE) {
				return SC_INVALID_INPUT_PARAM;
			}
			for (i = 0; i < pad_len; i++) {
				param->input[input_len + i] = pad_len;
			}
		}
	} else { /* for decryption */
		if (input_len % AES_BLOCK_SIZE != 0
				|| input_len < AES_BLOCK_SIZE) {
			TTY_LOG("%s invalid input length: %d", __FUNCTION__, input_len);
			return SC_INVALID_INPUT_PARAM;
		}
		pad_len = 0;
	}

#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	EVP_CIPHER_CTX_init(&ctx);
#else
	FIPS_cipher_ctx_init(&ctx);
#endif

	if (cmd_TAB == SC_ALG_AES_CBC) {
		switch (aes_key_size) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_cbc();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_cbc();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_cbc();
			break;
		}
	} else if (cmd_TAB == SC_ALG_AES_ECB) {
		switch (aes_key_size) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_ecb();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_ecb();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_ecb();
			break;
		}
	} else if (cmd_TAB == SC_ALG_AES_CFB1) {
		switch (aes_key_size) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_cfb1();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_cfb1();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_cfb1();
			break;
		}
	} else if (cmd_TAB == SC_ALG_AES_CFB8) {
		switch (aes_key_size) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_cfb8();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_cfb8();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_cfb8();
			break;
		}
	} else if (cmd_TAB == SC_ALG_AES_CFB128) {
		switch (aes_key_size) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_cfb128();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_cfb128();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_cfb128();
			break;
		}
	} else if (cmd_TAB == SC_ALG_AES_OFB) {
		switch (aes_key_size) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_ofb();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_ofb();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_ofb();
			break;
		}
	} else if (cmd_TAB == SC_ALG_AES_GCM) {
		switch (aes_key_size) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_gcm();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_gcm();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_gcm();
			break;
		}
	} 
#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	else if (cmd_TAB == SC_ALG_AES_CCM) {
		switch (aes_key_size) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_ccm();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_ccm();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_ccm();
			break;
		}
	} 
#endif
	else if (cmd_TAB == SC_ALG_AES_CTR) {
		switch (aes_key_size) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_ctr();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_ctr();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_ctr();
			break;
		}
	} else if (cmd_TAB == SC_ALG_AES_XTS) {
		switch (aes_key_size) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_xts();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_xts();
			break;
		}
	} else {
		TTY_LOG("%s unsupported AES block mode", __FUNCTION__);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	if (!cipher) {
		TTY_LOG("%s invalid key size %d", __FUNCTION__, aes_key_size);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	if (EVP_CipherInit(&ctx, cipher, aes_key, iv_ptr, dir) <= 0) {
		TTY_LOG("%s EVP_CipherInit failed", __FUNCTION__);
		goto exit;
	}
	if (1 != EVP_Cipher(&ctx, param->output, param->input, input_len + pad_len)) {
		TTY_LOG("%s EVP_Cipher failed", __FUNCTION__);
		if (dir)
			ret = SC_ENC_ERROR;
		else
			ret = SC_DEC_ERROR;
		goto exit;
	}
#else
	if (FIPS_cipherinit(&ctx, cipher, aes_key, iv_ptr, dir) <= 0) {
		TTY_LOG("%s FIPS_cipherinit failed", __FUNCTION__);
		goto exit;
	}

	if (cmd_TAB == SC_ALG_AES_CFB1) {
		M_EVP_CIPHER_CTX_set_flags(&ctx, EVP_CIPH_FLAG_LENGTH_BITS);
	}

	if (1 != FIPS_cipher(&ctx, param->output, param->input, input_len + pad_len)) {
		TTY_LOG("%s FIPS_cipher failed", __FUNCTION__);
		if (dir)
			ret = SC_ENC_ERROR;
		else
			ret = SC_DEC_ERROR;
		goto exit;
	}
#endif
	if (dir) { /* encryptino */
		param->output_len = input_len + pad_len;
	} else { /* decryption */
		if ((cmd & SC_MASK_PADDING) == SC_PAD_NOPAD) {
			param->output_len = input_len;
		} else { /* pkcs5 */
			if (param->output[input_len - 1] > AES_BLOCK_SIZE) {
				TTY_LOG("%s invalid output!", __FUNCTION__);
				ret = SC_INVALID_INPUT_PARAM;
				goto exit;
			}
			param->output_len = input_len - param->output[input_len - 1];
		}
	}
	ret = SC_OK;
exit:
#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	EVP_CIPHER_CTX_cleanup(&ctx);
#else
	FIPS_cipher_ctx_cleanup(&ctx);
#endif
	return ret;
}

uint32_t process_cipher_rsa(uint32_t cmd, void *in, uint32_t in_len)
{
	uint32_t ret = SC_UNKNOWN_ERROR;
	sc_rsa_t *param = (sc_rsa_t *)in;

	PRINT_BOUND_OUT(in_len, sizeof(sc_rsa_t))
	if(CHECK_IN_LEN(in_len, sizeof(sc_rsa_t)))
		return ret;

	if (param->input_len == 0
			|| param->input_len > INPUT_MAX_SIZE
			|| param->n_len > RSA_KEY_MAX_SIZE
			|| param->n_len == 0
			|| param->e_len > RSA_KEY_MAX_SIZE
			|| param->e_len == 0) {
		TTY_LOG("%s invalid input param", __FUNCTION__);
		TTY_LOG("%s %d, %d, %d, %d", __FUNCTION__, param->n_len, param->e_len, param->input_len, param->output_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	/* op = enc/dec */
	switch (cmd & SC_MASK_OP) {
		case SC_OP_ENC:
			ret = sc_rsa_encrypt(cmd, param);
			break;
		case SC_OP_DEC:
			ret = sc_rsa_decrypt(cmd, param);
			break;
		default:
			TTY_LOG("unsupported RSA OP");
			ret = SC_INVALID_INPUT_PARAM;
	}
exit:
	return ret;
}

uint32_t sc_rsa_encrypt(uint32_t cmd, sc_rsa_t *param)
{
	uint32_t ret = SC_UNKNOWN_ERROR;
	int sc_ret = -1;
	int padding = 0;
	RSA *rsa = NULL;

	rsa = RSA_new();
	if(NULL == rsa)
	{
		TTY_LOG("%s RSA_new() returned NULL!", __FUNCTION__);
		ret = SC_NULL_POINTER;
		goto exit;
	}
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	RSA_set_method(rsa, (const RSA_METHOD *)RSA_get_default_method());
	#endif
	ret = set_rsa_pub_key(rsa, param->n, param->n_len, param->e, param->e_len);
	if (ret != SC_OK) {
		TTY_LOG("%s failed to init rsa pub key", __FUNCTION__);
		goto exit;
	}

	/* padding */
	switch (cmd & SC_MASK_PADDING) {
	case SC_PAD_PKCS1_OAEP:
		if (param->input_len >= RSA_size(rsa) - 41) {
			TTY_LOG("%s invalid input_len for padding PKCS1_OAEP", __FUNCTION__);
			ret = SC_INVALID_INPUT_PARAM;
			goto exit;
		}
		padding = RSA_PKCS1_OAEP_PADDING;
		break;
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	case SC_PAD_SSLV23:
		if (param->input_len >= RSA_size(rsa) - 11) {
			TTY_LOG("%s invalid input_len for padding SSLV23", __FUNCTION__);
			ret = SC_INVALID_INPUT_PARAM;
			goto exit;
		}
		padding = RSA_SSLV23_PADDING;
		break;
	#endif
	case SC_PAD_NOPAD:
		if (param->input_len != RSA_size(rsa)) {
			TTY_LOG("%s invalid input_len for no padding", __FUNCTION__);
			ret = SC_INVALID_INPUT_PARAM;
			goto exit;
		}
		padding = RSA_NO_PADDING;
		break;
	case SC_PAD_PKCS1:
	default:
		if (param->input_len >= RSA_size(rsa) - 11) {
			TTY_LOG("%s invalid input_len for PKCS1", __FUNCTION__);
			ret = SC_INVALID_INPUT_PARAM;
			goto exit;
		}
		padding = RSA_PKCS1_PADDING;
		break;
	}

	sc_ret = RSA_public_encrypt(param->input_len, param->input, param->output, rsa, padding);
	if(sc_ret != param->n_len) {
		TTY_LOG("%s RSA_public_encrypt() returned an error!", __FUNCTION__);
		ret = SC_ENC_ERROR;
		goto exit;
	}
	param->output_len = sc_ret;
	ret = SC_OK;
exit:
	if (rsa != NULL) {
		RSA_free(rsa);
	}
	padding = 0;
	return ret;
}

uint32_t sc_rsa_decrypt(uint32_t cmd, sc_rsa_t *param)
{
	uint32_t ret = SC_UNKNOWN_ERROR;
	int sc_ret = -1;
	int padding = 0;
	RSA *rsa = NULL;

	rsa = RSA_new();
	if(NULL == rsa)
	{
		TTY_LOG("%s RSA_new() returned NULL!", __FUNCTION__);
		ret = SC_NULL_POINTER;
		goto exit;
	}
	
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	RSA_set_method(rsa, (const RSA_METHOD *)RSA_get_default_method());
	#endif

	ret = set_rsa_priv_key(rsa, param->n, param->n_len, param->e, param->e_len, param->d, param->d_len);
	if (ret != SC_OK) {
		TTY_LOG("%s failed to init rsa private key", __FUNCTION__);
		goto exit;
	}

	/* padding */
	switch (cmd & SC_MASK_PADDING) {
	case SC_PAD_PKCS1_OAEP:
		padding = RSA_PKCS1_OAEP_PADDING;
		break;
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	case SC_PAD_SSLV23:
		padding = RSA_SSLV23_PADDING;
		break;
	#endif
	case SC_PAD_NOPAD:
		padding = RSA_NO_PADDING;
		break;
	case SC_PAD_PKCS1:
	default:
		padding = RSA_PKCS1_PADDING;
		break;
	}

	sc_ret = RSA_private_decrypt(param->input_len, param->input, param->output, rsa, padding);
	if(sc_ret == -1) {
		TTY_LOG("%s RSA_private_decrypt() returned an error!", __FUNCTION__);
		ret = SC_DEC_ERROR;
		goto exit;
	}
	param->output_len = sc_ret;
	ret = SC_OK;
exit:
	if (rsa != NULL) {
		RSA_free(rsa);
	}
	padding = 0;
	return ret;
}


tlApiResult_t process_sig(uint32_t cmd, void *in, uint32_t in_len)
{
	uint32_t ret = SC_UNKNOWN_ERROR;

	switch (cmd & SC_MASK_ALG) {
	case SC_SIG_RSA:
		ret = process_sig_rsa(cmd, in, in_len);
		break;
	case SC_SIG_ECDSA:
		//ret = process_sig_ecdsa(cmd, in, in_len);
		ret = SC_UNSUPPORTED_ALG;
		break;
	case SC_SIG_DSA:
		//ret = process_sig_dsa(cmd, in, in_len);
		ret = SC_UNSUPPORTED_ALG;
		break;
	default:
		TTY_LOG("Unsupported SC_SIG algorithm");
		ret = SC_INVALID_INPUT_PARAM;
		break;
	}

	return ret;
}

uint32_t process_sig_rsa(uint32_t cmd, void *in, uint32_t in_len)
{
	uint32_t ret = SC_UNKNOWN_ERROR;
	sc_rsa_t *param = (sc_rsa_t *)in;

	PRINT_BOUND_OUT(in_len, sizeof(sc_rsa_t))
	if(CHECK_IN_LEN(in_len, sizeof(sc_rsa_t)))
		return ret;

	if (param->input_len == 0
			|| param->input_len > INPUT_MAX_SIZE
			|| param->n_len > RSA_KEY_MAX_SIZE
			|| param->n_len == 0
			|| param->e_len > RSA_KEY_MAX_SIZE
			|| param->e_len == 0) {
		TTY_LOG("%s invalid input param", __FUNCTION__);
		TTY_LOG("%s %d, %d, %d, %d", __FUNCTION__, param->n_len, param->e_len, param->input_len, param->output_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	/* op = enc/dec */
	switch (cmd & SC_MASK_OP) {
		case SC_OP_SIGN:
			ret = sc_rsa_sign(cmd, param);
			break;
		case SC_OP_VERIFY:
			ret = sc_rsa_verify(cmd, param);
			break;
		default:
			TTY_LOG("unsupported RSA OP");
			ret = SC_INVALID_INPUT_PARAM;
	}
exit:
	return ret;
}

uint32_t sc_rsa_sign(uint32_t cmd, sc_rsa_t *param)
{
	uint32_t ret = SC_UNKNOWN_ERROR;
	int sc_ret = -1;
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	int padding = 0;
	#endif
	RSA *rsa = NULL;
	const EVP_MD *md = NULL;
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	unsigned int digestlen = 0;
	#endif
	unsigned int sig_len = 0;
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	int salt_len = -3;
	#endif

	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	rsa = RSA_new();
	#else
	rsa = FIPS_rsa_new();
	#endif
	if(NULL == rsa)
	{
		TTY_LOG("%s RSA_new() returned NULL!", __FUNCTION__);
		ret = SC_NULL_POINTER;
		goto exit;
	}
	
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	RSA_set_method(rsa, (const RSA_METHOD *)RSA_get_default_method());
	#endif

	ret = set_rsa_priv_key(rsa, param->n, param->n_len, param->e, param->e_len, param->d, param->d_len);
	if (ret != SC_OK) {
		TTY_LOG("%s failed to init rsa private key", __FUNCTION__);
		goto exit;
	}

	/* MD */
	if (get_md(cmd & SC_MASK_SIG_MD, &md) != SC_OK) {
		TTY_LOG("%s, failed to get md", __FUNCTION__);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	/* padding */
	switch (cmd & SC_MASK_PADDING) {
	case SC_PAD_RSA_X931:
		padding = RSA_X931_PADDING;
		salt_len = -2;
		break;
	case SC_PAD_PKCS1_PSS:
		padding = RSA_PKCS1_PSS_PADDING;
		salt_len = EVP_MD_size(md);
		break;
	case SC_PAD_PKCS1:
	default:
		padding = RSA_PKCS1_PADDING;
		salt_len = 0;
		break;
	}
	#endif
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
		uint8_t digest[EVP_MAX_MD_SIZE]; 
		ret=EVP_Digest(param->input,param->input_len,digest,&digestlen,md,NULL);  // return 1 for success ... else return error
		if(ret != 1) {
			TTY_LOG("EVP_Digest returns an error!");
			ret = SC_EVP_ERROR;
			goto exit;
		}
		sc_ret = RSA_sign(EVP_MD_type(md),digest,digestlen,param->output, &sig_len,rsa);
		OPENSSL_cleanse(digest,digestlen); // Buffer zeroization mem.h
	#else
		sc_ret = FIPS_rsa_sign(rsa, param->input, param->input_len, md, padding, salt_len, NULL, param->output, &sig_len);
	#endif
	if(sc_ret == 0) {
		TTY_LOG("%s FIPS_rsa_sign() returned an error!", __FUNCTION__);
		ret = SC_SIGN_ERROR;
		goto exit;
	}
	param->output_len = sig_len;
	ret = SC_OK;
exit:
	if (rsa != NULL) {
		#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
			RSA_free(rsa);
		#else
			FIPS_rsa_free(rsa);
		#endif
	}
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
		padding = 0;
	#endif
	return ret;
}

uint32_t sc_rsa_verify(uint32_t cmd, sc_rsa_t *param)
{
	uint32_t ret = SC_UNKNOWN_ERROR;
	int sc_ret = -1;
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	int padding = 0;
	#endif
	RSA *rsa = NULL;
	const EVP_MD *md = NULL;
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	unsigned int digestlen = 0;
	#endif
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	int salt_len = -3;
	#endif

	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
		rsa = RSA_new();
	#else
		rsa = FIPS_rsa_new();
	#endif
	if(NULL == rsa)
	{
		TTY_LOG("%s RSA_new() returned NULL!", __FUNCTION__);
		ret = SC_NULL_POINTER;
		goto exit;
	}
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	RSA_set_method(rsa, (const RSA_METHOD *)RSA_get_default_method());
	#endif

	ret = set_rsa_pub_key(rsa, param->n, param->n_len, param->e, param->e_len);
	if (ret != SC_OK) {
		TTY_LOG("%s failed to init rsa pub key", __FUNCTION__);
		goto exit;
	}

	/* MD */
	if (get_md(cmd & SC_MASK_SIG_MD, &md) != SC_OK) {
		TTY_LOG("%s, failed to get md", __FUNCTION__);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	/* padding */
	switch (cmd & SC_MASK_PADDING) {
	case SC_PAD_RSA_X931:
		padding = RSA_X931_PADDING;
		salt_len = -2;
		break;
	case SC_PAD_PKCS1_PSS:
		padding = RSA_PKCS1_PSS_PADDING;
		salt_len = EVP_MD_size(md);
		break;
	case SC_PAD_PKCS1:
	default:
		padding = RSA_PKCS1_PADDING;
		salt_len = 0;
		break;
	}
	#endif
	
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	uint8_t digest[EVP_MAX_MD_SIZE]; 
	ret=EVP_Digest(param->input,param->input_len,digest,&digestlen,md,NULL);  // return 1 for success ... else return error
	if(ret != 1) {
		TTY_LOG("EVP_Digest returns an error!");
		ret = SC_EVP_ERROR;
		goto exit;
	}
	sc_ret = RSA_verify(EVP_MD_type(md), digest, digestlen, param->output, param->output_len,rsa);
	OPENSSL_cleanse(digest,digestlen); // Buffer zeroization mem.h
	#else
	sc_ret = FIPS_rsa_verify(rsa, param->input, param->input_len, md, padding, salt_len, NULL, param->output, param->output_len);
	#endif
	if(sc_ret == 0) {
		TTY_LOG("%s FIPS_rsa_verify() returned an error!", __FUNCTION__);
		ret = SC_VERIFY_ERROR;
		goto exit;
	}
	ret = SC_OK;
exit:
	if (rsa != NULL) {
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
		RSA_free(rsa);
	#else
		FIPS_rsa_free(rsa);
	#endif
	}
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	padding = 0;
	#endif
	return ret;
}

tlApiResult_t process_md(uint32_t cmd, void *in, uint32_t in_len)
{
	uint32_t ret = SC_UNKNOWN_ERROR;
	int sc_ret = -1;
	sc_md_t *param = (sc_md_t *)in;
	const EVP_MD *md = NULL;
	EVP_MD_CTX * mdCtx = NULL;
	unsigned int digest_len = 0;

	PRINT_BOUND_OUT(in_len, sizeof(sc_md_t))
	if(CHECK_IN_LEN(in_len, sizeof(sc_md_t)))
		return ret;

	if (param->input_len == 0
		|| param->input_len > INPUT_MAX_SIZE) {
		TTY_LOG("%s invalid input param", __FUNCTION__);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	if (get_md(cmd & SC_MASK_ALG, &md) != SC_OK) {
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	mdCtx = EVP_MD_CTX_create();
	if (!mdCtx)
	{
		TTY_LOG("EVP_MD_CTX_create() returns NULL!");
		ret = SC_EVP_ERROR;
		goto exit;
	}

	ret = EVP_DigestInit_ex(mdCtx, md, NULL);
	if(ret != 1) {
		TTY_LOG("EVP_DigestInit_ex returns an error!");
		ret = SC_EVP_ERROR;
		goto exit;
	}

	ret = EVP_DigestUpdate(mdCtx, param->input, param->input_len);
	if(ret != 1) {
		TTY_LOG("EVP_DigestUpdate returns an error!");
		ret = SC_EVP_ERROR;
		goto exit;
	}

	ret = EVP_DigestFinal_ex(mdCtx, param->digest, &digest_len);
	if(ret != 1) {
		TTY_LOG("EVP_DigestFinal_ex returns an error!");
		ret = SC_EVP_ERROR;
		goto exit;
	}
	//TTY_LOG("%s: EVP_DigestFinal_ex() succeeds", __FUNCTION__);

	param->digest_len = digest_len;

	sc_ret = SC_OK;
exit:
	if(mdCtx!=NULL) {
		EVP_MD_CTX_destroy(mdCtx);
	}
	return sc_ret;
}

tlApiResult_t process_rng(uint32_t cmd, void *in, uint32_t in_len)
{
	return SC_UNSUPPORTED_ALG;
}

#if TBASE_API_LEVEL >= 5
uint32_t process_cipher2(uint32_t cmd, void *in, uint32_t in_len, threadid_t ipcClient) {
#else
uint32_t process_cipher2(uint32_t cmd, void *in, uint32_t in_len) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;
	uint32_t block_mode = 0;

	switch (cmd & SC_MASK_ALG) {
#if TBASE_API_LEVEL >= 5
	case SC_CIPHER_AES:
		block_mode = cmd & SC_MASK_BLOCK_MODE;
		if (block_mode == SC_BLOCK_GCM
				|| block_mode == SC_BLOCK_CCM
				|| block_mode == SC_BLOCK_XTS) {
			ret = process_cipher2_aes_ae(cmd, in, in_len, ipcClient);
		} else { /* other block modes */
			ret = process_cipher2_aes(cmd, in, in_len, ipcClient);
		}
		break;
	case SC_CIPHER_TDEA:
		ret = process_cipher2_tdea(cmd, in, in_len, ipcClient);
		break;
	case SC_CIPHER_RSA:
		ret = process_cipher2_rsa(cmd, in, in_len, ipcClient);
#else
	case SC_CIPHER_AES:
		block_mode = cmd & SC_MASK_BLOCK_MODE;
		if (block_mode == SC_BLOCK_GCM
				|| block_mode == SC_BLOCK_CCM
				|| block_mode == SC_BLOCK_XTS) {
			ret = process_cipher2_aes_ae(cmd, in, in_len);
		} else { /* other block modes */
			ret = process_cipher2_aes(cmd, in, in_len);
		}
		break;
	case SC_CIPHER_TDEA:
		ret = process_cipher2_tdea(cmd, in, in_len);
		break;
	case SC_CIPHER_RSA:
		ret = process_cipher2_rsa(cmd, in, in_len);
#endif
		break;
	default:
		TTY_LOG("Unsupported SC_CIPHER algorithm");
		ret = SC_INVALID_INPUT_PARAM;
		break;
	}

	return ret;
}

#if TBASE_API_LEVEL >= 5
uint32_t process_cipher2_tdea(uint32_t cmd, void *in, uint32_t in_len, threadid_t ipcClient) {
#else
uint32_t process_cipher2_tdea(uint32_t cmd, void *in, uint32_t in_len) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;
	int sc_ret = -1;
	sc_tdea_t2 *param = (sc_tdea_t2 *)in;
	uint32_t cmd_TABK = cmd & (SC_MASK_TYPE | SC_MASK_ALG | SC_MASK_BLOCK_MODE | SC_MASK_KEYSIZE);
	uint32_t cmd_O = cmd & SC_MASK_OP;
	int enc = -1;
	EVP_CIPHER_CTX ctx;
	const EVP_CIPHER *cipher = NULL;
	uint8_t des3_keys[3*DES_KEY_SIZE] = { 0 };
	uint8_t iv_buf[DES_BLOCK_SIZE] = { 0 };
	uint8_t key_cnt = param->key_len / DES_KEY_SIZE;
	uint8_t iv_len = param->iv_len;
	uint8_t *iv_ptr = NULL;
	uint32_t input_len = param->input_len;
	void *input_ptr = NULL;
	uint32_t output_len = param->output_len;
	void *output_ptr = NULL;

	PRINT_BOUND_OUT(in_len, sizeof(sc_tdea_t2))
	if(CHECK_IN_LEN(in_len, sizeof(sc_tdea_t2)))
		return ret;

	if (key_cnt == 0) {
		TTY_LOG("ERROR : INVALID key_cnt:%d, key_len: %d", key_cnt, param->key_len);
		return SC_INVALID_INPUT_PARAM;
	}
	
	if (input_len == 0 || input_len > INPUT_MAX_SIZE) {
		TTY_LOG("ERROR : INVALID input_len: %d", input_len);
		return SC_INVALID_INPUT_PARAM;
	}
	
	if (output_len < input_len || output_len > OUTPUT_MAX_SIZE) {
		TTY_LOG("ERROR : INVALID output_len: %d", output_len);
		return SC_INVALID_INPUT_PARAM;
	}

	if (input_len) {
#if TBASE_API_LEVEL >= 5
		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->input_addr,
					input_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&input_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("input_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			return SC_TIMA_DR_ERROR;
		}
#else
		input_ptr = drApiAddrTranslateAndCheckBuffer(param->input_addr, input_len);
		if (NULL == input_ptr) {
			TTY_LOG("input_addr ADDRESS TRANSLATION ERROR");
			return SC_TIMA_DR_ERROR;
		}
#endif
	}
#if TBASE_API_LEVEL >= 5
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->output_addr,
				output_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&output_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR: %x", drRet);		
		return SC_TIMA_DR_ERROR;
	}
#else
	output_ptr = drApiAddrTranslateAndCheckBuffer(param->output_addr, output_len);
	if (NULL == output_ptr) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR");
		return SC_TIMA_DR_ERROR;
	}
#endif

#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	EVP_CIPHER_CTX_init(&ctx); 

	switch(cmd_TABK) {
	case SC2_ALG_TDEA_2KEY_ECB:
	
	case SC2_ALG_TDEA_3KEY_ECB:
		
	case SC2_ALG_TDEA_2KEY_CFB:
		
	case SC2_ALG_TDEA_3KEY_CFB:
		
	case SC2_ALG_TDEA_2KEY_OFB:
		
	case SC2_ALG_TDEA_3KEY_OFB:
		
	case SC2_ALG_TDEA_2KEY_CBC:
		cipher = EVP_des_ede_cbc();
		break;
	case SC2_ALG_TDEA_3KEY_CBC:
		cipher = EVP_des_ede3_cbc();
		break;
	default:
		TTY_LOG("Unsupported 3DES algorithm");
		ret = SC_UNSUPPORTED_ALG;
		goto exit;
	}

#else
	FIPS_cipher_ctx_init(&ctx);

	switch(cmd_TABK) {
	case SC2_ALG_TDEA_2KEY_ECB:
		cipher = EVP_des_ede_ecb();
		break;
	case SC2_ALG_TDEA_3KEY_ECB:
		cipher = EVP_des_ede3_ecb();
		break;
	case SC2_ALG_TDEA_2KEY_CFB:
		cipher = EVP_des_ede_cfb();
		break;
	case SC2_ALG_TDEA_3KEY_CFB:
		cipher = EVP_des_ede3_cfb();
		break;
	case SC2_ALG_TDEA_2KEY_OFB:
		cipher = EVP_des_ede_ofb();
		break;
	case SC2_ALG_TDEA_3KEY_OFB:
		cipher = EVP_des_ede3_ofb();
		break;
	case SC2_ALG_TDEA_2KEY_CBC:
		cipher = EVP_des_ede_cbc();
		break;
	case SC2_ALG_TDEA_3KEY_CBC:
		cipher = EVP_des_ede3_cbc();
		break;
	default:
		TTY_LOG("Unsupported 3DES algorithm");
		ret = SC_UNSUPPORTED_ALG;
		goto exit;
	}
#endif
	switch(key_cnt) {
		case 1:
			memcpy(des3_keys, param->key, DES_KEY_SIZE);
			memcpy(des3_keys + DES_KEY_SIZE, param->key, DES_KEY_SIZE);
			memcpy(des3_keys + 2*DES_KEY_SIZE, param->key, DES_KEY_SIZE);
			break;
		case 2:
			memcpy(des3_keys, param->key, DES_KEY_SIZE);
			memcpy(des3_keys + DES_KEY_SIZE, param->key + DES_KEY_SIZE, DES_KEY_SIZE);
			memcpy(des3_keys + 2*DES_KEY_SIZE, param->key, DES_KEY_SIZE);
			break;
		case 3:
			memcpy(des3_keys, param->key, DES_KEY_SIZE);
			memcpy(des3_keys + DES_KEY_SIZE, param->key + DES_KEY_SIZE, DES_KEY_SIZE);
			memcpy(des3_keys + 2*DES_KEY_SIZE, param->key + 2*DES_KEY_SIZE, DES_KEY_SIZE);
			break;
		default:
			TTY_LOG("invalid TDEA key size");
			ret = SC_INVALID_INPUT_PARAM;
			goto exit;
	}

	/* setup iv, default is NULL */
	memset(iv_buf, 0, sizeof(iv_buf));
	if (iv_len == DES_BLOCK_SIZE) {
		memcpy(iv_buf, param->iv, iv_len);
		iv_ptr = iv_buf;
	}

	if (cmd_O == SC_OP_ENC) {
		enc = DES_ENCRYPT;
	} else if (cmd_O == SC_OP_DEC) {
		enc = DES_DECRYPT;
	} else {
		 TTY_LOG("unsupported OP for TDEA");
		 ret = SC_INVALID_INPUT_PARAM;
		 goto exit;
	}
	/* instantiate cipher context */
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	sc_ret = EVP_CipherInit(&ctx, cipher, des3_keys, iv_ptr, enc);
	#else
	sc_ret = FIPS_cipherinit(&ctx, cipher, des3_keys, iv_ptr, enc);
	#endif
	if (sc_ret <= 0) {
		TTY_LOG("init error, %d", ret);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	/* do cipher */
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	sc_ret = EVP_Cipher(&ctx, output_ptr, input_ptr, input_len);
	#else
	sc_ret = FIPS_cipher(&ctx, output_ptr, input_ptr, input_len);
	#endif
	if (sc_ret <= 0) {
		TTY_LOG("EVP_CipherUpdate error %d", ret);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	param->output_len = param->input_len;
	ret = SC_OK;

exit:
	/* clean up cipher context */
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	EVP_CIPHER_CTX_cleanup(&ctx);
	#else
	FIPS_cipher_ctx_cleanup(&ctx);
	#endif
	param = NULL;
	cipher = NULL;
	memset(des3_keys, 0, 3*DES_KEY_SIZE);
	memset(iv_buf, 0, DES_BLOCK_SIZE);
	key_cnt = 0;
	iv_ptr = NULL;

	return ret;
}

#if TBASE_API_LEVEL >= 5
uint32_t process_cipher2_aes(uint32_t cmd, void *in, uint32_t in_len, threadid_t ipcClient) {
#else
uint32_t process_cipher2_aes(uint32_t cmd, void *in, uint32_t in_len) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;
	sc_aes_t2 *param = (sc_aes_t2 *)in;
	uint8_t key_len = param->key_len;
	void * key_ptr = NULL;
	uint32_t iv_len = param->iv_len;
	void * iv_ptr = NULL;
	uint32_t input_len = param->input_len;
	void *input_ptr = NULL;
	uint32_t output_len = param->output_len;
	void *output_ptr = NULL;
	uint32_t cmd_TAB = cmd & (SC_MASK_TYPE | SC_MASK_ALG | SC_MASK_BLOCK_MODE);
	EVP_CIPHER_CTX ctx;
	const EVP_CIPHER *cipher = NULL;
	int dir = 1; /* encrypt by default */

	PRINT_BOUND_OUT(in_len, sizeof(sc_aes_t2))
	if(CHECK_IN_LEN(in_len, sizeof(sc_aes_t2)))
		return ret;

	if (key_len != AES_128_KEY_SIZE
				&& key_len != AES_192_KEY_SIZE
				&& key_len != AES_256_KEY_SIZE) {
		TTY_LOG("ERROR : INVALID key_len: %d", key_len);
		return SC_INVALID_INPUT_PARAM;
	}
	
	if (input_len == 0
			|| input_len > INPUT_MAX_SIZE) {
		TTY_LOG("ERROR : INVALID input_len: %d", param->input_len);
		return SC_INVALID_INPUT_PARAM;
	}
	
	if (output_len < input_len 
				|| output_len > OUTPUT_MAX_SIZE) {
		TTY_LOG("ERROR : INVALID output_len: %d", output_len);
		return SC_INVALID_INPUT_PARAM;
	}
	
	if ((cmd & SC_MASK_PADDING) != SC_PAD_NOPAD) {
		TTY_LOG("Only support SC_PAD_NOPAD, please do padding in each TA");
		return SC_INVALID_INPUT_PARAM;
	}

	/* op = enc/dec */
	switch (cmd & SC_MASK_OP) {
		case SC_OP_ENC:
			dir = 1;
			break;
		case SC_OP_DEC:
			dir = 0;
			break;
		default:
			TTY_LOG("unsupported AES OP");
			return SC_INVALID_INPUT_PARAM;
	}
#if TBASE_API_LEVEL >= 5
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->key_addr,
				key_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&key_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("key_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		return SC_TIMA_DR_ERROR;
	}

	if (iv_len != 0 && param->iv_addr != NULL) {
		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->iv_addr,
					iv_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&iv_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("iv_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			return SC_TIMA_DR_ERROR;
		}
	}

	if (input_len) {
		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->input_addr,
					input_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&input_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("input_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			return SC_TIMA_DR_ERROR;
		}
	}

	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->output_addr,
				output_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&output_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		return SC_TIMA_DR_ERROR;
	}
#else
	key_ptr = drApiAddrTranslateAndCheckBuffer(param->key_addr, key_len);
	if (NULL == key_ptr) {
		TTY_LOG("key_addr ADDRESS TRANSLATION ERROR");
		return SC_TIMA_DR_ERROR;
	}

	if (iv_len != 0 && param->iv_addr != NULL) {
		iv_ptr = drApiAddrTranslateAndCheckBuffer(param->iv_addr, iv_len);
		if (NULL == iv_ptr) {
			TTY_LOG("iv_addr ADDRESS TRANSLATION ERROR");
			return SC_TIMA_DR_ERROR;
		}
	}

	if (input_len) {
		input_ptr = drApiAddrTranslateAndCheckBuffer(param->input_addr, input_len);
		if (NULL == input_ptr) {
			TTY_LOG("input_addr ADDRESS TRANSLATION ERROR");
			return SC_TIMA_DR_ERROR;
		}
	}

	output_ptr = drApiAddrTranslateAndCheckBuffer(param->output_addr, output_len);
	if (NULL == output_ptr) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR");
		return SC_TIMA_DR_ERROR;
	}
#endif

	if (cmd_TAB == SC2_ALG_AES_CBC) {
		switch (key_len) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_cbc();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_cbc();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_cbc();
			break;
		}
	} else if (cmd_TAB == SC2_ALG_AES_ECB) {
		switch (key_len) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_ecb();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_ecb();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_ecb();
			break;
		}
	} else if (cmd_TAB == SC2_ALG_AES_CFB1) {
		switch (key_len) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_cfb1();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_cfb1();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_cfb1();
			break;
		}
	} else if (cmd_TAB == SC2_ALG_AES_CFB8) {
		switch (key_len) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_cfb8();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_cfb8();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_cfb8();
			break;
		}
	} else if (cmd_TAB == SC2_ALG_AES_CFB128) {
		switch (key_len) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_cfb128();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_cfb128();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_cfb128();
			break;
		}
	} else if (cmd_TAB == SC2_ALG_AES_OFB) {
		switch (key_len) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_ofb();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_ofb();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_ofb();
			break;
		}
	} else if (cmd_TAB == SC2_ALG_AES_CTR) {
		switch (key_len) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_ctr();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_ctr();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_ctr();
			break;
		}
	} else {
		TTY_LOG("%s unsupported AES block mode", __FUNCTION__);
		return SC_INVALID_INPUT_PARAM;
	}

	if (!cipher) {
		TTY_LOG("%s invalid key size %d", __FUNCTION__, key_len);
		return SC_INVALID_INPUT_PARAM;
	}
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
			EVP_CIPHER_CTX_init(&ctx);

	if (EVP_CipherInit(&ctx, cipher, key_ptr, iv_ptr, dir) <= 0) {
		TTY_LOG("%s EVP_CipherInit failed", __FUNCTION__);
		goto exit;
	}
	if (1 != EVP_Cipher(&ctx, output_ptr, input_ptr, input_len)) {
		TTY_LOG("%s EVP_Cipher failed", __FUNCTION__);
		if (dir)
			ret = SC_ENC_ERROR;
		else
			ret = SC_DEC_ERROR;
		goto exit;
	}
	#else
	FIPS_cipher_ctx_init(&ctx);

	if (FIPS_cipherinit(&ctx, cipher, key_ptr, iv_ptr, dir) <= 0) {
		TTY_LOG("%s FIPS_cipherinit failed", __FUNCTION__);
		goto exit;
	}

	if (cmd_TAB == SC2_ALG_AES_CFB1) {
		M_EVP_CIPHER_CTX_set_flags(&ctx, EVP_CIPH_FLAG_LENGTH_BITS);
	}

	if (1 != FIPS_cipher(&ctx, output_ptr, input_ptr, input_len)) {
		TTY_LOG("%s FIPS_cipher failed", __FUNCTION__);
		if (dir)
			ret = SC_ENC_ERROR;
		else
			ret = SC_DEC_ERROR;
		goto exit;
	}
	#endif
	param->output_len = input_len;

	ret = SC_OK;
exit:
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	EVP_CIPHER_CTX_cleanup(&ctx);
	#else
	FIPS_cipher_ctx_cleanup(&ctx);
	#endif
	return ret;
}

/* authenticated encryption */
#if TBASE_API_LEVEL >= 5
uint32_t process_cipher2_aes_ae(uint32_t cmd, void *in, uint32_t in_len, threadid_t ipcClient) {
#else
uint32_t process_cipher2_aes_ae(uint32_t cmd, void *in, uint32_t in_len) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;
	sc_aes_t2 *param = (sc_aes_t2 *)in;
	uint8_t key_len = param->key_len;
	void * key_ptr = NULL;
	uint32_t iv_len = param->iv_len;
	void *iv_ptr = NULL;
	uint32_t aad_len = param->aad_len;
	void *aad_ptr = NULL;
	uint32_t input_len = param->input_len;
	void *input_ptr = NULL;
	uint32_t output_len = param->output_len;
	void *output_ptr = NULL;
	uint32_t tag_len = param->tag_len;
	void *tag_ptr = NULL;
	uint32_t cmd_TAB = cmd & (SC_MASK_TYPE | SC_MASK_ALG | SC_MASK_BLOCK_MODE);
	EVP_CIPHER_CTX ctx;
	const EVP_CIPHER *cipher = NULL;
	int dir = 1; /* encrypt by default */

	/* only support NO PADDING, please do padding in TA */
	if (input_len > output_len
			|| (key_len != AES_128_KEY_SIZE
				&& key_len != AES_192_KEY_SIZE
				&& key_len != AES_256_KEY_SIZE)) {
		TTY_LOG("%s: invalid input param, key_len: %d, input_len: %d, output_len: %d", __FUNCTION__, key_len, input_len, output_len);
		return SC_INVALID_INPUT_PARAM;
	}

	if ((cmd & SC_MASK_PADDING) != SC_PAD_NOPAD) {
		TTY_LOG("Only support SC_PAD_NOPAD, please do padding in each TA");
		return SC_INVALID_INPUT_PARAM;
	}

	/* op = enc/dec */
	switch (cmd & SC_MASK_OP) {
		case SC_OP_ENC:
			dir = 1;
			break;
		case SC_OP_DEC:
			dir = 0;
			break;
		default:
			TTY_LOG("unsupported AES OP");
			return SC_INVALID_INPUT_PARAM;
	}

#if TBASE_API_LEVEL >= 5
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->key_addr,
				key_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&key_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("key_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		return SC_TIMA_DR_ERROR;
	}

	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->iv_addr,
				iv_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&iv_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("iv_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		return SC_TIMA_DR_ERROR;
	}
	if (aad_len) { /* aad_len could be 0 */
		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->aad_addr,
					aad_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&aad_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("aad_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			return SC_TIMA_DR_ERROR;
		}
	}

	if (input_len) {
		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->input_addr,
					input_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&input_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("input_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			return SC_TIMA_DR_ERROR;
		}
	}

	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->output_addr,
				output_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&output_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		return SC_TIMA_DR_ERROR;
	}

	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->tag_addr,
				tag_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&tag_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("tag_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		return SC_TIMA_DR_ERROR;
	}
#else
	key_ptr = drApiAddrTranslateAndCheckBuffer(param->key_addr, key_len);
	if (NULL == key_ptr) {
		TTY_LOG("key_addr ADDRESS TRANSLATION ERROR");
		return SC_TIMA_DR_ERROR;
	}

	iv_ptr = drApiAddrTranslateAndCheckBuffer(param->iv_addr, iv_len);
	if (NULL == iv_ptr) {
		TTY_LOG("iv_addr ADDRESS TRANSLATION ERROR");
		return SC_TIMA_DR_ERROR;
	}

	if (aad_len) { /* aad_len could be 0 */
		aad_ptr = drApiAddrTranslateAndCheckBuffer(param->aad_addr, aad_len);
		if (NULL == aad_ptr) {
			TTY_LOG("aad_addr ADDRESS TRANSLATION ERROR");
			return SC_TIMA_DR_ERROR;
		}
	}

	if (input_len) {
		input_ptr = drApiAddrTranslateAndCheckBuffer(param->input_addr, input_len);
		if (NULL == input_ptr) {
			TTY_LOG("input_addr ADDRESS TRANSLATION ERROR");
			return SC_TIMA_DR_ERROR;
		}
	}

	output_ptr = drApiAddrTranslateAndCheckBuffer(param->output_addr, output_len);
	if (NULL == output_ptr) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR");
		return SC_TIMA_DR_ERROR;
	}

	tag_ptr = drApiAddrTranslateAndCheckBuffer(param->tag_addr, tag_len);
	if (NULL == tag_ptr) {
		TTY_LOG("tag_addr ADDRESS TRANSLATION ERROR");
		return SC_TIMA_DR_ERROR;
	}
#endif
	
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	EVP_CIPHER_CTX_init(&ctx);
	#else
	FIPS_cipher_ctx_init(&ctx);
	#endif
	
	if (cmd_TAB == SC2_ALG_AES_GCM) {
		switch (key_len) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_gcm();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_gcm();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_gcm();
			break;
		}
		#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
			if (!EVP_CipherInit(&ctx, cipher, NULL, NULL, dir))
			goto exit;
		if (!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) {
			TTY_LOG("%s: set iv len (%d) failed", __FUNCTION__, iv_len);
			goto exit;
		}
		if (dir == 0) {
			if (!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag_ptr))
				goto exit;
		}
		if (!EVP_CipherInit(&ctx, NULL, key_ptr, iv_ptr, dir))
			goto exit;
		if (aad_len) {
			if (EVP_Cipher(&ctx, NULL, aad_ptr, aad_len) < 0)
				goto exit;
		}
		if (input_len) {
			output_len = EVP_Cipher(&ctx, output_ptr, input_ptr, input_len);
			if (input_len != output_len){
				TTY_LOG("%s EVP_Cipher failed", __FUNCTION__);
				if (dir)
					ret = SC_ENC_ERROR;
				else
					ret = SC_DEC_ERROR;
				goto exit;
			}
		} else {
			output_len = input_len;
		}
		if (EVP_Cipher(&ctx, NULL, NULL, 0) < 0) {
			TTY_LOG("%s aes gcm failed", __FUNCTION__);
		}
		if (dir == 1)
			EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, tag_len, tag_ptr);
		#else
		if (!FIPS_cipherinit(&ctx, cipher, NULL, NULL, dir))
			goto exit;
		if (!FIPS_cipher_ctx_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) {
			TTY_LOG("%s: set iv len (%d) failed", __FUNCTION__, iv_len);
			goto exit;
		}
		if (dir == 0) {
			if (!FIPS_cipher_ctx_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag_ptr))
				goto exit;
		}
		if (!FIPS_cipherinit(&ctx, NULL, key_ptr, iv_ptr, dir))
			goto exit;
		if (aad_len) {
			if (FIPS_cipher(&ctx, NULL, aad_ptr, aad_len) < 0)
				goto exit;
		}
		if (input_len) {
			output_len = FIPS_cipher(&ctx, output_ptr, input_ptr, input_len);
			if (input_len != output_len){
				TTY_LOG("%s FIPS_cipher failed", __FUNCTION__);
				if (dir)
					ret = SC_ENC_ERROR;
				else
					ret = SC_DEC_ERROR;
				goto exit;
			}
		} else {
			output_len = input_len;
		}
		if (FIPS_cipher(&ctx, NULL, NULL, 0) < 0) {
			TTY_LOG("%s aes gcm failed", __FUNCTION__);
		}
		if (dir == 1)
			FIPS_cipher_ctx_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, tag_len, tag_ptr);
		#endif
	}
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	else if (cmd_TAB == SC2_ALG_AES_CCM) {
		switch (key_len) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_ccm();
			break;
		case AES_192_KEY_SIZE:
			cipher = EVP_aes_192_ccm();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_ccm();
			break;
		}
	} 
	#endif
	else if (cmd_TAB == SC2_ALG_AES_XTS) {
		switch (key_len) {
		case AES_128_KEY_SIZE:
			cipher = EVP_aes_128_xts();
			break;
		case AES_256_KEY_SIZE:
			cipher = EVP_aes_256_xts();
			break;
		}
	} else {
		TTY_LOG("%s unsupported AES block mode", __FUNCTION__);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	param->output_len = output_len;
	ret = SC_OK;
exit:
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	EVP_CIPHER_CTX_cleanup(&ctx);
	#else
	FIPS_cipher_ctx_cleanup(&ctx);
	#endif
	return ret;
}
#if TBASE_API_LEVEL >= 5
uint32_t process_cipher2_rsa(uint32_t cmd, void *in, uint32_t in_len, threadid_t ipcClient) {
#else
uint32_t process_cipher2_rsa(uint32_t cmd, void *in, uint32_t in_len) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;
	sc_rsa_t2 *param = (sc_rsa_t2 *)in;

	PRINT_BOUND_OUT(in_len, sizeof(sc_rsa_t2))
	if(CHECK_IN_LEN(in_len, sizeof(sc_rsa_t2)))
		return ret;

	/* op = enc/dec */
	switch (cmd & SC_MASK_OP) {
#if TBASE_API_LEVEL >= 5
		case SC_OP_ENC:
			ret = sc_rsa_encrypt2(cmd, param, ipcClient);
			break;
		case SC_OP_DEC:
			ret = sc_rsa_decrypt2(cmd, param, ipcClient);
			break;
#else
		case SC_OP_ENC:
			ret = sc_rsa_encrypt2(cmd, param);
			break;
		case SC_OP_DEC:
			ret = sc_rsa_decrypt2(cmd, param);
			break;
#endif
		default:
			TTY_LOG("unsupported RSA OP");
			ret = SC_INVALID_INPUT_PARAM;
	}
exit:
	return ret;
}

#if TBASE_API_LEVEL >= 5
uint32_t sc_rsa_encrypt2(uint32_t cmd, sc_rsa_t2 *param, threadid_t ipcClient) {
#else
uint32_t sc_rsa_encrypt2(uint32_t cmd, sc_rsa_t2 *param) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;
	int sc_ret = -1;
	int padding = 0;
	RSA *rsa = NULL;
	uint32_t n_len = param->n_len;
	void * n_ptr = NULL;
	uint32_t e_len = param->e_len;
	void * e_ptr = NULL;
	uint32_t input_len = param->input_len;
	void * input_ptr = NULL;
	uint32_t output_len = param->output_len;
	void * output_ptr = NULL;

#if TBASE_API_LEVEL >= 5
	if (n_len == 0 || n_len > RSA_KEY_MAX_SIZE) {
		TTY_LOG("%s ERROR : INVALID n_len :%d", __FUNCTION__, n_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->n_addr,
				n_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&n_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("n_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (e_len == 0 || e_len > RSA_KEY_MAX_SIZE) {
		TTY_LOG("%s ERROR : INVALID e_len :%d", __FUNCTION__, e_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->e_addr,
				e_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&e_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("e_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (input_len == 0 || input_len > INPUT_MAX_SIZE) {
		TTY_LOG("ERROR : INVALID input_len: %d", input_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->input_addr,
				input_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&input_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("input_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (output_len < input_len || output_len > OUTPUT_MAX_SIZE) {
		TTY_LOG("ERROR : INVALID output_len: %d", output_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->output_addr,
				output_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&output_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}
#else
	if (n_len == 0 || n_len > RSA_KEY_MAX_SIZE) {
		TTY_LOG("%s ERROR : INVALID n_len :%d", __FUNCTION__, n_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	n_ptr = drApiAddrTranslateAndCheckBuffer(param->n_addr, n_len);
	if (NULL == n_ptr) {
		TTY_LOG("n_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (e_len == 0 || e_len > RSA_KEY_MAX_SIZE) {
		TTY_LOG("%s ERROR : INVALID e_len :%d", __FUNCTION__, e_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	e_ptr = drApiAddrTranslateAndCheckBuffer(param->e_addr, e_len);
	if (NULL == e_ptr) {
		TTY_LOG("e_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (input_len == 0 || input_len > INPUT_MAX_SIZE) {
		TTY_LOG("ERROR : INVALID input_len: %d", input_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	input_ptr = drApiAddrTranslateAndCheckBuffer(param->input_addr, input_len);
	if (NULL == input_ptr) {
		TTY_LOG("input_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (output_len < input_len || output_len > OUTPUT_MAX_SIZE) {
		TTY_LOG("ERROR : INVALID output_len: %d", output_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	output_ptr = drApiAddrTranslateAndCheckBuffer(param->output_addr, output_len);
	if (NULL == output_ptr) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}
#endif
	rsa = RSA_new();
	if(NULL == rsa)
	{
		TTY_LOG("%s RSA_new() returned NULL!", __FUNCTION__);
		ret = SC_NULL_POINTER;
		goto exit;
	}
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	RSA_set_method(rsa, (const RSA_METHOD *)RSA_get_default_method());
	#endif

	ret = set_rsa_pub_key(rsa, n_ptr, n_len, e_ptr, e_len);
	if (ret != SC_OK) {
		TTY_LOG("%s failed to init rsa pub key", __FUNCTION__);
		goto exit;
	}

	/* padding */
	switch (cmd & SC_MASK_PADDING) {
	case SC_PAD_PKCS1_OAEP:
		if (input_len >= RSA_size(rsa) - 41) {
			TTY_LOG("%s invalid input_len for padding PKCS1_OAEP", __FUNCTION__);
			ret = SC_INVALID_INPUT_PARAM;
			goto exit;
		}
		padding = RSA_PKCS1_OAEP_PADDING;
		break;
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	case SC_PAD_SSLV23:
		if (input_len >= RSA_size(rsa) - 11) {
			TTY_LOG("%s invalid input_len for padding SSLV23", __FUNCTION__);
			ret = SC_INVALID_INPUT_PARAM;
			goto exit;
		}
		padding = RSA_SSLV23_PADDING;
		break;
	#endif
	case SC_PAD_NOPAD:
		if (input_len != RSA_size(rsa)) {
			TTY_LOG("%s invalid input_len for no padding", __FUNCTION__);
			ret = SC_INVALID_INPUT_PARAM;
			goto exit;
		}
		padding = RSA_NO_PADDING;
		break;
	case SC_PAD_PKCS1:
	default:
		if (input_len >= RSA_size(rsa) - 11) {
			TTY_LOG("%s invalid input_len for PKCS1", __FUNCTION__);
			ret = SC_INVALID_INPUT_PARAM;
			goto exit;
		}
		padding = RSA_PKCS1_PADDING;
		break;
	}

	sc_ret = RSA_public_encrypt(input_len, input_ptr, output_ptr, rsa, padding);
	if(sc_ret != param->n_len) {
		TTY_LOG("%s RSA_public_encrypt() returned an error!", __FUNCTION__);
		ret = SC_ENC_ERROR;
		goto exit;
	}
	param->output_len = sc_ret;
	ret = SC_OK;
exit:
	if (rsa != NULL) {
		RSA_free(rsa);
	}
	padding = 0;
	return ret;
}

#if TBASE_API_LEVEL >= 5
uint32_t sc_rsa_decrypt2(uint32_t cmd, sc_rsa_t2 *param, threadid_t ipcClient) {
#else
uint32_t sc_rsa_decrypt2(uint32_t cmd, sc_rsa_t2 *param) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;
	int sc_ret = -1;
	int padding = 0;
	RSA *rsa = NULL;
	uint32_t n_len = param->n_len;
	void * n_ptr = NULL;
	uint32_t e_len = param->e_len;
	void * e_ptr = NULL;
	uint32_t d_len = param->d_len;
	void * d_ptr = NULL;
	uint32_t p_len = param->p_len;
	void * p_ptr = NULL;
	uint32_t q_len = param->q_len;
	void * q_ptr = NULL;
	uint32_t dp_len = param->dp_len;
	void * dp_ptr = NULL;
	uint32_t dq_len = param->dq_len;
	void * dq_ptr = NULL;
	uint32_t qp_len = param->qp_len;
	void * qp_ptr = NULL;
	uint32_t input_len = param->input_len;
	void * input_ptr = NULL;
	uint32_t output_len = param->output_len;
	void * output_ptr = NULL;

#if TBASE_API_LEVEL >= 5
	if (n_len == 0 || n_len > RSA_KEY_MAX_SIZE) {
		TTY_LOG("%s ERROR : INVALID n_len :%d", __FUNCTION__, n_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->n_addr,
				n_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&n_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("n_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (e_len == 0 || e_len > RSA_KEY_MAX_SIZE) {
		TTY_LOG("%s ERROR : INVALID e_len :%d", __FUNCTION__, e_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->e_addr,
				e_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&e_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("e_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (d_len != 0 && param->d_addr != NULL) {
		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->d_addr,
					d_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&d_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("d_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}
	}

	if (p_len != 0 && param->p_addr != NULL
			&& q_len != 0 && param->q_addr != NULL
			&& dp_len != 0 && param->dp_addr != NULL
			&& dq_len != 0 && param->dq_addr != NULL
			&& qp_len != 0 && param->qp_addr != NULL) {
		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->p_addr,
					p_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&p_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("p_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->q_addr,
					q_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&q_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("q_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->dp_addr,
					dp_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&dp_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("dp_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->dq_addr,
					dq_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&dq_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("dq_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->qp_addr,
					qp_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&qp_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("qp_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}
	}

	if (input_len == 0 || input_len > INPUT_MAX_SIZE) {
		TTY_LOG("ERROR : INVALID input_len: %d", input_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->input_addr,
				input_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&input_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("input_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (output_len < input_len || output_len > OUTPUT_MAX_SIZE) {
		TTY_LOG("ERROR : INVALID output_len: %d", output_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->output_addr,
				output_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&output_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}
#else
	if (n_len == 0 || n_len > RSA_KEY_MAX_SIZE) {
		TTY_LOG("%s ERROR : INVALID n_len :%d", __FUNCTION__, n_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	n_ptr = drApiAddrTranslateAndCheckBuffer(param->n_addr, n_len);
	if (NULL == n_ptr) {
		TTY_LOG("n_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (e_len == 0 || e_len > RSA_KEY_MAX_SIZE) {
		TTY_LOG("%s ERROR : INVALID e_len :%d", __FUNCTION__, e_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	e_ptr = drApiAddrTranslateAndCheckBuffer(param->e_addr, e_len);
	if (NULL == e_ptr) {
		TTY_LOG("e_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (d_len != 0 && param->d_addr != NULL) {
		d_ptr = drApiAddrTranslateAndCheckBuffer(param->d_addr, d_len);
		if (NULL == d_ptr) {
			TTY_LOG("d_addr ADDRESS TRANSLATION ERROR");
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}
	}

	if (p_len != 0 && param->p_addr != NULL
			&& q_len != 0 && param->q_addr != NULL
			&& dp_len != 0 && param->dp_addr != NULL
			&& dq_len != 0 && param->dq_addr != NULL
			&& qp_len != 0 && param->qp_addr != NULL) {
		p_ptr = drApiAddrTranslateAndCheckBuffer(param->p_addr, p_len);
		if (NULL == p_ptr) {
			TTY_LOG("p_addr ADDRESS TRANSLATION ERROR");
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		q_ptr = drApiAddrTranslateAndCheckBuffer(param->q_addr, q_len);
		if (NULL == q_ptr) {
			TTY_LOG("q_addr ADDRESS TRANSLATION ERROR");
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		dp_ptr = drApiAddrTranslateAndCheckBuffer(param->dp_addr, dp_len);
		if (NULL == dp_ptr) {
			TTY_LOG("dp_addr ADDRESS TRANSLATION ERROR");
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		dq_ptr = drApiAddrTranslateAndCheckBuffer(param->dq_addr, dq_len);
		if (NULL == dq_ptr) {
			TTY_LOG("dq_addr ADDRESS TRANSLATION ERROR");
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		qp_ptr = drApiAddrTranslateAndCheckBuffer(param->qp_addr, qp_len);
		if (NULL == qp_ptr) {
			TTY_LOG("qp_addr ADDRESS TRANSLATION ERROR");
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}
	}

	if (input_len == 0 || input_len > INPUT_MAX_SIZE) {
		TTY_LOG("ERROR : INVALID input_len: %d", input_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	input_ptr = drApiAddrTranslateAndCheckBuffer(param->input_addr, input_len);
	if (NULL == input_ptr) {
		TTY_LOG("input_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (output_len < input_len || output_len > OUTPUT_MAX_SIZE) {
		TTY_LOG("ERROR : INVALID output_len: %d", output_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
	output_ptr = drApiAddrTranslateAndCheckBuffer(param->output_addr, output_len);
	if (NULL == output_ptr) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}
#endif

	rsa = RSA_new();
	if(NULL == rsa)
	{
		TTY_LOG("%s RSA_new() returned NULL!", __FUNCTION__);
		ret = SC_NULL_POINTER;
		goto exit;
	}
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	RSA_set_method(rsa, (const RSA_METHOD *)RSA_get_default_method());
	#endif

	ret = set_rsa_priv_key2(rsa, n_ptr, n_len, e_ptr, e_len, d_ptr, d_len, p_ptr, p_len, q_ptr, q_len, dp_ptr, dp_len, dq_ptr, dq_len, qp_ptr, qp_len);

	if (ret != SC_OK) {
		TTY_LOG("%s failed to init rsa private key", __FUNCTION__);
		goto exit;
	}

	/* padding */
	switch (cmd & SC_MASK_PADDING) {
	case SC_PAD_PKCS1_OAEP:
		padding = RSA_PKCS1_OAEP_PADDING;
		break;
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	case SC_PAD_SSLV23:
		padding = RSA_SSLV23_PADDING;
		break;
	#endif
	case SC_PAD_NOPAD:
		padding = RSA_NO_PADDING;
		break;
	case SC_PAD_PKCS1:
	default:
		padding = RSA_PKCS1_PADDING;
		break;
	}

	sc_ret = RSA_private_decrypt(input_len, input_ptr, output_ptr, rsa, padding);
	if(sc_ret == -1) {
		TTY_LOG("%s RSA_private_decrypt() returned an error!", __FUNCTION__);
		ret = SC_DEC_ERROR;
		goto exit;
	}
	param->output_len = sc_ret;
	ret = SC_OK;
exit:
	if (rsa != NULL) {
		RSA_free(rsa);
	}
	padding = 0;
	return ret;
}

#if TBASE_API_LEVEL >= 5
uint32_t process_md2(uint32_t cmd, void *in, uint32_t in_len, threadid_t ipcClient) {
#else
uint32_t process_md2(uint32_t cmd, void *in, uint32_t in_len) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;
	int sc_ret = -1;
	sc_md_t2 *param = (sc_md_t2 *)in;
	const EVP_MD *md = NULL;
	EVP_MD_CTX * mdCtx = NULL;
	unsigned int digest_len = 0;
	uint32_t input_len = param->input_len;
	void * input_ptr = NULL;

	PRINT_BOUND_OUT(in_len, sizeof(sc_md_t2))
	if(CHECK_IN_LEN(in_len, sizeof(sc_md_t2)))
		return ret;

	if (param->input_len == 0) {
		TTY_LOG("%s invalid input param", __FUNCTION__);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

#if TBASE_API_LEVEL >= 5
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->input_addr,
				input_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&input_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("input_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}
#else
	input_ptr = drApiAddrTranslateAndCheckBuffer(param->input_addr, input_len);
	if (NULL == input_ptr) {
		TTY_LOG("input_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}
#endif

	if (get_md(cmd & SC_MASK_ALG, &md) != SC_OK) {
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	mdCtx = EVP_MD_CTX_create();
	if (!mdCtx)
	{
		TTY_LOG("EVP_MD_CTX_create() returns NULL!");
		ret = SC_EVP_ERROR;
		goto exit;
	}

	ret = EVP_DigestInit_ex(mdCtx, md, NULL);
	if(ret != 1) {
		TTY_LOG("EVP_DigestInit_ex returns an error!");
		ret = SC_EVP_ERROR;
		goto exit;
	}

	ret = EVP_DigestUpdate(mdCtx, input_ptr, input_len);
	if(ret != 1) {
		TTY_LOG("EVP_DigestUpdate returns an error!");
		ret = SC_EVP_ERROR;
		goto exit;
	}

	ret = EVP_DigestFinal_ex(mdCtx, param->digest, &digest_len);
	if(ret != 1) {
		TTY_LOG("EVP_DigestFinal_ex returns an error!");
		ret = SC_EVP_ERROR;
		goto exit;
	}
	//TTY_LOG("%s: EVP_DigestFinal_ex() succeeds", __FUNCTION__);

	param->digest_len = digest_len;

	sc_ret = SC_OK;
exit:
	if(mdCtx!=NULL) {
		EVP_MD_CTX_destroy(mdCtx);
	}
	return sc_ret;
}

#if TBASE_API_LEVEL >= 5
uint32_t process_sig2(uint32_t cmd, void *in, uint32_t in_len, threadid_t ipcClient) {
#else
uint32_t process_sig2(uint32_t cmd, void *in, uint32_t in_len) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;

	switch (cmd & SC_MASK_ALG) {
	case SC_SIG_RSA:
#if TBASE_API_LEVEL >= 5
		ret = process_sig2_rsa(cmd, in, in_len, ipcClient);
#else
		ret = process_sig2_rsa(cmd, in, in_len);
#endif
		break;
	case SC_SIG_ECDSA:
		//ret = process_sig2_ecdsa(cmd, in, in_len);
		ret = SC_UNSUPPORTED_ALG;
		break;
	case SC_SIG_DSA:
		//ret = process_sig2_dsa(cmd, in, in_len);
		ret = SC_UNSUPPORTED_ALG;
		break;
	default:
		TTY_LOG("Unsupported SC_SIG algorithm");
		ret = SC_INVALID_INPUT_PARAM;
		break;
	}

	return ret;
}

#if TBASE_API_LEVEL >= 5
uint32_t process_sig2_rsa(uint32_t cmd, void *in, uint32_t in_len, threadid_t ipcClient) {
#else
uint32_t process_sig2_rsa(uint32_t cmd, void *in, uint32_t in_len) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;
	sc_rsa_t2 *param = (sc_rsa_t2 *)in;

	PRINT_BOUND_OUT(in_len, sizeof(sc_rsa_t2))
	if(CHECK_IN_LEN(in_len, sizeof(sc_rsa_t2)))
		return ret;
/*
	if (param->input_len == 0
			|| param->input_len > param->output_len
			|| param->n_len == 0
			|| param->e_len == 0) {
		TTY_LOG("%s invalid input param", __FUNCTION__);
		TTY_LOG("%s %d, %d, %d, %d", __FUNCTION__, param->n_len, param->e_len, param->input_len, param->output_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}
*/
	/* op = enc/dec */
	switch (cmd & SC_MASK_OP) {
#if TBASE_API_LEVEL >= 5
		case SC_OP_SIGN:
			ret = sc_rsa_sign2(cmd, param, ipcClient);
			break;
		case SC_OP_VERIFY:
			ret = sc_rsa_verify2(cmd, param, ipcClient);
			break;
#else
		case SC_OP_SIGN:
			ret = sc_rsa_sign2(cmd, param);
			break;
		case SC_OP_VERIFY:
			ret = sc_rsa_verify2(cmd, param);
			break;
#endif
		default:
			TTY_LOG("unsupported RSA OP");
			ret = SC_INVALID_INPUT_PARAM;
	}
exit:
	return ret;
}

#if TBASE_API_LEVEL >= 5
uint32_t sc_rsa_sign2(uint32_t cmd, sc_rsa_t2 *param, threadid_t ipcClient) {
#else
uint32_t sc_rsa_sign2(uint32_t cmd, sc_rsa_t2 *param) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;
	int sc_ret = -1;
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	int padding = 0;
	#endif
	RSA *rsa = NULL;
	const EVP_MD *md = NULL;
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	unsigned int digestlen = 0;
	#endif
	unsigned int sig_len = 0;
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	int salt_len = -3;
	#endif
	uint32_t n_len = param->n_len;
	void * n_ptr = NULL;
	uint32_t e_len = param->e_len;
	void * e_ptr = NULL;
	uint32_t d_len = param->d_len;
	void * d_ptr = NULL;
	uint32_t p_len = param->p_len;
	void * p_ptr = NULL;
	uint32_t q_len = param->q_len;
	void * q_ptr = NULL;
	uint32_t dp_len = param->dp_len;
	void * dp_ptr = NULL;
	uint32_t dq_len = param->dq_len;
	void * dq_ptr = NULL;
	uint32_t qp_len = param->qp_len;
	void * qp_ptr = NULL;
	uint32_t input_len = param->input_len;
	void * input_ptr = NULL;
	uint32_t output_len = param->output_len;
	void * output_ptr = NULL;

	if (input_len == 0
			|| input_len > output_len
			|| n_len == 0
			|| e_len == 0) {
		TTY_LOG("%s invalid input param", __FUNCTION__);
		TTY_LOG("%s %d, %d, %d, %d", __FUNCTION__, n_len, e_len, input_len, output_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

#if TBASE_API_LEVEL >= 5
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->n_addr,
				n_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&n_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("n_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->e_addr,
				e_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&e_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("e_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (d_len != 0 && param->d_addr != NULL) {
		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->d_addr,
					d_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&d_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("d_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}
	}

	if (p_len != 0 && param->p_addr != NULL
			&& q_len != 0 && param->q_addr != NULL
			&& dp_len != 0 && param->dp_addr != NULL
			&& dq_len != 0 && param->dq_addr != NULL
			&& qp_len != 0 && param->qp_addr != NULL) {
		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->p_addr,
					p_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&p_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("p_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->q_addr,
					q_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&q_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("q_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->dp_addr,
					dp_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&dp_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("dp_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->dq_addr,
					dq_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&dq_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("dq_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		drRet = drApiMapTaskBuffer(
					THREADID_TO_TASKID(ipcClient),
					param->qp_addr,
					qp_len,
					MAP_READABLE | MAP_WRITABLE,
					(void **)&qp_ptr);
		if (drRet != DRAPI_OK) {
			TTY_LOG("qp_addr ADDRESS TRANSLATION ERROR: %x", drRet);
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}
	}

	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->input_addr,
				input_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&input_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("input_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->output_addr,
				output_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&output_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}
#else
	n_ptr = drApiAddrTranslateAndCheckBuffer(param->n_addr, n_len);
	if (NULL == n_ptr) {
		TTY_LOG("n_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	e_ptr = drApiAddrTranslateAndCheckBuffer(param->e_addr, e_len);
	if (NULL == e_ptr) {
		TTY_LOG("e_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	if (d_len != 0 && param->d_addr != NULL) {
		d_ptr = drApiAddrTranslateAndCheckBuffer(param->d_addr, d_len);
		if (NULL == d_ptr) {
			TTY_LOG("d_addr ADDRESS TRANSLATION ERROR");
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}
	}

	if (p_len != 0 && param->p_addr != NULL
			&& q_len != 0 && param->q_addr != NULL
			&& dp_len != 0 && param->dp_addr != NULL
			&& dq_len != 0 && param->dq_addr != NULL
			&& qp_len != 0 && param->qp_addr != NULL) {

		p_ptr = drApiAddrTranslateAndCheckBuffer(param->p_addr, p_len);
		if (NULL == p_ptr) {
			TTY_LOG("p_addr ADDRESS TRANSLATION ERROR");
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		q_ptr = drApiAddrTranslateAndCheckBuffer(param->q_addr, q_len);
		if (NULL == q_ptr) {
			TTY_LOG("q_addr ADDRESS TRANSLATION ERROR");
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		dp_ptr = drApiAddrTranslateAndCheckBuffer(param->dp_addr, dp_len);
		if (NULL == dp_ptr) {
			TTY_LOG("dp_addr ADDRESS TRANSLATION ERROR");
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		dq_ptr = drApiAddrTranslateAndCheckBuffer(param->dq_addr, dq_len);
		if (NULL == dq_ptr) {
			TTY_LOG("dq_addr ADDRESS TRANSLATION ERROR");
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}

		qp_ptr = drApiAddrTranslateAndCheckBuffer(param->qp_addr, qp_len);
		if (NULL == qp_ptr) {
			TTY_LOG("qp_addr ADDRESS TRANSLATION ERROR");
			ret = SC_TIMA_DR_ERROR;
			goto exit;
		}
	}

	input_ptr = drApiAddrTranslateAndCheckBuffer(param->input_addr, input_len);
	if (NULL == input_ptr) {
		TTY_LOG("input_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	output_ptr = drApiAddrTranslateAndCheckBuffer(param->output_addr, output_len);
	if (NULL == output_ptr) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}
#endif
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
		rsa = RSA_new();
	#else
		rsa = FIPS_rsa_new();
	#endif
	if(NULL == rsa)
	{
		TTY_LOG("%s RSA_new() returned NULL!", __FUNCTION__);
		ret = SC_NULL_POINTER;
		goto exit;
	}
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	RSA_set_method(rsa, (const RSA_METHOD *)RSA_get_default_method());
	#endif

	ret = set_rsa_priv_key2(rsa, n_ptr, n_len, e_ptr, e_len, d_ptr, d_len, p_ptr, p_len, q_ptr, q_len, dp_ptr, dp_len, dq_ptr, dq_len, qp_ptr, qp_len);
	if (ret != SC_OK) {
		TTY_LOG("%s failed to init rsa private key", __FUNCTION__);
		goto exit;
	}

	/* MD */
	if (get_md(cmd & SC_MASK_SIG_MD, &md) != SC_OK) {
		TTY_LOG("%s, failed to get md", __FUNCTION__);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	/* padding */
	switch (cmd & SC_MASK_PADDING) {
	case SC_PAD_RSA_X931:
		padding = RSA_X931_PADDING;
		salt_len = -2;
		break;
	case SC_PAD_PKCS1_PSS:
		padding = RSA_PKCS1_PSS_PADDING;
		salt_len = EVP_MD_size(md);
		break;
	case SC_PAD_PKCS1:
	default:
		padding = RSA_PKCS1_PADDING;
		salt_len = 0;
		break;
	}
	#endif
	
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	uint8_t digest[EVP_MAX_MD_SIZE]; 
	ret=EVP_Digest(input_ptr,input_len,digest,&digestlen,md,NULL);  // return 1 for success ... else return error
	if(ret != 1) {
		TTY_LOG("EVP_Digest returns an error!");
		ret = SC_EVP_ERROR;
		goto exit;
	}
	sc_ret = RSA_sign(EVP_MD_type(md),digest, digestlen,output_ptr, &sig_len,rsa);
	OPENSSL_cleanse(digest,digestlen); // Buffer zeroization mem.h
	#else
	sc_ret = FIPS_rsa_sign(rsa, input_ptr, input_len, md, padding, salt_len, NULL, output_ptr, &sig_len);
	#endif
	if(sc_ret == 0) {
		TTY_LOG("%s FIPS_rsa_sign() returned an error!", __FUNCTION__);
		ret = SC_SIGN_ERROR;
		goto exit;
	}
	param->output_len = sig_len;
	ret = SC_OK;
exit:
	if (rsa != NULL) {
		#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
			RSA_free(rsa);
		#else
			FIPS_rsa_free(rsa);
		#endif
	}
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	padding = 0;
	#endif
	return ret;
}

#if TBASE_API_LEVEL >= 5
uint32_t sc_rsa_verify2(uint32_t cmd, sc_rsa_t2 *param, threadid_t ipcClient) {
#else
uint32_t sc_rsa_verify2(uint32_t cmd, sc_rsa_t2 *param) {
#endif
	uint32_t ret = SC_UNKNOWN_ERROR;
	int sc_ret = -1;
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	int padding = 0;
	#endif
	RSA *rsa = NULL;
	const EVP_MD *md = NULL;
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	int salt_len = -3;
	#endif
	uint32_t n_len = param->n_len;
	void * n_ptr = NULL;
	uint32_t e_len = param->e_len;
	void * e_ptr = NULL;
	uint32_t input_len = param->input_len;
	void * input_ptr = NULL;
	uint32_t output_len = param->output_len;
	void * output_ptr = NULL;
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	unsigned int digestlen = 0;
	#endif

	if (input_len == 0
			|| input_len > output_len
			|| n_len == 0
			|| e_len == 0) {
		TTY_LOG("%s invalid input param", __FUNCTION__);
		TTY_LOG("%s %d, %d, %d, %d", __FUNCTION__, n_len, e_len, input_len, output_len);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

#if TBASE_API_LEVEL >= 5
	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->n_addr,
				n_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&n_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("n_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->e_addr,
				e_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&e_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("e_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->input_addr,
				input_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&input_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("input_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	drRet = drApiMapTaskBuffer(
				THREADID_TO_TASKID(ipcClient),
				param->output_addr,
				output_len,
				MAP_READABLE | MAP_WRITABLE,
				(void **)&output_ptr);
	if (drRet != DRAPI_OK) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR: %x", drRet);
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}
#else
	n_ptr = drApiAddrTranslateAndCheckBuffer(param->n_addr, n_len);
	if (NULL == n_ptr) {
		TTY_LOG("n_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	e_ptr = drApiAddrTranslateAndCheckBuffer(param->e_addr, e_len);
	if (NULL == e_ptr) {
		TTY_LOG("e_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	input_ptr = drApiAddrTranslateAndCheckBuffer(param->input_addr, input_len);
	if (NULL == input_ptr) {
		TTY_LOG("input_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}

	output_ptr = drApiAddrTranslateAndCheckBuffer(param->output_addr, output_len);
	if (NULL == output_ptr) {
		TTY_LOG("output_addr ADDRESS TRANSLATION ERROR");
		ret = SC_TIMA_DR_ERROR;
		goto exit;
	}
#endif
	
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	rsa = RSA_new();
	#else
	rsa = FIPS_rsa_new();
	#endif
	if(NULL == rsa)
	{
		TTY_LOG("%s RSA_new() returned NULL!", __FUNCTION__);
		ret = SC_NULL_POINTER;
		goto exit;
	}
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	RSA_set_method(rsa, (const RSA_METHOD *)RSA_get_default_method());
	#endif

	ret = set_rsa_pub_key(rsa, n_ptr, n_len, e_ptr, e_len);
	if (ret != SC_OK) {
		TTY_LOG("%s failed to init rsa pub key", __FUNCTION__);
		goto exit;
	}

	/* MD */
	if (get_md(cmd & SC_MASK_SIG_MD, &md) != SC_OK) {
		TTY_LOG("%s, failed to get md", __FUNCTION__);
		ret = SC_INVALID_INPUT_PARAM;
		goto exit;
	}

	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	/* padding */
	switch (cmd & SC_MASK_PADDING) {
	case SC_PAD_RSA_X931:
		padding = RSA_X931_PADDING;
		salt_len = -2;
		break;
	case SC_PAD_PKCS1_PSS:
		padding = RSA_PKCS1_PSS_PADDING;
		salt_len = EVP_MD_size(md);
		break;
	case SC_PAD_PKCS1:
	default:
		padding = RSA_PKCS1_PADDING;
		salt_len = 0;
		break;
	}
	#endif
	
	#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
	uint8_t digest[EVP_MAX_MD_SIZE]; 
	ret=EVP_Digest(input_ptr,input_len,digest,&digestlen,md,NULL);  // return 1 for success ... else return error
	if(ret != 1) {
		TTY_LOG("EVP_Digest returns an error!");
		ret = SC_EVP_ERROR;
		goto exit;
	}
	sc_ret = RSA_verify(EVP_MD_type(md),digest,digestlen,output_ptr,output_len,rsa);
	OPENSSL_cleanse(digest,digestlen); // Buffer zeroization mem.h
	#else
	sc_ret = FIPS_rsa_verify(rsa, input_ptr, input_len, md, padding, salt_len, NULL, output_ptr, output_len);
	#endif
	if(sc_ret == 0) {
		TTY_LOG("%s FIPS_rsa_verify() returned an error!", __FUNCTION__);
		ret = SC_VERIFY_ERROR;
		goto exit;
	}
	param->output_len = output_len;
	ret = SC_OK;
exit:
	if (rsa != NULL) {
		#if defined(CONFIG_SMDK8895) || defined(CONFIG_SMDK9810) || defined(CONFIG_SMDK7870) || defined(CONFIG_SMDK7885)
		RSA_free(rsa);
		#else
		FIPS_rsa_free(rsa);
		#endif
	}
	#if !defined(CONFIG_SMDK8895) && !defined(CONFIG_SMDK9810) && !defined(CONFIG_SMDK7870) && !defined(CONFIG_SMDK7885)
	padding = 0;
	#endif
	return ret;
}

