/*
 * src/crypto.c
 *
 * Copyright (C) 2013, Samsung Electronics Co., Ltd.
 *
 * TEE crypto support
 */
#include <tee_internal_api.h>

#include <crypto.h>
#include <operations.h>

#ifndef BORING_SSL
#include <openssl/opensslconf.h>
#include "unistd.h"
#endif

#include <string.h>
#include <stdarg.h>
#include <inttypes.h>

#include <openssl/crypto.h> /*needed for FIPS symbols declaration*/
#include "openssl/aes.h"
#include "openssl/err.h"
#include "openssl/evp.h"
#ifndef BORING_SSL
#include "openssl/modes/modes_lcl.h"
#else
#ifndef USE_SCRYPTO_VER2_4
#include "openssl/gcm.h"
#endif
#include "openssl/dh.h"
#endif
#ifndef USE_SCRYPTO_VER2_4
#include "openssl/obj_mac.h"
#endif
#include "openssl/rsa.h"

#ifndef OPENSSL_NO_HMAC
#include "openssl/hmac.h"
#endif
#ifndef OPENSSL_NO_ECDSA
#include <openssl/ecdsa.h>
#endif
#ifndef OPENSSL_NO_ECDH
#include <openssl/ecdh.h>
#endif
#ifndef OPENSSL_NO_DSA
#include <openssl/dsa.h>
#endif
#ifndef OPENSSL_NO_CMAC
#include <openssl/cmac.h>
#include <openssl/cbc_mac.h>
#endif
#ifndef OPENSSL_NO_DES
#include <openssl/des.h>
#endif
#ifdef USE_SCRYPTO_VER2_4
#include <openssl/bn.h>
#endif
#if !defined(BORING_SSL) && !defined(HOST_OPENSSL)
#include <pd_rand/pd_rand.h>
#endif

#include <cryptolib_init.h>

#include <misc_defs.h>
#include <gpapi_log.h>

#ifndef BORING_SSL

#define GCM_SUCCESS 0

unsigned long ERR_peek_error(void) {return 0;}

#else

#define GCM_SUCCESS 1

#ifndef RSA_R_DATA_GREATER_THAN_MOD_LEN
  #define RSA_R_DATA_GREATER_THAN_MOD_LEN RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN
#endif /* !RSA_R_DATA_GREATER_THAN_MOD_LEN */

#endif

void object_to_rsa_cc(TEE_ObjectHandle object, RSA** rsa);
void object_to_dsa_cc(TEE_ObjectHandle object, DSA** dsa);
void object_to_dh_cc(TEE_ObjectHandle object, DH** dh);

extern void FINGERPRINT_premain(void);

# ifdef ECC_IMPLEMENTATION
void object_to_ecc_cc(TEE_ObjectHandle object, EC_KEY** ec);
# endif /* ECC_IMPLEMENTATION */

/*Flags for EVP cryptocore cipher functions*/
#define EVP_ENCRYPT_MODE 1
#define EVP_DECRYPT_MODE 0

/* Update/Final flags for HW cipher operation */
#define HW_CIPHER_UPDATE 0
#define HW_CIPHER_FINAL  1

typedef unsigned char (*CMAC_K)[16];

typedef struct
{
    uint8_t* aad_buff;       /* buffer to accumulate CCM AAD*/
    size_t   aad_req_len;    /* required AAD length for AES CCM*/
    size_t   aad_prov_len;   /* provided AAD length for AES CCM*/

    uint8_t* ae_buff;       /* buffer to accumulate CCM cipher data*/
    size_t   ae_req_len;    /* required data length for AES CCM*/
    size_t   ae_prov_len;   /* provided data length for AES CCM*/
} CCM_Update_CTX;

typedef struct AES_CTS_ctx
{
    AES_KEY *key;
    uint8_t  iv[16];
    uint32_t fPadding;
} AES_CTS_ctx_t;

#ifndef USE_SCRYPTO_VER2_4
typedef struct AES_GCM_ctx
{
  AES_KEY *key;
  GCM128_CONTEXT ctx;
} AES_GCM_ctx_t;
#endif

struct __TEE_ObjectHandle
{
    TEE_ObjectInfo info;
};

struct __TEE_OperationHandle
{
    TEE_OperationInfo info;
};

struct TEE_Operation
{
    TEE_OperationInfo   info;
    uint32_t            operationState; /* This is set to OPERATION_STATE_ACTIVE if the operation
                                         * is in active state and to OPERATION_STATE_INITIAL
                                         * if the operation is in initial state.*/
    TEE_ObjectHandle    key1;
    TEE_ObjectHandle    key2;
    int                 crypto_fd;      /* file descriptor of crypto driver for
                                         * operations implemented in hardware
                                         * -1 if it is not used. */
    void                *crypto_ctx;    /* library crypto context for software
                                         * implemented algorithms.
                                         * NULL if it is not used. */
                                        /* NOTE: Decision to use crypto_fd or
                                         * crypto_ctx in the operation implementation
                                         * should be made by calling
                                         * is_operation_implemented_in_hw() function.
                                         * If it returns 1 - than crypto_fd should
                                         * be used. 0 - crypto_ctx */

    char                data[64];       /* accumulated stream data*/
    size_t              data_len;       /* accumulated data length*/
    size_t              block_len;      /* cipher block data length*/
    TEE_Result          macinit_result; /* TEE_MACInit is void, but OpenSSL implementation
                                           allocates memory for that algorithms, that can
                                           lead to an error that can't be handled
                                           in TEE_MACInit. So save error here and check it
                                           on TEE_MACUpdate, TEE_MACComputeFinal, TEE_MACCompareFinal*/
    CCM_Update_CTX      ccm_upd_ctx;     /* Context for stream-like behaviour of AES_CCM*/
};

static const EVP_MD * EVP_MD_type_from_algorithm(uint32_t alg)
{
    switch (alg)
    {
    /* Not supported due to FIPS
    case TEE_ALG_MD5:
    case TEE_ALG_HMAC_MD5:
        return EVP_md5();
    */
#ifndef OPENSSL_NO_SHA1
    case TEE_ALG_SHA1:
    case TEE_ALG_HMAC_SHA1:
        return EVP_sha1();
#endif /* OPENSSL_NO_SHA1 */
#ifndef OPENSSL_NO_SHA256
    case TEE_ALG_SHA224:
    case TEE_ALG_HMAC_SHA224:
        return EVP_sha224();
    case TEE_ALG_SHA256:
    case TEE_ALG_HMAC_SHA256:
        return EVP_sha256();
#endif /* OPENSSL_NO_SHA256 */
#ifndef OPENSSL_NO_SHA512
    case TEE_ALG_SHA384:
    case TEE_ALG_HMAC_SHA384:
        return EVP_sha384();
    case TEE_ALG_SHA512:
    case TEE_ALG_HMAC_SHA512:
        return EVP_sha512();
#endif /* OPENSSL_NO_SHA512 */
    }

    return 0;
};
static uint32_t object_type_from_algorithm(uint32_t alg)
{
    uint32_t obj_type = 0;

    switch(alg)
    {
    case TEE_ALG_AES_ECB_NOPAD:
    case TEE_ALG_AES_CBC_NOPAD:
    case TEE_ALG_AES_CTR:
    case TEE_ALG_AES_CTS:
    case TEE_ALG_AES_XTS:
    case TEE_ALG_AES_CCM:
    case TEE_ALG_AES_GCM:
    case TEE_ALG_AES_CBC_MAC_NOPAD:
    case TEE_ALG_AES_CBC_MAC_PKCS5:
    case TEE_ALG_AES_CBC_MAC_ISO9797_M2:
    case TEE_ALG_AES_CMAC:
#ifdef NON_GP_PADDING
    case TEE_ALG_AES_ECB_PKCS5:
    case TEE_ALG_AES_ECB_PKCS7:
    case TEE_ALG_AES_CBC_PKCS5:
    case TEE_ALG_AES_CBC_PKCS7:
    case TEE_ALG_AES_ECB_ISO9797_M1:
    case TEE_ALG_AES_ECB_ISO9797_M2:
    case TEE_ALG_AES_CBC_ISO9797_M1:
    case TEE_ALG_AES_CBC_ISO9797_M2:
#endif
    case TEE_ALG_AES_CFB_1:
    case TEE_ALG_AES_CFB_8:
    case TEE_ALG_AES_CFB_128:
        obj_type = TEE_TYPE_AES;
        break;

    case TEE_ALG_DES3_ECB_NOPAD:
    case TEE_ALG_DES3_CBC_NOPAD:
    case TEE_ALG_DES3_CBC_MAC_NOPAD:
    case TEE_ALG_DES3_CBC_MAC_PKCS5:
        obj_type = TEE_TYPE_DES3;
        break;

    case TEE_ALG_RSASSA_PKCS1_V1_5_MD5:
    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA1:
    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA224:
    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA256:
    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA384:
    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA512:
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1:
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224:
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384:
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512:
    case TEE_ALG_RSAES_PKCS1_V1_5:
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1:
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA224:
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256:
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA384:
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA512:
    case TEE_ALG_RSA_NOPAD:
        obj_type = TEE_TYPE_RSA_KEYPAIR;
        break;

    case TEE_ALG_DSA_SHA1:
    case TEE_ALG_DSA_SHA224:
    case TEE_ALG_DSA_SHA256:
        obj_type = TEE_TYPE_DSA_KEYPAIR;
        break;

#ifdef ECC_IMPLEMENTATION
    case TEE_ALG_ECDSA_P160:
    case TEE_ALG_ECDSA_P192:
    case TEE_ALG_ECDSA_P224:
    case TEE_ALG_ECDSA_P256:
    case TEE_ALG_ECDSA_P384:
    case TEE_ALG_ECDSA_P521:
        obj_type = TEE_TYPE_ECDSA_KEYPAIR;
        break;

    case TEE_ALG_ECDH_P192:
    case TEE_ALG_ECDH_P224:
    case TEE_ALG_ECDH_P256:
    case TEE_ALG_ECDH_P384:
    case TEE_ALG_ECDH_P521:
        obj_type = TEE_TYPE_ECDH_KEYPAIR;
        break;
#endif

    case TEE_ALG_DH_DERIVE_SHARED_SECRET:
        obj_type = TEE_TYPE_DH_KEYPAIR;
        break;

    case TEE_ALG_HMAC_SHA1:
        obj_type = TEE_TYPE_HMAC_SHA1;
        break;

    case TEE_ALG_HMAC_SHA224:
        obj_type = TEE_TYPE_HMAC_SHA224;
        break;

    case TEE_ALG_HMAC_SHA256:
        obj_type = TEE_TYPE_HMAC_SHA256;
        break;

    case TEE_ALG_HMAC_SHA384:
        obj_type = TEE_TYPE_HMAC_SHA384;
        break;

    case TEE_ALG_HMAC_SHA512:
        obj_type = TEE_TYPE_HMAC_SHA512;
        break;

    }

    return obj_type;
}

/*
 * check_IV_validity(uint32_t alg, const void* IV) will check whether algorithm has valid IV reference.
 * ECB doesn't adapt any chaining to block operations (don't need to check invalid IV).
 * for more information, please refer Annex C from TEE Internal Core API Specification v1.1.
 */
static bool check_IV_validity(uint32_t alg, const void* IV)
{
    switch(alg)
    {
    case TEE_ALG_AES_ECB_NOPAD:
    case TEE_ALG_AES_ECB_ISO9797_M1:
    case TEE_ALG_AES_ECB_ISO9797_M2:
    case TEE_ALG_AES_ECB_PKCS5:
    case TEE_ALG_AES_ECB_PKCS7:
    case TEE_ALG_DES_ECB_NOPAD:  /* NOT SUPPORTED */
    case TEE_ALG_DES3_ECB_NOPAD:
        return true;  /* Don't need to check invalid IV */

    default:
        MB_LOGD("Need to check valid IV\n");
    }

    if(IV == NULL) {
        MB_LOGE("IV is invalid (NULL) \n");
        return false;
    }
    return true;   /* by default */
}

/*
 * check_IV_size_symm(uint32_t alg, uint32_t IVlen) will check
 * the size of IV passed to TEE_CipherInit(..) to be valid for
 * the algorithm, set by alg parameter
 * for more information, please refer Annex C from TEE Internal Core API Specification v1.1
 */
static bool check_IV_size_symm(uint32_t alg, uint32_t IVlen)
{
    switch(alg)
    {
    case TEE_ALG_AES_CBC_NOPAD:
    case TEE_ALG_AES_CTS:
    case TEE_ALG_AES_XTS:
    case TEE_ALG_AES_CBC_ISO9797_M1:
    case TEE_ALG_AES_CBC_ISO9797_M2:
    case TEE_ALG_AES_CFB_1:
    case TEE_ALG_AES_CFB_8:
    case TEE_ALG_AES_CFB_128:
    case TEE_ALG_AES_CBC_PKCS5:
    case TEE_ALG_AES_CBC_PKCS7:
    /* Due to NIST publication 800-38A & OPENSSL definitions */
    case TEE_ALG_AES_CTR:
    case TEE_ALG_AES_CTR_NOPAD:
        return IVlen == 16;
    case TEE_ALG_DES3_CBC_NOPAD:
        return IVlen == 8;

    case TEE_ALG_AES_ECB_NOPAD:
    case TEE_ALG_AES_ECB_ISO9797_M1:
    case TEE_ALG_AES_ECB_ISO9797_M2:
    case TEE_ALG_AES_ECB_PKCS5:
    case TEE_ALG_AES_ECB_PKCS7:
    case TEE_ALG_DES_ECB_NOPAD:
    case TEE_ALG_DES3_ECB_NOPAD:
        return true;	/* Regardless of IV length, ECB always has valid IV size */

    default:
        MB_LOGE("Panic Reason: Invalid algorithm. \n");
        TEE_Panic(ID_TEE_CipherInit);
    }
    return false;
}

/*
 * Check the size of digest passed to TEE_AsymmetricSignDigest and TEE_AsymmetricVerifyDigest
 * for the specified algorithm (see "GPD TEE Internal Core API Specification v1.1", p.6.7.2, p6.7.3).
 */
static bool check_digest_size(uint32_t alg, uint32_t digest_size)
{
    switch(alg)
    {
    case TEE_ALG_RSASSA_PKCS1_V1_5_MD5:
        return digest_size == 16;

    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA1:
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1:
    case TEE_ALG_DSA_SHA1:
        return digest_size == 20;
    case TEE_ALG_DSA_SHA224:
        return digest_size == 28;
    case TEE_ALG_DSA_SHA256:
        return digest_size == 32;

    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA224:
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224:
        return digest_size == 28;

    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA256:
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:
        return digest_size == 32;

    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA384:
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384:
        return digest_size == 48;

    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA512:
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512:
        return digest_size == 64;

#ifdef ECC_IMPLEMENTATION
    case TEE_ALG_ECDSA_P192:
    case TEE_ALG_ECDSA_P224:
    case TEE_ALG_ECDSA_P256:
    case TEE_ALG_ECDSA_P384:
    case TEE_ALG_ECDSA_P521:
    /* GP API 1.1. says: "6.7.2 TEE_AsymmetricSignDigest, 6.7.3 TEE_AsymmetricVerifyDigest
     * Page 170, 172.
     * Where a hash algorithm is specified in the algorithm,
     * digestLen SHALL be equal to the digest length of this hash algorithm".
     * For these algorithms hash algorithm is not specified,
     * so that check isn't needed.
     *  */
        return true;
#endif

    default:
        MB_LOGE("Algorithm is unknown. \n");
        break;
    }

    return false;
}

/*
 * crypto_open() will open crypto driver and places its file descriptor
 * in op->crypto_fd variable for algorithms implemented in hardware.
 * For software implemented algorithms it will allocate library context
 * and places its pointer in op->context_ctx.
 * -1 in op->crypto_fd or NULL in op->crypto_ctx means that driver or
 * library context is not needed for algorithm implementation
 */
static TEE_Result crypto_open(struct TEE_Operation *op)
{
    uint32_t algorithm = op->info.algorithm;

    op->crypto_ctx = NULL;
    op->crypto_fd = -1;

    /* Allocate context for software implemented algorithm */
    int err_no_mem = 0;
    void *crypto_ctx = NULL;
    switch(algorithm)
    {
    case TEE_ALG_MD5:
    case TEE_ALG_SHA1:
    case TEE_ALG_SHA224:
    case TEE_ALG_SHA256:
    case TEE_ALG_SHA384:
    case TEE_ALG_SHA512:
#ifdef USE_SCRYPTO_VER2_4
        crypto_ctx = EVP_MD_CTX_new();
#else
        crypto_ctx = EVP_MD_CTX_create();
#endif
        if (!crypto_ctx) {
            err_no_mem = 1;
        }
        break;

#ifndef OPENSSL_NO_HMAC
    case TEE_ALG_HMAC_MD5:
    case TEE_ALG_HMAC_SHA1:
    case TEE_ALG_HMAC_SHA224:
    case TEE_ALG_HMAC_SHA256:
    case TEE_ALG_HMAC_SHA384:
    case TEE_ALG_HMAC_SHA512:
        crypto_ctx = OPENSSL_malloc(sizeof(HMAC_CTX));
        if (!crypto_ctx) {
            err_no_mem = 1;
            break;
        }
        HMAC_CTX_init((HMAC_CTX *)crypto_ctx);
        break;
#endif /* OPENSSL_NO_HMAC */

#ifndef OPENSSL_NO_CMAC
    case TEE_ALG_AES_CMAC:
        crypto_ctx = CMAC_CTX_new();
        if (!crypto_ctx) err_no_mem = 1;
        break;
#endif /* OPENSSL_NO_CMAC */

#ifndef OPENSSL_NO_CMAC
    case TEE_ALG_AES_CBC_MAC_NOPAD:
    case TEE_ALG_AES_CBC_MAC_PKCS5:
    case TEE_ALG_AES_CBC_MAC_ISO9797_M2:
    case TEE_ALG_DES3_CBC_MAC_NOPAD:
    case TEE_ALG_DES3_CBC_MAC_PKCS5:
        crypto_ctx = CBCMAC_CTX_new();
        if (!crypto_ctx) {
            err_no_mem = 1;
        }
        break;
#endif /* OPENSSL_NO_CMAC */
#ifndef OPENSSL_NO_AES_CTR
    case TEE_ALG_AES_CTR: /* it is the same as CTR_NOPAD, Barany CTR does not have any padding*/
#endif /* OPENSSL_NO_AES_CTR */
    case TEE_ALG_AES_CBC_NOPAD:
    case TEE_ALG_AES_CBC_PKCS5:
    case TEE_ALG_AES_CBC_PKCS7:
#ifndef OPENSSL_NO_AES_CFB
    case TEE_ALG_AES_CFB_1:
    case TEE_ALG_AES_CFB_8:
    case TEE_ALG_AES_CFB_128:
#endif /* OPENSSL_NO_AES_CFB */
    case TEE_ALG_AES_ECB_NOPAD:
    case TEE_ALG_AES_ECB_PKCS5:
    case TEE_ALG_AES_ECB_PKCS7:
#ifndef OPENSSL_NO_AES_XTS
    case TEE_ALG_AES_XTS:
#endif /* OPENSSL_NO_AES_XTS */
    case TEE_ALG_AES_ECB_ISO9797_M1:
    case TEE_ALG_AES_ECB_ISO9797_M2:
    case TEE_ALG_AES_CBC_ISO9797_M1:
    case TEE_ALG_AES_CBC_ISO9797_M2:
    case TEE_ALG_DES3_ECB_NOPAD:
    case TEE_ALG_DES3_CBC_NOPAD:
#ifdef USE_SCRYPTO_VER2_4
    case TEE_ALG_AES_GCM:
#endif
#ifndef OPENSSL_NO_AES_CCM
    case TEE_ALG_AES_CCM:
#endif /* OPENSSL_NO_AES_CCM */
#ifndef OPENSSL_NO_CTS
    case TEE_ALG_AES_CTS:
#endif /* OPENSSL_NO_CTS */
        /* TODO: add TEE_ALG_AES_CBC and allocate EVP ctx*/
        crypto_ctx = EVP_CIPHER_CTX_new();
        if (!crypto_ctx) {
            err_no_mem = 1;
        }
        break;
#ifndef USE_SCRYPTO_VER2_4
    case TEE_ALG_AES_GCM:
    {
#ifndef BORING_SSL
        GCM128_CONTEXT *ctx;
#else
        AES_GCM_ctx_t *ctx;
#endif
        ctx = OPENSSL_malloc(sizeof(*ctx));
        if (!ctx) {
            err_no_mem = 1;
        } else {
            TEE_MemFill(ctx, 0, sizeof(*ctx));
        }
        crypto_ctx = ctx;
        break;
    }
#endif
    default:
        /* For algorithms where op->crypto_ctx is not used we set NULL there.
         * For RSA, DSA, DH, ECDSA, ECDH etc. */
        crypto_ctx = NULL;
        break;
    }

    if (err_no_mem) {
        return TEE_ERROR_OUT_OF_MEMORY;
    }

    op->crypto_ctx = crypto_ctx;
    return TEE_SUCCESS;
}


static TEE_Result crypto_close(struct TEE_Operation *op)
{
    uint32_t algorithm = op->info.algorithm;

    void *crypto_ctx = op->crypto_ctx;
    switch(algorithm) {
    case TEE_ALG_MD5:
    case TEE_ALG_SHA1:
    case TEE_ALG_SHA224:
    case TEE_ALG_SHA256:
    case TEE_ALG_SHA384:
    case TEE_ALG_SHA512:
#ifdef USE_SCRYPTO_VER2_4
        EVP_MD_CTX_free((EVP_MD_CTX *)crypto_ctx);
#else
	EVP_MD_CTX_destroy((EVP_MD_CTX *)crypto_ctx);
#endif
        break;

#ifndef OPENSSL_NO_HMAC
    case TEE_ALG_HMAC_MD5:
    case TEE_ALG_HMAC_SHA1:
    case TEE_ALG_HMAC_SHA224:
    case TEE_ALG_HMAC_SHA256:
    case TEE_ALG_HMAC_SHA384:
    case TEE_ALG_HMAC_SHA512:
        HMAC_CTX_cleanup((HMAC_CTX *)crypto_ctx);
        OPENSSL_free(crypto_ctx);
        break;
#endif /* OPENSSL_NO_HMAC */

#ifndef OPENSSL_NO_CMAC
    case TEE_ALG_AES_CMAC:
        CMAC_CTX_free((CMAC_CTX *)crypto_ctx);
        break;

    case TEE_ALG_AES_CBC_MAC_NOPAD:
    case TEE_ALG_AES_CBC_MAC_PKCS5:
    case TEE_ALG_AES_CBC_MAC_ISO9797_M2:
    case TEE_ALG_DES3_CBC_MAC_NOPAD:
    case TEE_ALG_DES3_CBC_MAC_PKCS5:
        CBCMAC_CTX_free((CBCMAC_CTX *)crypto_ctx);
        break;
#endif /* OPENSSL_NO_CMAC */

    case TEE_ALG_AES_CTR:
    case TEE_ALG_AES_CBC_NOPAD:
    case TEE_ALG_AES_CBC_PKCS5:
    case TEE_ALG_AES_CBC_PKCS7:
    case TEE_ALG_AES_CFB_1:
    case TEE_ALG_AES_CFB_8:
    case TEE_ALG_AES_CFB_128:
    case TEE_ALG_AES_ECB_NOPAD:
    case TEE_ALG_AES_ECB_PKCS5:
    case TEE_ALG_AES_ECB_PKCS7:
    case TEE_ALG_AES_ECB_ISO9797_M1:
    case TEE_ALG_AES_CBC_ISO9797_M1:
    case TEE_ALG_AES_CBC_ISO9797_M2:
    case TEE_ALG_AES_ECB_ISO9797_M2:
    case TEE_ALG_AES_XTS:
    case TEE_ALG_DES3_ECB_NOPAD:
    case TEE_ALG_DES3_CBC_NOPAD:
    case TEE_ALG_AES_CCM:
#ifdef USE_SCRYPTO_VER2_4
    case TEE_ALG_AES_GCM:
#endif
#ifndef OPENSSL_NO_CTS
    case TEE_ALG_AES_CTS:
#endif /* OPENSSL_NO_CTS */
        EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)crypto_ctx);
        break;
#ifndef USE_SCRYPTO_VER2_4
    case TEE_ALG_AES_GCM:
    {
#ifndef BORING_SSL
        GCM128_CONTEXT *stCipher = (GCM128_CONTEXT *)crypto_ctx;
#else
        AES_GCM_ctx_t *stCipher = (AES_GCM_ctx_t *)crypto_ctx;
#endif
        if (stCipher->key) {
            TEE_MemFill(stCipher->key, 0, sizeof(AES_KEY));
            OPENSSL_free(stCipher->key);
        }
        OPENSSL_free(stCipher);
        break;
    }
#endif
    default:
        /* If there are no special close case than crypto_ctx should be NULL.
         * Panic otherwise */
        if (crypto_ctx) {
            MB_LOGE("Panic reason: unknown algorithm value(0x%x)\n", algorithm);
            TEE_Panic(0);
        }
        break;
    };
    op->crypto_ctx = NULL;

    return TEE_SUCCESS;
}

/*
 * crypto_cleanup() should clean all key material associated
 * with the op->crypto_fd or op->crypto_ctx object and reset it's
 * internal state so it will be just like newly opened/allocated object
 * after crypto_open() call.
 */
static void crypto_cleanup(struct TEE_Operation *op)
{
    uint32_t alg = op->info.algorithm;

    void *crypto_ctx = op->crypto_ctx;

    switch (alg) {
    case TEE_ALG_MD5:
    case TEE_ALG_SHA1:
    case TEE_ALG_SHA224:
    case TEE_ALG_SHA256:
    case TEE_ALG_SHA384:
    case TEE_ALG_SHA512:
        if (!crypto_ctx) {
            MB_LOGE("Panic reason: crypto context is NULL\n");
            TEE_Panic(0);
        }
        EVP_MD_CTX_cleanup((EVP_MD_CTX *)crypto_ctx);
        break;

#ifndef OPENSSL_NO_HMAC
    case TEE_ALG_HMAC_MD5:
    case TEE_ALG_HMAC_SHA1:
    case TEE_ALG_HMAC_SHA224:
    case TEE_ALG_HMAC_SHA256:
    case TEE_ALG_HMAC_SHA384:
    case TEE_ALG_HMAC_SHA512:
        if (!crypto_ctx) {
            MB_LOGE("Panic reason: crypto context is NULL\n");
            TEE_Panic(0);
        }
        HMAC_CTX_cleanup((HMAC_CTX *)crypto_ctx);
        break;
#endif /* OPENSSL_NO_HMAC */

#ifndef OPENSSL_NO_CMAC
    case TEE_ALG_AES_CMAC:
        if (!crypto_ctx) {
            MB_LOGE("Panic reason: crypto context is NULL\n");
            TEE_Panic(0);
        }
        CMAC_CTX_cleanup((CMAC_CTX *)crypto_ctx);
        break;

    case TEE_ALG_AES_CBC_MAC_NOPAD:
    case TEE_ALG_AES_CBC_MAC_PKCS5:
    case TEE_ALG_AES_CBC_MAC_ISO9797_M2:
    case TEE_ALG_DES3_CBC_MAC_NOPAD:
    case TEE_ALG_DES3_CBC_MAC_PKCS5:
        CBCMAC_CTX_cleanup((CBCMAC_CTX *)crypto_ctx);
        break;
#endif /* OPENSSL_NO_CMAC */

    case TEE_ALG_AES_GCM:
#ifndef USE_SCRYPTO_VER2_4
    {
        if (!crypto_ctx) {
            MB_LOGE("Panic reason: crypto context is NULL\n");
            TEE_Panic(0);
        }
#ifndef BORING_SSL
        GCM128_CONTEXT *ctx = crypto_ctx;
#else
        AES_GCM_ctx_t *ctx = crypto_ctx;
#endif
        AES_KEY *key = ctx->key;
        if (key) {
            OPENSSL_cleanse(key, sizeof(*key));
            OPENSSL_free(key);
        }
        TEE_MemFill(ctx, 0, sizeof(*ctx));
        DO_NOT_OPTIMIZE(ctx);
        break;
    }
#endif
    case TEE_ALG_AES_CCM:
    case TEE_ALG_AES_CTR:
    case TEE_ALG_AES_CBC_NOPAD:
    case TEE_ALG_AES_CBC_PKCS5:
    case TEE_ALG_AES_CBC_PKCS7:
    case TEE_ALG_AES_CFB_1:
    case TEE_ALG_AES_CFB_8:
    case TEE_ALG_AES_CFB_128:
    case TEE_ALG_AES_ECB_NOPAD:
    case TEE_ALG_AES_ECB_PKCS5:
    case TEE_ALG_AES_ECB_PKCS7:
    case TEE_ALG_AES_XTS:
#ifndef OPENSSL_NO_CTS
    case TEE_ALG_AES_CTS:
#endif /* OPENSSL_NO_CTS */
        if (!crypto_ctx) {
            MB_LOGE("Panic reason: crypto context is NULL\n");
            TEE_Panic(0);
        }
        EVP_CIPHER_CTX_cleanup((EVP_CIPHER_CTX *)crypto_ctx);
        break;
    default:
        /* If there are no special cleanup case than crypto_ctx should be NULL.
         * Panic otherwise */
        if (crypto_ctx) {
            MB_LOGE("Panic reason: unknown algorithm value(0x%x)\n", alg);
            TEE_Panic(0);
        }
        break;
    }
}

#ifndef OPENSSL_NO_CMAC
static const EVP_CIPHER *aes_cbc_cipher_from_keysize(uint32_t keysize)
{
    switch(keysize) {
    case 128:
        return EVP_aes_128_cbc();
    case 192:
        return EVP_aes_192_cbc();
    case 256:
        return EVP_aes_256_cbc();
    default:
        /* not supported*/
        MB_LOGE("Panic reason: key size isn't supported, keysize = %d\n",
                keysize);
        TEE_Panic(0);
    }
    return NULL;
}
#endif /* OPENSSL_NO_CMAC */

static TEE_Result init_digest_mac(TEE_OperationHandle operation)
{
    struct TEE_Operation *op = (struct TEE_Operation *) operation;
    TEE_Result teeInitResult = TEE_SUCCESS;
    int openssl_res;

    uint32_t key_len = (op->info.maxKeySize +7) / 8; /* in bytes*/
    unsigned char *key = NULL;
    if (0 < key_len) {
        key = TEE_Malloc(key_len, HINT_FILL_WITH_ZEROS);
        if (key == NULL) {
            return TEE_ERROR_OUT_OF_MEMORY;
        }
    }

#if !defined(OPENSSL_NO_CMAC) || !defined(OPENSSL_NO_HMAC)
     /* Get an operation key for MAC operations
        TODO: This method of getting key should be refactored in a new key manager module*/
    if (op->key1 && TEE_OPERATION_MAC == op->info.operationClass) {
        TEE_Result rc = TEE_GetObjectBufferAttribute(op->key1, TEE_ATTR_SECRET_VALUE, key, &key_len);
        if (TEE_SUCCESS != rc) {
            MB_LOGE("Panic reason: failed to get private key from operation handle\n");
            TEE_Panic(0);
        }
    }

    void *crypto_ctx = op->crypto_ctx;
#endif
    switch(op->info.algorithm)
    {
            case TEE_ALG_MD5:
            case TEE_ALG_SHA1:
            case TEE_ALG_SHA224:
            case TEE_ALG_SHA256:
            case TEE_ALG_SHA384:
            case TEE_ALG_SHA512:
                openssl_res = EVP_DigestInit_ex((EVP_MD_CTX *)op->crypto_ctx,
                        EVP_MD_type_from_algorithm(op->info.algorithm), NULL);
                if (!openssl_res) {
                    if (CHECK_OSSL_MALLOC_FAILURE) {
                        teeInitResult = TEE_ERROR_OUT_OF_MEMORY;
                        goto err;
                    }
                    PRINT_OSSL_ERROR_AND_PANIC(0);
                }

                break;
#ifndef OPENSSL_NO_HMAC
            case TEE_ALG_HMAC_MD5:
            case TEE_ALG_HMAC_SHA1:
            case TEE_ALG_HMAC_SHA224:
            case TEE_ALG_HMAC_SHA256:
            case TEE_ALG_HMAC_SHA384:
            case TEE_ALG_HMAC_SHA512:
                openssl_res = HMAC_Init((HMAC_CTX *)crypto_ctx,
                        key, key_len,
                        EVP_MD_type_from_algorithm(op->info.algorithm));
                if (!openssl_res) {
                    if (CHECK_OSSL_MALLOC_FAILURE) {
                        teeInitResult = TEE_ERROR_OUT_OF_MEMORY;
                        goto err;
                    }
                    PRINT_OSSL_ERROR_AND_PANIC(0);
                }
                break;
#endif /* OPENSSL_NO_HMAC */
#ifndef OPENSSL_NO_CMAC
            case TEE_ALG_AES_CMAC:
                openssl_res = CMAC_Init((CMAC_CTX *)crypto_ctx, key, key_len,
                        aes_cbc_cipher_from_keysize(op->info.maxKeySize),
                        NULL);
                if (!openssl_res) {
                    if (CHECK_OSSL_MALLOC_FAILURE) {
                        teeInitResult = TEE_ERROR_OUT_OF_MEMORY;
                        goto err;
                    }
                    PRINT_OSSL_ERROR_AND_PANIC(0);
                }
                break;
            case TEE_ALG_AES_CBC_MAC_NOPAD:
                if (!CBCMAC_Init((CBCMAC_CTX *)crypto_ctx, key, key_len,
                                 aes_cbc_cipher_from_keysize(op->info.maxKeySize), NULL)) {
                    if (CHECK_OSSL_MALLOC_FAILURE) {
                        teeInitResult = TEE_ERROR_OUT_OF_MEMORY;
                        goto err;
                    }
                    PRINT_OSSL_ERROR_AND_PANIC(0);
                }
                break;
            case TEE_ALG_AES_CBC_MAC_PKCS5:
                if (!CBCMAC_Init((CBCMAC_CTX *)crypto_ctx, key, key_len,
                                 aes_cbc_cipher_from_keysize(op->info.maxKeySize), NULL)) {
                    if (CHECK_OSSL_MALLOC_FAILURE) {
                        teeInitResult = TEE_ERROR_OUT_OF_MEMORY;
                        goto err;
                    }
                    PRINT_OSSL_ERROR_AND_PANIC(0);
                }
                CBCMAC_CTX_set_padding((CBCMAC_CTX *)crypto_ctx, CBCMAC_PKCS_PADDING);
                break;
            case TEE_ALG_AES_CBC_MAC_ISO9797_M2:
                if (!CBCMAC_Init((CBCMAC_CTX *)crypto_ctx, key, key_len,
                                 aes_cbc_cipher_from_keysize(op->info.maxKeySize), NULL)) {
                    if (CHECK_OSSL_MALLOC_FAILURE) {
                        teeInitResult = TEE_ERROR_OUT_OF_MEMORY;
                        goto err;
                    }
                    PRINT_OSSL_ERROR_AND_PANIC(0);
                }
                CBCMAC_CTX_set_padding((CBCMAC_CTX *)crypto_ctx, CBCMAC_ISO9797_M2_PADDING);
                break;
#ifndef OPENSSL_NO_DES
            case TEE_ALG_DES3_CBC_MAC_NOPAD:
            {
                const EVP_CIPHER *cipher = NULL;
                if (op->info.maxKeySize == 128) {
                    cipher = EVP_des_ede_cbc();
                } else if (op->info.maxKeySize == 192) {
                    cipher = EVP_des_ede3_cbc();
                } else {
                    MB_LOGE("Panic reason: max key size isn't supported, "
                              "maxKeySize = %d\n", op->info.maxKeySize);
                    TEE_Panic(0);
                }

                if (!CBCMAC_Init(crypto_ctx, key, key_len, cipher, NULL)) {
                    if (CHECK_OSSL_MALLOC_FAILURE) {
                        teeInitResult = TEE_ERROR_OUT_OF_MEMORY;
                        goto err;
                    }
                    PRINT_OSSL_ERROR_AND_PANIC(0);
                }
                break;
            }
            case TEE_ALG_DES3_CBC_MAC_PKCS5:
            {
                const EVP_CIPHER *cipher = NULL;
                if (op->info.maxKeySize == 128)
                    cipher = EVP_des_ede_cbc();
                else if (op->info.maxKeySize == 192)
                    cipher = EVP_des_ede3_cbc();
                else {
                    MB_LOGE("Panic reason: max key size isn't supported, "
                              "maxKeySize = %d\n", op->info.maxKeySize);
                    TEE_Panic(0);
                }

                if (!CBCMAC_Init(crypto_ctx, key, key_len, cipher, NULL)) {
                    if (CHECK_OSSL_MALLOC_FAILURE) {
                        teeInitResult = TEE_ERROR_OUT_OF_MEMORY;
                        goto err;
                    }
                    PRINT_OSSL_ERROR_AND_PANIC(0);
                }
                CBCMAC_CTX_set_padding(crypto_ctx, CBCMAC_PKCS_PADDING);
                break;
            }
#endif /* OPENSSL_NO_DES */
#endif /* OPENSSL_NO_CMAC */

    default:
        break;
    }

err:
    if (NULL != key) {
        TEE_MemFill(key, 0, key_len);
        DO_NOT_OPTIMIZE(key);
        TEE_Free(key);
    }

    return teeInitResult;
}


/* check parameters compatibility for CryptoCore implementation*/
static TEE_Error_Codes check_parameters_comp(uint32_t algorithm,
                                             uint32_t mode,
                                             size_t* pBlock_len,
                                             uint32_t* pAlg_class,
                                             size_t* pDigest_len )
{
    switch( algorithm )
    {
    case TEE_ALG_AES_ECB_NOPAD:
    case TEE_ALG_AES_CBC_NOPAD:
#ifndef OPENSSL_NO_AES_CTR
    case TEE_ALG_AES_CTR:
#endif /* OPENSSL_NO_AES_CTR */

#ifdef NON_GP_PADDING
    /* PKCS#5 padding is identical to PKCS#7 padding,
       except that it has only been defined for block
       ciphers that use a 64 bit (8 byte) block size.
       In practice the two can be used interchangeably.
       http://en.wikipedia.org/wiki/Padding_%28cryptography%29#PKCS7*/
    case TEE_ALG_AES_ECB_PKCS5:
    case TEE_ALG_AES_ECB_PKCS7:
    case TEE_ALG_AES_CBC_PKCS5:
    case TEE_ALG_AES_CBC_PKCS7:
    case TEE_ALG_AES_ECB_ISO9797_M1:
    case TEE_ALG_AES_CBC_ISO9797_M1:
    case TEE_ALG_AES_CBC_ISO9797_M2:
    case TEE_ALG_AES_ECB_ISO9797_M2:
#endif
#ifndef OPENSSL_NO_AES_CFB
    case TEE_ALG_AES_CFB_1:
    case TEE_ALG_AES_CFB_8:
    case TEE_ALG_AES_CFB_128:
#endif /* OPENSSL_NO_AES_CFB */
#ifndef OPENSSL_NO_CTS
    case TEE_ALG_AES_CTS:
#endif /* OPENSSL_NO_CTS */
    case TEE_ALG_AES_ECB_NOPAD_HW:
    case TEE_ALG_AES_CBC_NOPAD_HW:
    case TEE_ALG_AES_CTR_HW:
    case TEE_ALG_AES_CTS_HW:
        *pBlock_len = 16;
        if (mode != TEE_MODE_ENCRYPT && mode != TEE_MODE_DECRYPT) {
            return TEE_ERROR_NOT_SUPPORTED;
        }

        *pAlg_class = TEE_OPERATION_CIPHER;
        break;

#ifndef OPENSSL_NO_AES_XTS
    case TEE_ALG_AES_XTS:

        *pBlock_len = 32; /*for CTS & XTS need 2 AES blocks*/
        if (mode != TEE_MODE_ENCRYPT && mode != TEE_MODE_DECRYPT) {
            return TEE_ERROR_NOT_SUPPORTED;
        }

        *pAlg_class = TEE_OPERATION_CIPHER;
        break;
#endif /* OPENSSL_NO_AES_XTS */
#ifndef OPENSSL_NO_DES
        /* DES is not supported in CryptoCore (due to FIPS validation)*/
    case TEE_ALG_DES_ECB_NOPAD:
    case TEE_ALG_DES_CBC_NOPAD:
        return TEE_ERROR_NOT_SUPPORTED;
        break;

    case TEE_ALG_DES3_ECB_NOPAD:
    case TEE_ALG_DES3_CBC_NOPAD:
        if ( mode != TEE_MODE_ENCRYPT && mode != TEE_MODE_DECRYPT ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pBlock_len = 8;
        *pAlg_class = TEE_OPERATION_CIPHER;
        break;
#endif /* OPENSSL_NO_DES */

#ifndef OPENSSL_NO_AES_CCM
    case TEE_ALG_AES_CCM:
        *pBlock_len = 16;
        if ( mode != TEE_MODE_ENCRYPT && mode != TEE_MODE_DECRYPT ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pDigest_len = 0; /* will be set during initialisation*/
        *pAlg_class = TEE_OPERATION_AE;
        break;
#endif /* OPENSSL_NO_AES_CCM */

    case TEE_ALG_AES_GCM:
        *pBlock_len = 16;
        if ( mode != TEE_MODE_ENCRYPT && mode != TEE_MODE_DECRYPT ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pDigest_len = 0; /* will be set during initialisation*/
        *pAlg_class = TEE_OPERATION_AE;
        break;

#ifndef OPENSSL_NO_CMAC
    case TEE_ALG_AES_CMAC:
    case TEE_ALG_AES_CBC_MAC_NOPAD:
    case TEE_ALG_AES_CBC_MAC_PKCS5:
    case TEE_ALG_AES_CBC_MAC_ISO9797_M2:
        *pBlock_len = 16;
        *pDigest_len = 16;
        if (mode != TEE_MODE_MAC) {
            return TEE_ERROR_NOT_SUPPORTED;
        }

        *pAlg_class = TEE_OPERATION_MAC;
        break;

    case TEE_ALG_DES3_CBC_MAC_NOPAD:
    case TEE_ALG_DES3_CBC_MAC_PKCS5:
        if (mode != TEE_MODE_MAC) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pBlock_len = 8;
        *pDigest_len = 8;
        *pAlg_class = TEE_OPERATION_MAC;
        break;
    /* DES is not supported in CryptoCore*/
    case TEE_ALG_DES_CBC_MAC_NOPAD:
    case TEE_ALG_DES_CBC_MAC_PKCS5:
        return TEE_ERROR_NOT_SUPPORTED;
        break;
#endif /* OPENSSL_NO_CMAC */

#ifndef OPENSSL_NO_SHA1
    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA1:
#endif /* OPENSSL_NO_SHA1 */
#ifndef OPENSSL_NO_SHA256
    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA224:
    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA256:
#endif /* OPENSSL_NO_SHA256 */
#ifndef OPENSSL_NO_SHA512
    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA384:
    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA512:
#endif /* OPENSSL_NO_SHA512 */
#ifndef OPENSSL_NO_SHA1
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1:
#endif /* OPENSSL_NO_SHA1 */
#ifndef OPENSSL_NO_SHA256
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224:
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:
#endif /* OPENSSL_NO_SHA256 */
#ifndef OPENSSL_NO_SHA512
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384:
    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512:
#endif /* OPENSSL_NO_SHA512 */
        if ( mode != TEE_MODE_SIGN && mode != TEE_MODE_VERIFY ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }

        *pAlg_class = TEE_OPERATION_ASYMMETRIC_SIGNATURE;
        break;
#ifndef OPENSSL_NO_DSA
    case TEE_ALG_DSA_SHA1:
    case TEE_ALG_DSA_SHA224:
    case TEE_ALG_DSA_SHA256:
#endif /* OPENSSL_NO_DSA */
#ifdef ECC_IMPLEMENTATION
    case TEE_ALG_ECDSA_P160:
    case TEE_ALG_ECDSA_P192:
    case TEE_ALG_ECDSA_P224:
    case TEE_ALG_ECDSA_P256:
    case TEE_ALG_ECDSA_P384:
    case TEE_ALG_ECDSA_P521:
#endif
        if ( mode != TEE_MODE_SIGN && mode != TEE_MODE_VERIFY ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }

        *pAlg_class = TEE_OPERATION_ASYMMETRIC_SIGNATURE;
        break;

    case TEE_ALG_RSA_NOPAD:
    case TEE_ALG_RSAES_PKCS1_V1_5:
#ifndef OPENSSL_NO_SHA1
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1:
#endif /* OPENSSL_NO_SHA1 */
#ifndef OPENSSL_NO_SHA256
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA224:
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256:
#endif /* OPENSSL_NO_SHA256 */
#ifndef OPENSSL_NO_SHA512
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA384:
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA512:
#endif /* OPENSSL_NO_SHA512 */
        if ( mode != TEE_MODE_ENCRYPT && mode != TEE_MODE_DECRYPT ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }

        *pAlg_class = TEE_OPERATION_ASYMMETRIC_CIPHER;
        break;

#ifndef OPENSSL_NO_DH
    case TEE_ALG_DH_DERIVE_SHARED_SECRET:
        if ( mode != TEE_MODE_DERIVE ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }

        *pAlg_class = TEE_OPERATION_KEY_DERIVATION;
        break;
#endif /* OPENSSL_NO_DH */

#ifndef OPENSSL_NO_ECDH
    case TEE_ALG_ECDH_P192:
    case TEE_ALG_ECDH_P224:
    case TEE_ALG_ECDH_P256:
    case TEE_ALG_ECDH_P384:
    case TEE_ALG_ECDH_P521:
        if (mode != TEE_MODE_DERIVE) {
            return TEE_ERROR_NOT_SUPPORTED;
        }

        *pAlg_class = TEE_OPERATION_KEY_DERIVATION;
        break;
#endif /* OPENSSL_NO_ECDH */

    case TEE_ALG_MD5:
        /* Not supported due to FIPS
        if ( mode != TEE_MODE_DIGEST )
            return TEE_ERROR_NOT_SUPPORTED;

        *pDigest_len = 16;
        *pBlock_len = 64;
        *pAlg_class = TEE_OPERATION_DIGEST; */
        return TEE_ERROR_NOT_SUPPORTED;

#ifndef OPENSSL_NO_SHA1
    case TEE_ALG_SHA1:
        if ( mode != TEE_MODE_DIGEST ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pDigest_len = 20;
        *pBlock_len = 64;
        *pAlg_class = TEE_OPERATION_DIGEST;
        break;
#endif /* OPENSSL_NO_SHA1 */

#ifndef OPENSSL_NO_SHA256
    case TEE_ALG_SHA224:
        if ( mode != TEE_MODE_DIGEST ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pDigest_len = 28;
        *pAlg_class = TEE_OPERATION_DIGEST;
        break;

    case TEE_ALG_SHA256:
        if ( mode != TEE_MODE_DIGEST ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pDigest_len = 32;
        *pBlock_len = 64;
        *pAlg_class = TEE_OPERATION_DIGEST;
        break;
#endif /* OPENSSL_NO_SHA256 */

#ifndef OPENSSL_NO_SHA512
    case TEE_ALG_SHA384:
        if ( mode != TEE_MODE_DIGEST ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pDigest_len = 48;
        *pAlg_class = TEE_OPERATION_DIGEST;
        break;

    case TEE_ALG_SHA512:
        if ( mode != TEE_MODE_DIGEST ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pDigest_len = 64;
        *pAlg_class = TEE_OPERATION_DIGEST;
        break;
#endif /* OPENSSL_NO_SHA512 */

#ifndef OPENSSL_NO_HMAC
    case TEE_ALG_HMAC_MD5:
        /* Not supported due to FIPS */
        return TEE_ERROR_NOT_SUPPORTED;
/*        if ( mode != TEE_MODE_MAC )
            return TEE_ERROR_NOT_SUPPORTED;
        *pDigest_len = 16;
        *pBlock_len = 64;
        *pAlg_class = TEE_OPERATION_MAC;
        break;*/

    case TEE_ALG_HMAC_SHA1:
        if ( mode != TEE_MODE_MAC ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pDigest_len = 20;
        *pBlock_len = 64;
        *pAlg_class = TEE_OPERATION_MAC;
        break;

    case TEE_ALG_HMAC_SHA224:
        if ( mode != TEE_MODE_MAC ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pDigest_len = 28;
        *pBlock_len = 64;
        *pAlg_class = TEE_OPERATION_MAC;
        break;

    case TEE_ALG_HMAC_SHA256:
        if ( mode != TEE_MODE_MAC ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pDigest_len = 32;
        *pBlock_len = 64;
        *pAlg_class = TEE_OPERATION_MAC;
        break;

    case TEE_ALG_HMAC_SHA384:
        if ( mode != TEE_MODE_MAC ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pDigest_len = 48;
        *pAlg_class = TEE_OPERATION_MAC;
        break;

    case TEE_ALG_HMAC_SHA512:
        if ( mode != TEE_MODE_MAC ) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
        *pDigest_len = 64;
        *pAlg_class = TEE_OPERATION_MAC;
        break;
#endif /* OPENSSL_NO_HMAC */

    default:
        return TEE_ERROR_NOT_SUPPORTED;
    }
    return TEE_SUCCESS;
}

/* Generic Operation Functions*/
static void check_operation_handle(const TEE_OperationHandle operation, enum tee_function_id function_id)
{
    if (operation == TEE_HANDLE_NULL) {
        MB_LOGE("Panic Reason: operation handle is NULL. \
            function_id = %d\n", function_id);
        TEE_Panic(function_id);
    }

    if (!in_operations_list(operation)) {
        MB_LOGE("Panic Reason: operation is not in the operation list. \
            function_id = %d\n", function_id);
        TEE_Panic(function_id);
    }
}

TEE_Result TEE_AllocateOperation(TEE_OperationHandle *operation, uint32_t algorithm, uint32_t mode, uint32_t maxKeySize)
{
    struct TEE_Operation *op;
    uint32_t alg_class = 0, object_type = 0;
    TEE_Result rc;
    TEE_ObjectHandle key1 = TEE_HANDLE_NULL;
    TEE_ObjectHandle key2 = TEE_HANDLE_NULL;
    size_t digest_len = 0;
    size_t block_len = 0;
    TEE_Error_Codes teeErrorCode = TEE_SUCCESS;

    /* check parameters compatibility*/
    teeErrorCode = check_parameters_comp( algorithm, mode, &block_len, &alg_class, &digest_len);
    if ( teeErrorCode != TEE_SUCCESS ) {
        return teeErrorCode;
    }

    if (alg_class != TEE_OPERATION_DIGEST) {
        object_type = object_type_from_algorithm(algorithm);

        /* DSA key depends on algorithm, so we should place keysize check right
                   here (see GP API spec. Table 5-9, page 103 */
        if (algorithm == TEE_ALG_DSA_SHA1) {
            if (maxKeySize < 512 || maxKeySize > 1024 || maxKeySize % 64) {
                return TEE_ERROR_NOT_SUPPORTED;
            }
        } else if (algorithm == TEE_ALG_DSA_SHA224) {
            if (maxKeySize != 2048) {
                return TEE_ERROR_NOT_SUPPORTED;
            }
        } else if (algorithm == TEE_ALG_DSA_SHA256) {
            if (maxKeySize != 2048 && maxKeySize != 3072) {
                return TEE_ERROR_NOT_SUPPORTED;
            }
        }

        rc = TEE_AllocateTransientObject(object_type, maxKeySize, &key1);
        if (rc != TEE_SUCCESS) {
            return rc;
        }

        if (algorithm == TEE_ALG_AES_XTS) { /* 2 keys for TEE_ALG_AES_XTS*/
            rc = TEE_AllocateTransientObject(object_type, maxKeySize, &key2);
            if (rc != TEE_SUCCESS) {
                TEE_CloseObject(key1);
                return rc;
            }
        }
    }
    op = TEE_Malloc(sizeof (struct TEE_Operation), HINT_FILL_WITH_ZEROS);
    if (!op)
    {
        goto close_keys;
    }
    TEE_MemFill(op, 0, sizeof (struct TEE_Operation));
    op->info.algorithm = algorithm;
    op->info.mode = mode;
    op->info.maxKeySize = maxKeySize;
    op->info.digestLength = digest_len;
    op->info.keySize = 0;
    op->info.operationClass = alg_class;
    op->info.requiredKeyUsage = 0;
    if (mode == TEE_MODE_ENCRYPT) op->info.requiredKeyUsage |= TEE_USAGE_ENCRYPT;
    if (mode == TEE_MODE_DECRYPT) op->info.requiredKeyUsage |= TEE_USAGE_DECRYPT;
    if (mode == TEE_MODE_MAC) op->info.requiredKeyUsage |= TEE_USAGE_MAC;
    if (mode == TEE_MODE_DERIVE) op->info.requiredKeyUsage |= TEE_USAGE_DERIVE;
    if (mode == TEE_MODE_SIGN) op->info.requiredKeyUsage |= TEE_USAGE_SIGN;
    if (mode == TEE_MODE_VERIFY) op->info.requiredKeyUsage |= TEE_USAGE_VERIFY;
    if (algorithm == TEE_ALG_RSA_NOPAD) {
        if (mode == TEE_MODE_ENCRYPT) op->info.requiredKeyUsage |= TEE_USAGE_VERIFY;
        else if (mode == TEE_MODE_DECRYPT) op->info.requiredKeyUsage |= TEE_USAGE_SIGN;
    }
    op->info.handleState = 0;
    if (alg_class == TEE_OPERATION_DIGEST) {
        op->info.handleState |= TEE_HANDLE_FLAG_KEY_SET | TEE_HANDLE_FLAG_INITIALIZED;
    }
    if (algorithm == TEE_ALG_AES_XTS) {
        op->info.handleState |= TEE_HANDLE_FLAG_EXPECT_TWO_KEYS;
    }
    op->operationState = TEE_OPERATION_STATE_INITIAL;
    op->key1 = key1;
    op->key2 = key2;

    op->data_len = 0;
    op->block_len = block_len;

    if (crypto_open(op) != TEE_SUCCESS) {
        goto cleanup_res;
    }

    *operation = (TEE_OperationHandle) &op->info;

    if (alg_class == TEE_OPERATION_DIGEST) {
        rc = init_digest_mac(*operation);

        if (TEE_SUCCESS != rc) {
            crypto_close(op);
            goto cleanup_res;
        }
    }

    if (add_to_operations_list(*operation)) {
        MB_LOGE("Panic Reason: can't add operation into the operation list\n");
        TEE_Panic(ID_TEE_AllocateOperation);
    }

    return TEE_SUCCESS;

cleanup_res:
    TEE_Free(op);
close_keys:
    TEE_CloseObject(key1);
    TEE_CloseObject(key2);

    return TEE_ERROR_OUT_OF_MEMORY;
}

void TEE_FreeOperation(TEE_OperationHandle operation)
{
    check_operation_handle(operation, ID_TEE_FreeOperation);

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (op->key1) {
        TEE_CloseObject(op->key1);
    }

    if (op->key2) {
        TEE_CloseObject(op->key2);
    }

    if(TEE_ALG_AES_CCM == op->info.algorithm)
    {
        /* Because on CCM AEInit it is allocated buffers for accumulation
           we must free them*/
        TEE_Free(op->ccm_upd_ctx.aad_buff);
        op->ccm_upd_ctx.aad_buff = NULL;
        op->ccm_upd_ctx.aad_req_len = 0;
        op->ccm_upd_ctx.aad_prov_len = 0;

        TEE_Free(op->ccm_upd_ctx.ae_buff);
        op->ccm_upd_ctx.ae_buff = NULL;
        op->ccm_upd_ctx.ae_req_len = 0;
        op->ccm_upd_ctx.ae_prov_len = 0;
    }

    crypto_close(op);
    remove_from_operations_list(operation);
    TEE_Free(op);
}

void TEE_GetOperationInfo( TEE_OperationHandle operation, TEE_OperationInfo * operationInfo)
{
    check_operation_handle(operation, ID_TEE_GetOperationInfo);

    operationInfo->algorithm = operation->info.algorithm;
    operationInfo->digestLength = operation->info.digestLength;
    operationInfo->handleState = operation->info.handleState;
    operationInfo->keySize = operation->info.keySize;
    operationInfo->maxKeySize = operation->info.maxKeySize;
    operationInfo->mode = operation->info.mode;
    operationInfo->operationClass = operation->info.operationClass;
    operationInfo->requiredKeyUsage = operation->info.requiredKeyUsage;
}


TEE_Result TEE_GetOperationInfoMultiple( TEE_OperationHandle operation, TEE_OperationInfoMultiple* operationInfoMultiple, uint32_t* operationSize)
{
    uint32_t required_numb_of_keys = 1;
    uint32_t required_buf_size;
    struct TEE_Operation *op;

    if (operation == NULL) {
        MB_LOGE("Panic Reason: operation is NULL\n");
        TEE_Panic(ID_TEE_GetOperationInfoMultiple);
    }
    if (operationInfoMultiple == NULL || operationSize == NULL) {
        MB_LOGE("Panic Reason: operationInfoMultiple is NULL or operationSize is NULL\n");
        TEE_Panic(ID_TEE_GetOperationInfoMultiple);
    }

    if (operation->info.operationClass == TEE_OPERATION_DIGEST) {
        required_numb_of_keys = 0;
    }
    if (operation->info.algorithm == TEE_ALG_AES_XTS) {
        required_numb_of_keys = 2;
    }
    required_buf_size = sizeof(TEE_OperationInfoMultiple) + required_numb_of_keys * sizeof(TEE_OperationInfoKey);

    if (*operationSize < required_buf_size) {
        *operationSize = required_buf_size;
        return TEE_ERROR_SHORT_BUFFER;
    }
    operationInfoMultiple->algorithm = operation->info.algorithm;
    operationInfoMultiple->operationClass = operation->info.operationClass;
    operationInfoMultiple->mode = operation->info.mode;
    operationInfoMultiple->digestLength = operation->info.digestLength;
    operationInfoMultiple->maxKeySize = operation->info.maxKeySize;
    operationInfoMultiple->handleState = operation->info.handleState;
    op = (struct TEE_Operation *) operation;
    operationInfoMultiple->operationState = op->operationState;
    operationInfoMultiple->numberOfKeys = required_numb_of_keys;
    switch(required_numb_of_keys){
    case 2:
        /* This case for TEE_ALG_AES_XTS only.
           Second key has the same keySize and requiredKeyUsage as first.*/
        operationInfoMultiple->keyInformation[1].keySize = operation->info.keySize;
        operationInfoMultiple->keyInformation[1].requiredKeyUsage = operation->info.requiredKeyUsage;
    case 1:
        operationInfoMultiple->keyInformation[0].keySize = operation->info.keySize;
        operationInfoMultiple->keyInformation[0].requiredKeyUsage = operation->info.requiredKeyUsage;
    case 0:
        break;
    default:
        MB_LOGE("Panic Reason: required_numb_of_keys is not 0, 1 or 2\n");
        TEE_Panic(ID_TEE_GetOperationInfoMultiple);
    }
    *operationSize = required_buf_size;
    return TEE_SUCCESS;
}


void TEE_ResetOperation(TEE_OperationHandle operation)
{
    check_operation_handle(operation, ID_TEE_ResetOperation);

    struct TEE_Operation *op = (struct TEE_Operation *) operation;
    if (op->info.operationClass != TEE_OPERATION_DIGEST) {
        if ((op->key1 == NULL) || !(op->info.handleState & TEE_HANDLE_FLAG_KEY_SET)) {
            TEE_Panic(ID_TEE_ResetOperation);
        }

        if(TEE_ALG_AES_CCM == op->info.algorithm) {
            /* Because on CCM AEInit it is allocated buffers for accumulation
               we must free them*/
            TEE_Free(op->ccm_upd_ctx.aad_buff);
            op->ccm_upd_ctx.aad_buff = NULL;
            op->ccm_upd_ctx.aad_req_len = 0;
            op->ccm_upd_ctx.aad_prov_len = 0;

            TEE_Free(op->ccm_upd_ctx.ae_buff);
            op->ccm_upd_ctx.ae_buff = NULL;
            op->ccm_upd_ctx.ae_req_len = 0;
            op->ccm_upd_ctx.ae_prov_len = 0;
        }

        operation->info.handleState &= ~TEE_HANDLE_FLAG_INITIALIZED;
    }
    op->operationState = TEE_OPERATION_STATE_INITIAL;
}

/* This wrapper function is needed because TEE_CopyOperation and
 * TEE_SetOperationKey functions have a different restriction for an
 * operation state. The operation state in TEE_CopyOperation function
 * may be TEE_OPERATION_STATE_ACTIVE, for TEE_SetOperationKey function
 * it is a panic reason.
*/
static TEE_Result set_operation_key(TEE_OperationHandle operation,
                                    TEE_ObjectHandle key,
                                    bool ActiveState)
{
    check_operation_handle(operation, ID_TEE_SetOperationKey);

    TEE_Result rc;
    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (op->operationState != TEE_OPERATION_STATE_INITIAL && ActiveState) {
        MB_LOGE("Panic reason: the operation MUST be in initial state\n");
        TEE_Panic(ID_TEE_SetOperationKey);
    }

    if (operation->info.operationClass == TEE_OPERATION_DIGEST ||
            operation->info.algorithm == TEE_ALG_AES_XTS) {
        MB_LOGE("Panic reason: operationClass (0x%x) == 0x%x or\n"
                  "algorithm(0x%x) == 0x%x\n",
                  operation->info.operationClass, TEE_OPERATION_DIGEST,
                  operation->info.algorithm, TEE_ALG_AES_XTS);
        TEE_Panic(ID_TEE_SetOperationKey);
    }

    /* Check that operation is in initial state */
    if (operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) {
        MB_LOGE("Panic Reason: object is already initialized\n");
        TEE_Panic(ID_TEE_SetOperationKey);
    }

    if (operation->info.handleState & TEE_HANDLE_FLAG_KEY_SET) {
        TEE_ResetTransientObject(op->key1);
        crypto_cleanup(op);
        operation->info.handleState &= ~(TEE_HANDLE_FLAG_KEY_SET);
    }

    if (!key)
        return TEE_SUCCESS;

    /* check key usage flags*/
    if ((key->info.objectUsage | ~op->info.requiredKeyUsage) != 0xffffffff) {
        MB_LOGE("Panic Reason: key usage flags check failed\n");
        TEE_Panic(ID_TEE_SetOperationKey);
    }

    if ( (key->info.objectType == TEE_TYPE_RSA_PUBLIC_KEY && op->key1->info.objectType == TEE_TYPE_RSA_KEYPAIR) ||
         (key->info.objectType == TEE_TYPE_DSA_PUBLIC_KEY && op->key1->info.objectType == TEE_TYPE_DSA_KEYPAIR)
     #ifdef ECC_IMPLEMENTATION
         || (key->info.objectType == TEE_TYPE_ECDSA_PUBLIC_KEY && op->key1->info.objectType == TEE_TYPE_ECDSA_KEYPAIR)
         || (key->info.objectType == TEE_TYPE_ECDH_PUBLIC_KEY  && op->key1->info.objectType == TEE_TYPE_ECDH_KEYPAIR)
     #endif
         )
        op->key1->info.objectType = key->info.objectType; /* change object object type of key1 in DSA, RSA, ECDSA, ECDH cases*/

    rc = TEE_CopyObjectAttributes1(op->key1, key);
    if (TEE_SUCCESS != rc) {
        MB_LOGE("TEE_CopyObjectAttributes failed with error code: 0x%x\n", rc);
        return rc;
    }

    operation->info.handleState |= TEE_HANDLE_FLAG_KEY_SET;
    return TEE_SUCCESS;
}

TEE_Result TEE_SetOperationKey(TEE_OperationHandle operation, TEE_ObjectHandle key)
{
    return set_operation_key(operation, key, true);
}
/* This wrapper function is needed because TEE_CopyOperation and
 * TEE_SetOperationKey2 functions have a different restriction for an
 * operation state. The operation state in TEE_CopyOperation function
 * may be TEE_OPERATION_STATE_ACTIVE, for TEE_SetOperationKey2 function
 * it is a panic reason.
*/
static TEE_Result set_operation_key2(TEE_OperationHandle operation,
                                     TEE_ObjectHandle key1,
                                     TEE_ObjectHandle key2,
                                     bool ActiveState)
{
    check_operation_handle(operation, ID_TEE_SetOperationKey2);

    TEE_Result rc;
    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (op->operationState != TEE_OPERATION_STATE_INITIAL && ActiveState) {
        MB_LOGE("Panic reason: the operation MUST be in initial state\n");
        TEE_Panic(ID_TEE_SetOperationKey2);
    }

    if ( (key1 && !key2) || (!key1 && key2)) {
        MB_LOGE("Panic Reason: one of keys is NULL, "
                  "key1 = %p, key2 = %p\n", key1, key2);
        TEE_Panic(ID_TEE_SetOperationKey2);
    }

    if (operation->info.algorithm != TEE_ALG_AES_XTS) {
        MB_LOGE("Panic Reason: algorithm(0x%x) isn't TEE_ALG_AES_XTS\n",
                  operation->info.algorithm);
        TEE_Panic(ID_TEE_SetOperationKey2);
    }

    /* Check that operation is in initial state */
    if (operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) {
        MB_LOGE("Panic Reason: object is already initialized\n");
        TEE_Panic(ID_TEE_SetOperationKey2);
    }

    if (operation->info.handleState & TEE_HANDLE_FLAG_KEY_SET) {
        TEE_ResetTransientObject(op->key1);
        TEE_ResetTransientObject(op->key2);
        crypto_cleanup(op);
        operation->info.handleState &= ~(TEE_HANDLE_FLAG_KEY_SET);
    }

    if (!key1 && !key2)
        return TEE_SUCCESS;


    /* check key usage flags*/
    if ((key1->info.objectUsage | ~op->info.requiredKeyUsage) != 0xffffffff) {
        MB_LOGE("Panic Reason: key usage flags check failed\n");
        TEE_Panic(ID_TEE_SetOperationKey2);
    }

    if ((key2->info.objectUsage | ~op->info.requiredKeyUsage) != 0xffffffff) {
        MB_LOGE("Panic Reason: key usage flags check failed\n");
        TEE_Panic(ID_TEE_SetOperationKey2);
    }

    rc = TEE_CopyObjectAttributes1(op->key1, key1);
    if (TEE_SUCCESS != rc) {
        MB_LOGE("TEE_CopyObjectAttributes failed with error code: 0x%x\n", rc);
        return rc;
    }
    rc = TEE_CopyObjectAttributes1(op->key2, key2);
    if (TEE_SUCCESS != rc) {
        MB_LOGE("TEE_CopyObjectAttributes failed with error code: 0x%x\n", rc);
        return rc;
    }

    operation->info.handleState |= TEE_HANDLE_FLAG_KEY_SET;

    return TEE_SUCCESS;
}

TEE_Result TEE_SetOperationKey2(TEE_OperationHandle operation,
                                TEE_ObjectHandle key1,
                                TEE_ObjectHandle key2)
{
    return set_operation_key2(operation, key1, key2, true);
}

void TEE_CopyOperation( TEE_OperationHandle dstOperation, TEE_OperationHandle srcOperation)
{
    check_operation_handle(dstOperation, ID_TEE_CopyOperation);
    check_operation_handle(srcOperation, ID_TEE_CopyOperation);

    struct TEE_Operation *dstOp = (struct TEE_Operation *) dstOperation;
    struct TEE_Operation *srcOp = (struct TEE_Operation *) srcOperation;

    if (dstOperation->info.mode != srcOperation->info.mode ||
            dstOperation->info.algorithm != srcOperation->info.algorithm) {
        MB_LOGE("Panic Reason: mode or algorithm of operations aren't equal\n"
                  "dst mode = 0x%x src mode = 0x%x\n"
                  "dst algorithm = 0x%x src algorithm = 0x%x\n",
                  dstOperation->info.mode, srcOperation->info.mode,
                  dstOperation->info.algorithm, srcOperation->info.algorithm);
        TEE_Panic(ID_TEE_CopyOperation);
    }

    if (dstOperation->info.maxKeySize < srcOperation->info.maxKeySize) {
        MB_LOGE("Panic Reason: dst max key(%d) size less than "
                  "src max key(%d) size\n",
                  dstOperation->info.maxKeySize,
                  srcOperation->info.maxKeySize);
        TEE_Panic(ID_TEE_CopyOperation);
    }

    dstOperation->info.digestLength = srcOperation->info.digestLength;
    dstOperation->info.keySize = srcOperation->info.keySize;
    dstOperation->info.operationClass = srcOperation->info.operationClass;
    dstOperation->info.requiredKeyUsage = srcOperation->info.requiredKeyUsage;


    if (dstOperation->info.operationClass != TEE_OPERATION_DIGEST) {
        /* Copy key material for all operations except digests */

        /* TEE_SetOperationKey() is perfectly fits copy key material action we
         * are trying to perform here. But it works only with the objects
         * that does not have TEE_HANDLE_FLAG_INITIALIZED flag. We clear
         * this flag here so TEE_SetOperationKey() may do its job. Later all the
         * handleState flags will be copied from srcOperation */
        dstOperation->info.handleState &= ~(TEE_HANDLE_FLAG_INITIALIZED);

        if (dstOp->info.handleState & TEE_HANDLE_FLAG_EXPECT_TWO_KEYS) {
            TEE_ObjectHandle key1, key2;
            if (srcOp->info.handleState & TEE_HANDLE_FLAG_KEY_SET) {
                key1 = srcOp->key1;
                key2 = srcOp->key2;
            } else {
                key1 = NULL;
                key2 = NULL;
            }
            if (set_operation_key2(dstOperation, key1, key2, false) != TEE_SUCCESS) {
                MB_LOGE("Panic Reason: TEE_SetOperationKey2 failed\n");
                TEE_Panic(ID_TEE_CopyOperation);
            }
        } else {
            TEE_ObjectHandle key1;
            if (srcOp->info.handleState & TEE_HANDLE_FLAG_KEY_SET) {
                key1 = srcOp->key1;
            } else {
                key1 = NULL;
            }

            if (set_operation_key(dstOperation, key1, false) != TEE_SUCCESS) {
                MB_LOGE("Panic Reason: TEE_SetOperationKey failed\n");
                TEE_Panic(ID_TEE_CopyOperation);
            }
        }

        dstOp->operationState = srcOp->operationState;

        /* Copy accumulated stream data */
        if (dstOp->data_len) {
            TEE_MemFill(dstOp->data, 0, dstOp->data_len);
        }

        dstOp->data_len = srcOp->data_len;
        if (srcOp->data_len) {
            TEE_MemMove(dstOp->data, srcOp->data, srcOp->data_len);
        }

        dstOp->ccm_upd_ctx.aad_prov_len = srcOp->ccm_upd_ctx.aad_prov_len;
        dstOp->ccm_upd_ctx.aad_req_len = srcOp->ccm_upd_ctx.aad_req_len;
    } else {
        /* For TEE_OPERATION_DIGEST class we need to clean crypto context
         * so lone crypto_cleanup() call is put here. For other operation classes
         * cleaning is handled by TEE_SetOperationKey()/TEE_SetOperationKey2() */
        crypto_cleanup(dstOp);
    }

    dstOperation->info.handleState = srcOperation->info.handleState;

    /* Copy crypto library context if it is present */
    if (srcOp->crypto_ctx) {
        void *src = srcOp->crypto_ctx;
        void *dst = dstOp->crypto_ctx;
        if (!dst) {
            MB_LOGE("Panic Reason: dst is NULL\n");
            TEE_Panic(ID_TEE_CopyOperation);
        }

        switch(srcOperation->info.algorithm)
        {
#ifndef OPENSSL_NO_SHA1
        case TEE_ALG_SHA1:
#endif /* OPENSSL_NO_SHA1 */
#ifndef OPENSSL_NO_SHA256
        case TEE_ALG_SHA224:
        case TEE_ALG_SHA256:
#endif /* OPENSSL_NO_SHA256 */
#ifndef OPENSSL_NO_SHA512
        case TEE_ALG_SHA384:
        case TEE_ALG_SHA512:
#endif /* OPENSSL_NO_SHA512 */
            if (!EVP_MD_CTX_copy(dst, src)) {
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_CopyOperation);
            }
            break;

#ifndef OPENSSL_NO_HMAC
        case TEE_ALG_HMAC_MD5:
        case TEE_ALG_HMAC_SHA1:
        case TEE_ALG_HMAC_SHA224:
        case TEE_ALG_HMAC_SHA256:
        case TEE_ALG_HMAC_SHA384:
        case TEE_ALG_HMAC_SHA512:
            if (srcOp->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) {
                if (!HMAC_CTX_copy((HMAC_CTX *)dst, src)) {
                    PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_CopyOperation);
                }
            }
            break;
#endif /* OPENSSL_NO_HMAC */

#ifndef OPENSSL_NO_CMAC
        case TEE_ALG_AES_CMAC:
            if (srcOp->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) {
                if (!CMAC_CTX_copy(dst, src)) {
                    PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_CopyOperation);
                }
            }
            break;
        case TEE_ALG_AES_CBC_MAC_NOPAD:
        case TEE_ALG_AES_CBC_MAC_PKCS5:
        case TEE_ALG_AES_CBC_MAC_ISO9797_M2:
        case TEE_ALG_DES3_CBC_MAC_NOPAD:
        case TEE_ALG_DES3_CBC_MAC_PKCS5:
            if (srcOp->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) {
                if ( !CBCMAC_CTX_copy(dst, src) ) {
                    PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_CopyOperation);
                }
            }
            break;
#endif /* OPENSSL_NO_CMAC */

#ifndef OPENSSL_NO_AES_CTR
        case TEE_ALG_AES_CTR:
#endif /* OPENSSL_NO_AES_CTR */
        case TEE_ALG_AES_CBC_NOPAD:
        case TEE_ALG_AES_CBC_PKCS5:
        case TEE_ALG_AES_CBC_PKCS7:
#ifndef OPENSSL_NO_AES_CFB
        case TEE_ALG_AES_CFB_1:
        case TEE_ALG_AES_CFB_8:
        case TEE_ALG_AES_CFB_128:
#endif /* OPENSSL_NO_AES_CFB */
        case TEE_ALG_AES_ECB_NOPAD:
        case TEE_ALG_AES_ECB_PKCS5:
        case TEE_ALG_AES_ECB_PKCS7:
        case TEE_ALG_AES_ECB_ISO9797_M1:
        case TEE_ALG_AES_CBC_ISO9797_M1:
        case TEE_ALG_AES_CBC_ISO9797_M2:
        case TEE_ALG_AES_ECB_ISO9797_M2:
#ifndef OPENSSL_NO_AES_XTS
        case TEE_ALG_AES_XTS:
#endif /* OPENSSL_NO_AES_XTS */
#ifndef OPENSSL_NO_AES_CCM
        case TEE_ALG_AES_CCM:
#endif /* OPENSSL_NO_AES_CCM */
#ifndef OPENSSL_NO_CTS
        case TEE_ALG_AES_CTS:
#endif /* OPENSSL_NO_CTS */
            if (srcOp->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) {
                if (!EVP_CIPHER_CTX_copy(dst, src)) {
                    PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_CopyOperation);
                }
            }

            /* Copy the accumulation buffers to a new operation */

            /* allocate accumulation buffer for CCM AAD Update */
            dstOp->ccm_upd_ctx.aad_req_len = srcOp->ccm_upd_ctx.aad_req_len;
            dstOp->ccm_upd_ctx.aad_prov_len = srcOp->ccm_upd_ctx.aad_prov_len ;
            dstOp->ccm_upd_ctx.aad_buff = TEE_Malloc((uint32_t)(srcOp->ccm_upd_ctx.aad_req_len), HINT_FILL_WITH_ZEROS);
            if(NULL == dstOp->ccm_upd_ctx.aad_buff)
            {
                MB_LOGE("No memory for copy operation, CCM AAD accumulation buffer\n");
                TEE_Panic(ID_TEE_CopyOperation);
            }

            /* allocate accumulation buffer for CCM data Update */
            dstOp->ccm_upd_ctx.ae_req_len = srcOp->ccm_upd_ctx.ae_req_len;
            dstOp->ccm_upd_ctx.ae_prov_len = srcOp->ccm_upd_ctx.ae_prov_len ;
            dstOp->ccm_upd_ctx.ae_buff = TEE_Malloc((uint32_t)(srcOp->ccm_upd_ctx.ae_req_len), HINT_FILL_WITH_ZEROS);
            if(NULL == dstOp->ccm_upd_ctx.ae_buff)
            {
                MB_LOGE("No memory for copy operation, CCM data accumulation buffer\n");
                TEE_Panic(ID_TEE_CopyOperation);
            }
            break;

        case TEE_ALG_AES_GCM:
        {
#ifdef USE_SCRYPTO_VER2_4
            if (srcOp->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) {
                if (!EVP_CIPHER_CTX_copy(dst, src)) {
                    PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_CopyOperation);
                }
            }
#else
#ifndef BORING_SSL
            GCM128_CONTEXT *src_ctx = (GCM128_CONTEXT *)src;
            GCM128_CONTEXT *dst_ctx = (GCM128_CONTEXT *)dst;
#else
            AES_GCM_ctx_t *src_ctx = (AES_GCM_ctx_t *)src;
            AES_GCM_ctx_t *dst_ctx = (AES_GCM_ctx_t *)dst;
#endif
            AES_KEY *dst_key = dst_ctx->key;
            TEE_MemMove(dst_ctx, src_ctx, sizeof(*dst_ctx));
            if (src_ctx->key) {
                /* Copy source key */
                if (!dst_key) {
                    dst_key = OPENSSL_malloc(sizeof(*dst_key));
                }
                if (!dst_key) {
                    MB_LOGE("Failed to alloc dst key\n");
                    TEE_Panic(ID_TEE_CopyOperation);
                }
                OPENSSL_cleanse(dst_key, sizeof(*dst_key));
                TEE_MemMove(dst_key, src_ctx->key, sizeof(*dst_key));
            } else {
                /* If src_ctx context has no key programmed
                 * the key in dstOp should be cleared */
                if (dst_key) {
                    OPENSSL_cleanse(dst_key, sizeof(*dst_key));
                }
            }
            dst_ctx->key = dst_key;
#endif
            break;
        }

        default:
            /* If srcOp crypto_ctx handle is present there definitely should be
             * the case for copying it. Panic otherwise */
            MB_LOGE("Panic reason: unknown algorithm value(0x%x)\n",
                      srcOperation->info.algorithm);
            TEE_Panic(ID_TEE_CopyOperation);
            break;
        }
    }
    else {
        /* If srcOp->crypto_ctx is NULL than
         * dstOp->crypto_ctx should also be NULL. Panic otherwise */
        if (dstOp->crypto_ctx) {
            MB_LOGE("Panic Reason: crypto context handle is NULL\n");
            TEE_Panic(ID_TEE_CopyOperation);
        }
    }
}

/* Message Digest Functions*/

void TEE_DigestUpdate( TEE_OperationHandle operation, const void * chunk, uint32_t chunkSize)
{
    check_operation_handle(operation, ID_TEE_DigestUpdate);

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (operation->info.operationClass != TEE_OPERATION_DIGEST) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_DIGEST\n");
        TEE_Panic(ID_TEE_DigestUpdate);
    }

    if (chunkSize == 0) return;

        switch(op->info.algorithm)
        {
        case TEE_ALG_MD5:
        case TEE_ALG_SHA1:
        case TEE_ALG_SHA224:
        case TEE_ALG_SHA256:
        case TEE_ALG_SHA384:
        case TEE_ALG_SHA512:
            if (1 != EVP_DigestUpdate((EVP_MD_CTX *)op->crypto_ctx, chunk,
                                      chunkSize)) {
                MB_LOGE("Panic Reason: EVP digest update failed\n");
                TEE_Panic(ID_TEE_DigestUpdate);
            }
            break;
	}
    op->operationState = TEE_OPERATION_STATE_ACTIVE;
}

TEE_Result TEE_DigestDoFinal( TEE_OperationHandle operation, const void* chunk, uint32_t chunkLen, void* hash, uint32_t *hashLen)
{
    check_operation_handle(operation, ID_TEE_DigestDoFinal);

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (!hashLen) {
        MB_LOGE("Panic Reason: hashLen is NULL\n");
        TEE_Panic(ID_TEE_DigestDoFinal);
    }
    if (!(*hashLen) || *hashLen < operation->info.digestLength) {
        *hashLen = operation->info.digestLength;
        return TEE_ERROR_SHORT_BUFFER;
    }
    if (!hash) {
        MB_LOGE("Panic Reason: hash is NULL and hashLen > 0\n");
        TEE_Panic(ID_TEE_DigestDoFinal);
    }

    if (operation->info.operationClass != TEE_OPERATION_DIGEST) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_DIGEST\n");
        TEE_Panic(ID_TEE_DigestDoFinal);
    }

    switch(op->info.algorithm)
    {
    case TEE_ALG_MD5:
        if (*hashLen < 16) {
            return TEE_ERROR_SHORT_BUFFER;
        }
        break;
    case TEE_ALG_SHA1:
        if (*hashLen < 20) {
            return TEE_ERROR_SHORT_BUFFER;
        }
        break;
    case TEE_ALG_SHA224:
        if (*hashLen < 28) {
            return TEE_ERROR_SHORT_BUFFER;
        }
        break;
    case TEE_ALG_SHA256:
        if (*hashLen < 32) {
            return TEE_ERROR_SHORT_BUFFER;
        }
        break;
    case TEE_ALG_SHA384:
        if (*hashLen < 48) {
            return TEE_ERROR_SHORT_BUFFER;
        }
        break;
    case TEE_ALG_SHA512:
        if (*hashLen < 64) {
            return TEE_ERROR_SHORT_BUFFER;
        }
        break;
    }
    ERR_clear_error();
    if (1 != EVP_DigestUpdate((EVP_MD_CTX *)op->crypto_ctx, chunk, chunkLen)) {
        if (CHECK_OSSL_MALLOC_FAILURE) {
            return TEE_ERROR_OUT_OF_MEMORY;
        }
        PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_DigestUpdate);
    }

    if (1 != EVP_DigestFinal_ex((EVP_MD_CTX *)op->crypto_ctx,
                                (unsigned char *)hash, hashLen)) {
        if (CHECK_OSSL_MALLOC_FAILURE) {
            return TEE_ERROR_OUT_OF_MEMORY;
        }
        PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_DigestUpdate);
    }

    op->operationState = TEE_OPERATION_STATE_INITIAL;

    return TEE_SUCCESS;
}


/* Symmetric Cipher Functions*/

void TEE_CipherInit( TEE_OperationHandle operation, const void* IV, uint32_t IVLen)
{
    check_operation_handle(operation, ID_TEE_CipherInit);

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (op->operationState == TEE_OPERATION_STATE_ACTIVE) {
        TEE_ResetOperation(operation);
    }

    if (operation->info.operationClass != TEE_OPERATION_CIPHER) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_CIPHER\n");
        TEE_Panic(ID_TEE_CipherInit);
    }

    if (!(operation->info.handleState & TEE_HANDLE_FLAG_KEY_SET)) {
        MB_LOGE("Panic Reason: key isn't set to operation handle state isn't\n");
        TEE_Panic(ID_TEE_CipherInit);
    }

    if (!check_IV_validity(op->info.algorithm, IV)) {
        MB_LOGE("Panic Reason: IV is invalid\n");
        TEE_Panic(ID_TEE_CipherInit);
    }

    if (!check_IV_size_symm(op->info.algorithm, IVLen)) {
        MB_LOGE("Panic Reason: IV has wrong size\n");
        TEE_Panic(ID_TEE_CipherInit);
    }

        enum { CIPHER_NO_PADDING = 0, CIPHER_WITH_PADDING = 1};
        uint32_t fPadding = CIPHER_WITH_PADDING;

        EVP_CIPHER_CTX_init((EVP_CIPHER_CTX *)op->crypto_ctx);
        EVP_CIPHER const *evp_cipher_algo = NULL;

        int rc = 0;
        unsigned char key[64];
        uint32_t key_len = sizeof(key);
        S_VAR_NOT_USED(IVLen);

        switch (op->info.algorithm) {
#ifndef OPENSSL_NO_AES_CTR
        case TEE_ALG_AES_CTR:
        {
            /* default padding is PKCS5*/
            switch (op->info.maxKeySize) {
            case 128:
                evp_cipher_algo = EVP_aes_128_ctr();
                break;
            case 192:
                evp_cipher_algo = EVP_aes_192_ctr();
                break;
            case 256:
                evp_cipher_algo = EVP_aes_256_ctr();
                break;
            default:
                /* operation not supported*/
                MB_LOGE("Panic Reason: unsupported max key size(%d)\n",
                      op->info.maxKeySize);
                TEE_Panic(ID_TEE_CipherInit);
                break;
        }
            break;
    }
#endif /* OPENSSL_NO_AES_CTR */

        case TEE_ALG_AES_CBC_ISO9797_M1:
        case TEE_ALG_AES_CBC_ISO9797_M2:
        case TEE_ALG_AES_CBC_NOPAD:
#ifndef OPENSSL_NO_CTS
        /* Uses simple cbc */
        case TEE_ALG_AES_CTS:
#endif //OPENSSL_NO_CTS
            fPadding = CIPHER_NO_PADDING;
        /* The further propagation of this operation is OK. The further steps are common for TEE_ALG_AES_CBC_NOPAD and TEE_ALG_AES_CBC_PKCS5/TEE_ALG_AES_CBC_PKCS7*/
        case TEE_ALG_AES_CBC_PKCS5:
        case TEE_ALG_AES_CBC_PKCS7:
        {
        /* default padding is PKCS5*/
            switch (op->info.maxKeySize) {
            case 128:
                evp_cipher_algo = EVP_aes_128_cbc();
                break;
            case 192:
                evp_cipher_algo = EVP_aes_192_cbc();
                break;
            case 256:
                 evp_cipher_algo = EVP_aes_256_cbc();
                break;
            default:
                /* operation not supported*/
                MB_LOGE("Panic Reason: unsupported max key size "
                      "value = %d\n", op->info.maxKeySize);
                TEE_Panic(ID_TEE_CipherInit);
                break;
            }
            break;
        }

#ifndef OPENSSL_NO_AES_CFB
        case TEE_ALG_AES_CFB_1:
            switch (op->info.maxKeySize) {
            case 128:
                evp_cipher_algo = EVP_aes_128_cfb1();
                break;
            case 192:
                evp_cipher_algo = EVP_aes_192_cfb1();
                break;
            case 256:
                evp_cipher_algo = EVP_aes_256_cfb1();
                break;
            default:
                /* operation not supported */
                MB_LOGE("Panic Reason: unsupported max key size "
                        "value = %d\n", op->info.maxKeySize);
                TEE_Panic(ID_TEE_CipherInit);
                break;
            }
            break;
        case TEE_ALG_AES_CFB_8:
            switch (op->info.maxKeySize) {
            case 128:
                evp_cipher_algo = EVP_aes_128_cfb8();
                break;
            case 192:
                evp_cipher_algo = EVP_aes_192_cfb8();
                break;
            case 256:
                evp_cipher_algo = EVP_aes_256_cfb8();
                break;
            default:
                /* operation not supported */
                MB_LOGE("Panic Reason: unsupported max key size "
                        "value = %d\n", op->info.maxKeySize);
                TEE_Panic(ID_TEE_CipherInit);
                break;
            }
            break;
        case TEE_ALG_AES_CFB_128:
            switch (op->info.maxKeySize) {
            case 128:
                evp_cipher_algo = EVP_aes_128_cfb128();
                break;
            case 192:
                evp_cipher_algo = EVP_aes_192_cfb128();
                break;
            case 256:
                evp_cipher_algo = EVP_aes_256_cfb128();
                break;
            default:
                /* operation not supported */
                MB_LOGE("Panic Reason: unsupported max key size "
                        "value = %d\n", op->info.maxKeySize);
                TEE_Panic(ID_TEE_CipherInit);
                break;
            }
            break;
#endif /* OPENSSL_NO_AES_CFB */

        case TEE_ALG_AES_ECB_ISO9797_M1:
        case TEE_ALG_AES_ECB_ISO9797_M2:
        case TEE_ALG_AES_ECB_NOPAD:
            fPadding = CIPHER_NO_PADDING;
        /*
         * The further propagation of this operation is OK.
         * The further steps are common for TEE_ALG_AES_ECB_NOPAD
         * and TEE_ALG_AES_ECB_PKCS5/TEE_ALG_AES_ECB_PKCS7
         */
        case TEE_ALG_AES_ECB_PKCS5:
        case TEE_ALG_AES_ECB_PKCS7:
        /*
         * default padding is PKCS5
         * Real key is to be set in another function - TEE_SetOperationKey
         */
        {
            switch (op->info.maxKeySize) {
            case 128:
                evp_cipher_algo = EVP_aes_128_ecb();
                break;
            case 192:
                evp_cipher_algo = EVP_aes_192_ecb();
                break;
            case 256:
                evp_cipher_algo = EVP_aes_256_ecb();
                break;
            default:
                /* operation not supported*/
                MB_LOGE("Panic Reason: unsupported max key size "
                          "value = %d\n", op->info.maxKeySize);
                TEE_Panic(ID_TEE_CipherInit);
                break;
            }
            break;
        }
#ifndef OPENSSL_NO_AES_XTS
        case TEE_ALG_AES_XTS:
        {
            switch (op->info.maxKeySize) {
            case 128:
                evp_cipher_algo = EVP_aes_128_xts();
                break;
            case 256:
                evp_cipher_algo = EVP_aes_256_xts();
                break;
            default:
                /* operation not supported */
                MB_LOGE("Panic Reason: unsupported max key size "
                          "value = %d\n", op->info.maxKeySize);
                TEE_Panic(ID_TEE_CipherInit);
                break;
            }
        }
            break;
#endif /* OPENSSL_NO_AES_XTS */

#ifndef OPENSSL_NO_DES
        case TEE_ALG_DES_ECB_NOPAD:
        {
            /* evp_cipher_algo = EVP_des_ecb(); */

            /* Panic accordingly with FIPS validation*/
            MB_LOGE("Panic Reason: TEE_ALG_DES_ECB_NOPAD is unsupported\n");
            TEE_Panic(ID_TEE_CipherInit);
            break;
        }

        case TEE_ALG_DES_CBC_NOPAD:
        {
            /* evp_cipher_algo = EVP_des_cbc();*/

            /* Panic accordingly with FIPS validation */
            MB_LOGE("Panic Reason: TEE_ALG_DES_CBC_NOPAD is unsupported\n");
            TEE_Panic(ID_TEE_CipherInit);
            break;
        }

        case TEE_ALG_DES3_ECB_NOPAD:
        {
            fPadding = CIPHER_NO_PADDING;
            switch (op->info.maxKeySize){
                case 128:
                    evp_cipher_algo = EVP_des_ede_ecb();
                    break;
                case 192:
                    evp_cipher_algo = EVP_des_ede3_ecb();
                    break;
                default:
                    /* operation not supported*/
                    MB_LOGE("Panic Reason: unsupported max key size "
                            "value = %d\n", op->info.maxKeySize);
                    TEE_Panic(ID_TEE_CipherInit);
                    break;
            }
            break;
        }

        case TEE_ALG_DES3_CBC_NOPAD:
        {
            fPadding = CIPHER_NO_PADDING;
            switch (op->info.maxKeySize){
                case 128:
                    evp_cipher_algo = EVP_des_ede_cbc();
                    break;
                case 192:
                    evp_cipher_algo = EVP_des_ede3_cbc();
                    break;
                default:
                    /* operation not supported*/
                    MB_LOGE("Panic Reason: unsupported max key size "
                            "value = %d\n", op->info.maxKeySize);
                    TEE_Panic(ID_TEE_CipherInit);
                    break;
            }
            break;
        }
#endif /* OPENSSL_NO_DES */

        default:
            /* operation not supported*/
            MB_LOGE("Panic Reason: operation not supported\n");
            TEE_Panic(ID_TEE_CipherInit);
            break;
        } /* switch (op->info.algorithm)*/


        rc = TEE_GetObjectBufferAttribute(op->key1, TEE_ATTR_SECRET_VALUE, key, &key_len);
        if (rc != TEE_SUCCESS) {
            MB_LOGE("Panic Reason: TEE_GetObjectBufferAttribute failed\n");
            TEE_Panic(ID_TEE_CipherInit);
        }

        if (op->info.algorithm == TEE_ALG_AES_XTS) {
            uint32_t key2_len = sizeof(key) - key_len;
            rc = TEE_GetObjectBufferAttribute(op->key2, TEE_ATTR_SECRET_VALUE, &key[key_len], &key2_len);
            if (rc != TEE_SUCCESS) {
                MB_LOGE("Panic Reason: TEE_GetObjectBufferAttribute failed\n");
                TEE_Panic(ID_TEE_CipherInit);
            }
        }

        if (!EVP_CipherInit_ex( (EVP_CIPHER_CTX *)op->crypto_ctx,
                            evp_cipher_algo,
                            NULL,
                            key,
                            (unsigned char *)IV,
                            ((op->info.mode == TEE_MODE_DECRYPT)
                             ? EVP_DECRYPT_MODE : EVP_ENCRYPT_MODE) )) {
        /* operation initialization error*/
        MB_LOGE("Panic Reason: EVP cipher operation initialization failed\n");
        TEE_Panic(ID_TEE_CipherInit);
        }

        EVP_CIPHER_CTX_set_padding((EVP_CIPHER_CTX *)op->crypto_ctx, fPadding);

    operation->info.handleState |= TEE_HANDLE_FLAG_INITIALIZED;
    if (op->operationState == TEE_OPERATION_STATE_INITIAL) {
        op->operationState = TEE_OPERATION_STATE_ACTIVE;
    }

}

#ifndef OPENSSL_NO_CTS

void accumulate_AES_CTS_block(TEE_OperationHandle operation, const void* srcData, size_t srcLen, void* destData, size_t *destLen)
{
    MB_LOGD("FUNCTION = %s, line = %d\n", __FUNCTION__, __LINE__);
    struct TEE_Operation *op = (struct TEE_Operation *) operation;
    int outlen = 0;
    op->data_len += srcLen;

    if (op->data_len <= 2 * op->block_len) {
        TEE_MemMove(op->data + (op->data_len - srcLen), srcData, srcLen);
        *destLen = 0;
    } else {
        uint32_t extra_len = 2 * op->block_len - (op->data_len - srcLen);
        /* blocks already added */
        uint32_t addedBlocks = 0;

        /* accumulate 1st block */
        TEE_MemMove(op->data + (op->data_len - srcLen), srcData, extra_len);
        if (!EVP_CipherUpdate((EVP_CIPHER_CTX *) op->crypto_ctx,
                (unsigned char *) destData, &outlen,
                (const unsigned char *) op->data, op->block_len)) {
            MB_LOGE("Panic Reason: EVP cipher update operation failed\n");
            TEE_Panic(0);
        }
        ++addedBlocks;
        outlen = 0;

        /* accumulate next blocks*/
        uint32_t num = op->data_len / op->block_len - 1;
        uint32_t add_len = op->data_len % op->block_len;
        if (add_len == 0) {
            add_len = op->block_len;
            --num;
        }
        if (num > 1) {
            if (!EVP_CipherUpdate((EVP_CIPHER_CTX *) op->crypto_ctx,
                    (unsigned char *) destData + op->block_len, &outlen,
                    (const unsigned char *) (op->data + op->block_len),
                    op->block_len)) {
                MB_LOGE("Panic Reason: EVP cipher update operation failed\n");
                TEE_Panic(0);
            }
            ++addedBlocks;
            if (!EVP_CipherUpdate((EVP_CIPHER_CTX *) op->crypto_ctx,
                    (unsigned char *) destData + op->block_len * addedBlocks,
                    &outlen, (const unsigned char *) srcData + extra_len,
                    op->block_len * (num - addedBlocks))) {
                MB_LOGE("Panic Reason: EVP cipher update operation failed\n");
                TEE_Panic(0);
            }
            /* for AES CTS we must accumulate 2 blocks */
            //void PlatformSysMemcpy(void *dest, const void *src, uint32_t size)
            TEE_MemMove(op->data,
                   (const unsigned char *)srcData + extra_len + op->block_len * (num - addedBlocks),
                   op->block_len);
            TEE_MemMove(op->data + op->block_len,
                   (const unsigned char *)srcData + extra_len + op->block_len * (num - addedBlocks) + op->block_len,
                   add_len);
        } else {
            // have >=33 and <=48 bytes. accumulate from op->data and src+extra_len
            TEE_MemMove(op->data, op->data + op->block_len, op->block_len);
            TEE_MemMove(op->data + op->block_len, (const unsigned char *)srcData + extra_len, add_len);
        }

        *destLen = outlen + addedBlocks * op->block_len;
        op->data_len = add_len + op->block_len;
    }
}

AES_KEY * get_AES_CTS_Key(TEE_OperationHandle operation)
{
    struct TEE_Operation *op = (struct TEE_Operation *) operation;
    unsigned char key[64];
    uint32_t key_len = sizeof(key);
    AES_KEY *aes_key;

    aes_key = OPENSSL_malloc(sizeof(*aes_key));
    if (!aes_key) {
        if (CHECK_OSSL_MALLOC_FAILURE) {
            MB_LOGE("Panic Reason: AES CTS key creating memory error\n");
            TEE_Panic(ID_TEE_CipherDoFinal);
        }
        PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_CipherDoFinal);
    }

    if (TEE_GetObjectBufferAttribute(op->key1, TEE_ATTR_SECRET_VALUE, key,
                                     &key_len) != TEE_SUCCESS) {
        MB_LOGE("Panic Reason: Can't get AES_CTS key\n");
#ifndef USE_SCRYPTO_VER2_4        
        OPENSSL_cleanse(aes_key, sizeof(*aes_key));
#endif        
        OPENSSL_free(aes_key);
        TEE_Panic(ID_TEE_CipherDoFinal);
    }

    if (op->info.mode == TEE_MODE_DECRYPT) {
        if (AES_set_decrypt_key((const unsigned char *) key, (int) key_len * 8,
                                aes_key)) {
            char malloc_error = 0;
            if (CHECK_OSSL_MALLOC_FAILURE) {
                malloc_error = 1;
            }

#ifndef USE_SCRYPTO_VER2_4
            OPENSSL_cleanse(aes_key, sizeof(*aes_key));
#endif            
            OPENSSL_free(aes_key);
            if (malloc_error) {
                MB_LOGE("Panic Reason: AES_CTS key memory error\n");
                TEE_Panic(ID_TEE_CipherDoFinal);
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_CipherDoFinal);
        }
    } else {
        if (AES_set_encrypt_key((const unsigned char *) key, (int) key_len * 8,
                                aes_key)) {
            char malloc_error = 0;
            if (CHECK_OSSL_MALLOC_FAILURE) {
                malloc_error = 1;
            }

#ifndef USE_SCRYPTO_VER2_4
            OPENSSL_cleanse(aes_key, sizeof(*aes_key));
#endif            
            OPENSSL_free(aes_key);
            if (malloc_error) {
                MB_LOGE("Panic Reason: AES_CTS key memory error\n");
                TEE_Panic(ID_TEE_CipherDoFinal);
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_CipherDoFinal);
        }
    }

    TEE_MemFill(key, 0, sizeof(key));
    DO_NOT_OPTIMIZE(key);

    return aes_key;
}

#endif //OPENSSL_NO_CTS

void accumulate_AES_block(TEE_OperationHandle operation, const void* srcData, size_t srcLen, void* destData, size_t *destLen)
{
    struct TEE_Operation *op = (struct TEE_Operation *) operation;
    int outlen = 0;
    op->data_len += srcLen;
    if (op->data_len < op->block_len) {
        TEE_MemMove(op->data + (op->data_len - srcLen), srcData, srcLen);
        *destLen = 0;
    }

    if (op->data_len >= op->block_len) {
        uint32_t extra_len = op->block_len - (op->data_len - srcLen);

        /* accumulate 1st block*/
        TEE_MemMove(op->data + (op->data_len - srcLen), srcData, extra_len);
        if (!EVP_CipherUpdate((EVP_CIPHER_CTX *) op->crypto_ctx,
                              (unsigned char *) destData, &outlen,
                              (const unsigned char *) op->data,
                              op->block_len)) {
            MB_LOGE("Panic Reason: EVP cipher update operation failed\n");
            TEE_Panic(0);
        }

        /* accumulate next blocks*/
        uint32_t num = op->data_len / op->block_len - 1;
        uint32_t add_len = op->data_len % op->block_len;

        if (!EVP_CipherUpdate((EVP_CIPHER_CTX *) op->crypto_ctx,
                              (unsigned char *) destData + op->block_len, &outlen,
                              (const unsigned char *) srcData + extra_len,
                              op->block_len * num)) {
            MB_LOGE("Panic Reason: EVP cipher update operation failed\n");
            TEE_Panic(0);
        }
        TEE_MemMove(op->data, (const unsigned char *)srcData + extra_len + op->block_len * num, add_len);
        op->data_len = add_len;
        *destLen = outlen + op->block_len;
    }
}

static int shortBufferCheck(const uint32_t srcLen, const uint32_t accLen,
        uint32_t *destLen, uint32_t blockLen, uint32_t alg, int final)
{
    /* Total length for encrypt/decrypt */
    uint32_t expectedLen = srcLen + accLen;

    if (!final) {
        switch (alg) {
            case TEE_ALG_AES_CTR:
                break;
            case TEE_ALG_AES_CTS:
                /* Check if all length will be placed to accumulator */
                if (expectedLen <= 2 * blockLen) {
                    return 0;
                } else {
                    expectedLen -= blockLen + 1;
                }
                /* Fall through into default code */
            default:
                /* Length of full blocks */
                expectedLen = ROUND_DOWN(expectedLen, blockLen);
        }
    } else if (*destLen == 0) {
        *destLen = expectedLen;
        return 1;
    }
    if (*destLen < expectedLen) {
        *destLen = expectedLen;
        return 1;
    }
    return 0;
}

TEE_Result TEE_CipherUpdate( TEE_OperationHandle operation, const void* srcData, uint32_t srcLen, void* destData, uint32_t *destLen)
{
    check_operation_handle(operation, ID_TEE_CipherUpdate);

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (operation->info.operationClass != TEE_OPERATION_CIPHER) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_CIPHER\n");
        TEE_Panic(ID_TEE_CipherUpdate);
    }

    if (!(operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED)) {
        MB_LOGE("Panic Reason: operation handle isn't initialized\n");
        TEE_Panic(ID_TEE_CipherUpdate);
    }

    if (op->operationState != TEE_OPERATION_STATE_ACTIVE) {
        MB_LOGE("Panic Reason: the operation MUST be in active state\n");
        TEE_Panic(ID_TEE_CipherUpdate);
    }

    if (!destLen) {
        MB_LOGE("Panic Reason: parameter destLen is NULL\n");
        TEE_Panic(ID_TEE_CipherUpdate);
    }

    uint32_t accLen = op->data_len;
    if (op->crypto_ctx) {
        accLen += ((EVP_CIPHER_CTX*)op->crypto_ctx)->buf_len;
    }
    if (shortBufferCheck(srcLen, accLen, destLen, op->block_len,
                         op->info.algorithm, 0)) {
        return TEE_ERROR_SHORT_BUFFER;
    }

        uint32_t alg = op->info.algorithm;

        /* accumulation logic*/
        if ((alg == TEE_ALG_AES_ECB_ISO9797_M1)
         || (alg == TEE_ALG_AES_ECB_ISO9797_M2)
         || (alg == TEE_ALG_AES_CBC_ISO9797_M1)
         || (alg == TEE_ALG_AES_CBC_ISO9797_M2)) {
            size_t outlen1 = 0;
            accumulate_AES_block((TEE_OperationHandle)op, srcData, srcLen, destData, &outlen1);
            *destLen = outlen1;
#ifndef OPENSSL_NO_CTS
        } else if (alg == TEE_ALG_AES_CTS) {
            size_t outlen1 = 0;
            accumulate_AES_CTS_block((TEE_OperationHandle)op, srcData, srcLen, destData, &outlen1);
            *destLen = outlen1;
#endif  //OPENSSL_NO_CTS
        } else {
            if (!EVP_CipherUpdate((EVP_CIPHER_CTX *)op->crypto_ctx,
            	(unsigned char *)destData, (int *)destLen,
                (const unsigned char *)srcData, srcLen)) {
                MB_LOGE("Panic Reason: EVP cipher update failed\n");
                TEE_Panic(ID_TEE_CipherUpdate);
            }
        }

    return TEE_SUCCESS;
}


TEE_Result TEE_CipherDoFinal( TEE_OperationHandle operation, const void* srcData, uint32_t srcLen, void* destData, uint32_t *destLen)
{
    check_operation_handle(operation, ID_TEE_CipherDoFinal);

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (!destLen) {
        TEE_ResetOperation(operation);
        return TEE_SUCCESS;
    }

    if (operation->info.operationClass != TEE_OPERATION_CIPHER) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_CIPHER\n");
        TEE_Panic(ID_TEE_CipherDoFinal);
    }

    if (!(operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED)) {
        MB_LOGE("Panic Reason: operation handle isn't initialized\n");
        TEE_Panic(ID_TEE_CipherDoFinal);
    }

    if (op->operationState != TEE_OPERATION_STATE_ACTIVE) {
        MB_LOGE("Panic Reason: the operation MUST be in active state\n");
        TEE_Panic(ID_TEE_CipherDoFinal);
    }

    uint32_t accLen = op->data_len;
    if (op->crypto_ctx) {
        accLen += ((EVP_CIPHER_CTX*)op->crypto_ctx)->buf_len;
    }
    if (shortBufferCheck(srcLen, accLen, destLen, op->block_len,
                         op->info.algorithm, 1)) {
        return TEE_ERROR_SHORT_BUFFER;
    }

    int outlen1 = 0;
    int outlen2 = 0;
    uint32_t alg1 = op->info.algorithm;

    /* accumulation logic*/
#ifndef OPENSSL_NO_CTS
    if (alg1 == TEE_ALG_AES_CTS) {
        AES_KEY * aes_key = get_AES_CTS_Key(operation);
        EVP_CIPHER_CTX *stCipher = (EVP_CIPHER_CTX *)op->crypto_ctx;
        accumulate_AES_CTS_block((TEE_OperationHandle) op, srcData, srcLen,
                                 destData, (size_t *) &outlen1);
        if (op->info.mode == TEE_MODE_DECRYPT) {
            outlen2 = CRYPTO_cts128_decrypt((const unsigned char *) op->data,
                                            (unsigned char *) destData + outlen1,
                                            op->data_len, aes_key, stCipher->iv,
                                            (cbc128_f)AES_cbc_encrypt);
        } else {
            outlen2 = CRYPTO_cts128_encrypt((const unsigned char *) op->data,
                                            (unsigned char *) destData + outlen1,
                                            op->data_len, aes_key, stCipher->iv,
                                            (cbc128_f)AES_cbc_encrypt);
        }

#ifndef USE_SCRYPTO_VER2_4        
        OPENSSL_cleanse(aes_key, sizeof(*aes_key));
#endif        
        OPENSSL_free(aes_key);
        if (outlen2 == 0) {
            MB_LOGE("Panic Reason: AES_CTS cipher update operation failed\n");
            TEE_Panic(0);
        }
        TEE_ResetOperation(operation);
        *destLen = outlen1 + outlen2;
        return TEE_SUCCESS;
    } else
#endif  //OPENSSL_NO_CTS
    if ((alg1 == TEE_ALG_AES_ECB_ISO9797_M1)
     || (alg1 == TEE_ALG_AES_CBC_ISO9797_M1)) {
        accumulate_AES_block((TEE_OperationHandle)op, srcData, srcLen, destData, (size_t *)&outlen1);
        uint8_t block[16] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";

        if (op->data_len != 0) {
            TEE_MemMove(op->data + op->data_len, block, op->block_len - op->data_len);
            if (!EVP_CipherUpdate((EVP_CIPHER_CTX *)op->crypto_ctx, (unsigned char *)destData + outlen1, &outlen2,
                                  (const unsigned char *)op->data, op->block_len)) {
                MB_LOGE("Panic Reason: EVP cipher update failed\n");
                TEE_Panic(ID_TEE_CipherDoFinal);
            }

            outlen1 += op->block_len;
        }
    } else if ((alg1 == TEE_ALG_AES_ECB_ISO9797_M2)
            || (alg1 == TEE_ALG_AES_CBC_ISO9797_M2)) {
        accumulate_AES_block((TEE_OperationHandle)op, srcData, srcLen, destData, (size_t *)&outlen1);
        uint8_t block[16] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
        op->data[op->data_len] = 0x80;

        if (op->data_len != 0) {
            TEE_MemMove(op->data + op->data_len + 1, block, op->block_len - op->data_len - 1);

            if (!EVP_CipherUpdate((EVP_CIPHER_CTX *)op->crypto_ctx,
                                  (unsigned char *)destData + outlen1, &outlen2,
                                  (const unsigned char *)op->data, op->block_len)) {
                MB_LOGE("Panic Reason: EVP cipher update failed\n");
                TEE_Panic(ID_TEE_CipherDoFinal);
            }

            outlen1 += op->block_len;
        }

        if ((op->info.mode == TEE_MODE_ENCRYPT) && (op->data_len == 0)) {
            TEE_MemMove(op->data + 1, block, op->block_len - 1);

            if (!EVP_CipherUpdate((EVP_CIPHER_CTX *)op->crypto_ctx,
                                  (unsigned char *)destData + outlen1, &outlen2,
                                  (const unsigned char *)op->data, op->block_len)) {
                MB_LOGE("Panic Reason: EVP cipher update failed\n");
                TEE_Panic(ID_TEE_CipherDoFinal);
            }

            outlen1 += op->block_len;
        }
    } else {
        if (!EVP_CipherUpdate((EVP_CIPHER_CTX *)op->crypto_ctx,
                              (unsigned char *)destData, &outlen1,
                              (const unsigned char *)srcData, srcLen)) {
            MB_LOGE("Panic Reason: EVP cipher update failed\n");
            TEE_Panic(ID_TEE_CipherDoFinal);
        }
    }

    if (!EVP_CipherFinal_ex((EVP_CIPHER_CTX *)op->crypto_ctx,
                            (((unsigned char *) destData) + outlen1),
                            (int *)&outlen2)) {
        if (CHECK_OSSL_MALLOC_FAILURE) {
            return TEE_ERROR_OUT_OF_MEMORY;
        }
        PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_CipherDoFinal);
    }

    *destLen = outlen1 + outlen2;

    /* destLen calculation*/
    if (op->info.mode == TEE_MODE_DECRYPT &&
            ((alg1 == TEE_ALG_AES_ECB_ISO9797_M1) || (alg1 == TEE_ALG_AES_CBC_ISO9797_M1)))
    {
        uint32_t i = *destLen - 1, zero_count = 0;
        while (((unsigned char *)destData)[i] == 0x00) {
            zero_count++;
            i--;
        }

        *destLen = *destLen - zero_count;
    }

    if (op->info.mode == TEE_MODE_DECRYPT &&
            ((alg1 == TEE_ALG_AES_ECB_ISO9797_M2) ||
                    (alg1 == TEE_ALG_AES_CBC_ISO9797_M2))) {
        uint32_t i = *destLen - 1, zero_count = 0;
        while (((unsigned char *)destData)[i] == 0x00) {
            zero_count++;
            i--;
        }

        if (zero_count == 0) {
            if (((unsigned char *)destData)[*destLen - 1] == 0x80)
                *destLen = *destLen - 1;
        }
        else {
            *destLen = *destLen - zero_count - 1;
        }
    }

    TEE_ResetOperation(operation);

    return TEE_SUCCESS;
}



/* MAC Functions*/

void TEE_MACInit( TEE_OperationHandle operation, const void* IV, uint32_t IVLen)
{
    check_operation_handle(operation, ID_TEE_MACInit);

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (op->operationState == TEE_OPERATION_STATE_ACTIVE) {
        TEE_ResetOperation(operation);
    }

    if (operation->info.operationClass != TEE_OPERATION_MAC) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_MAC\n");
        TEE_Panic(ID_TEE_MACInit);
    }

    if (!(operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED)) {
        TEE_ResetOperation(operation);
    }

    if (!(operation->info.handleState & TEE_HANDLE_FLAG_KEY_SET)) {
        MB_LOGE("Panic Reason: operation handle key isn't set\n");
        TEE_Panic(ID_TEE_MACInit);
    }

    /* to suppress warning */
    (void)IVLen;
    (void)IV;


    ((struct TEE_Operation *) operation)->macinit_result = init_digest_mac(operation);

    operation->info.handleState |= TEE_HANDLE_FLAG_INITIALIZED;
    if (op->operationState == TEE_OPERATION_STATE_INITIAL) {
        op->operationState = TEE_OPERATION_STATE_ACTIVE;
    }
}

void TEE_MACUpdate( TEE_OperationHandle operation, const void* chunk, uint32_t chunkSize)
{
    check_operation_handle(operation, ID_TEE_MACUpdate);

    (void)chunk;
    (void)chunkSize;
    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (TEE_SUCCESS != op->macinit_result) {
        return;
    }

    if (operation->info.operationClass != TEE_OPERATION_MAC) {
        TEE_Panic(ID_TEE_MACUpdate);
    }

    if (!(operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED)) {
        MB_LOGE("Panic Reason: object isn't initialized\n");
        TEE_Panic(ID_TEE_MACUpdate);
    }

    if (op->operationState != TEE_OPERATION_STATE_ACTIVE) {
        MB_LOGE("Panic Reason: the operation MUST be in active state\n");
        TEE_Panic(ID_TEE_MACUpdate);
    }
        switch(op->info.algorithm)
        {
#ifndef OPENSSL_NO_HMAC
#ifndef OPENSSL_NO_SHA1
        case TEE_ALG_HMAC_SHA1:
#endif
#ifndef OPENSSL_NO_SHA256
        case TEE_ALG_HMAC_SHA224:
        case TEE_ALG_HMAC_SHA256:
#endif
#ifndef OPENSSL_NO_SHA512
        case TEE_ALG_HMAC_SHA384:
        case TEE_ALG_HMAC_SHA512:
#endif
            if (!HMAC_Update((HMAC_CTX *)op->crypto_ctx, chunk, chunkSize))
                TEE_Panic(ID_TEE_MACUpdate);
            break;
#endif /* OPENSSL_NO_HMAC */
#ifndef OPENSSL_NO_CMAC
        case TEE_ALG_AES_CMAC:
            if (!CMAC_Update((CMAC_CTX *)op->crypto_ctx, chunk, chunkSize))
                TEE_Panic(ID_TEE_MACUpdate);
            break;
        case TEE_ALG_AES_CBC_MAC_NOPAD:
        case TEE_ALG_AES_CBC_MAC_PKCS5:
        case TEE_ALG_AES_CBC_MAC_ISO9797_M2:
#ifndef OPENSSL_NO_DES
        case TEE_ALG_DES3_CBC_MAC_NOPAD:
        case TEE_ALG_DES3_CBC_MAC_PKCS5:
#endif /* OPENSSL_NO_DES */
            if (!CBCMAC_Update((CBCMAC_CTX *)op->crypto_ctx, chunk, chunkSize))
                TEE_Panic(ID_TEE_MACUpdate);
            break;
#endif /* OPENSSL_NO_CMAC */
        default:
            /* not supported HMAC*/
            TEE_Panic(ID_TEE_MACUpdate);
        }
}

TEE_Result TEE_MACComputeFinal( TEE_OperationHandle operation, const void* message, uint32_t messageLen, void* mac, uint32_t *macLen)
{
    check_operation_handle(operation, ID_TEE_MACComputeFinal);

    (void)messageLen;
    (void)message;
    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (TEE_SUCCESS != op->macinit_result) {
            return op->macinit_result;
    }

    if (!mac || !macLen) {
        MB_LOGE("Panic Reason: mac = %p or macLen = %p is NULL\n",
                  mac, macLen);
        TEE_Panic(ID_TEE_MACComputeFinal);
    }
    if (*macLen < operation->info.digestLength) return TEE_ERROR_SHORT_BUFFER;

    if (operation->info.operationClass != TEE_OPERATION_MAC) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_MAC\n");
        TEE_Panic(ID_TEE_MACComputeFinal);
    }

    if (!(operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED)) {
        MB_LOGE("Panic Reason: operation handle isn't initialized\n");
        TEE_Panic(ID_TEE_MACComputeFinal);
    }

    if (op->operationState != TEE_OPERATION_STATE_ACTIVE) {
        MB_LOGE("Panic Reason: the operation MUST be in active state\n");
        TEE_Panic(ID_TEE_MACComputeFinal);
    }

    switch( op->info.algorithm )
    {
#ifndef OPENSSL_NO_HMAC
    case TEE_ALG_HMAC_SHA1:
    case TEE_ALG_HMAC_SHA224:
    case TEE_ALG_HMAC_SHA256:
    case TEE_ALG_HMAC_SHA384:
    case TEE_ALG_HMAC_SHA512:
        if (!HMAC_Update( (HMAC_CTX *) op->crypto_ctx, message, messageLen )) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_MACComputeFinal);
        }
        if (!HMAC_Final( (HMAC_CTX *) op->crypto_ctx, mac, macLen )) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_MACComputeFinal);
        }
        break;
#endif /* OPENSSL_NO_HMAC */

#ifndef OPENSSL_NO_CMAC
    case TEE_ALG_AES_CMAC: {
        size_t macLen_cpy = *macLen;
        if (!CMAC_Update( (CMAC_CTX *) op->crypto_ctx, message, messageLen )) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_MACComputeFinal);
        }

        if (!CMAC_Final( (CMAC_CTX *) op->crypto_ctx, mac, &macLen_cpy)) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_MACComputeFinal);
        }
        *macLen = (uint32_t) macLen_cpy;
        break;
    }
    case TEE_ALG_AES_CBC_MAC_NOPAD:
    case TEE_ALG_AES_CBC_MAC_PKCS5:
    case TEE_ALG_AES_CBC_MAC_ISO9797_M2:
    case TEE_ALG_DES3_CBC_MAC_NOPAD:
    case TEE_ALG_DES3_CBC_MAC_PKCS5: {
        if (!CBCMAC_Update( (CBCMAC_CTX *) op->crypto_ctx, message, messageLen )) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_MACComputeFinal);
        }
        size_t macLen_cpy = *macLen;
        if (!CBCMAC_Final( (CBCMAC_CTX *) op->crypto_ctx, mac, &macLen_cpy)) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_MACComputeFinal);
        }
        *macLen = (uint32_t) macLen_cpy;
        break;
    }
#endif /* OPENSSL_NO_CMAC */
    default:
        /* not supported HMAC*/
        MB_LOGE("Panic Reason: not supported algorithm\n");
        TEE_Panic(ID_TEE_MACComputeFinal);
    }
    TEE_ResetOperation(operation);
    return TEE_SUCCESS;
}

TEE_Result TEE_MACCompareFinal( TEE_OperationHandle operation, const void* message, uint32_t messageLen, const void* mac, uint32_t macLen)
{
    check_operation_handle(operation, ID_TEE_MACCompareFinal);

    TEE_Result ret = TEE_SUCCESS;
    char result[64];
    uint32_t result_len = sizeof result;

    struct TEE_Operation *op = (struct TEE_Operation *) operation;
    if (TEE_SUCCESS != op->macinit_result) {
        return op->macinit_result;
    }

    ret = TEE_MACComputeFinal(operation, message, messageLen, result, &result_len);
    if (ret != TEE_SUCCESS) {
        return ret;
    }

    if (!mac) {
        MB_LOGE("Panic Reason: mac is NULL\n");
        TEE_Panic(ID_TEE_MACCompareFinal);
    }
    if (macLen != operation->info.digestLength) {
        return TEE_ERROR_MAC_INVALID;
    }

    if (TEE_MemCompare(mac, result, macLen)) {
        ret = TEE_ERROR_MAC_INVALID;
    }
    else {
        ret = TEE_SUCCESS;
    }

    return ret;
}

/* Authenticated Encryption Functions*/

TEE_Result TEE_AEInit(TEE_OperationHandle operation, const void* nonce, uint32_t nonceLen, uint32_t tagLen, uint32_t AADLen, uint32_t payloadLen)
{
    check_operation_handle(operation, ID_TEE_AEInit);

    (void)AADLen;
    (void)payloadLen;
    struct crypto_info info;
    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    TEE_MemFill(&info, 0, sizeof(struct crypto_info));
    info.keylen = sizeof(info.key);

    if (operation->info.operationClass != TEE_OPERATION_AE) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_AE\n");
        TEE_Panic(ID_TEE_AEInit);
    }

    /* Check that operation is in initial state */
     if (operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) {
         MB_LOGE("Panic Reason: operation handle is already initialized\n");
         TEE_Panic(ID_TEE_AEInit);
     }

    if (op->operationState != TEE_OPERATION_STATE_INITIAL) {
        MB_LOGE("Panic Reason: the operation must be in initial state\n");
        TEE_Panic(ID_TEE_AEInit);
    }

    if (!(operation->info.handleState & TEE_HANDLE_FLAG_KEY_SET)) {
        MB_LOGE("Panic Reason: operation handle key isn't set\n");
        TEE_Panic(ID_TEE_AEInit);
    }

    if (TEE_GetObjectBufferAttribute(op->key1, TEE_ATTR_SECRET_VALUE, info.key, &info.keylen) != TEE_SUCCESS) {
        MB_LOGE("Panic Reason: get object buffer attribute failed\n");
        TEE_Panic(ID_TEE_AEInit);
    }

#ifndef OPENSSL_NO_AES_CCM
    if (operation->info.algorithm == TEE_ALG_AES_CCM)
    {
        int len;
        if (tagLen != 128 && tagLen != 112 && tagLen != 96 &&
                tagLen != 64 && tagLen != 48 && tagLen != 32) {
            return TEE_ERROR_NOT_SUPPORTED;
        }

        EVP_CIPHER_CTX_init(op->crypto_ctx);
        EVP_CIPHER const *cipher = NULL;

        switch (op->info.maxKeySize) {
        case 128:
            cipher = EVP_aes_128_ccm();
            break;
        case 192:
            cipher = EVP_aes_192_ccm();
            break;
        case 256:
            cipher = EVP_aes_256_ccm();
            break;
        default: {
            MB_LOGE("Panic Reason: unsupported key max size = %d\n",
                      op->info.maxKeySize);
            TEE_Panic(ID_TEE_AEInit);
        }
        }
        ERR_clear_error();
        if (op->info.mode == TEE_MODE_ENCRYPT) {
            if (!EVP_EncryptInit_ex(op->crypto_ctx, cipher, NULL, NULL, NULL)) {
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
            }

            if (!EVP_CIPHER_CTX_ctrl(op->crypto_ctx, EVP_CTRL_CCM_SET_IVLEN, nonceLen, NULL)) {
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
            }

            if (!EVP_CIPHER_CTX_ctrl(op->crypto_ctx, EVP_CTRL_CCM_SET_TAG, tagLen/8, NULL)) {
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
            }

            if (!EVP_EncryptInit_ex(op->crypto_ctx, NULL, NULL, info.key, nonce)) {
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
            }

            if (!EVP_EncryptUpdate(op->crypto_ctx, NULL, &len, NULL, payloadLen)) {
                MB_LOGE("Panic Reason: EVP encrypt update failed\n");
                TEE_Panic(ID_TEE_AEInit);
            }
        } else if (op->info.mode == TEE_MODE_DECRYPT) {
            unsigned char zero_tag[16]; /* Maximum allowed tagLen*/

            if (!EVP_DecryptInit_ex(op->crypto_ctx, cipher, NULL, NULL, NULL)) {
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
            }

            if (!EVP_CIPHER_CTX_ctrl(op->crypto_ctx, EVP_CTRL_CCM_SET_IVLEN, nonceLen, NULL)) {
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
            }

            /* Zero tag value is set here to make EVP_DecryptUpdate() work.
             * Valid tag will be set later in TEE_AEDecryptFinal() before
             * actual decryption. */
            if (tagLen/8 > sizeof(zero_tag)) {
                MB_LOGE("Panic Reason: tag length is bigger than zero tag\n");
                TEE_Panic(ID_TEE_AEInit);
            }
            TEE_MemFill(zero_tag, 0, tagLen/8);
            if (!EVP_CIPHER_CTX_ctrl(op->crypto_ctx, EVP_CTRL_CCM_SET_TAG, tagLen/8, zero_tag)) {
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
            }

            if (!EVP_DecryptInit_ex(op->crypto_ctx, NULL, NULL, info.key, nonce)) {
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
            }

            if (!EVP_DecryptUpdate(op->crypto_ctx, NULL, &len, NULL, payloadLen)) {
                MB_LOGE("Panic Reason: EVP decrypt updatefailed\n");
                TEE_Panic(ID_TEE_AEInit);
            }
        } else {
            MB_LOGE("Panic Reason: unsupported mode\n");
            TEE_Panic(ID_TEE_AEInit);
        }

        /* allocate accumulation buffer for CCM AAD Update */
        op->ccm_upd_ctx.aad_buff = TEE_Malloc(AADLen, HINT_FILL_WITH_ZEROS);
        if(NULL == op->ccm_upd_ctx.aad_buff)
        {
            MB_LOGE("No memory for CCM AAD accumulation buffer\n");
            return TEE_ERROR_OUT_OF_MEMORY;
        }
        op->ccm_upd_ctx.aad_req_len = AADLen;
        op->ccm_upd_ctx.aad_prov_len = 0;

        /* allocate accumulation buffer for CCM data Update */
        op->ccm_upd_ctx.ae_buff = TEE_Malloc(payloadLen, HINT_FILL_WITH_ZEROS);
        if(NULL == op->ccm_upd_ctx.ae_buff)
        {
            TEE_Free(op->ccm_upd_ctx.aad_buff);
            MB_LOGE("No memory for CCM data accumulation buffer\n");
            return TEE_ERROR_OUT_OF_MEMORY;
        }
        op->ccm_upd_ctx.ae_req_len = payloadLen;
        op->ccm_upd_ctx.ae_prov_len = 0;
    }
#endif /* OPENSSL_NO_AES_CCM */
    if (operation->info.algorithm == TEE_ALG_AES_GCM)
    {
        if (tagLen != 128 && tagLen != 120 && tagLen != 112 && tagLen != 104 && tagLen != 96) {
            return TEE_ERROR_NOT_SUPPORTED;
        }
#ifdef USE_SCRYPTO_VER2_4
        EVP_CIPHER_CTX_init(op->crypto_ctx);
        EVP_CIPHER const *cipher = NULL;

        switch (op->info.maxKeySize) {
            case 128:
                cipher = EVP_aes_128_gcm();
                break;
            case 192:
                cipher = EVP_aes_192_gcm();
                break;
            case 256:
                cipher = EVP_aes_256_gcm();
                break;
            default: {
                MB_LOGE("Panic Reason: unsupported key max size = %d\n",
                        op->info.maxKeySize);
                TEE_Panic(ID_TEE_AEInit);
            }
        }

        ERR_clear_error();

        int enc = 0;
        if (op->info.mode == TEE_MODE_ENCRYPT) {
            enc = 1;
        } else if (op->info.mode != TEE_MODE_DECRYPT) {
            MB_LOGE("Panic Reason: unsupported mode\n");
            TEE_Panic(ID_TEE_AEInit);
        }

        if (!EVP_CipherInit_ex(op->crypto_ctx, cipher, NULL, NULL, NULL, enc)) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
        }

        if (!EVP_CIPHER_CTX_ctrl(op->crypto_ctx, EVP_CTRL_GCM_SET_IVLEN, nonceLen, NULL)) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
        }

        if (!EVP_CipherInit_ex(op->crypto_ctx, NULL, NULL, info.key, nonce, enc)) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
        }
#else
#ifndef BORING_SSL
        GCM128_CONTEXT *stCipher = (GCM128_CONTEXT *)op->crypto_ctx;
        AES_KEY *aes_key = stCipher->key;
#else
        AES_GCM_ctx_t *gcmContext = (AES_GCM_ctx_t *)op->crypto_ctx;
        GCM128_CONTEXT *stCipher = &gcmContext->ctx;
        AES_KEY *aes_key = gcmContext->key;
#endif

        /* Allocate memory for new key or clean previous key before use */
        if (!aes_key) {
            aes_key = OPENSSL_malloc(sizeof(*aes_key));
        } else {
            OPENSSL_cleanse(aes_key, sizeof(*aes_key));
        }

        if (!aes_key) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
        }

        if (AES_set_encrypt_key((const unsigned char *)info.key, (int)info.keylen*8, aes_key)) {
            char malloc_error = 0;
            if (CHECK_OSSL_MALLOC_FAILURE) {
                malloc_error = 1;
            }

            OPENSSL_cleanse(aes_key, sizeof(*aes_key));
            OPENSSL_free(aes_key);
            if (malloc_error) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEInit);
        }
        CRYPTO_gcm128_init(stCipher, (void *)aes_key, (block128_f)AES_encrypt);
#ifdef BORING_SSL
        CRYPTO_gcm128_setiv(stCipher, (void *)aes_key, nonce, nonceLen);
        gcmContext->key = aes_key;
#else
        CRYPTO_gcm128_setiv(stCipher, nonce, nonceLen);
#endif
#endif
    }

    operation->info.digestLength = tagLen;
    operation->info.handleState |= TEE_HANDLE_FLAG_INITIALIZED;

    return TEE_SUCCESS;
}

void TEE_AEUpdateAAD(TEE_OperationHandle operation, const void* AADdata, uint32_t AADdataLen)
{
    check_operation_handle(operation, ID_TEE_AEUpdateAAD);

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (operation->info.operationClass != TEE_OPERATION_AE) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_AE\n");
        TEE_Panic(ID_TEE_AEUpdateAAD);
    }

    if (!(operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED)) {
        MB_LOGE("Panic Reason: operation handle isn't initialized\n");
        TEE_Panic(ID_TEE_AEUpdateAAD);
    }

    if (operation->info.algorithm == TEE_ALG_AES_CCM) {
        size_t curr_len = op->ccm_upd_ctx.aad_prov_len + AADdataLen;
        /* Check if the AAD length has already been reached */
        if (curr_len > op->ccm_upd_ctx.aad_req_len) {
            MB_LOGE("Panic Reason: AAD length has already been reached\n");
            TEE_Panic(ID_TEE_AEUpdateAAD);
        }

        if (AADdataLen) {
            if (!AADdata) {
                MB_LOGE("Panic Reason: AAD is NULL\n");
                TEE_Panic(ID_TEE_AEUpdateAAD);
            }
            TEE_MemMove(op->ccm_upd_ctx.aad_buff + op->ccm_upd_ctx.aad_prov_len, AADdata, AADdataLen );
        }
        op->ccm_upd_ctx.aad_prov_len = curr_len;
    } else if (operation->info.algorithm == TEE_ALG_AES_GCM) {
#ifdef USE_SCRYPTO_VER2_4
        if (!op->crypto_ctx) {
            MB_LOGE("Panic Reason: cipher is NULL\n");
            TEE_Panic(ID_TEE_AEUpdateAAD);
        }

        if (AADdataLen) {
            if (!AADdata) {
                MB_LOGE("Panic Reason: AAD is NULL\n");
                TEE_Panic(ID_TEE_AEUpdateAAD);
            }
        }

        int len = 0;
        if (!EVP_CipherUpdate(op->crypto_ctx, NULL, &len, AADdata, AADdataLen))
        {
            MB_LOGE("Panic Reason: Update AAD is failed\n");
            TEE_Panic(ID_TEE_AEUpdateAAD);
        }
#else
#ifndef BORING_SSL
        GCM128_CONTEXT *stCipher = (GCM128_CONTEXT *)op->crypto_ctx;
#else
        AES_GCM_ctx_t *gcmContext = (AES_GCM_ctx_t *)op->crypto_ctx;
        GCM128_CONTEXT *stCipher = &gcmContext->ctx;
#endif
        int ret = CRYPTO_gcm128_aad(stCipher, AADdata, AADdataLen);
        if (GCM_SUCCESS != ret) {
            MB_LOGE("Panic Reason: CRYPTO_gcm128_aad failed\n");
            TEE_Panic(ID_TEE_AEUpdateAAD);
        }
#endif
    }
    op->operationState = TEE_OPERATION_STATE_ACTIVE;
}

TEE_Result TEE_AEUpdate(TEE_OperationHandle operation, const void* srcData, uint32_t srcLen, void* destData, uint32_t *destLen)
{
    check_operation_handle(operation, ID_TEE_AEUpdate);

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (operation->info.operationClass != TEE_OPERATION_AE) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_AE\n");
        TEE_Panic(ID_TEE_AEUpdate);
    }

    if (!(operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED)) {
        MB_LOGE("Panic Reason: operation handle isn't initialized\n");
        TEE_Panic(ID_TEE_AEUpdate);
    }

    if (!destLen) {
        MB_LOGE("Panic Reason: dst length is 0\n");
        TEE_Panic(ID_TEE_AEUpdate);
    }

    /* see GPAPI 1.1. Chapter 3.4.3 [inbuf] */
    if (0 == srcLen) {
        *destLen  = 0;
        op->operationState = TEE_OPERATION_STATE_ACTIVE;
        return TEE_SUCCESS;
    }

    if (NULL == destData && *destLen != 0) {
        MB_LOGE("Panic Reason: destData is NULL and destLen != 0\n");
        TEE_Panic(ID_TEE_AEUpdate);
    }

    if( NULL == srcData ) {
        MB_LOGE("Panic Reason: srcData is NULL\n");
        TEE_Panic(ID_TEE_AEUpdate);
    }

    if (operation->info.algorithm == TEE_ALG_AES_CCM) {
        /*Unless  one or more calls of this function have supplied sufficient
        input data, no output is generated.*/
        *destLen = 0; /* due to accumulation */
        
        /* The required AAD length has not been provided yet (AES-CCM only)*/
        if(op->ccm_upd_ctx.aad_prov_len < op->ccm_upd_ctx.aad_req_len) {
            MB_LOGE("Panic Reason: The required CCM AAD length has not been provided yet\n");
            TEE_Panic(ID_TEE_AEUpdate);
        }
        
        /* The payload length has already been reached (AES-CCM only).*/
        size_t curr_len = op->ccm_upd_ctx.ae_prov_len + srcLen;
        if (curr_len > op->ccm_upd_ctx.ae_req_len) {
            MB_LOGE("Panic Reason: CCM Payload length has already been reached\n");
            TEE_Panic(ID_TEE_AEUpdate);
        }
        TEE_MemMove(op->ccm_upd_ctx.ae_buff + op->ccm_upd_ctx.ae_prov_len, srcData, srcLen );
        op->ccm_upd_ctx.ae_prov_len = curr_len;
    } else if (operation->info.algorithm == TEE_ALG_AES_GCM) {
        if (*destLen < srcLen) {
            MB_LOGE("Provided destination buffer is not sufficient to store output data\n");
            return TEE_ERROR_SHORT_BUFFER;
        }

#ifdef USE_SCRYPTO_VER2_4
        if (!op->crypto_ctx) {
            MB_LOGE("Panic Reason: cipher is NULL\n");
            TEE_Panic(ID_TEE_AEUpdate);
        }

        if ((op->info.mode != TEE_MODE_ENCRYPT) && (op->info.mode != TEE_MODE_DECRYPT)) {
            MB_LOGE("Panic Reason: not supported mode\n");
            TEE_Panic(ID_TEE_AEUpdate);
        }
        
        if (!EVP_CipherUpdate(op->crypto_ctx, destData, (int *)destLen, srcData, srcLen)) {
            MB_LOGE("Panic Reason: encrypt/decrypt operation failed\n");
            TEE_Panic(ID_TEE_AEUpdate);
        }

#else
        int ret = 1;
#ifndef BORING_SSL
        GCM128_CONTEXT *stCipher = (GCM128_CONTEXT *)op->crypto_ctx;
#else
        AES_GCM_ctx_t *gcmContext = (AES_GCM_ctx_t *)op->crypto_ctx;
        GCM128_CONTEXT *stCipher = &gcmContext->ctx;
#endif
        if (!stCipher) {
            MB_LOGE("Panic Reason: cipher is NULL\n");
            TEE_Panic(ID_TEE_AEUpdate);
        }

        if (op->info.mode == TEE_MODE_ENCRYPT) {
#ifndef BORING_SSL
            ret = CRYPTO_gcm128_encrypt(stCipher, srcData, destData, srcLen);
#else
            ret = CRYPTO_gcm128_encrypt(stCipher, gcmContext->key, srcData, destData, srcLen);
#endif
        } else if (op->info.mode == TEE_MODE_DECRYPT) {
#ifndef BORING_SSL
            ret = CRYPTO_gcm128_decrypt(stCipher, srcData, destData, srcLen);
#else
            ret = CRYPTO_gcm128_decrypt(stCipher, gcmContext->key, srcData, destData, srcLen);
#endif
        } else {
            MB_LOGE("Panic Reason: not supported mode\n");
            TEE_Panic(ID_TEE_AEUpdate);
        }

        if (GCM_SUCCESS != ret) {
            MB_LOGE("Panic Reason: gcm128 encrypt/decrypt operation failed\n");
            TEE_Panic(ID_TEE_AEUpdate);
        }
        *destLen = srcLen;
#endif
    }
    op->operationState = TEE_OPERATION_STATE_ACTIVE;
    return TEE_SUCCESS;
}

TEE_Result TEE_AEEncryptFinal(TEE_OperationHandle operation, const void* srcData, uint32_t srcLen, void* destData, uint32_t* destLen, void* tag, uint32_t* tagLen)
{
    check_operation_handle(operation, ID_TEE_AEEncryptFinal);

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (operation->info.operationClass != TEE_OPERATION_AE) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_AE\n");
        TEE_Panic(ID_TEE_AEEncryptFinal);
    }

    if (!(operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED)) {
        MB_LOGE("Panic Reason: operation handle isn't initialized\n");
        TEE_Panic(ID_TEE_AEEncryptFinal);
    }

    if (op->info.mode != TEE_MODE_ENCRYPT) {
        MB_LOGE("Panic Reason: mode ins't TEE_MODE_ENCRYPT\n");
        TEE_Panic(ID_TEE_AEEncryptFinal);
    }

    if (!destLen || !tagLen) {
        MB_LOGE("Panic Reason: destLen=%p or "
                "tagLen=%p is NULL\n", destLen, tagLen);
        TEE_Panic(ID_TEE_AEEncryptFinal);
    }

#ifndef OPENSSL_NO_AES_CCM
    if (operation->info.algorithm == TEE_ALG_AES_CCM)
    {
        if (*destLen < op->ccm_upd_ctx.ae_req_len) {
            return TEE_ERROR_SHORT_BUFFER;
        }

        int tmplen, len1 = 0, len2 = 0;
        size_t curr_len = 0;

        /* Check if the required AAD length has not been provided yet */
        if (op->ccm_upd_ctx.aad_prov_len != op->ccm_upd_ctx.aad_req_len) {
            MB_LOGE("Panic Reason: AAD provided length isn't equal to required\n");
            TEE_Panic(ID_TEE_AEEncryptFinal);
        }

        /* process AAD accumulated in TEE_AEUpdateAAD */
        if (!EVP_EncryptUpdate(op->crypto_ctx, NULL, &tmplen, op->ccm_upd_ctx.aad_buff, op->ccm_upd_ctx.aad_prov_len)) {
            MB_LOGE("Panic Reason: EVP encrypt update failed for AAD\n");
            TEE_Panic(ID_TEE_AEEncryptFinal);
        }

        curr_len = op->ccm_upd_ctx.ae_prov_len + srcLen;
        if (curr_len != op->ccm_upd_ctx.ae_req_len){
            MB_LOGE("Panic Reason: requiered and actualy recieved payload sizes mismatch\n");
            TEE_Panic(ID_TEE_AEEncryptFinal);
        }

        if (curr_len) {
            if (!srcData || !destData) {
                MB_LOGE("Panic Reason: srcData(%p) or destData(%p) is NULL\n",
                        srcData, destData);
                TEE_Panic(ID_TEE_AEEncryptFinal);
            }

            /* update data buffer with srcData if srcLen not 0*/
            if (srcLen) {
                TEE_MemMove(op->ccm_upd_ctx.ae_buff + op->ccm_upd_ctx.ae_prov_len, srcData, srcLen);
            }

            if (!EVP_EncryptUpdate(op->crypto_ctx, destData, &len1, op->ccm_upd_ctx.ae_buff, op->ccm_upd_ctx.ae_req_len)) {
                MB_LOGE("Panic Reason: EVP encrypt update failed\n");
                TEE_Panic(ID_TEE_AEEncryptFinal);
            }
        } else {
            /* If payload is 0 GP API Specification allows srcData and/or destData to be NULL.
             * In this case we cannot call EVP_EncryptUpdate() as we do it above,
             * because EVP_EncryptUpdate(ctx, NULL, &len1, NULL, srcLen) is the
             * special convention to setup plaintext length. */
             unsigned char buf[1];
             if (!EVP_EncryptUpdate(op->crypto_ctx, buf, &len1, buf, curr_len)) {
                 MB_LOGE("Panic Reason: EVP encrypt update failed\n");
                 TEE_Panic(ID_TEE_AEEncryptFinal);
             }
        }

        if (!EVP_EncryptFinal_ex(op->crypto_ctx, ((unsigned char *)destData + len1), &len2)) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEEncryptFinal);
        }

        *destLen = len1 + len2;

        if (*tagLen < operation->info.digestLength/8) {
            return TEE_ERROR_SHORT_BUFFER;
        }
        if (!tag) {
            MB_LOGE("Panic Reason: tag is NULL\n");
            TEE_Panic(ID_TEE_AEEncryptFinal);
        }

        if (!EVP_CIPHER_CTX_ctrl(op->crypto_ctx, EVP_CTRL_CCM_GET_TAG, operation->info.digestLength/8, tag)) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEEncryptFinal);
        }
        *tagLen = operation->info.digestLength/8;

        TEE_ResetOperation(operation);
    }
#endif /* OPENSSL_NO_AES_CCM */

    if (operation->info.algorithm == TEE_ALG_AES_GCM)
    {
        if (*destLen < srcLen) {
            MB_LOGE("Provided destination buffer is not sufficient to store output data\n");
            return TEE_ERROR_SHORT_BUFFER;
        }
#ifdef USE_SCRYPTO_VER2_4
        if (!op->crypto_ctx) {
            MB_LOGE("Panic Reason: cipher is NULL\n");
            TEE_Panic(ID_TEE_AEEncryptFinal);
        }

        if (srcLen != 0) {
            if (!destData) {
                MB_LOGE("Panic Reason: destData is NULL\n");
                TEE_Panic(ID_TEE_AEEncryptFinal);
            }

            if (!EVP_CipherUpdate(op->crypto_ctx, destData, (int *)destLen, srcData, srcLen)) {
                MB_LOGE("Panic Reason: encrypt operation failed\n");
                TEE_Panic(ID_TEE_AEEncryptFinal);
            }
        }

        if (*tagLen < operation->info.digestLength/8) {
            return TEE_ERROR_SHORT_BUFFER;
        }

        if (!tag) {
            MB_LOGE("Panic Reason: tag is NULL\n");
            TEE_Panic(ID_TEE_AEEncryptFinal);
        }

        if (!EVP_CipherFinal_ex(op->crypto_ctx, tag, (int *)tagLen)) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEEncryptFinal);
        }
        
        if (!EVP_CIPHER_CTX_ctrl(op->crypto_ctx, EVP_CTRL_GCM_GET_TAG, operation->info.digestLength/8, tag))
        {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEEncryptFinal);
        }

        *tagLen = operation->info.digestLength/8;
#else
#ifndef BORING_SSL
        GCM128_CONTEXT *stCipher = (GCM128_CONTEXT *)op->crypto_ctx;
#else
        AES_GCM_ctx_t *gcmContext = (AES_GCM_ctx_t *)op->crypto_ctx;
        GCM128_CONTEXT *stCipher = &gcmContext->ctx;
#endif
        if (!stCipher) {
            MB_LOGE("Panic Reason: cipher is NULL\n");
            TEE_Panic(ID_TEE_AEEncryptFinal);
        }
        if (srcLen != 0) {
            int ret;
            if (!destData) {
                MB_LOGE("Panic Reason: destData is NULL\n");
                TEE_Panic(ID_TEE_AEEncryptFinal);
            }
#ifndef BORING_SSL
            ret = CRYPTO_gcm128_encrypt(stCipher, (unsigned char *)srcData, destData, srcLen);
#else
            ret = CRYPTO_gcm128_encrypt(stCipher, gcmContext->key, (unsigned char *)srcData, destData, srcLen);
#endif
            if (GCM_SUCCESS != ret) {
                MB_LOGE("Panic Reason: gcm128 encrypt failed\n");
                TEE_Panic(ID_TEE_AEEncryptFinal);
            }
            *destLen = srcLen;
        }

        if (*tagLen < operation->info.digestLength/8) return TEE_ERROR_SHORT_BUFFER;
        if (!tag) {
            MB_LOGE("Panic Reason: tag is NULL\n");
            TEE_Panic(ID_TEE_AEEncryptFinal);
        }

        CRYPTO_gcm128_tag(stCipher, tag, operation->info.digestLength/8);
        *tagLen = operation->info.digestLength/8;
#endif
    }

    TEE_ResetOperation(operation);

    return TEE_SUCCESS;
}

TEE_Result TEE_AEDecryptFinal(TEE_OperationHandle operation, const void* srcData, uint32_t srcLen, void* destData, uint32_t *destLen, void* tag, uint32_t tagLen)
{
    check_operation_handle(operation, ID_TEE_AEDecryptFinal);

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (operation->info.operationClass != TEE_OPERATION_AE) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_AE\n");
        TEE_Panic(ID_TEE_AEDecryptFinal);
    }

    if (!(operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED)) {
        MB_LOGE("Panic Reason: operation handle isn't initialized\n");
        TEE_Panic(ID_TEE_AEDecryptFinal);
    }

    if (op->info.mode != TEE_MODE_DECRYPT) {
        MB_LOGE("Panic Reason: mode isn't TEE_MODE_DECRYPT\n");
        TEE_Panic(ID_TEE_AEDecryptFinal);
    }

    if (!destLen) {
        MB_LOGE("Panic Reason: dstLen is 0\n");
        TEE_Panic(ID_TEE_AEDecryptFinal);
    }

#ifndef OPENSSL_NO_AES_CCM
    if (operation->info.algorithm == TEE_ALG_AES_CCM) {
        int len;
        size_t curr_len;
        int rv;

        if (*destLen < op->ccm_upd_ctx.ae_req_len) {
            MB_LOGE("Provided destination buffer is not sufficient to store output data\n");
            return TEE_ERROR_SHORT_BUFFER;
        }

        /* Check if the required AAD length has not been provided yet */
        if (op->ccm_upd_ctx.aad_prov_len != op->ccm_upd_ctx.aad_req_len) {
            MB_LOGE("Panic Reason: AAD provided length isn't equal to required\n");
            TEE_Panic(ID_TEE_AEDecryptFinal);
        }

        /* process AAD accumulated in TEE_AEUpdateAAD */
        if (!EVP_DecryptUpdate(op->crypto_ctx, NULL, &len, op->ccm_upd_ctx.aad_buff, op->ccm_upd_ctx.aad_prov_len)) {
            MB_LOGE("Panic Reason: EVP encrypt update failed for AAD\n");
            TEE_Panic(ID_TEE_AEDecryptFinal);
        }

        if (!EVP_CIPHER_CTX_ctrl(op->crypto_ctx, EVP_CTRL_CCM_SET_TAG, tagLen, tag)) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEDecryptFinal);
        }

        curr_len = op->ccm_upd_ctx.ae_prov_len + srcLen;

        if (curr_len != op->ccm_upd_ctx.ae_req_len){
            MB_LOGE("Panic Reason: requiered and actualy recieved payload sizes mismatch\n");
            TEE_Panic(ID_TEE_AEDecryptFinal);
        }

        if (curr_len) {
            if (!srcData || !destData) {
                MB_LOGE("Panic Reason: srcData(%p) or destData(%p) is NULL\n",
                          srcData, destData);
                TEE_Panic(ID_TEE_AEDecryptFinal);
            }

            /* update data buffer with srcData if srcLen not 0 */
            if (srcLen) {
                TEE_MemMove(op->ccm_upd_ctx.ae_buff + op->ccm_upd_ctx.ae_prov_len, srcData, srcLen);
            }

            rv = EVP_DecryptUpdate(op->crypto_ctx, destData, &len, op->ccm_upd_ctx.ae_buff, op->ccm_upd_ctx.ae_req_len);
        } else {
            /* If srcLen is 0 GP API Specification allows srcData and/or destData to be NULL.
             * In this case we cannot call EVP_DecryptUpdate() as we do it above,
             * because EVP_DecryptUpdate(ctx, NULL, &len, NULL, srcLen) is the
             * special convention to setup ciphertext length. */
            unsigned char buf[1];
            rv = EVP_DecryptUpdate(op->crypto_ctx, buf, &len, buf, curr_len);
        }

        TEE_ResetOperation(operation);

        if (!rv) {
            return TEE_ERROR_MAC_INVALID;
        }

        *destLen = len;
    }
#endif /* !OPENSSL_NO_AES_CCM */
    if (operation->info.algorithm == TEE_ALG_AES_GCM) {
        if (*destLen < srcLen) {
            MB_LOGE("Provided destination buffer is not sufficient to store output data\n");
            return TEE_ERROR_SHORT_BUFFER;
        }

#ifdef USE_SCRYPTO_VER2_4
        if (!op->crypto_ctx) {
            MB_LOGE("Panic Reason: cipher is NULL\n");
            TEE_Panic(ID_TEE_AEDecryptFinal);
        }

        if (srcLen != 0) {
            if (!destData) {
                MB_LOGE("Panic Reason: destData is NULL\n");
                TEE_Panic(ID_TEE_AEDecryptFinal);
            }

            if (!EVP_CipherUpdate(op->crypto_ctx, destData, (int *)destLen, srcData, srcLen)) {
                MB_LOGE("Panic Reason: decrypt operation failed\n");
                TEE_Panic(ID_TEE_AEDecryptFinal);
            }
        }

        if (operation->info.digestLength/8 != tagLen) {
            return TEE_ERROR_MAC_INVALID;
        }

        if (!tag) {
            MB_LOGE("Panic Reason: tag is NULL\n");
            TEE_Panic(ID_TEE_AEEncryptFinal);
        }

        if (!EVP_CIPHER_CTX_ctrl(op->crypto_ctx, EVP_CTRL_GCM_SET_TAG, tagLen, tag)) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AEDecryptFinal);
        }

        int len_out;
        if (!EVP_CipherFinal_ex(op->crypto_ctx, NULL, &len_out))
        {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            return TEE_ERROR_MAC_INVALID;
        }
#else
        int ret;
#ifndef BORING_SSL
        GCM128_CONTEXT *stCipher = (GCM128_CONTEXT *)op->crypto_ctx;
#else
        AES_GCM_ctx_t *gcmContext = (AES_GCM_ctx_t *)op->crypto_ctx;
        GCM128_CONTEXT *stCipher = &gcmContext->ctx;
#endif
        if (!stCipher) {
            MB_LOGE("Panic Reason: cipher is NULL\n");
            TEE_Panic(ID_TEE_AEDecryptFinal);
        }

        if (srcLen != 0) {
            if (!destData) {
                MB_LOGE("Panic Reason: destData is NULL\n");
                TEE_Panic(ID_TEE_AEDecryptFinal);
            }
#ifndef BORING_SSL
            ret = CRYPTO_gcm128_decrypt(stCipher, (unsigned char *)srcData, destData, srcLen);
#else
            ret = CRYPTO_gcm128_decrypt(stCipher, gcmContext->key, (unsigned char *)srcData, destData, srcLen);
#endif
            if (GCM_SUCCESS != ret) {
                MB_LOGE("Panic Reason: gcm128 decrypt failed\n");
                TEE_Panic(ID_TEE_AEDecryptFinal);
            }
            *destLen = srcLen;
        }

        if (operation->info.digestLength/8 != tagLen) {
            return TEE_ERROR_MAC_INVALID;
        }
        ret = CRYPTO_gcm128_finish(stCipher, tag, tagLen);
        if (GCM_SUCCESS != ret) return TEE_ERROR_MAC_INVALID;
#endif
    }

    TEE_ResetOperation(operation);

    return TEE_SUCCESS;
}

/* Asymmetric Functions*/


static void get_sign_mode_hash_cc(int alg, int *cc_type)
{
    switch(alg)
    {
    case TEE_ALG_RSASSA_PKCS1_V1_5_MD5:
        *cc_type = NID_md5;
        break;

    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA1:
        *cc_type = NID_sha1;
        break;

    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA224:
        *cc_type = NID_sha224;
        break;

    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA256:
        *cc_type = NID_sha256;
        break;

    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA384:
        *cc_type = NID_sha384;
        break;

    case TEE_ALG_RSASSA_PKCS1_V1_5_SHA512:
        *cc_type = NID_sha512;
        break;

    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1:
        *cc_type = NID_sha1;
        break;

    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224:
        *cc_type = NID_sha224;
        break;

    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:
        *cc_type = NID_sha256;
        break;

    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384:
        *cc_type = NID_sha384;
        break;

    case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512:
        *cc_type = NID_sha512;
        break;

    case TEE_ALG_DSA_SHA1:
    case TEE_ALG_DSA_SHA224:
    case TEE_ALG_DSA_SHA256:
        break;

    default:
        MB_LOGE("Panic Reason: unsupported algorithm\n");
        TEE_Panic(0);
    }
}

TEE_Result TEE_AsymmetricEncrypt( TEE_OperationHandle operation,
                                  const TEE_Attribute* params,
                                  uint32_t paramCount,
                                  const void* srcData,
                                  uint32_t srcLen,
                                  void* destData,
                                  uint32_t *destLen )
{
    check_operation_handle(operation, ID_TEE_AsymmetricEncrypt);

    RSA *rsa;
    const void *label;
    int label_len;
    int padding = 0;
    int labelHash = 0;

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (op->info.operationClass != TEE_OPERATION_ASYMMETRIC_CIPHER) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_ASYMMETRIC_CIPHER\n");
        TEE_Panic(ID_TEE_AsymmetricEncrypt);
    }
    if (!(operation->info.handleState & TEE_HANDLE_FLAG_KEY_SET)) {
        MB_LOGE("Panic Reason: operation handle key isn't set\n");
        TEE_Panic(ID_TEE_AsymmetricEncrypt);
    }
    if (op->info.mode != TEE_MODE_ENCRYPT) {
        MB_LOGE("Panic Reason: mode isn't TEE_MODE_ENCRYPT\n");
        TEE_Panic(ID_TEE_AsymmetricEncrypt);
    }

    unsigned int alg = operation->info.algorithm;
    object_to_rsa_cc(op->key1, &rsa);

    if (!rsa) {
        MB_LOGE("Panic Reason: rsa handle is NULL\n");
        TEE_Panic(ID_TEE_AsymmetricEncrypt);
    }

    if( !params && paramCount ) {
        MB_LOGE("Panic Reason: attribute params is NULL and paramCount is not NULL\n");
        TEE_Panic(ID_TEE_AsymmetricEncrypt);
    }

    if ( (size_t)RSA_size(rsa) > (*destLen) ) {
        return TEE_ERROR_SHORT_BUFFER;
    }
    if ((alg == TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1 ||
         alg == TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA224 ||
         alg == TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256 ||
         alg == TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA384 ||
         alg == TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA512) && params) {
        unsigned int i;
        /* Clean previously set label and label_len */
        if (!RSA_set_ex_data(rsa, 0, NULL) || !RSA_set_ex_data(rsa, 1, NULL)) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricEncrypt);
        }
        for (i = 0; i < paramCount; i++) {
            if (params[i].attributeID == TEE_ATTR_RSA_OAEP_LABEL) {
                label = params[i].content.ref.buffer;
                if (!label) {
                    MB_LOGE("Panic Reason: label is 0\n");
                    TEE_Panic(ID_TEE_AsymmetricEncrypt);
                }
                label_len = (int)params[i].content.ref.length;
                if (!RSA_set_ex_data(rsa, 0, (void *)label) ||
                    !RSA_set_ex_data(rsa, 1, (void *)(intptr_t)label_len)) {
                    if (CHECK_OSSL_MALLOC_FAILURE) {
                        return TEE_ERROR_OUT_OF_MEMORY;
                    }
                    PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricEncrypt);
                }
                break;
            }
            else if (params[i].attributeID == TEE_ATTR_RSA_OAEP_LABEL_HASH) {
                switch (params[i].content.value.a) {
                    case TEE_ALG_SHA1:
                        labelHash = RSA_PKCS1_OAEP_PADDING;
                        break;
                    case TEE_ALG_SHA224:
                        labelHash = RSA_PKCS1_OAEP_SHA224_PADDING;
                        break;
                    case TEE_ALG_SHA256:
                        labelHash = RSA_PKCS1_OAEP_SHA256_PADDING;
                        break;
                    case TEE_ALG_SHA384:
                        labelHash = RSA_PKCS1_OAEP_SHA384_PADDING;
                        break;
                    case TEE_ALG_SHA512:
                        labelHash = RSA_PKCS1_OAEP_SHA512_PADDING;
                        break;
                    default:
                        MB_LOGE("Panic Reason: wrong label hash!\n");
                        TEE_Panic(ID_TEE_AsymmetricEncrypt);
                        break;
                }
            }
        }
    }

    switch(alg) {
    case TEE_ALG_RSAES_PKCS1_V1_5:
        labelHash = padding = RSA_PKCS1_PADDING;
        break;
    case TEE_ALG_RSA_NOPAD:
        labelHash = padding = RSA_NO_PADDING;
        break;
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1:
        padding = RSA_PKCS1_OAEP_PADDING;
        break;
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA224:
        padding = RSA_PKCS1_OAEP_SHA224_PADDING;
        break;
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256:
        padding = RSA_PKCS1_OAEP_SHA256_PADDING;
        break;
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA384:
        padding = RSA_PKCS1_OAEP_SHA384_PADDING;
        break;
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA512:
        padding = RSA_PKCS1_OAEP_SHA512_PADDING;
        break;
    default:
        /* not supported padding*/
        MB_LOGE("Panic Reason: unsupported algorithm\n");
        TEE_Panic(ID_TEE_AsymmetricEncrypt);
    }

    if (labelHash == 0) {
        labelHash = padding;
    }

    if (!RSA_set_ex_data(rsa, 2, (void *)(intptr_t)labelHash)) {
        if (CHECK_OSSL_MALLOC_FAILURE) {
            return TEE_ERROR_OUT_OF_MEMORY;
        }
        PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricEncrypt);
    }

    *destLen = RSA_public_encrypt(srcLen, srcData, destData, rsa, padding);

    if (-1 == (int)*destLen) {
        unsigned long ulOsslError = ERR_peek_error();
        unsigned long ulOsslReason = ERR_GET_REASON(ulOsslError);
        if ( RSA_R_MODULUS_TOO_LARGE == ulOsslReason ||
                RSA_R_BAD_E_VALUE == ulOsslReason ||
                RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE == ulOsslReason ||
                RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE == ulOsslReason)
        {
            return TEE_ERROR_BAD_PARAMETERS;
        }
        MB_LOGE("Panic Reason: RSA encrypt failed\n");
        TEE_Panic(ID_TEE_AsymmetricEncrypt);
    }


    return TEE_SUCCESS;
}


TEE_Result TEE_AsymmetricDecrypt( TEE_OperationHandle operation,
                                  const TEE_Attribute* params,
                                  uint32_t paramCount,
                                  const void* srcData,
                                  uint32_t srcLen,
                                  void* destData,
                                  uint32_t *destLen)
{
    check_operation_handle(operation, ID_TEE_AsymmetricDecrypt);

    (void) srcLen;

    RSA *rsa;
    TEE_Result teeRes = TEE_SUCCESS;
    int padding = 0;
    int labelHash = 0;
    const void *label;
    int label_len;

    struct TEE_Operation *op = (struct TEE_Operation *) operation;

    if (op->info.operationClass != TEE_OPERATION_ASYMMETRIC_CIPHER) {
        MB_LOGE("Panic Reason: operation class isn't TEE_OPERATION_ASYMMETRIC_CIPHER\n");
        TEE_Panic(ID_TEE_AsymmetricDecrypt);
    }
    if (!(operation->info.handleState & TEE_HANDLE_FLAG_KEY_SET)) {
        MB_LOGE("Panic Reason: operation handle key isn't set\n");
        TEE_Panic(ID_TEE_AsymmetricDecrypt);
    }
    if (op->info.mode != TEE_MODE_DECRYPT) {
        MB_LOGE("Panic Reason: mode isn't TEE_MODE_DECRYPT\n");
        TEE_Panic(ID_TEE_AsymmetricDecrypt);
    }

    unsigned int alg = operation->info.algorithm;
    object_to_rsa_cc(op->key1, &rsa);

    if (!rsa) {
        MB_LOGE("Panic Reason: RSA handle is NULL\n");
        TEE_Panic(ID_TEE_AsymmetricDecrypt);
    }
    if( !params && paramCount ) {
        MB_LOGE("Panic Reason: attribute params is NULL and paramCount is not NULL\n");
        TEE_Panic(ID_TEE_AsymmetricEncrypt);
    }
    if ((alg == TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1 ||
         alg == TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA224 ||
         alg == TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256 ||
         alg == TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA384 ||
         alg == TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA512) && params) {
        unsigned int i;
        /* Clean previously set label and label_len */
        if (!RSA_set_ex_data(rsa, 0, NULL) || !RSA_set_ex_data(rsa, 1, NULL)) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricDecrypt);
        }
        for (i = 0; i < paramCount; i++) {
            if (params[i].attributeID == TEE_ATTR_RSA_OAEP_LABEL) {
                label = params[i].content.ref.buffer;
                if (!label) {
                    MB_LOGE("Panic Reason: label is NULL\n");
                    TEE_Panic(ID_TEE_AsymmetricDecrypt);
                }
                label_len = params[i].content.ref.length;
                if (!RSA_set_ex_data(rsa, 0, (void *)label) ||
                    !RSA_set_ex_data(rsa, 1, (void *)(intptr_t)label_len)) {
                    if (CHECK_OSSL_MALLOC_FAILURE) {
                        return TEE_ERROR_OUT_OF_MEMORY;
                    }
                    PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricDecrypt);
                }
                break;
            }
            else if (params[i].attributeID == TEE_ATTR_RSA_OAEP_LABEL_HASH) {
                switch (params[i].content.value.a) {
                    case TEE_ALG_SHA1:
                        labelHash = RSA_PKCS1_OAEP_PADDING;
                        break;
                    case TEE_ALG_SHA224:
                        labelHash = RSA_PKCS1_OAEP_SHA224_PADDING;
                        break;
                    case TEE_ALG_SHA256:
                        labelHash = RSA_PKCS1_OAEP_SHA256_PADDING;
                        break;
                    case TEE_ALG_SHA384:
                        labelHash = RSA_PKCS1_OAEP_SHA384_PADDING;
                        break;
                    case TEE_ALG_SHA512:
                        labelHash = RSA_PKCS1_OAEP_SHA512_PADDING;
                        break;
                    default:
                        MB_LOGE("Panic Reason: wrong label hash!\n");
                        TEE_Panic(ID_TEE_AsymmetricDecrypt);
                        break;
                }
            }
        }
    }

    /* flen must be less than RSA_size(rsa) - 11 for the PKCS #1 v1.5 based padding modes,
       less than RSA_size(rsa) - 41 for RSA_PKCS1_OAEP_PADDING and
       exactly RSA_size(rsa) for RSA_NO_PADDING.
       The random number generator must be seeded prior to calling RSA_public_encrypt().*/

    uint32_t sizRSAsize = (uint32_t) RSA_size(rsa);
    void* pMaxOutBuffer = TEE_Malloc( sizRSAsize, 0);
    if ( !pMaxOutBuffer ) {
        MB_LOGE("Failed to alloc out buffer\n");
        return TEE_ERROR_OUT_OF_MEMORY;
    }

    int nDecryptedLen = -1;
    switch(alg)
    {
    case TEE_ALG_RSAES_PKCS1_V1_5:
        labelHash = padding = RSA_PKCS1_PADDING;
        break;
    case TEE_ALG_RSA_NOPAD:
        labelHash = padding = RSA_NO_PADDING;
        break;
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1:
        padding = RSA_PKCS1_OAEP_PADDING;
        break;
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA224:
        padding = RSA_PKCS1_OAEP_SHA224_PADDING;
        break;
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256:
        padding = RSA_PKCS1_OAEP_SHA256_PADDING;
        break;
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA384:
        padding = RSA_PKCS1_OAEP_SHA384_PADDING;
        break;
    case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA512:
        padding = RSA_PKCS1_OAEP_SHA512_PADDING;
        break;
    default:
        /* not supported padding*/
        MB_LOGE("Panic Reason: unsupported algorithm\n");
        TEE_Panic(ID_TEE_AsymmetricDecrypt);
    }

    if (labelHash == 0) {
        labelHash = padding;
    }

    if (!RSA_set_ex_data(rsa, 2, (void *)(intptr_t)labelHash)) {
        if (CHECK_OSSL_MALLOC_FAILURE) {
            TEE_Free(pMaxOutBuffer);
            return TEE_ERROR_OUT_OF_MEMORY;
        }
        PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricDecrypt);
    }

    nDecryptedLen = RSA_private_decrypt(srcLen, srcData, pMaxOutBuffer, rsa, padding);

    /* Check if rsa encrypt has an error*/
    if (nDecryptedLen != -1) {
        /* Check if destination len is small*/
        if ((size_t)nDecryptedLen <= (*destLen)) {
            TEE_MemMove( destData, pMaxOutBuffer, (size_t) nDecryptedLen );
            *destLen = nDecryptedLen;
        } else {
            *destLen = nDecryptedLen = 0;
            teeRes = TEE_ERROR_SHORT_BUFFER;
            goto rsa_cleanup;
        }
    } else {
        nDecryptedLen = 0; /* reset value -1 to 0 to avoid buffer overflow*/
        unsigned long ulOsslError = ERR_peek_error();
        unsigned long ulOsslReason = ERR_GET_REASON(ulOsslError);
        if ( RSA_R_DATA_GREATER_THAN_MOD_LEN == ulOsslReason ||
                RSA_R_DATA_TOO_LARGE_FOR_MODULUS == ulOsslReason ) {
            teeRes = TEE_ERROR_BAD_PARAMETERS;
            goto rsa_cleanup;
        }
        MB_LOGE("Panic Reason: RSA private decrypt failed\n");
        TEE_Panic(ID_TEE_AsymmetricDecrypt);
    }

rsa_cleanup:
    /* clean up temporary buffer (it can consist secure keys)*/
    TEE_MemFill( pMaxOutBuffer, 0, nDecryptedLen );
    TEE_Free( pMaxOutBuffer);

    return teeRes;
}

#ifdef ECC_IMPLEMENTATION_DIGEST
static void calc_hash(const void* digest, size_t digestLen, unsigned int alg, unsigned char* hash, unsigned int* hashlen)
{
    switch (alg)
    {
    case TEE_ALG_ECDSA_P160:
        sha1( digest, digestLen, hash );
        *hashlen = 20;
        break;
    case TEE_ALG_ECDSA_P192:
        sha1( digest, digestLen, hash );
        *hashlen = 20;
        break;
    case TEE_ALG_ECDSA_P224:
        sha2( digest, digestLen, hash, 1 /* 1 for 224 */ );
        *hashlen = 28;
        break;
    case TEE_ALG_ECDSA_P256:
        sha2( digest, digestLen, hash, 0 /* 0 for 256 */ );
        *hashlen = 32;
        break;
    case TEE_ALG_ECDSA_P384:
        sha4( digest, digestLen, hash, 1 /* 1 for 384 */ );
        *hashlen = 48;
        break;
    case TEE_ALG_ECDSA_P521:
        sha4( digest, digestLen, hash, 0 /* 0 for 512 */ );
        *hashlen = 64;
        break;
    default:
        MB_LOGE("Panic Reason: unsupported algorithm\n");
        TEE_Panic(ID_TEE_AsymmetricDecrypt);
        break;
    }
}
#endif

#if defined(ECC_IMPLEMENTATION)

static int ec_key_order_num_bytes(const EC_KEY *key, size_t *num)
{
    const EC_GROUP *ec_group;
    BIGNUM *bn_order;

    if (!(ec_group = EC_KEY_get0_group(key))) return 0;

    if (!(bn_order = BN_new())) return 0;

    if (!EC_GROUP_get_order(ec_group, bn_order, NULL)) {
        BN_free(bn_order);
        return 0;
    }

    *num = BN_num_bytes(bn_order);

    BN_free(bn_order);
    return 1;
}

static int cc_ecdsa_sign(const unsigned char *dgst, int dlen, unsigned char *sig,
                         unsigned int *siglen, EC_KEY *eckey, size_t order_len)
{
    ECDSA_SIG *ec_sig;
    int off;

    ec_sig = ECDSA_do_sign(dgst, dlen, eckey);
    if (!ec_sig) {
        return 0;
    }

    TEE_MemFill(sig, 0, order_len*2);

    off = order_len - BN_num_bytes(ec_sig->r);
    BN_bn2bin(ec_sig->r, sig + off);

    off = order_len - BN_num_bytes(ec_sig->s);
    BN_bn2bin(ec_sig->s, sig + order_len + off);

    *siglen = order_len*2;

    ECDSA_SIG_free(ec_sig);

    return 1;
}

#endif /* defined(ECC_IMPLEMENTATION) */

#ifndef OPENSSL_NO_DSA

static int cc_dsa_sign(const unsigned char *dgst, int dlen, unsigned char *sig,
        unsigned int *siglen, DSA *dsa, size_t dsa_subprime_len)
{
    DSA_SIG * dsa_sig;
    int off;
    if (!(dsa_sig = DSA_do_sign(dgst, dlen, dsa))) {
        return 0;
    }

    TEE_MemFill(sig, 0, dsa_subprime_len * 2);

    off = dsa_subprime_len - BN_num_bytes(dsa_sig->r);
    BN_bn2bin(dsa_sig->r, sig + off);

    off = dsa_subprime_len - BN_num_bytes(dsa_sig->s);
    BN_bn2bin(dsa_sig->s, sig + dsa_subprime_len + off);

    *siglen = dsa_subprime_len * 2;

    DSA_SIG_free(dsa_sig);
    return 1;
}

#endif /* OPENSSL_NO_DSA */

TEE_Result TEE_AsymmetricSignDigest( TEE_OperationHandle operation, const TEE_Attribute* params, uint32_t paramCount, const void* digest, uint32_t digestLen, void* signature, uint32_t *signatureLen )
{
    check_operation_handle(operation, ID_TEE_AsymmetricSignDigest);

    int rc = -1;

    struct TEE_Operation *op = (struct TEE_Operation *) operation;
    unsigned int alg = operation->info.algorithm;

    if (TEE_MODE_SIGN != op->info.mode ||
            TEE_OPERATION_ASYMMETRIC_SIGNATURE != op->info.operationClass) {
        MB_LOGE("Panic Reason: operation class isn't "
                  "TEE_OPERATION_ASYMMETRIC_SIGNATURE or mode ins't TEE_MODE_SIGN\n");
        TEE_Panic(ID_TEE_AsymmetricSignDigest);
    }

    if (!check_digest_size(alg, digestLen)) {
        MB_LOGE("Panic Reason: digestLen is not equal to the hash size of the algorithm\n");
        TEE_Panic(ID_TEE_AsymmetricSignDigest);
    }

#ifndef OPENSSL_NO_DSA
    if (alg == TEE_ALG_DSA_SHA1 || alg == TEE_ALG_DSA_SHA224 || alg == TEE_ALG_DSA_SHA256) {
        size_t dsa_subprime_len = 0;
        if (alg == TEE_ALG_DSA_SHA1)
            dsa_subprime_len = 20;
        else if (alg == TEE_ALG_DSA_SHA224)
            dsa_subprime_len = 28;
        else if (alg == TEE_ALG_DSA_SHA256)
            dsa_subprime_len = 32;
        DSA *dsa;
        uint32_t order_len;

        if (!params && paramCount) {
            MB_LOGE("Panic: attribute params is NULL and paramCount is not 0\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        if ((paramCount > 1) || (params && (params[0].attributeID != TEE_ATTR_DSA_SIGN_FORMAT))) {
            MB_LOGE("Panic: number of params is too much or wrong params type\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        object_to_dsa_cc(op->key1, &dsa);

        if (!dsa) {
            MB_LOGE("Panic Reason: DSA handle is NULL\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        if (params == NULL || params[0].content.value.a == TEE_DSA_SIGN_FORMAT_BIGINT) {
            order_len = dsa_subprime_len * 2;
        } else if (params[0].content.value.a == TEE_DSA_SIGN_FORMAT_ASN) {
            order_len = (uint32_t) DSA_size(dsa);
        } else {
            MB_LOGE("Panic: wrong parameter\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        if (*signatureLen < order_len) {
            return TEE_ERROR_SHORT_BUFFER;
        }

        if (params == NULL || params[0].content.value.a == TEE_DSA_SIGN_FORMAT_BIGINT) {
            rc = cc_dsa_sign(digest, digestLen, signature, signatureLen, dsa, dsa_subprime_len);
        } else {
            rc = DSA_sign(0, digest, digestLen, signature, signatureLen, dsa);
        }

        if (!rc) {
            MB_LOGE("Panic: failed DSA sign\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        return TEE_SUCCESS;
    }
#endif /* OPENSSL_NO_DSA */
    
#ifdef ECC_IMPLEMENTATION
    else if (TEE_ALG_ECDSA_P160 == alg ||
             TEE_ALG_ECDSA_P192 == alg ||
             TEE_ALG_ECDSA_P224 == alg ||
             TEE_ALG_ECDSA_P256 == alg ||
             TEE_ALG_ECDSA_P384 == alg ||
             TEE_ALG_ECDSA_P521 == alg) {
        EC_KEY *ec_key;
        size_t order_len;

        if (!digest || !signatureLen || !signature) {
            MB_LOGE("Panic: digest or signature is NULL or signature length is 0\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        if (!params && paramCount) {
            MB_LOGE("Panic: attribute params is NULL and paramCount is not 0\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        if ((paramCount > 1) || (params && (params[0].attributeID != TEE_ATTR_ECDSA_SIGN_FORMAT))) {
            MB_LOGE("Panic: number of params is too much or wrong params type\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        object_to_ecc_cc(op->key1, &ec_key);
        if (!ec_key) {
            MB_LOGE("Panic: key is NULL\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        if (params == NULL || params[0].content.value.a == TEE_ECDSA_SIGN_FORMAT_BIGINT) {
            if (!ec_key_order_num_bytes(ec_key, &order_len)) {
                MB_LOGE("Panic: failed to get key order number of bytes\n");
                TEE_Panic(ID_TEE_AsymmetricSignDigest);
            }
            order_len *= 2;
        } else if (params[0].content.value.a == TEE_ECDSA_SIGN_FORMAT_ASN) {
            order_len = (uint32_t) ECDSA_size(ec_key);
        } else {
            MB_LOGE("Panic: wrong parameter\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        if (*signatureLen < order_len) {
            return TEE_ERROR_SHORT_BUFFER;
        }

        if (params == NULL || params[0].content.value.a == TEE_ECDSA_SIGN_FORMAT_BIGINT) {
            rc = cc_ecdsa_sign(digest, digestLen, signature, signatureLen, ec_key, order_len / 2);
        } else {
            rc = ECDSA_sign(0, digest, digestLen, signature, signatureLen, ec_key);
        }

        if (!rc) {
            MB_LOGE("Panic: failed ECDSA sign\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        return TEE_SUCCESS;
    }
#endif /* ECC_IMPLEMENTATION */
    else
    {
        RSA *rsa;
        /*
         * From OpenSSL implementation:
         * Negative salt_len has special meanings:
         *	-1	salt_len == hash length
         *	-2	salt length is maximized
         *	-N	reserved
         * salt_len = -1 is requiered by GPAPI Specification v.1.1
        */
        int salt_len = -1;
        int cc_type;

        if (!digest || !signatureLen || !signature) {
            MB_LOGE("Panic Reason: digest(%p) or signature(%p) "
                      "or signatureLen(%p) is NULL\n",
                      digest, signature, signatureLen);
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        get_sign_mode_hash_cc(alg, &cc_type);

        object_to_rsa_cc(op->key1, &rsa);
        if (!rsa) {
            MB_LOGE("Panic Reason: RSA handle is NULL\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        if( !params && paramCount ) {
            MB_LOGE("Panic Reason: attribute params is NULL and paramCount is not NULL\n");
            TEE_Panic(ID_TEE_AsymmetricSignDigest);
        }

        if (*signatureLen < (size_t)RSA_size(rsa)) {
            return TEE_ERROR_SHORT_BUFFER;
        }
        ERR_clear_error();
        if (   0
#ifndef OPENSSL_NO_SHA1
                 || alg == TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1
#endif
#ifndef OPENSSL_NO_SHA256
                 || alg == TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224
                 || alg == TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256
#endif
#ifndef OPENSSL_NO_SHA512
                 || alg == TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384
                 || alg == TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512
#endif
                ) {

            const EVP_MD *md = NULL;
            ERR_clear_error();
            md = EVP_get_digestbynid(cc_type);
            if (!md) {
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                MB_LOGE("Panic Reason: MD handle is NULL\n");
                TEE_Panic(ID_TEE_AsymmetricSignDigest);
            }

            unsigned char *to_be_signed = TEE_Malloc(RSA_size(rsa), HINT_FILL_WITH_ZEROS);
            if (!to_be_signed) {
                MB_LOGE("Panic Reason: failed to allocate %d bytes\n", RSA_size(rsa));
                TEE_Panic(ID_TEE_AsymmetricSignDigest);
            }

            if (params != NULL) {
	        unsigned int i;
	        for(i = 0; i < paramCount; i++) {
		    if (params[i].attributeID == TEE_ATTR_RSA_PSS_SALT_LENGTH) {
		        salt_len = params[i].content.value.a;
		        break;
		    }
	        }
            }

            if (!RSA_padding_add_PKCS1_PSS_mgf1(rsa, to_be_signed, digest, md, md, salt_len)) {
                TEE_Free(to_be_signed);
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricSignDigest);
            }

            rc = RSA_private_encrypt(RSA_size(rsa), to_be_signed, signature, rsa, RSA_NO_PADDING);
            if (rc < 0) {
                TEE_Free(to_be_signed);
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricSignDigest);
            }

            *signatureLen = rc;

            TEE_Free(to_be_signed);
            return TEE_SUCCESS;
        } /* if (params && */
        unsigned int sigLen;
        rc = RSA_sign(cc_type, digest, digestLen, signature, &sigLen, rsa);

        if (!rc) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricSignDigest);
        }

        *signatureLen = sigLen;

    }
    return TEE_SUCCESS;
}

TEE_Result TEE_AsymmetricVerifyDigest( TEE_OperationHandle operation, const TEE_Attribute* params, uint32_t paramCount, const void* digest, uint32_t digestLen, const void* signature, uint32_t signatureLen )
{
    check_operation_handle(operation, ID_TEE_AsymmetricVerifyDigest);

    int rc;

    struct TEE_Operation *op = (struct TEE_Operation *) operation;
    unsigned int alg = operation->info.algorithm;

    if (TEE_MODE_VERIFY != op->info.mode ||
            TEE_OPERATION_ASYMMETRIC_SIGNATURE != op->info.operationClass) {
        MB_LOGE("Panic Reason: operation mode 0x%x != TEE_MODE_VERIFY or"
                  "operation class 0x%x != TEE_OPERATION_ASYMMETRIC_SIGNATURE\n",
                  op->info.mode, op->info.operationClass);
        TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
    }

    if( !params && paramCount ) {
        MB_LOGE("Panic Reason: attribute params is NULL and paramCount is not NULL\n");
        TEE_Panic(ID_TEE_AsymmetricEncrypt);
    }

    if (!check_digest_size(alg, digestLen)) {
        MB_LOGE("Panic Reason: digestLen is not equal to the hash size of the algorithm\n");
        TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
    }

    if (!digest || !signature) {
        MB_LOGE("Panic Reason: digest(%p) or signature(%p) is NULL\n",
                  digest, signature);
        TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
    }

#ifndef OPENSSL_NO_DSA
    if (alg == TEE_ALG_DSA_SHA1 || alg == TEE_ALG_DSA_SHA224 || alg == TEE_ALG_DSA_SHA256) {
        size_t dsa_subprime_len = 0;
        if (alg == TEE_ALG_DSA_SHA1)
            dsa_subprime_len = 20;
        else if (alg == TEE_ALG_DSA_SHA224)
            dsa_subprime_len = 28;
        else if (alg == TEE_ALG_DSA_SHA256)
            dsa_subprime_len = 32;

        DSA *dsa;
        int rc;

        if (digestLen != dsa_subprime_len) {
            MB_LOGE("Panic Reason: digest length (%" PRIu32 ") isn't "
                      "equal to subprime length (%zu)\n",
                      digestLen, dsa_subprime_len);
            TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
        }

        if ((paramCount > 1) || (params && (params[0].attributeID != TEE_ATTR_DSA_SIGN_FORMAT))) {
            MB_LOGE("Panic: number of params is too much or wrong params type\n");
            TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
        }

        object_to_dsa_cc(op->key1, &dsa);
        if (!dsa) {
            MB_LOGE("Panic Reason: DSA handle is NULL\n");
            TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
        }

        if (params == NULL || params[0].content.value.a == TEE_DSA_SIGN_FORMAT_BIGINT) {
            DSA_SIG *sig;

            if (signatureLen != dsa_subprime_len*2) {
                TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
            }

            sig = DSA_SIG_new();
            if (!sig) {
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricVerifyDigest);
            }

            if (!(sig->r = BN_bin2bn(signature, dsa_subprime_len, NULL))
                    || !(sig->s = BN_bin2bn((unsigned char*)signature + dsa_subprime_len,
                            dsa_subprime_len, NULL))) {
                DSA_SIG_free(sig);
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricVerifyDigest);
            }

            rc = DSA_do_verify(digest, digestLen, sig, dsa);

            DSA_SIG_free(sig);
        } else if (params[0].content.value.a == TEE_DSA_SIGN_FORMAT_ASN) {
            rc = DSA_verify(0, digest, digestLen, signature, signatureLen, dsa);
        } else {
            MB_LOGE("Panic: wrong parameter\n");
            TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
        }


        if (rc == 1) {
            return TEE_SUCCESS;
        } else if (rc == 0) {
            return TEE_ERROR_SIGNATURE_INVALID;
        } else {
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricVerifyDigest);
        }
    }
#endif /* OPENSSL_NO_DSA */

#ifdef ECC_IMPLEMENTATION
    else if (TEE_ALG_ECDSA_P160 == alg ||
             TEE_ALG_ECDSA_P192 == alg ||
             TEE_ALG_ECDSA_P224 == alg ||
             TEE_ALG_ECDSA_P256 == alg ||
             TEE_ALG_ECDSA_P384 == alg ||
             TEE_ALG_ECDSA_P521 == alg)
    {
        EC_KEY *ec_key;
        int res;

        if (!params && paramCount) {
            MB_LOGE("Panic: attribute params is NULL and paramCount is not 0\n");
            TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
        }

        if ((paramCount > 1) || (params && (params[0].attributeID != TEE_ATTR_ECDSA_SIGN_FORMAT))) {
            MB_LOGE("Panic: number of params is too much or wrong params type\n");
            TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
        }

        object_to_ecc_cc(op->key1, &ec_key);

        if (!ec_key) {
            MB_LOGE("Panic: key is NULL\n");
            TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
        }

        if (params == NULL || params[0].content.value.a == TEE_ECDSA_SIGN_FORMAT_BIGINT) {
            ECDSA_SIG *ec_sig;
            BIGNUM *bn_r;
            BIGNUM *bn_s;
            size_t r_size;
            size_t s_size;

            if (!(ec_sig = ECDSA_SIG_new())) {
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricVerifyDigest);
            }

            r_size = s_size = signatureLen >> 1;
            if (!(bn_r = BN_bin2bn((unsigned char *) signature, r_size, ec_sig->r))) {
                ECDSA_SIG_free(ec_sig);
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricVerifyDigest);
            }

            if (!(bn_s = BN_bin2bn((unsigned char *) signature + r_size, s_size, ec_sig->s))) {
                ECDSA_SIG_free(ec_sig);
                if (CHECK_OSSL_MALLOC_FAILURE) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricVerifyDigest);
            }

            ec_sig->r = bn_r;
            ec_sig->s = bn_s;
            ERR_clear_error();

            res = ECDSA_do_verify(digest, digestLen, ec_sig, ec_key);

            ECDSA_SIG_free(ec_sig);
        } else if (params[0].content.value.a == TEE_ECDSA_SIGN_FORMAT_ASN) {
            res = ECDSA_verify(0, digest, digestLen, signature, signatureLen, ec_key);
        } else {
            MB_LOGE("Panic: wrong parameter\n");
            TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
        }

        if (res == -1) {
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricVerifyDigest);
        }

        if (!res) return TEE_ERROR_SIGNATURE_INVALID;

        return TEE_SUCCESS;
    }
#endif /* ECC_IMPLEMENTATION */
    else {
        RSA *rsa;
        int salt_len = -2;
        int cc_type;

        get_sign_mode_hash_cc(alg, &cc_type);

        object_to_rsa_cc(op->key1, &rsa);
        if (!rsa) {
            MB_LOGE("Panic Reason: RSA handle is NULL\n");
            TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
        }

        if (
#ifndef OPENSSL_NO_SHA1
                    alg == TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1
#endif
#ifndef OPENSSL_NO_SHA256
                 || alg == TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224
                 || alg == TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256
#endif
#ifndef OPENSSL_NO_SHA512
                 || alg == TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384
                 || alg == TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512
#endif
                ) {
            const EVP_MD *md = NULL;

            md = EVP_get_digestbynid(cc_type);
            if (!md) {
                MB_LOGE("Panic Reason: MD handle is NULL\n");
                TEE_Panic(ID_TEE_AsymmetricVerifyDigest);
            }

            unsigned char *decr_sig = TEE_Malloc(RSA_size(rsa), HINT_FILL_WITH_ZEROS);
            if (!decr_sig) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }

            rc = RSA_public_decrypt(signatureLen, signature, decr_sig, rsa, RSA_NO_PADDING);
            if (rc <= 0) {
                TEE_Free(decr_sig);
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_AsymmetricVerifyDigest);
            }

            if (params) {
                unsigned int i;
                for(i = 0; i < paramCount; i++) {
                    if (params[i].attributeID == TEE_ATTR_RSA_PSS_SALT_LENGTH) {
                        salt_len = params[i].content.value.a;
                        break;
                    }
                }
            }

            TEE_Result ret = TEE_SUCCESS;
            rc = RSA_verify_PKCS1_PSS_mgf1(rsa, digest, md, md, decr_sig, salt_len);
            if (!rc) {
                PRINT_OSSL_ERROR();
                ret = TEE_ERROR_SIGNATURE_INVALID;
            }

            TEE_Free(decr_sig);
            return ret;
        }

        rc = RSA_verify(cc_type, digest, digestLen, signature, signatureLen, rsa);
        if (!rc) {
            if (CHECK_OSSL_MALLOC_FAILURE) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            return TEE_ERROR_SIGNATURE_INVALID;
        }
    }
    return TEE_SUCCESS;
}

/* Key Derivation Functions*/

void TEE_DeriveKey( TEE_OperationHandle operation, const TEE_Attribute* params, uint32_t paramCount, TEE_ObjectHandle derivedKey)
{
    check_operation_handle(operation, ID_TEE_DeriveKey);

    (void)derivedKey;
    (void)paramCount;

    struct TEE_Operation *op = (struct TEE_Operation *) operation;
    unsigned int alg = operation->info.algorithm;

    if (op->info.operationClass != TEE_OPERATION_KEY_DERIVATION) {
        MB_LOGE("Panic Reason: operation class isn't "
                  "TEE_OPERATION_KEY_DERIVATION\n");
        TEE_Panic(ID_TEE_DeriveKey);
    }
    if (!params) {
        MB_LOGE("Panic Reason: attribute params is NULL\n");
        TEE_Panic(ID_TEE_DeriveKey);
    }
    if (op->info.mode != TEE_MODE_DERIVE) {
        MB_LOGE("Panic Reason: operation mode isn't TEE_MODE_DERIVE\n");
        TEE_Panic(ID_TEE_DeriveKey);
    }

    switch (alg) {
#ifndef OPENSSL_NO_DH
    case TEE_ALG_DH_DERIVE_SHARED_SECRET: {
        const unsigned char *pub_key = NULL;
        DH *dh;
        size_t pub_key_len = 0;
        TEE_Attribute attrs[1];
        BIGNUM *bn = NULL;
        unsigned char *buf = NULL;
        size_t secret_len;
        uint32_t i;

        object_to_dh_cc(op->key1, &dh);
        if (!dh) {
            MB_LOGE("Panic Reason: DH handle is NULL\n");
            goto dh_err;
        }

        for (i = 0; i < paramCount; i++) {
            if (params[i].attributeID == TEE_ATTR_DH_PUBLIC_VALUE) {
                pub_key = params[i].content.ref.buffer;
                pub_key_len = params[i].content.ref.length;
                break;
            }
        }
        if (!pub_key) {
            MB_LOGE("Panic Reason: public key is NULL\n");
            goto dh_err;
        }

        bn = BN_bin2bn(pub_key, pub_key_len, NULL);
        if (!bn) {
            PRINT_OSSL_ERROR();
            goto dh_err;
        }

        secret_len = (size_t) DH_size(dh);

        buf = OPENSSL_malloc(secret_len);
        if (!buf) {
            MB_LOGE("Panic Reason: failed to allocate %zu bytes\n", secret_len);
            goto dh_err;
        }

        if ((int) (secret_len = DH_compute_key(buf, bn, dh)) == -1) {
            PRINT_OSSL_ERROR();
            goto dh_err;
        }

        TEE_InitRefAttribute(&attrs[0], TEE_ATTR_SECRET_VALUE, buf, secret_len);
        if (TEE_PopulateTransientObject(derivedKey, attrs, 1) != TEE_SUCCESS) {
            MB_LOGE("Panic reason: failed to populate transient object\n");
            goto dh_err;
        }

        BN_free(bn);
#ifndef USE_SCRYPTO_VER2_4        
        OPENSSL_cleanse(buf, secret_len);
#endif        
        OPENSSL_free(buf);
        break;
        dh_err: if (bn)
            BN_free(bn);
        if (buf) {
#ifndef USE_SCRYPTO_VER2_4            
            OPENSSL_cleanse(buf, DH_size(dh));
#endif            
            OPENSSL_free(buf);
        }
        TEE_Panic(ID_TEE_DeriveKey);
        break;
    }
#endif /* OPENSSL_NO_DH */
#ifndef OPENSSL_NO_ECDH
    case TEE_ALG_ECDH_P192:
    case TEE_ALG_ECDH_P224:
    case TEE_ALG_ECDH_P256:
    case TEE_ALG_ECDH_P384:
    case TEE_ALG_ECDH_P521:
    {
        EC_KEY *our_privatekey;
        uint32_t i;
        const unsigned char *Qx = NULL, *Qy = NULL;
        size_t Qx_len = 0, Qy_len = 0;
        BIGNUM bn_Qx, bn_Qy;
        EC_POINT *peer_publickey;
        const EC_GROUP *ec_group;
        int field_size, secret_len;
        unsigned char *buf;
        uint32_t rv;

        TEE_Attribute attrs[1];

        object_to_ecc_cc(op->key1, &our_privatekey);
        if (!our_privatekey) {
            MB_LOGE("Panic reason: private key is NULL\n");
            TEE_Panic(ID_TEE_DeriveKey);
        }

        if (!EC_KEY_check_key(our_privatekey)) {
            MB_LOGE("Panic reason: key check failed\n");
            TEE_Panic(ID_TEE_DeriveKey);
        }

        ec_group = EC_KEY_get0_group(our_privatekey);

        /* Get peer's public key */
        for (i = 0; i < paramCount; i++) {
            switch (params[i].attributeID) {
            case TEE_ATTR_ECC_PUBLIC_VALUE_X:
                Qx = params[i].content.ref.buffer;
                Qx_len = params[i].content.ref.length;
                break;
            case TEE_ATTR_ECC_PUBLIC_VALUE_Y:
                Qy = params[i].content.ref.buffer;
                Qy_len = params[i].content.ref.length;
                break;
            }
        }

        /* Check mandatory parameters */
        if (!Qx || !Qx_len || !Qy || !Qy_len) {
            MB_LOGE("Panic reason: some of Qx(%p) Qx_len(%zu) Qy(%p) Qy_len(%zu)"
                      " is 0 or NULL\n", Qx, Qx_len, Qy, Qy_len);
            TEE_Panic(ID_TEE_DeriveKey);
        }

        /* Convert public key into EC_POINT */
        BN_init(&bn_Qx);
        BN_init(&bn_Qy);
        if (!BN_bin2bn(Qx, Qx_len, &bn_Qx)) {
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_DeriveKey);
        }
        if (!BN_bin2bn(Qy, Qy_len, &bn_Qy)) {
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_DeriveKey);
        }

        peer_publickey = EC_POINT_new(ec_group);
        if (!peer_publickey) {
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_DeriveKey);
        }

        if (!EC_POINT_set_affine_coordinates_GFp(ec_group, peer_publickey, &bn_Qx, &bn_Qy, NULL)) {
            BN_free(&bn_Qx);
            BN_free(&bn_Qy);
            EC_POINT_free(peer_publickey);
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_DeriveKey);
        }

        BN_free(&bn_Qx);
        BN_free(&bn_Qy);

        /* Calculate the size of the buffer for the shared secret */
        if (!(field_size = EC_GROUP_get_degree(ec_group))) TEE_Panic(ID_TEE_DeriveKey);
        secret_len = (field_size + 7) >> 3;

        /* Allocate memory for secret */
        buf = OPENSSL_malloc(secret_len);
        if (!buf) {
            EC_POINT_free(peer_publickey);
            MB_LOGE("Panic Reason: failed to allocate %d bytes\n", secret_len);
            PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_DeriveKey);
        }

        /* Derive the shared secret */
        secret_len = ECDH_compute_key(buf, secret_len, peer_publickey, our_privatekey, NULL);

        EC_POINT_free(peer_publickey);

        if (secret_len == -1) {
            OPENSSL_free(buf);
            MB_LOGE("Panic reason: ECDH_compute_key() failed\n");
            TEE_Panic(ID_TEE_DeriveKey);
        }

        TEE_InitRefAttribute(&attrs[0], TEE_ATTR_SECRET_VALUE, buf, secret_len);
        rv = TEE_PopulateTransientObject(derivedKey, attrs, 1);

#ifndef USE_SCRYPTO_VER2_4
        OPENSSL_cleanse(buf, secret_len);
#endif        
        OPENSSL_free(buf);

        if (rv != TEE_SUCCESS) {
            MB_LOGE("Panic reason: failed to populate transient object\n");
            TEE_Panic(ID_TEE_DeriveKey);
        }

        break;
    }
#endif /* OPENSSL_NO_ECDH */
    default:
        MB_LOGE("Panic reason: unknown algorithm value(0x%x)\n", alg);
        TEE_Panic(ID_TEE_DeriveKey);
        break;
    }
}

int32_t getRandBlock(uint8_t *buf, uint32_t len)
{
    (void)buf;
    (void)len;
    return 0;
}

int init_crypto(void)
{
    static int cc_init_done = 0;
    if( cc_init_done )
        return cc_init_done;

#if !defined(BORING_SSL) && !defined(HOST_OPENSSL)
    InitPDRandEntropySource((Entropy_f_t) getRandBlock);

    if (cryptolib_init() != 1) {
        MB_LOGE("cryptolib_init() failed\n");
        TEE_Panic(TEE_ERROR_BAD_STATE);
    }
#endif
    cc_init_done = 1;

    return cc_init_done;
}

void fini_crypto(void)
{
    /* Cleanup of Cryptocore library resources */
    /* EVP_cleanup(); */
}
