#include "ssp_util.h"
#include "sem.h"
#include "tz_utils.h"

#include "tz_debug.h"
#include "tz_platform.h"

#include "sec_apdu.h"

#ifdef USE_BLOWFISH
#ifndef NULL
#define NULL '\0'
#endif
#endif

#ifdef USE_TRUSTY_UNISOC
#include <lib/storage/storage.h>
#endif

#if defined(USE_QSEE)

#ifdef SECBOOT_OEM_SECAPP
// Seperate secure object target TA name between model sign. and chip sign.
const static int gChipSignTaListCnt = 3;
const static char gChipSignTaList[gChipSignTaListCnt][MAX_QSEE_ID_SIZE] = {
    "chncmm_pay", "passese", "digital_key"};
#endif

#if defined(USE_ALT_ROTHASH)
#include "qsee_cfg_prop.h"
#define MAX_DISTNAME_PREFIX_SZ      128
#define MAX_TANAME_SZ               32
#define MAX_FULLNAME_SZ             160

#define ALT_ROT_DOMAIN_NAME         "alt_rot_domain_name_dot"
#define DL_ROT_DOMAIN_NAME          "dl_rot_domain_name_dot"

void get_alt_rot_distname(const char *prop_name, char *i_appname, char *o_distname) {
    uint32_t ret_size = 0;
    size_t len = 0;
    qsee_cfg_propvar_t *ptr = NULL;
    uint32_t prop[2 + (MAX_DISTNAME_PREFIX_SZ / sizeof(uint32_t))] = {0};
    char distname_prefix[MAX_DISTNAME_PREFIX_SZ] = {0};
    if (QSEE_CFG_SUCCESS != qsee_cfg_getpropval(prop_name,
                                                strlen(prop_name) + 1, 0,
                                                (qsee_cfg_propvar_t *)&prop,
                                                sizeof(prop), &ret_size)) {
        LOGE("'alt_rot_domain_name_dot' read failed, using legacy appname");
        ret_size = strlcpy(o_distname, i_appname, MAX_TANAME_SZ);
        return;
    }
    ptr = (qsee_cfg_propvar_t *)prop;
    /* len = ret_size - sizeof(qsee_cfg_propvar_t) + padding */
    len = ret_size - sizeof(*ptr) + 2 * sizeof(ptr->val) + 1;
    if (len + 1 > sizeof(distname_prefix)) {
        LOGE("'alt_rot_domain_name_dot' len invalid, using legacy appname");
        strlcpy(o_distname, i_appname, MAX_TANAME_SZ);
        return;
    }
    /* remove the quotes only when read from devcfg */
    memcpy(distname_prefix, &ptr->val[1], len - 1);
    distname_prefix[len] = '\0';
    /* finalize fully qualified distname */
    strlcpy(o_distname, distname_prefix, MAX_DISTNAME_PREFIX_SZ);
    strlcat(o_distname, i_appname, MAX_FULLNAME_SZ);
}
#endif
#endif

#ifdef USE_BLOWFISH
#include <tees_secure_object.h>
#include <tee_internal_api.h>
#endif

//#define GET_SSP_CERTIFICATE

#ifdef DEBUG_LOW
#define GET_SSP_CERTIFICATE
#define SKIP_GET_CERT_VERIFICATION
#endif

SSPSTATUS verify_casd_cert(uint8_t *cert, uint32_t cert_size, uint8_t eSEPubKey[SSP_ECC_PUBKEY_SIZE], uint8_t sspVer[2]) {
    SSPSTATUS status = SSPSTATUS_SUCCESS;
    uint32_t cur_pos = 0;
    uint32_t sig_start_pos, sig_data_start_pos, sig_data_size;
    uint32_t sig_size = 2 + 1 + 64;
#if defined(COMMON_VENDOR)
    uint8_t eSERootPubKey[] = {
        0x04, 0x9D, 0x89, 0x9A, 0xA9, 0x03, 0x5D, 0x27, 0x6D, 0xAE, 0x20, 0xD5, 0x95, 0x7F, 0x1A, 0x4E, 0xA0,
        0xC2, 0x4D, 0x4B, 0x41, 0xE9, 0x10, 0xF9, 0x76, 0x95, 0xEE, 0x88, 0xC5, 0xCA, 0xBA, 0xB0, 0x73,
        0x4F, 0x9E, 0x33, 0x9D, 0x54, 0xC3, 0x60, 0x9B, 0x51, 0x8C, 0xD1, 0x3B, 0x71, 0x8D, 0xE7, 0x6C,
        0x16, 0x77, 0x74, 0x93, 0x7C, 0xE3, 0x10, 0xB6, 0xD7, 0x22, 0xDA, 0xCC, 0x08, 0xA1, 0x1F, 0x58};

    if (chip_vendor < CHIP_VENDOR_THALES_UT20) {
        uint8_t eSERootPubKeyNxp[] = {
            0x04, 0xa8, 0x49, 0x4e, 0xc8, 0xe8, 0x84, 0x78, 0x6a, 0xf9, 0xb1, 0x8d, 0x54, 0x0e, 0x25, 0xef, 0xfe,
            0xeb, 0xa1, 0x06, 0x25, 0xf0, 0x3e, 0xff, 0x59, 0xe9, 0xc5, 0xfb, 0xdc, 0xc5, 0x54, 0xdd, 0x0f,
            0xf0, 0xc0, 0x59, 0x98, 0x82, 0xa5, 0xd9, 0xdc, 0x21, 0x97, 0x3d, 0xa7, 0x27, 0xfe, 0x6e, 0x97,
            0xf0, 0x74, 0xba, 0xfc, 0x3b, 0x6b, 0x87, 0xaf, 0x45, 0xa2, 0x01, 0x7e, 0x8d, 0x7a, 0x69, 0xa7};

        memcpy(eSERootPubKey, eSERootPubKeyNxp, sizeof(eSERootPubKey));
    }
#elif defined(OT)
    // PROD key
    uint8_t eSERootPubKey[] = {
        0x04, 0xf8, 0xc2, 0x2b, 0x2e, 0xb2, 0x4d, 0x91, 0xcc, 0x09, 0xfe, 0x6b, 0x66, 0x8d, 0xf9, 0xdf, 0x62,
        0x58, 0xb0, 0x2b, 0x77, 0x41, 0xb5, 0xba, 0x69, 0xf5, 0x97, 0x8f, 0xd3, 0x8f, 0xef, 0xee, 0x68,
        0x3e, 0xa2, 0xc8, 0x25, 0x0e, 0x6d, 0x2e, 0x0c, 0x8f, 0x0f, 0x41, 0x4c, 0xfd, 0xaa, 0x80, 0x81,
        0x48, 0xc8, 0x39, 0xe8, 0x04, 0x9e, 0x69, 0xe8, 0xb6, 0x78, 0x7f, 0x65, 0x9b, 0x52, 0x74, 0xeb};
#elif defined(NXP)
    // PROD key
    uint8_t eSERootPubKey[] = {
        0x04, 0xa8, 0x49, 0x4e, 0xc8, 0xe8, 0x84, 0x78, 0x6a, 0xf9, 0xb1, 0x8d, 0x54, 0x0e, 0x25, 0xef, 0xfe,
        0xeb, 0xa1, 0x06, 0x25, 0xf0, 0x3e, 0xff, 0x59, 0xe9, 0xc5, 0xfb, 0xdc, 0xc5, 0x54, 0xdd, 0x0f,
        0xf0, 0xc0, 0x59, 0x98, 0x82, 0xa5, 0xd9, 0xdc, 0x21, 0x97, 0x3d, 0xa7, 0x27, 0xfe, 0x6e, 0x97,
        0xf0, 0x74, 0xba, 0xfc, 0x3b, 0x6b, 0x87, 0xaf, 0x45, 0xa2, 0x01, 0x7e, 0x8d, 0x7a, 0x69, 0xa7};
#elif defined(GEM)
    // PROD key
    uint8_t eSERootPubKey[] = {
        0x04, 0x9D, 0x89, 0x9A, 0xA9, 0x03, 0x5D, 0x27, 0x6D, 0xAE, 0x20, 0xD5, 0x95, 0x7F, 0x1A, 0x4E, 0xA0,
        0xC2, 0x4D, 0x4B, 0x41, 0xE9, 0x10, 0xF9, 0x76, 0x95, 0xEE, 0x88, 0xC5, 0xCA, 0xBA, 0xB0, 0x73,
        0x4F, 0x9E, 0x33, 0x9D, 0x54, 0xC3, 0x60, 0x9B, 0x51, 0x8C, 0xD1, 0x3B, 0x71, 0x8D, 0xE7, 0x6C,
        0x16, 0x77, 0x74, 0x93, 0x7C, 0xE3, 0x10, 0xB6, 0xD7, 0x22, 0xDA, 0xCC, 0x08, 0xA1, 0x1F, 0x58};
#else
    uint8_t eSERootPubKey[] = {};
#endif

    if ( cert[0] != 0x7F || cert[1] != 0x21 ) {
        LOGE("Invalid cert format");
        status = SSPSTATUS_FAILED;
        goto ret_point;
    }

    if ( cert[2] == 0x81 ) {
        sig_data_start_pos = 4;
        sig_data_size = (0x000000FF & cert[3]) - sig_size;
    } else {
        sig_data_start_pos = 3;
        sig_data_size = (0x000000FF & cert[2]) - sig_size;
    }

#ifdef GET_SSP_CERTIFICATE
    hex_print_tag("cert", cert, cert_size);
#endif
    LOGD("sig_data_start_pos : %u, sig_data_size : %u", sig_data_start_pos, sig_data_size);

    cur_pos = cert_size - sig_size;

    LOGD("cert_size: %u, cur_pos : %u", cert_size, cur_pos);

    if ( cert[cur_pos] != 0x5F || cert[cur_pos + 1] != 0x37 ) {
        LOGE("Invalid sig format");
        status = SSPSTATUS_FAILED;
        goto ret_point;
    }
    sig_start_pos = cur_pos + 3;

#ifdef SKIP_GET_CERT_VERIFICATION
    LOGI("Skip CASD certificate verification");
    LOGI("sig_start_pos : %u, sig_data_start_pos : %u, sig_data_size : %u ", sig_start_pos, sig_data_start_pos, sig_data_size);
    hex_print_tag_debug("eSERootPubKey", eSERootPubKey, sizeof(eSERootPubKey));
    (void) sspVer;
#else
#if defined(OT)
    if (sspVer[0] == 0x20 && (sspVer[1] == 0x08 || sspVer[1] == 0x09)) {
        CHECK_OP_STATUS(verify_ecdsa_signature(cert, sig_data_size + sig_data_start_pos, cert + sig_start_pos, eSERootPubKey));
    } else {
        if ( sig_data_start_pos + sig_data_size > cert_size || sig_start_pos > cert_size){
            status = SSPSTATUS_OVER_MAX_DATA_SIZE;
            goto ret_point;
        }
        CHECK_OP_STATUS(verify_ecdsa_signature(cert + sig_data_start_pos, sig_data_size, cert + sig_start_pos, eSERootPubKey));
    }
#else
    (void)sspVer;
    if ( sig_data_start_pos + sig_data_size > cert_size || sig_start_pos > cert_size){
        status = SSPSTATUS_OVER_MAX_DATA_SIZE;
        goto ret_point;
    }    
    CHECK_OP_STATUS(verify_ecdsa_signature(cert + sig_data_start_pos, sig_data_size, cert + sig_start_pos, eSERootPubKey));
#endif
#endif

    cur_pos = cert_size - sig_size - 73;
#if 0
    LOGD("cur_pos : %u", cur_pos);
    LOGD("cert[%u] : %x, cert[%u] : %x", cur_pos, cert[cur_pos], cur_pos+1, cert[cur_pos+1]);
#endif

    if ( cert[cur_pos] != 0x7F || cert[cur_pos + 1] != 0x49 ) {
        LOGE("Invalid pubkey format");
        status = SSPSTATUS_FAILED;
        goto ret_point;
    }
    cur_pos += 5;

    memcpy(eSEPubKey, cert + cur_pos, SSP_ECC_PUBKEY_SIZE);

ret_point:

    hex_print_tag_debug("eSEPubKey", cert + cur_pos, SSP_ECC_PUBKEY_SIZE);

    return status;
}

SSPSTATUS verify_ecdsa_signature(uint8_t *in, uint32_t in_size, uint8_t *sig, uint8_t eSEPubKey[SSP_ECC_PUBKEY_SIZE]) {
    SSPSTATUS status = SSPSTATUS_SUCCESS;
    ecc_key_t eccPubKey;

    uint8_t raw_sig_r[32], raw_sig_s[32];
    uint8_t sig_r[32], sig_s[32];
    int32_t sig_r_size, sig_s_size;

    hex_print_tag_debug("In", in, in_size);

    memcpy(raw_sig_r, sig, 32);
    memcpy(raw_sig_s, sig + 32, 32);

#if 0
    if (raw_sig_r[0] == 0x00 && (int)raw_sig_r[1] < 128) {
        LOGI("Exception verify_ecdsa_signature sig r : 0x%02x 0x%02x", raw_sig_r[0], raw_sig_r[1]);
    }
    if (raw_sig_s[0] == 0x00 && (int)raw_sig_s[1] < 128) {
        LOGI("Exception verify_ecdsa_signature sig s : 0x%02x 0x%02x", raw_sig_s[0], raw_sig_s[1]);
    }
#endif

    if (raw_sig_r[0] == 0x00) {
        memcpy(sig_r, raw_sig_r + 1, 31);
        sig_r_size = 31;
    } else {
        memcpy(sig_r, raw_sig_r, 32);
        sig_r_size = 32;
    }

    if (raw_sig_s[0] == 0x00) {
        memcpy(sig_s, raw_sig_s + 1, 31);
        sig_s_size = 31;
    } else {
        memcpy(sig_s, raw_sig_s, 32);
        sig_s_size = 32;
    }

    CHECK_OP_STATUS( crypto_regen_ecc_pubkey(&eccPubKey, eSEPubKey, SSP_ECC_PUBKEY_SIZE) );
    if ( crypto_ecdsa_verify_with_sha256(eccPubKey.ecc_keypair, in, in_size, sig_r, sig_r_size, sig_s, sig_s_size) != SSPSTATUS_SUCCESS ) {
        status = SSPSTATUS_GET_CERT_VERIFICATION_FAIL;
    }
    crypto_clear_ecc_context(&eccPubKey);

ret_point:

    return status;
}

SSPSTATUS generate_ecdsa_signature(uint8_t *in, uint32_t in_size, uint8_t *sig, uint8_t teePrivKey[SSP_ECC_PRIVKEY_SIZE]) {
    SSPSTATUS status = SSPSTATUS_SUCCESS;
    ecc_key_t eccPrivKey;

    uint16_t offset = 0;
    uint8_t sig_r[32], sig_s[32];
    int32_t sig_r_size, sig_s_size;

    CHECK_OP_STATUS( crypto_regen_ecc_privkey(&eccPrivKey, teePrivKey, SSP_ECC_PRIVKEY_SIZE) );
    CHECK_OP_STATUS( crypto_ecdsa_sign_with_sha256(eccPrivKey.ecc_keypair, in, in_size, sig_r, &sig_r_size, sig_s, &sig_s_size) );
    crypto_clear_ecc_context(&eccPrivKey);

#if 0
    if (sig_r_size < 32 && (int)sig_r[0] < 128) {
        LOGI("Exception generate_ecdsa_signature sig r : 0x%02x", sig_r[0]);
    }
    if (sig_s_size < 32 && (int)sig_s[0] < 128) {
        LOGI("Exception generate_ecdsa_signature sig s : 0x%02x", sig_s[0]);
    }
#endif

    if (sig_r_size < 32) {
        memset(sig + offset, 0x00, 32 - sig_r_size);
        offset += (32 - sig_r_size);
        memcpy(sig + offset, sig_r, sig_r_size);
        offset += sig_r_size;
    } else {
        memcpy(sig + offset, sig_r, sig_r_size);
        offset += sig_r_size;
    }

    if (sig_s_size < 32) {
        memset(sig + offset, 0x00, 32 - sig_s_size);
        offset += (32 - sig_s_size);
        memcpy(sig + offset, sig_s, sig_s_size);
        offset += sig_s_size;
    } else {
        memcpy(sig + offset, sig_s, sig_s_size);
        offset += sig_s_size;
    }

#if 0
    if (sig_r_size < 32 || sig_s_size < 32) {
        hex_print_tag_debug("sig_r", sig_r, sig_r_size);
        hex_print_tag_debug("sig_s", sig_s, sig_s_size);
        hex_print_tag_debug("signature", sig, offset);
    }
#endif

ret_point:
    return status;
}

SSPSTATUS generatePutCertData(uint8_t *root_cert, uint32_t root_cert_size,
    uint8_t *service_cert, uint32_t service_cert_size, uint8_t *out, uint32_t *out_size) {
    SSPSTATUS status = SSPSTATUS_SUCCESS;

    uint8_t tempBuffer[SSP_MAX_X509_CERT_SIZE + SSP_MAX_X509_CERT_SIZE + 32];
    uint8_t root_cert_with_tag[SSP_MAX_X509_CERT_SIZE + 14] = {0, };
    uint32_t root_cert_with_tag_size = 0;
    uint8_t service_cert_with_tag[SSP_MAX_X509_CERT_SIZE + 14] = {0, };
    uint32_t service_cert_with_tag_size = 0;

    uint8_t temp_tlv_buf[3];
    uint8_t temp_tlv_buf_len;

    uint8_t tag_cert_info_template[1] = { 0xE0 };
    uint8_t tag_cert_info_data[1] = { 0xF0 };
    uint8_t tag_cert_type_with_x509[3] = { 0xF1, 0x01, 0x01 };
    uint8_t tag_key_type_with_rsa[3] = { 0xF2, 0x01, 0x02  };
    uint8_t tag_key_type_with_ecc[3] = { 0xF2, 0x01, 0x01  };
    uint8_t tag_cert_data[1] = { 0xF3 };

    BUFFER_APPEND( root_cert_with_tag, root_cert_with_tag_size, root_cert, root_cert_size );
    BER_TLV_LENGTH(root_cert_size, temp_tlv_buf, temp_tlv_buf_len);
    BUFFER_APPEND_FRONT( tempBuffer, root_cert_with_tag, root_cert_with_tag_size, temp_tlv_buf, temp_tlv_buf_len );
    BUFFER_APPEND_FRONT( tempBuffer, root_cert_with_tag, root_cert_with_tag_size, tag_cert_data, sizeof(tag_cert_data) );
    BUFFER_APPEND_FRONT( tempBuffer, root_cert_with_tag, root_cert_with_tag_size, tag_key_type_with_rsa, sizeof(tag_key_type_with_rsa) );
    BUFFER_APPEND_FRONT( tempBuffer, root_cert_with_tag, root_cert_with_tag_size, tag_cert_type_with_x509, sizeof(tag_cert_type_with_x509) );
    BER_TLV_LENGTH(root_cert_with_tag_size, temp_tlv_buf, temp_tlv_buf_len);
    BUFFER_APPEND_FRONT( tempBuffer, root_cert_with_tag, root_cert_with_tag_size, temp_tlv_buf, temp_tlv_buf_len );
    BUFFER_APPEND_FRONT( tempBuffer, root_cert_with_tag, root_cert_with_tag_size, tag_cert_info_data, sizeof(tag_cert_info_data) );

    BUFFER_APPEND( service_cert_with_tag, service_cert_with_tag_size, service_cert, service_cert_size );
    BER_TLV_LENGTH(service_cert_size, temp_tlv_buf, temp_tlv_buf_len);
    BUFFER_APPEND_FRONT( tempBuffer, service_cert_with_tag, service_cert_with_tag_size, temp_tlv_buf, temp_tlv_buf_len );
    BUFFER_APPEND_FRONT( tempBuffer, service_cert_with_tag, service_cert_with_tag_size, tag_cert_data, sizeof(tag_cert_data) );
    BUFFER_APPEND_FRONT( tempBuffer, service_cert_with_tag, service_cert_with_tag_size, tag_key_type_with_ecc, sizeof(tag_key_type_with_rsa));
    BUFFER_APPEND_FRONT( tempBuffer, service_cert_with_tag, service_cert_with_tag_size, tag_cert_type_with_x509, sizeof(tag_cert_type_with_x509) );
    BER_TLV_LENGTH(service_cert_with_tag_size, temp_tlv_buf, temp_tlv_buf_len);
    BUFFER_APPEND_FRONT( tempBuffer, service_cert_with_tag, service_cert_with_tag_size, temp_tlv_buf, temp_tlv_buf_len );
    BUFFER_APPEND_FRONT( tempBuffer, service_cert_with_tag, service_cert_with_tag_size, tag_cert_info_data, sizeof(tag_cert_info_data) );

    *out_size = 0;
    BUFFER_APPEND( out, *out_size, service_cert_with_tag, service_cert_with_tag_size );
    BUFFER_APPEND_FRONT( tempBuffer, out, *out_size, root_cert_with_tag, root_cert_with_tag_size );
    BER_TLV_LENGTH(*out_size, temp_tlv_buf, temp_tlv_buf_len);
    BUFFER_APPEND_FRONT( tempBuffer, out, *out_size, temp_tlv_buf, temp_tlv_buf_len );
    BUFFER_APPEND_FRONT( tempBuffer, out, *out_size, tag_cert_info_template, sizeof(tag_cert_info_template) );

    return status;
}

SSPSTATUS extractRawSigFromAsn1WithEcc(uint8_t *sig, uint32_t sig_len, uint8_t *rawSig) {
    SSPSTATUS status = SSPSTATUS_SUCCESS;
    uint16_t current_pos = 3;
    uint8_t sig_r[32];
    uint8_t sig_s[32];
    uint8_t tempLen;

    (void)sig_len;
    tempLen = sig[current_pos];
    current_pos++;
    if ( tempLen == 33 ) {
        current_pos++;
        tempLen--;
    }
    memcpy(sig_r, sig + current_pos, tempLen);
    current_pos += tempLen;
    current_pos++;

    tempLen = sig[current_pos];
    current_pos++;
    if ( tempLen == 33 ) {
        current_pos++;
        tempLen--;
    }
    memcpy(sig_s, sig + current_pos, tempLen);

    hex_print_tag_debug("Extracted sig r ", sig_r, tempLen);
    hex_print_tag_debug("Extracted sig s", sig_s, tempLen);

    memcpy(rawSig, sig_r, 32);
    memcpy(rawSig + 32, sig_s, 32);

    return status;
}

SSPSTATUS rebuildAsn1FromRawSigWithEcc(uint8_t *rawSig, uint8_t *sig, uint32_t *sig_len) {
    SSPSTATUS status = SSPSTATUS_SUCCESS;
    uint8_t raw_sig_r[32], raw_sig_s[32];
    uint8_t raw_sig_r_len, raw_sig_s_len;
    uint8_t sig_r[33], sig_s[33]; 
    uint8_t sig_r_len, sig_s_len;
    uint8_t temp_sig[32];
    int i;

    // Sig R
    memcpy(temp_sig, rawSig, 32);
    // Remove 0x00 bytes in front
    for (i = 0; i < 32; i++) {
        if (temp_sig[i] != 0x00) {
            break;
        }
    }
    memcpy(raw_sig_r, temp_sig + i, 32 - i);
    raw_sig_r_len = 32 - i;

    // Sig S
    memcpy(temp_sig, rawSig + 32, 32);
    // Remove 0x00 bytes in front
    for (i = 0; i < 32; i++) {
        if (temp_sig[i] != 0x00) {
            break;
        }
    }
    memcpy(raw_sig_s, temp_sig + i, 32 - i);
    raw_sig_s_len = 32 - i;

    if (raw_sig_r[0] > 127) {
        sig_r[0] = 0x00;
        memcpy(sig_r + 1, raw_sig_r, raw_sig_r_len);
        sig_r_len = raw_sig_r_len + 1;
    } else {
        memcpy(sig_r, raw_sig_r, raw_sig_r_len);
        sig_r_len = raw_sig_r_len;
    }

    if (raw_sig_s[0] > 127) {
        sig_s[0] = 0x00;
        memcpy(sig_s + 1, raw_sig_s, raw_sig_s_len);
        sig_s_len = raw_sig_s_len + 1;
    } else {
        memcpy(sig_s, raw_sig_s, raw_sig_s_len);
        sig_s_len = raw_sig_s_len;
    }

    *sig_len = 0;
    sig[(*sig_len)++] = 0x30;
    sig[(*sig_len)++] = sig_r_len + sig_s_len + 4;
    sig[(*sig_len)++] = 0x02;
    sig[(*sig_len)++] = sig_r_len;
    memcpy(sig + (*sig_len), sig_r, sig_r_len);
    (*sig_len) += sig_r_len;
    sig[(*sig_len)++] = 0x02;
    sig[(*sig_len)++] = sig_s_len;
    memcpy(sig + (*sig_len), sig_s, sig_s_len);
    (*sig_len) += sig_s_len;

    return status;
}

SSPSTATUS  ssp_genEntryID( const uint8_t *input, uint32_t inputLen, uint8_t eID[SSP_ENTRY_ID_SIZE] ) {
    SSPSTATUS status;
    uint8_t digest[SHA1_DIGEST_SIZE];
    uint8_t i;

    LOGD("ssp_genEntryID is called");
    if ( input == NULL ) {
        LOGE("Invalid input !!");
        status = SSPSTATUS_INVALID_ARGUMENT;
        goto ret_point;
    }

    if ( inputLen > 128 ) {
        LOGE("Input data size is over 128 bytes !!");
        status = SSPSTATUS_OVER_MAX_DATA_SIZE;
        goto ret_point;
    }

    status = crypto_sha1(digest, input, inputLen, NULL);
    if ( status != SSPSTATUS_SUCCESS ) {
        goto ret_point;
    }

    hex_print_tag_debug("ssp_genEntryID sha1", digest, SHA1_DIGEST_SIZE);

    for ( i = 0 ; i < SSP_ENTRY_ID_SIZE ; i++ ) {
        digest[0] ^= digest[(i*4)+4];
        digest[1] ^= digest[(i*4)+5];
        digest[2] ^= digest[(i*4)+6];
        digest[3] ^= digest[(i*4)+7];
    }

    memcpy(eID, digest, SSP_ENTRY_ID_SIZE);

ret_point:
    return status;
}

SSPSTATUS  ssp_genTaID( const uint8_t *input, uint32_t inputLen, uint8_t taID[SSP_TID_SIZE] ) {
    SSPSTATUS status;
    uint8_t digest[SHA256_DIGEST_SIZE];
    uint8_t i;

    LOGD("ssp_genTaID is called");
    if ( input == NULL ) {
        LOGE("Invalid input !!");
        status = SSPSTATUS_INVALID_ARGUMENT;
        goto ret_point;
    }

    status = crypto_sha256(digest, input, inputLen, NULL);
    if ( status != SSPSTATUS_SUCCESS ) {
        goto ret_point;
    }

    for ( i = 0 ; i < SSP_TID_SIZE ; i++ ) {
        digest[i] ^= digest[i + SSP_TID_SIZE];
    }

    memcpy(taID, digest, SSP_TID_SIZE);
    hex_print_tag_debug("Generated TA id", taID, SSP_TID_SIZE);

ret_point:
    return status;
}

#if defined USE_BLOWFISH
static int32_t wrap_object(const uint8_t *tID, const uint8_t *inKeyBuffer, uint32_t inkeyBufferLen, uint32_t *maxBufferLen, void *outWrapObj) {
    uint32_t ret = 0;
    uint32_t outPutSize;
    SO_AccessControlInfoType wrap_uuid;

    memset(&wrap_uuid, 0x00, sizeof(SO_AccessControlInfoType));
    memcpy(&wrap_uuid.ta_id, tID, sizeof(TEEC_UUID));
#ifdef USE_TEEGRIS_V4
    memcpy(&wrap_uuid.auth_id, "samsung_ta", strlen("samsung_ta"));
#endif
    wrap_uuid.access_flags = DELEGATED_TA_ID_AC;

#ifdef USE_TEEGRIS
    outPutSize = SO_OUT_BUF_SIZE(inkeyBufferLen, 1);
//    LOGI("outPutSize : %u", outPutSize);
    if (outPutSize > *maxBufferLen) {
        LOGE("ouput data is over the buffer.");
        return -1;
    }
#endif

    ret = TEES_WrapSecureObject((void *)inKeyBuffer, inkeyBufferLen, outWrapObj, maxBufferLen, &wrap_uuid);
    if (TEE_SUCCESS != ret) {
        LOGE("TEES_WrapSecureObject: 0x%08X", ret);
        return -1;
    }

    return 0;
}

static int32_t unwrap_object(const uint8_t *sourceTid, uint8_t *inBuffer, uint32_t inBufferLen, uint8_t *outBuffer, uint32_t *outBufferLen) {
    uint32_t ret = 0;

#ifdef USE_TEEGRIS
    SO_AccessControlInfoType wrap_uuid;

    memset(&wrap_uuid, 0x00, sizeof(SO_AccessControlInfoType));
    memcpy(&wrap_uuid.ta_id, sourceTid, sizeof(TEEC_UUID));
    memcpy(&wrap_uuid.auth_id, "samsung_ta", strlen("samsung_ta"));
#ifdef USE_TEEGRIS_V4
    wrap_uuid.access_flags = DELEGATED_TA_ID_AC;
#endif

    ret = TEES_CheckSecureObjectCreator(inBuffer, inBufferLen, &wrap_uuid);
    if (TEE_SUCCESS != ret) {
        LOGE("TEES_CheckSecureObjectCreator: 0x%08X", ret);
        return -1;
    }
#endif

    ret = TEES_UnwrapSecureObject(inBuffer, inBufferLen, outBuffer, outBufferLen);
    if (TEE_SUCCESS != ret) {
        LOGE("TEES_UnwrapSecureObject: 0x%08X", ret);
        return -1;
    }

    return 0;
}
#endif

#if defined(USE_TRUSTY_UNISOC)
static int32_t wrap_object(const uint8_t *tID, const uint8_t *inKeyBuffer, uint32_t inkeyBufferLen, uint32_t *maxBufferLen, void *outWrapObj) {
    return 0;
}

static int32_t unwrap_object(const uint8_t *sourceTid, uint8_t *inBuffer, uint32_t inBufferLen, uint8_t *outBuffer, uint32_t *outBufferLen) {
    return 0;
}
#endif

#ifdef USE_MOBICORE
static int32_t wrap_object(const uint8_t *tID, const uint8_t *inKeyBuffer, uint32_t inkeyBufferLen, uint32_t *maxBufferLen, void *outWrapObj) {
    uint32_t ret = 0;
    tlApiSpTrustletId_t wrap_uuid;

    wrap_uuid.spid = MC_SPID_SYSTEM;
    memcpy(&(wrap_uuid.uuid), tID, sizeof(mcUuid_t));
    //MC_SO_LIFETIME_PERMANENT
    //MC_SO_LIFETIME_POWERCYCLE
    ret = tlApiWrapObject((void *)inKeyBuffer, 0, inkeyBufferLen, outWrapObj, maxBufferLen,
                    MC_SO_CONTEXT_TLT, MC_SO_LIFETIME_PERMANENT, &wrap_uuid, TLAPI_WRAP_DEFAULT);

    if (TLAPI_OK != ret) {
        LOGE("tlApiWrapObject: 0x%08X", ret);
        return -1;
    }

    return 0;
}

#define UNWRAP_FLAGS ( TLAPI_UNWRAP_PERMIT_DELEGATED | \
                       TLAPI_UNWRAP_PERMIT_CONTEXT_TL | \
                       TLAPI_UNWRAP_PERMIT_CONTEXT_SP | \
                       TLAPI_UNWRAP_PERMIT_CONTEXT_DEVICE )

static int32_t unwrap_object(uint8_t *inBuffer, uint32_t *inBufferLen) {
    uint32_t ret = 0;
    uint32_t maxBufferLen = *inBufferLen;

    ret = tlApiUnwrapObject(inBuffer, *inBufferLen, inBuffer, &maxBufferLen, UNWRAP_FLAGS);
    if (TLAPI_OK != ret) {
        LOGE("tlApiUnwrapObject: 0x%08X", ret);
        return -1;
    }
    *inBufferLen = maxBufferLen;
    return 0;
}
#endif

SSPSTATUS ssp_wrap_secure_object(const uint8_t *appId, const uint8_t *input, uint32_t input_size, uint8_t *output, uint32_t *output_size) {
    SSPSTATUS ret = SSPSTATUS_SUCCESS;

#if defined USE_MOBICORE || defined USE_BLOWFISH || defined(USE_TRUSTY_UNISOC)
    hex_print_tag_debug("Input", (uint8_t*)input, input_size);

    if (wrap_object(appId, input, input_size, output_size, output) == 0) {
        hex_print_tag_debug("Wrapped", output, *output_size);
    } else {
        LOGE("Wrapped data failed !!");
        ret = SSPSTATUS_FAILED;
    }

#endif
#ifdef USE_QSEE
    int qsee_ret;

    LOGD("appId : %s", (char*)appId);
    hex_print_tag_debug("Input", (uint8_t*)input, input_size);
    if (*output_size < input_size + 144) {
        LOGE("Output data size is lower than input+header size");
        return SSPSTATUS_OVER_MAX_DATA_SIZE;
    }

#ifdef SECBOOT_OEM_SECAPP
    int i, chipSigned = 0;

    for (i = 0; i < gChipSignTaListCnt; i++) {
        if (strncmp((char*)appId, gChipSignTaList[i], strlen(gChipSignTaList[i])) == 0) {
            chipSigned = 1;
        }
    }

    if (chipSigned) {
#ifdef USE_ALT_ROTHASH
        char rotHashAppId[MAX_DISTNAME_PREFIX_SZ + MAX_TANAME_SZ + 1] = {0};
        get_alt_rot_distname(DL_ROT_DOMAIN_NAME, (char*)appId, rotHashAppId);
        LOGI("Use ALTROTHASH AppId : %s", rotHashAppId);
        qsee_ret = qsee_encapsulate_inter_app_message((char*)rotHashAppId, (uint8_t *)input, input_size, output, output_size);
#else // USE_ALT_ROTHASH
        char chipSignedAppId[QSEE_MESSAGE_APP_NAME_MAX_LEN] = SECBOOT_OEM_SECAPP;
        strcat(chipSignedAppId, (char*)appId);
        LOGI("Use chipSignedAppId : %s", chipSignedAppId);
        qsee_ret = qsee_encapsulate_inter_app_message((char*)chipSignedAppId, (uint8_t *)input, input_size, output, output_size);
#endif // USE_ALT_ROTHASH
    } else {
#ifdef USE_ALT_ROTHASH
        char rotHashAppId[MAX_DISTNAME_PREFIX_SZ + MAX_TANAME_SZ + 1] = {0};
        get_alt_rot_distname(ALT_ROT_DOMAIN_NAME, (char*)appId, rotHashAppId);
        LOGI("Use ALTROTHASH AppId : %s", rotHashAppId);
        //LOGI("Use rotHashAppId %s", (char*)rotHashAppId);
        qsee_ret = qsee_encapsulate_inter_app_message((char*)rotHashAppId, (uint8_t *)input, input_size, output, output_size);
#else // USE_ALT_ROTHASH
        qsee_ret = qsee_encapsulate_inter_app_message((char*)appId, (uint8_t *)input, input_size, output, output_size);
#endif // USE_ALT_ROTHASH
    }
#else // SECBOOT_OEM_SECAPP
    qsee_ret = qsee_encapsulate_inter_app_message((char*)appId, (uint8_t *)input, input_size, output, output_size);
#endif // SECBOOT_OEM_SECAPP

    if (qsee_ret != 0) {
        LOGE("Wrapped data failed !!, ret = %x", qsee_ret);
        ret = SSPSTATUS_FAILED;
    }

    hex_print_tag_debug("Wrapped", output, *output_size);
#endif

    return ret;
}

#if defined(USE_BLOWFISH) || defined(USE_QSEE) || defined(USE_TRUSTY_UNISOC)
SSPSTATUS ssp_unwrap_secure_object(const uint8_t *sourceTid, const uint8_t *input, uint32_t input_size, uint8_t *output, uint32_t *output_size) {
    SSPSTATUS ret = SSPSTATUS_SUCCESS;

#if defined USE_BLOWFISH || defined(USE_TRUSTY_UNISOC)
    uint8_t temp_out[SSP_MAX_SECURE_OBJECT_SIZE] = {0, };
    uint32_t temp_out_size = sizeof(temp_out);

    hex_print_tag_debug("Wrapped", (uint8_t*)input, input_size);
    if (unwrap_object(sourceTid, (uint8_t*)input, input_size, temp_out, &temp_out_size) == 0) {
        hex_print_tag_debug("Unwrapped", temp_out, temp_out_size);
        if (temp_out_size > *output_size) {
            LOGE("ouput data is over the buffer.");
            return SSPSTATUS_FAILED;
        }
        memcpy(output, temp_out, temp_out_size);
        *output_size = temp_out_size;
    } else {
        LOGE("Unwrapped data failed !!");
        ret = SSPSTATUS_FAILED;
    }
#endif
#ifdef USE_QSEE
    char appName[QSEE_MESSAGE_APP_NAME_MAX_LEN] = "";
    int qsee_ret;

    LOGD("sourceTid : %s", (char*)sourceTid);
    hex_print_tag_debug("Wrapped", (uint8_t*)input, input_size);
    qsee_ret = qsee_decapsulate_inter_app_message(appName, (uint8_t *)input, input_size, output, output_size);
    if (qsee_ret == 0) {
        LOGD("appName : %s", appName);

#ifdef USE_ALT_ROTHASH
        char rotHashAppId[MAX_DISTNAME_PREFIX_SZ + MAX_TANAME_SZ + 1] = {0};
        get_alt_rot_distname(ALT_ROT_DOMAIN_NAME, (char*)sourceTid, rotHashAppId);
        LOGI("Use ALTROTHASH AppId : %s", rotHashAppId);

        if (strncmp(appName, rotHashAppId, strlen(appName)) != 0) {
#else
        if (strncmp(appName, (char*)sourceTid, strlen(appName)) != 0) {
#endif
            LOGE("appName is not matched : %s", appName);
            return SSPSTATUS_FAILED;
        }
        hex_print_tag_debug("Unwrapped", (uint8_t*)output, *output_size);
    } else {
        LOGE("Unwrapped data failed !!, ret = %x", qsee_ret);
        ret = SSPSTATUS_FAILED;
    }
#endif

    return ret;
}
#else
SSPSTATUS ssp_unwrap_secure_object(const uint8_t *input, uint32_t input_size, uint8_t *output, uint32_t *output_size) {
    SSPSTATUS ret = SSPSTATUS_SUCCESS;

#if defined USE_MOBICORE
    uint8_t temp_in[SSP_MAX_SECURE_OBJECT_SIZE];
    uint32_t temp_in_size = input_size;

    if (SSP_MAX_SECURE_OBJECT_SIZE < temp_in_size) {
        LOGE("Input data is over the buffer.");
        return SSPSTATUS_FAILED;
    }

    memcpy(temp_in, input, input_size);
    hex_print_tag_debug("Wrapped", (uint8_t*)temp_in, input_size);
    if (unwrap_object(temp_in, &temp_in_size) == 0) {
        hex_print_tag_debug("Unwrapped", (uint8_t*)temp_in, temp_in_size);
       if (temp_in_size > *output_size) {
           LOGE("ouput data is over the buffer.");
           return SSPSTATUS_FAILED;
       }

       memcpy(output, temp_in, temp_in_size);
       *output_size = temp_in_size;
     } else {
        LOGE("Unwrapped data failed !!");
        ret = SSPSTATUS_FAILED;
    }
#endif

    return ret;
}
#endif

#if defined(USE_TRUSTY_UNISOC)
SSPSTATUS wrapInternalData(char *name, uint8_t* input, uint32_t inputSize) {
    int rc;
    storage_session_t session_write;

    rc = storage_open_session_async(&session_write, STORAGE_CLIENT_TP_PORT, 100);
    if (rc < 0) {
        LOGE("Error: [%d] failed to open storage session", rc);
        return SSPSTATUS_FAILED;
    }

    file_handle_t handle_w;
    rc = storage_open_file(session_write, &handle_w, name,
            STORAGE_FILE_OPEN_CREATE|STORAGE_FILE_OPEN_TRUNCATE, 0);
    if (rc < 0) {
        LOGE("Error: [%d] failed to open storage object", rc);
        storage_close_session(session_write);
        return SSPSTATUS_FAILED;
    }

    rc = storage_write(handle_w, 0, input, inputSize, 0);

    storage_close_file(handle_w);
    storage_end_transaction(session_write, true);
    storage_close_session(session_write);

    if (rc == 0) {
        LOGE("wrapInternalData Failed !!, ret : %x", rc);
        return SSPSTATUS_FAILED;
    }
    return SSPSTATUS_SUCCESS;
}

SSPSTATUS unwrapInternalData(char *name, uint8_t* output, uint32_t *outputSize) {
    storage_session_t session_read;
    int rc;

    rc = storage_open_session_async(&session_read, STORAGE_CLIENT_TP_PORT, 100);
    if (rc < 0) {
        LOGE("Error: [%d] failed to open storage session", rc);
        return SSPSTATUS_FAILED;
    }

    file_handle_t handle_r;
    rc = storage_open_file(session_read, &handle_r, name,
            STORAGE_FILE_OPEN_CREATE, 0);
    if (rc < 0) {
        LOGE("Error: [%d] failed to open storage object", rc);
        storage_close_session(session_read);
        return SSPSTATUS_FAILED;
    }

    rc = storage_read(handle_r, 0, output, *outputSize);

    storage_close_file(handle_r);
    storage_end_transaction(session_read, true);
    storage_close_session(session_read);

    if (rc == 0) {
        LOGD("unwrapInternalData failed !!, ret : %x", rc);
        return SSPSTATUS_FAILED;
    }
    *outputSize = rc;
    hex_print_tag_debug("unwrapped data", output, *outputSize);
    return SSPSTATUS_SUCCESS;
}

#else
SSPSTATUS wrapInternalData(uint8_t* input, uint32_t inputSize,
                         uint8_t* output, uint32_t *outputSize) {
    SSPSTATUS ret = SSPSTATUS_SUCCESS;

#if defined (USE_QSEE)
    uint8_t wrapKey[AES_256_KEY_SIZE];
    uint8_t iv[AES_BLOCK_SIZE] = {0,};
    uint8_t temp[SSP_MAX_SECURE_OBJECT_SIZE] = {0, };
    uint8_t hash[SHA256_DIGEST_SIZE] = {0,};
    uint32_t offset = 0;
#endif

    LOGD("wrapInternalData started");

#if defined USE_MOBICORE || defined USE_BLOWFISH
    ret = ssp_wrap_secure_object(SEM_TID, input, inputSize, output, outputSize);
#endif
#if defined (USE_QSEE)
    crypto_gen_random(iv, AES_BLOCK_SIZE);
    hex_print_tag_debug("iv", iv, AES_BLOCK_SIZE);
    crypto_get_tz_encryption_key(wrapKey);
    hex_print_tag_debug("wrapKey", wrapKey, AES_256_KEY_SIZE);

    hex_print_tag_debug("input", input, inputSize);
    crypto_sha256(hash, input, inputSize, NULL);
    hex_print_tag_debug("hash", hash, SHA256_DIGEST_SIZE);

    /* Encrypt plain data */
    ret = crypto_aes_cbc_256_encrypt(input, inputSize, output, outputSize, iv, wrapKey);
    secure_memclear(wrapKey, sizeof(wrapKey));
    hex_print_tag_debug("out", output, *outputSize);
    if (SSP_MAX_SECURE_OBJECT_SIZE > *outputSize + AES_BLOCK_SIZE + AES_BLOCK_SIZE + AES_BLOCK_SIZE + SHA256_DIGEST_SIZE) {
        hex_print_tag_debug("iv", iv, AES_BLOCK_SIZE);
        memset(temp, 0x00, AES_BLOCK_SIZE);
        offset += AES_BLOCK_SIZE;
        memcpy(temp + offset, iv, AES_BLOCK_SIZE);
        offset += AES_BLOCK_SIZE;
        memset(temp + offset, 0x00, AES_BLOCK_SIZE);
        offset += AES_BLOCK_SIZE;
        memcpy(temp + offset, hash, SHA256_DIGEST_SIZE);
        offset += SHA256_DIGEST_SIZE;
        memcpy(temp + offset, output, *outputSize);
        offset += *outputSize;
        *outputSize = offset;
        memcpy(output, temp, *outputSize);
        hex_print_tag_debug("out with iv", output, *outputSize);
    } else {
        LOGE("Input data is over the buffer.");
        return SSPSTATUS_FAILED;
    }
#endif

    if (ret != SSPSTATUS_SUCCESS) {
        LOGE("wrapInternalData Failed !!, ret : %x", ret);
    }
    hex_print_tag_debug("wrapped data", output, *outputSize);
    return ret;
}

#if defined(MSM8916) || defined(MSM8936) || defined(MSM8953) || \
    defined(MSM8952) || defined(MSM8956) || defined(MSM8956_PRO) || \
    defined(MSM8996) || defined(MSM8998) || defined(SDM660) || \
    defined(SDM660_SPF20) || defined(SDM710) || defined(SDM710_SPF20) || \
    defined(SDM845) || defined(SM6150) || defined(SM7150) || \
    defined(SM6150_SPF20) || defined(SM7150_SPF20) || \
    defined(SM8150) || defined(SM8150_FUSION) || defined(SM8150_FUSION_LA20)|| \
    defined(MT6757) || defined(EXYNOS3250) || \
    defined(EXYNOS7420) || defined(EXYNOS7570) || defined(EXYNOS7580) || \
    defined(EXYNOS7870) || defined(EXYNOS7880) || defined(EXYNOS7885) || \
    defined(EXYNOS8890) || defined(EXYNOS8890_310B) || \
    defined(EXYNOS8895) || defined(EXYNOS9110) || defined(EXYNOS9610) || \
    defined(EXYNOS9810) || defined(EXYNOS9820)
#define CHECK_UNWRAPP_CONDITION
#endif

SSPSTATUS unwrapInternalData(uint8_t* input, uint32_t inputSize,
                            uint8_t* output, uint32_t *outputSize) {
    SSPSTATUS ret = SSPSTATUS_SUCCESS;
#if defined (USE_QSEE)
    uint8_t wrapKey[AES_256_KEY_SIZE];
    uint8_t iv[AES_BLOCK_SIZE] = {0,};
    uint8_t temp[SSP_MAX_SECURE_OBJECT_SIZE] = {0, };
    uint8_t hash[SHA256_DIGEST_SIZE] = {0,};
    uint8_t calHash[SHA256_DIGEST_SIZE] = {0,};
    uint32_t offset = 0;
#endif

    LOGD("unwrapInternalData started");

#ifdef USE_MOBICORE
    ret = ssp_unwrap_secure_object(input, inputSize, output, outputSize);
#endif
#if defined USE_BLOWFISH
    ret = ssp_unwrap_secure_object(SEM_TID, input, inputSize, output, outputSize);
#endif
#if defined (USE_QSEE)
    hex_print_tag_debug("Input", input, inputSize);
    crypto_get_tz_encryption_key(wrapKey);
    hex_print_tag_debug("wrapKey", wrapKey, AES_256_KEY_SIZE);
#ifdef CHECK_UNWRAPP_CONDITION
    if (memcmp(iv, input, AES_BLOCK_SIZE) == 0) {
#endif
        offset += AES_BLOCK_SIZE;
        if (inputSize < offset + AES_BLOCK_SIZE) {
            LOGE("Wrapped key data is not correct");
            return SSPSTATUS_FAILED;
        }
        memcpy(iv, input + offset, AES_BLOCK_SIZE);
        hex_print_tag_debug("iv", iv, AES_BLOCK_SIZE);
        offset += AES_BLOCK_SIZE;
#ifdef CHECK_UNWRAPP_CONDITION
        if (memcmp(hash, input + offset, AES_BLOCK_SIZE) == 0) {
#endif
            if (inputSize < offset + AES_BLOCK_SIZE) {
                LOGE("Wrapped key data is not correct");
                return SSPSTATUS_FAILED;
            }
            offset += AES_BLOCK_SIZE;
            memcpy(hash, input + offset, SHA256_DIGEST_SIZE);
            hex_print_tag_debug("hash", hash, SHA256_DIGEST_SIZE);
            offset += SHA256_DIGEST_SIZE;
#ifdef CHECK_UNWRAPP_CONDITION
        }
#endif
        inputSize -= offset;
        if (inputSize > sizeof(temp)) {
            LOGE("Not enough buffer");
            return SSPSTATUS_FAILED;
        }
        memcpy(temp, input + offset, inputSize);
        hex_print_tag_debug("Input without iv", temp, inputSize);
#ifdef CHECK_UNWRAPP_CONDITION
    } else {
        if (inputSize > sizeof(temp)) {
            LOGE("Not enough buffer");
            return SSPSTATUS_FAILED;
        }
        memcpy(temp, input, inputSize);
    }
#endif

    ret = crypto_aes_cbc_256_decrypt(temp, inputSize, output, outputSize, iv, wrapKey);
    secure_memclear(wrapKey, sizeof(wrapKey));
    hex_print_tag_debug("Ouput", output, *outputSize);

#ifdef CHECK_UNWRAPP_CONDITION
    if (memcmp(hash, calHash, SHA256_DIGEST_SIZE) != 0) {
#endif
        crypto_sha256(calHash, output, *outputSize, NULL);

        hex_print_tag_debug("hash", hash, SHA256_DIGEST_SIZE);
        hex_print_tag_debug("calHash", calHash, SHA256_DIGEST_SIZE);
        if (memcmp(hash, calHash, SHA256_DIGEST_SIZE) != 0) {
            LOGE("Data is corrupted");
            return SSPSTATUS_FAILED;
        }
#ifdef CHECK_UNWRAPP_CONDITION
    }
#endif

#endif

    if (ret != SSPSTATUS_SUCCESS) {
        LOGD("unwrapInternalData failed !!, ret : %x", ret);
    }
    hex_print_tag_debug("unwrapped data", output, *outputSize);
    return ret;
}
#endif

