/**
 * @(#) ifaa_ta_common module  1.0 2015/12/12
 *
 * Copyright (c) 2014, IFAA and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of IFAA or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. IFAA, INC.
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL IFAA OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF IFAA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 *
 * ***********************************************************************************
 *
 * This head file defines the interfaces that library presents to client programs, and
 * is intended for call from Trusted Execution Application.
 */

#include "ifaa_ta_common.h"
#include "ifaa_tee_common.h"
#include "ifaa_mem_utils.h"

#include "tzWrappers/TzwMemory.h"
#include "ifaa_ta_vendor.h"
#include "ta_logger.h"

#define LOG_ERROR  LOG_E
#define LOG_DBG    LOG_D

#ifdef TZ_MODEL_QCOM /*TZ_MODEL_QCOM*/
#define __QUALCOMM__
#elif defined(TZ_MODEL_BLOWFISH) /*TZ_MODEL_BLOWFISH*/
#define __SAMSUNG_TEEGRIS__
#elif defined(TZ_MODEL_Kinibi) /*TZ_MODEL_Kinibi*/
#define __SAMSUNG_Kinibi__
#endif

IFAA_Result IFAA_GetFpLastIdentifiedResult(uint8_t *buf_id, uint32_t *id_len) {
    LOG_PERF_BEGIN

    ///////////////////////////////////////////////////
    ///注意: 实现时注意，指纹模板id有效期为3秒。
    ///指纹ID的存储必须在trustzone里，不可存储在REE里
    ///////////////////////////////////////////////////
    int32_t lst_id = 0;
    if (TEE_GetFpLastIdentifiedResult(&lst_id) != TEE_SUCCESS) {
        LOG_ERROR("fail to get last identified id.");
        *id_len = 0;
        return IFAA_ERR_GET_LAST_IDENTIFIED_RESULT;
    }

    *id_len = sizeof(lst_id);
    write32(buf_id, lst_id);

    LOG_PERF_END

    return IFAA_ERR_SUCCESS;
}

IFAA_Result IFAA_GetFpAuthenticatorVersion(uint32_t *version)
{
    *version = TEE_GetAuthenticatorVersion();
    return IFAA_ERR_SUCCESS;
}

MACRO_IFAA_IMPL_MARKER
IFAA_Result IFAA_GetFpEnrolledIdList(uint8_t* buf_id_list, uint32_t* id_list_len)
{
   //////////////////////////////////////////////////////
   ////获取系统中录入的指纹id列表
   //////////////////////////////////////////////////////
   S_VAR_NOT_USED(buf_id_list);
   S_VAR_NOT_USED(id_list_len);

   return IFAA_ERR_SUCCESS;
}

IFAABoolean IFAA_FpIdCompare(const uint8_t* buf_l, const uint8_t* buf_r, uint32_t buf_len)
{
    return memcmp(buf_l, buf_r, buf_len) == 0 ? IFAA_YES : IFAA_NO;
}


////////////////////////////////////////////////
////容器管理参考实现
////////////////////////////////////////////////
static void* IFAA_funaddress_t[8][5];

IFAA_Result IFAA_TaAddEntry(IFAA_BioType bioType,IFAA_TaEntry entry, void* func)
{
    IFAA_Result result=IFAA_ERR_SUCCESS;
    if (func == NULL || (bioType <= 0 || bioType >= 255)||(entry <= 0 || entry > 5)) {
        LOG_ERROR("Invalid parameters");
        return IFAA_ERR_BAD_PARAM;
    }

    switch(bioType)
    {
        case IFAA_BIO_FINGERPRINT:
            IFAA_funaddress_t[0][entry - 1] = func;
            break;
        case IFAA_BIO_IRIS:
            IFAA_funaddress_t[1][entry - 1] = func;
            break;
        case IFAA_BIO_FACE:
            IFAA_funaddress_t[2][entry - 1] = func;
            break;
        default:
            result = IFAA_ERR_UNKNOWN_CMD;
            break;
    }

    return result;
}

IFAA_Result IFAA_TaGetEntry(IFAA_BioType bioType, IFAA_TaEntry entry, void** func)
{
    if ((bioType <= 0 ) || (bioType >= 255)
       || (entry <= 0) || (entry > 5)) {
        LOG_ERROR("Invalid parameters");
        return IFAA_ERR_BAD_PARAM;
    }

    switch(bioType)
    {
        case IFAA_BIO_FINGERPRINT:
            *func = IFAA_funaddress_t[0][entry-1];
            break;
        case IFAA_BIO_IRIS:
            *func = IFAA_funaddress_t[1][entry-1];
            break;
        case IFAA_BIO_FACE:
            *func = IFAA_funaddress_t[2][entry-1];
            break;
        default:
            return IFAA_ERR_UNKNOWN_CMD;
    }

    return IFAA_ERR_SUCCESS;
}


#if defined(__QUALCOMM__) /*__QUALCOMM__*/
IFAA_Result IFAA_Sha256(const uint8_t* msg, uint32_t msg_len, uint8_t* digest, uint32_t* digest_len)
{
    ////////////////////////////////////////////////
    ////SHA256在高通上的的参考实现
    ////////////////////////////////////////////////

    *digest_len = 32;
    int ret = qsee_hash(QSEE_HASH_SHA256, msg, msg_len, digest, *digest_len);
    if (ret < 0) {
        LOG_ERROR("qsee_hash failed");
        return IFAA_ERR_HASH;
    }

    return IFAA_ERR_SUCCESS;
}
#elif defined(__SAMSUNG_TEEGRIS__) || defined(__SAMSUNG_Kinibi__) /*__SAMSUNG_TEEGRIS__ || __SAMSUNG_Kinibi__*/
IFAA_Result IFAA_Sha256(const uint8_t *msg, uint32_t msg_len, uint8_t *digest, uint32_t *digest_len)
{
    ////////////////////////////////////////////////
    ////SHA256在GP的参考实现
    ////////////////////////////////////////////////

    TEE_OperationHandle digestop = NULL;
    TEE_Result ret = TEE_AllocateOperation(&digestop, TEE_ALG_SHA256, TEE_MODE_DIGEST, 0);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_AllocateOperation failed: %08x", ret);
        return IFAA_ERR_HASH;
    }

    TEE_DigestUpdate(digestop, msg, msg_len);
    ret = TEE_DigestDoFinal(digestop, NULL, 0, digest, digest_len);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_DigestDoFinal failed: %08x", ret);
        ret = IFAA_ERR_HASH;
    }

    TEE_FreeOperation(digestop);
    if (TEE_SUCCESS == ret) ret = IFAA_ERR_SUCCESS;

    return ret;
}
#else
#error ("TEE is not defined yet");
#endif


#if defined(__QUALCOMM__) /*__QUALCOMM__*/

/* Endianness converter Macro */
#define htonl(x)                            \
    (((((uint32_t)(x)&0x000000FFU) << 24) | \
      (((uint32_t)(x)&0x0000FF00U) << 8) |  \
      (((uint32_t)(x)&0x00FF0000U) >> 8) |  \
      (((uint32_t)(x)&0xFF000000U) >> 24)))

static int copy_S_BIGINT(uint8_t* dst, uint32_t dst_len, QSEE_S_BIGINT* src, uint32_t max_len)
{
    uint32_t i = 0;
    uint32_t array_length = 0;
    if (dst_len > max_len) {
        return -1;
    }

    array_length = dst_len / 4;
    for (i = 0; i < array_length; i++) {
        *((uint32_t *) dst + i) = htonl(src->bi.a[array_length - 1 - i]);
    }

    return 0;
}

static bool init_key(QSEE_S_BIGINT **key, uint8_t *buf, uint32_t size) {
    *key = (QSEE_S_BIGINT *) tzwMalloc(sizeof(QSEE_S_BIGINT));
    if (*key != NULL) {
        qsee_BIGINT_read_unsigned_bin(&(*key)->bi, buf, size);
        return true;
    }
    return false;
}

IFAA_Result IFAA_RsaSignDigest(const IFAA_RsaKey* key,
                               const uint8_t* digest, uint32_t digest_len,
                               uint8_t* sig, uint32_t* sig_len)
{
    ////////////////////////////////////////////////
    ////rsa秘钥签名在高通的参考实现
    ////////////////////////////////////////////////

    IFAA_Result ret = IFAA_ERR_SUCCESS;
    QSEE_RSA_KEY rsa_key = {0};

    if(init_key(&(rsa_key.N), key->n.buf, key->n.len)
            && init_key(&(rsa_key.d), key->d.buf, key->d.len)
            && init_key(&(rsa_key.e), key->e.buf, key->e.len)) {

        rsa_key.type = QSEE_RSA_KEY_PRIVATE;
        int status = qsee_rsa_sign_hash(&rsa_key, QSEE_RSA_PAD_PKCS1_V1_5_SIG, NULL,
                                        QSEE_HASH_IDX_SHA256, digest, digest_len,
                                        sig, (int *) sig_len);
        if (status != 0) {
            LOG_E("qsee_rsa_sign_hash failed");
            ret = IFAA_ERR_SIGN;
        }
    } else {
        LOG_E("qsee_rsa_sign_hash failed");
        ret = IFAA_ERR_SIGN;
    }

    if (rsa_key.N != NULL) tzwFree(rsa_key.N);
    if (rsa_key.d != NULL) tzwFree(rsa_key.d);
    if (rsa_key.e != NULL) tzwFree(rsa_key.e);

    return ret;
}

#elif defined(__SAMSUNG_TEEGRIS__) || defined(__SAMSUNG_Kinibi__) /*__SAMSUNG_TEEGRIS__ || __SAMSUNG_Kinibi__*/

#define RSA2048_LEN 256
IFAA_Result IFAA_RsaSignDigest(const IFAA_RsaKey* key,
                               const uint8_t* digest, uint32_t digest_len,
                               uint8_t* sig, uint32_t* sig_len)
{
    LOG_I_PERF_BEGIN
    LOG_FUNC_BEGIN

    ////////////////////////////////////////////////
    ////rsa秘钥签名在GP的参考实现
    ////////////////////////////////////////////////

    TEE_Attribute attr[3];
    TEE_ObjectHandle keyobj = NULL;
    TEE_OperationHandle signop = NULL;
    TEE_Result ret = TEE_AllocateTransientObject(TEE_TYPE_RSA_KEYPAIR, 8 * RSA2048_LEN, &keyobj);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_AllocateTransientObject failed: %08x", ret);
        return IFAA_ERR_OUT_OF_MEM;
    }

    TEE_InitRefAttribute(&attr[0], TEE_ATTR_RSA_MODULUS, key->n.buf,
                         key->n.len);
    TEE_InitRefAttribute(&attr[1], TEE_ATTR_RSA_PUBLIC_EXPONENT, key->e.buf,
                         key->e.len);
    TEE_InitRefAttribute(&attr[2], TEE_ATTR_RSA_PRIVATE_EXPONENT, key->d.buf,
                         key->d.len);
    ret = TEE_PopulateTransientObject(keyobj, attr, 3);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_PopulateTransientObject failed: %08x", ret);
        ret = IFAA_ERR_UNKNOWN;
        goto bye;
    }

    ret = TEE_AllocateOperation(&signop, TEE_ALG_RSASSA_PKCS1_V1_5_SHA256,
                                TEE_MODE_SIGN, 8 * RSA2048_LEN);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_AllocateOperation failed: %08x", ret);
        ret = IFAA_ERR_UNKNOWN;
        goto bye;
    }

    TEE_SetOperationKey(signop, keyobj);
    ret = TEE_AsymmetricSignDigest(signop, NULL, 0, digest, digest_len, sig, sig_len);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_AsymmetricSignDigest failed: %08x", ret);
        ret = IFAA_ERR_UNKNOWN;
        goto bye;
    }

bye:
    if (keyobj != NULL) {
        TEE_FreeTransientObject(keyobj);
        keyobj = NULL;
    }

    if (signop != NULL) {
        TEE_FreeOperation(signop);
        signop = NULL;
    }

    if (TEE_SUCCESS == ret) ret = IFAA_ERR_SUCCESS;

    LOG_FUNC_END
    LOG_I_PERF_END

    return ret;
}
#else
#error ("TEE is not defined yet");
#endif

#if defined(__QUALCOMM__) /*__QUALCOMM__*/
IFAA_Result IFAA_RsaVerifyDigest(const IFAA_RsaKey* key,
                                 const uint8_t* digest, uint32_t digest_len,
                                 const uint8_t* sig, uint32_t sig_len)
{
    ////////////////////////////////////////////////
    ////rsa秘钥验签的高通的参考实现
    ////////////////////////////////////////////////

    IFAA_Result ret = IFAA_ERR_SUCCESS;
    QSEE_RSA_KEY rsa_key = {0};

    if(init_key(&(rsa_key.N), key->n.buf, key->n.len)
            && init_key(&(rsa_key.d), key->d.buf, key->d.len)
            && init_key(&(rsa_key.e), key->e.buf, key->e.len)) {


        rsa_key.type = QSEE_RSA_KEY_PUBLIC;
        int status = qsee_rsa_verify_signature(&rsa_key, QSEE_RSA_PAD_PKCS1_V1_5_SIG, NULL,
                                               QSEE_HASH_IDX_SHA256,
                                               (uint8_t *) digest, digest_len, (uint8_t *) sig,
                                               sig_len);
        if (status != 0) {
            LOG_E("qsee_rsa_verify_signature failed");
            ret = IFAA_ERR_VERIFY;
        }
    }
    else {
        LOG_E("verify digist: init_key failed.");
        ret = IFAA_ERR_VERIFY;
    }
    if (rsa_key.N != NULL) tzwFree(rsa_key.N);
    if (rsa_key.d != NULL) tzwFree(rsa_key.d);
    if (rsa_key.e != NULL) tzwFree(rsa_key.e);

    return ret;
}

#elif defined(__SAMSUNG_TEEGRIS__) || defined(__SAMSUNG_Kinibi__) /*__SAMSUNG_TEEGRIS__ || __SAMSUNG_Kinibi__*/
IFAA_Result IFAA_RsaVerifyDigest(const IFAA_RsaKey* key,
                                 const uint8_t* digest, uint32_t digest_len,
                                 const uint8_t* sig, uint32_t sig_len)
{
    LOG_I_PERF_BEGIN

    ////////////////////////////////////////////////
    ////rsa秘钥验签的GP的参考实现
    ////////////////////////////////////////////////
    TEE_Attribute       attr[2];
    TEE_ObjectHandle    keyobj = NULL;
    TEE_OperationHandle verifyop = NULL;
    TEE_Result          ret = TEE_AllocateTransientObject(TEE_TYPE_RSA_PUBLIC_KEY, 8 * RSA2048_LEN, &keyobj);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_AllocateTransientObject failed: %08x", ret);
        return IFAA_ERR_OUT_OF_MEM;
    }

    TEE_InitRefAttribute(&attr[0], TEE_ATTR_RSA_MODULUS, key->n.buf,
                         key->n.len);
    TEE_InitRefAttribute(&attr[1], TEE_ATTR_RSA_PUBLIC_EXPONENT, key->e.buf,
                         key->e.len);

    ret = TEE_PopulateTransientObject(keyobj, attr, 2);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_PopulateTransientObject failed: %08x", ret);
        ret = IFAA_ERR_UNKNOWN;
        goto bye;
    }

    ret = TEE_AllocateOperation(&verifyop, TEE_ALG_RSASSA_PKCS1_V1_5_SHA256, TEE_MODE_VERIFY, 8 * RSA2048_LEN);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_AllocateOperation failed: %08x", ret);
        ret = IFAA_ERR_UNKNOWN;
        goto bye;
    }

    TEE_SetOperationKey(verifyop, keyobj);
    ret = TEE_AsymmetricVerifyDigest(verifyop, NULL, 0, digest, digest_len, sig, sig_len);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_AsymmetricVerifyDigest failed: %08x", ret);
        ret = IFAA_ERR_UNKNOWN;
        goto bye;
    }

bye:
    if (keyobj != NULL) {
        TEE_FreeTransientObject(keyobj);
        keyobj = NULL;
    }
    if (verifyop != NULL) {
        TEE_FreeOperation(verifyop);
        verifyop = NULL;
    }

    if (TEE_SUCCESS == ret) {
        ret = IFAA_ERR_SUCCESS;
    }

    LOG_I_PERF_END

    return ret;
}
#else
#error ("TEE is not defined yet");
#endif

#if defined(__QUALCOMM__) /*__QUALCOMM__*/
IFAA_Result IFAA_RsaKeyGenerate(IFAA_RsaBit bits, IFAA_RsaKey* key)
{
    ////////////////////////////////////////////////
    ////rsa秘钥生成的高通参考实现
    ////////////////////////////////////////////////

    IFAA_Result ret = IFAA_ERR_SUCCESS;
    QSEE_RSA_KEY rsa_key = {0};
    uint8_t pub_exp[] = {0x00, 0x00, 0x01, 0x00, 0x01};

    do {
        if (qsee_util_init_s_bigint(&(rsa_key.e)) ||
            qsee_util_init_s_bigint(&(rsa_key.d)) ||
            qsee_util_init_s_bigint(&(rsa_key.N)) ||
            qsee_util_init_s_bigint(&(rsa_key.p)) ||
            qsee_util_init_s_bigint(&(rsa_key.q))) {
            LOG_ERROR("qsee_util_init_s_bigint failed.\n");
            ret = IFAA_ERR_KEY_GEN;
            break;
        }

        rsa_key.type = QSEE_RSA_KEY_PRIVATE_PUBLIC;

        switch(bits) {
            case RSA_BITS_2048:
                bits = 2048;
                break;
            case RSA_BITS_4096:
                bits = 4096;
                break;
        }

        int status =
        qsee_rsa_key_gen(&rsa_key, bits / 8, pub_exp, sizeof(pub_exp));
        if (status != 0) {
            LOG_ERROR("qsee_rsa_key_gen failed.\n");
            ret = IFAA_ERR_KEY_GEN;
            break;
        }

        if (copy_S_BIGINT(key->n.buf, QSEE_RSA_KEY_SIZE(rsa_key.N), rsa_key.N,
                          key->n.len) ||
            copy_S_BIGINT(key->d.buf, QSEE_RSA_KEY_SIZE(rsa_key.d), rsa_key.d,
                          key->d.len) ||
            copy_S_BIGINT(key->e.buf, QSEE_RSA_KEY_SIZE(rsa_key.e), rsa_key.e,
                          key->e.len)) {
                LOG_ERROR("copy_S_BIGINT failed.\n");
                ret = IFAA_ERR_KEY_GEN;
                break;
            }

        key->n.len = QSEE_RSA_KEY_SIZE(rsa_key.N);
        key->d.len = QSEE_RSA_KEY_SIZE(rsa_key.d);
        key->e.len = QSEE_RSA_KEY_SIZE(rsa_key.e);
    } while (false);

    if (rsa_key.d != NULL) qsee_util_free_s_bigint(rsa_key.d);
    if (rsa_key.N != NULL) qsee_util_free_s_bigint(rsa_key.N);
    if (rsa_key.p != NULL) qsee_util_free_s_bigint(rsa_key.p);
    if (rsa_key.q != NULL) qsee_util_free_s_bigint(rsa_key.q);
    if (rsa_key.e != NULL) qsee_util_free_s_bigint(rsa_key.e);

    return ret;
}

#elif defined(__SAMSUNG_TEEGRIS__) || defined(__SAMSUNG_Kinibi__) /*__SAMSUNG_TEEGRIS__ || __SAMSUNG_Kinibi__*/
IFAA_Result IFAA_RsaKeyGenerate(IFAA_RsaBit bits, IFAA_RsaKey *key)
{
    LOG_I_PERF_BEGIN

    ////////////////////////////////////////////////
    ////rsa秘钥生成的GP参考实现
    ////////////////////////////////////////////////

    TEE_ObjectHandle    keyobj = NULL;
    TEE_Result          ret;
    uint32_t            rsa_key_bits = 0;

    switch(bits)
    {
        case RSA_BITS_2048:
            rsa_key_bits = 2048;
            break;
        case RSA_BITS_4096:
            rsa_key_bits = 4096;
            break;
        default:
            return IFAA_ERR_BAD_PARAM;
    }

    ret = TEE_AllocateTransientObject(TEE_TYPE_RSA_KEYPAIR, rsa_key_bits, &keyobj);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_AllocateTransientObject failed: %08x", ret);
        return IFAA_ERR_UNKNOWN;
    }

    ret = TEE_GenerateKey(keyobj, rsa_key_bits, NULL, 0);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_GenerateKey failed: %08x", ret);
        ret = IFAA_ERR_UNKNOWN;
        goto bye;
    }

    ret = TEE_GetObjectBufferAttribute(keyobj, TEE_ATTR_RSA_MODULUS, key->n.buf, &key->n.len);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_GetObjectBufferAttribute for MODULUS failed: %08x", ret);
        ret = IFAA_ERR_UNKNOWN;
        goto bye;
    }

    ret = TEE_GetObjectBufferAttribute(keyobj, TEE_ATTR_RSA_PUBLIC_EXPONENT, key->e.buf, &key->e.len);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_GetObjectBufferAttribute for PUBLIC EXPONENT failed: %08x", ret);
        ret = IFAA_ERR_UNKNOWN;
        goto bye;
    }

    ret = TEE_GetObjectBufferAttribute(keyobj, TEE_ATTR_RSA_PRIVATE_EXPONENT, key->d.buf, &key->d.len);
    if (ret != IFAA_ERR_SUCCESS) {
        LOG_ERROR("TEE_GetObjectBufferAttribute for PRIVATE EXPONENT failed: %08x", ret);
        ret = IFAA_ERR_UNKNOWN;
        goto bye;
    }

bye:
    if (keyobj != NULL) {
        TEE_FreeTransientObject(keyobj);
        keyobj = NULL;
    }

    if (TEE_SUCCESS == ret) {
        ret = IFAA_ERR_SUCCESS;
    }

    LOG_I_PERF_END

    return ret;
}
#else
#error ("TEE is not defined yet");
#endif

#if defined(__QUALCOMM__) /*__QUALCOMM__*/
//Domain parameters for prime256v1
char m[] = "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff";

char a[] = "ffffffff00000001000000000000000000000000fffffffffffffffffffffffc";

char b[] = "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b";

char G_x[] = "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296";

char G_y[] = "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5";

char n[] = "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551";

IFAA_Result IFAA_EccKeyGenerate(IFAA_EccKey* key)
{
    ////////////////////////////////////////////////
    ////ECC秘钥生成的高通参考实现
    ////////////////////////////////////////////////

    IFAA_Result                     ret = IFAA_ERR_SUCCESS;
    QSEE_qrlbn_ecc_domain_t         domain;
    QSEE_qrlbn_ecc_affine_point_t   publicKey;
    QSEE_qrlbn_ecc_bigval_t         privateKey;
    uint8_t                         privateKeyBin[32];
    uint8_t                         publicKeyXBin[32];
    uint8_t                         publicKeyYBin[32];

    do {

        /* Initialise the domain parameters for the Brainpool prime256v1 curve */
        ret = qsee_SW_GENERIC_ECC_init(&domain, m, a, b, G_x, G_y, n, 1);
        if (ret) {
            LOG_ERROR("qsee_SW_GENERIC_ECC_init API failed.\n");
            ret = IFAA_ERR_KEY_GEN;
            break;
        }

        /* Generate a public/private key pair */
        ret = qsee_SW_GENERIC_ECC_keypair_generate(&privateKey, &publicKey, &domain);
        if (ret) {
            LOG_ERROR("qsee_SW_GENERIC_ECC_keypair_generate API failed to generate pair.\n");
            ret = IFAA_ERR_KEY_GEN;
            break;
        }

        ret = qsee_SW_GENERIC_ECC_bigval_to_binary(&privateKeyBin[0],
                                               sizeof(privateKeyBin),
                                               &privateKey,
                                               &domain,
                                               QSEE_qrlbn_tag_privkey);
        if (ret) {
            LOG_ERROR("qsee_SW_GENERIC_ECC_bigval_to_binary API failed on key p");
            ret = IFAA_ERR_KEY_GEN;
            break;
        }

        /* Convert the public key X coordinate to a binary form */
        ret = qsee_SW_GENERIC_ECC_bigval_to_binary(&publicKeyXBin[0],
                                           sizeof(publicKeyXBin),
                                           &publicKey.x,
                                           &domain,
                                           QSEE_qrlbn_tag_X);
        if (ret) {
            LOG_ERROR("qsee_SW_GENERIC_ECC_bigval_to_binary API failed on key x");
            ret = IFAA_ERR_KEY_GEN;
            break;
        }

        /* Convert the public key Y coordinate to a binary form */
        ret = qsee_SW_GENERIC_ECC_bigval_to_binary(&publicKeyYBin[0],
                                           sizeof(publicKeyYBin),
                                           &publicKey.y,
                                           &domain,
                                           QSEE_qrlbn_tag_Y);
        if (ret) {
            LOG_ERROR("qsee_SW_GENERIC_ECC_bigval_to_binary API failed on key y");
            ret = IFAA_ERR_KEY_GEN;
            break;
        }

        /* copy binary to IFAA_EccKey */
        memcpy(key->p.buf, (char*)privateKeyBin, 32);
        key->p.len = 32;
        memcpy(key->x.buf, (char*)publicKeyXBin, 32);
        key->x.len = 32;
        memcpy(key->y.buf, (char*)publicKeyYBin, 32);
        key->y.len = 32;
    } while (false);

    return ret;
}

#elif defined(__SAMSUNG_TEEGRIS__) || defined(__SAMSUNG_Kinibi__) /*__SAMSUNG_TEEGRIS__ || __SAMSUNG_Kinibi__*/
IFAA_Result IFAA_EccKeyGenerate(IFAA_EccKey* key)
{
    ////////////////////////////////////////////////
    ////ECC秘钥生成的GP参考实现
    ////////////////////////////////////////////////

	TEE_ObjectHandle    keyobj = NULL;
	uint32_t			keySize = 256; //Between 160 and 521 bits.
	uint32_t			attributeId = 0;
	TEE_Attribute		attr[1];
	
    TEE_Result ret = TEE_AllocateTransientObject(TEE_TYPE_ECDSA_KEYPAIR, keySize, &keyobj);
    if(ret != TEE_SUCCESS) {
    	LOG_E("TEE_AllocateTransientObject failed: %08x", ret);
    	return IFAA_ERR_UNKNOWN;
    }

	switch(keySize) {
		case 256:
			attributeId = TEE_ECC_CURVE_NIST_P256;
			break;
		default:
			break;
	}
	TEE_InitValueAttribute(attr, TEE_ATTR_ECC_CURVE, attributeId, 0);

	ret = TEE_GenerateKey(keyobj, keySize, attr, 1);
    if (ret != TEE_SUCCESS) {
		LOG_E("TEE_GenerateKey failed: %08x", ret);
    	ret = IFAA_ERR_UNKNOWN;
    	goto bye;
    }
	
	ret = TEE_GetObjectBufferAttribute(keyobj, TEE_ATTR_ECC_PUBLIC_VALUE_X, key->x.buf, &key->x.len);
  	if (ret != TEE_SUCCESS) {
		LOG_E("TEE_GetObjectBufferAttribute for PUBLIC X failed: %08x", ret);
		ret = IFAA_ERR_UNKNOWN;
		goto bye;
	}

  	ret = TEE_GetObjectBufferAttribute(keyobj, TEE_ATTR_ECC_PUBLIC_VALUE_Y, key->y.buf, &key->y.len);
  	if (ret != TEE_SUCCESS) {
  		LOG_E("TEE_GetObjectBufferAttribute for PUBLIC Y failed: %08x", ret);
  		ret = IFAA_ERR_UNKNOWN;
  		goto bye;
  	}

  	ret = TEE_GetObjectBufferAttribute(keyobj, TEE_ATTR_ECC_PRIVATE_VALUE, key->p.buf, &key->p.len);
  	if (ret != IFAA_ERR_SUCCESS) {
  		LOG_E("TEE_GetObjectBufferAttribute for ECC_PRIVATE  failed: %08x", ret);
  		ret = IFAA_ERR_UNKNOWN;
  		goto bye;
  	}

bye:
  	if (keyobj != NULL) {
  		TEE_FreeTransientObject(keyobj);
		keyobj = NULL;
  	}

	if (TEE_SUCCESS == ret) ret = IFAA_ERR_SUCCESS;
    LOG_D("ECCKey generate result = 0x%04x", ret);
    return ret;
}
#else
#error ("TEE is not defined yet");
#endif

#if defined(__QUALCOMM__) /*__QUALCOMM__*/
IFAA_Result IFAA_EccSignDigest(const IFAA_EccKey* key,
                               const uint8_t* digest, uint32_t digest_len,
                               uint8_t* sig, uint32_t* sig_len)
{
    ////////////////////////////////////////////////
    ////ECC秘钥签名在高通的参考实现
    ////////////////////////////////////////////////

    IFAA_Result              ret = IFAA_ERR_SUCCESS;
    QSEE_qrlbn_ecc_domain_t  domain;
    QSEE_qrlbn_ecc_bigval_t  private_key = {0};
    QSEE_qrlbn_ECDSA_sig_t   signature_data = {0};
    uint8_t                  sig_r_bin[32];
    uint8_t                  sig_s_bin[32];
    uint8_t*                 buf = sig;

    /* Initialise the domain parameters for the Brainpool 256r1 curve */
    ret = qsee_SW_GENERIC_ECC_init(&domain, m, a, b, G_x, G_y, n, 1);
    if (ret) {
        LOG_ERROR("qsee_SW_GENERIC_ECC_init API failed.\n");
        ret = IFAA_ERR_SIGN;
        goto ret_handle;
    }

    //Convert private_key binary data to private.key.data Bigval
    ret = qsee_SW_GENERIC_ECC_binary_to_bigval(&private_key, key->p.buf, key->p.len,
                                                &domain, QSEE_qrlbn_tag_privkey);
    if (ret != 0) {
        LOG_ERROR("qsee_SW_GENERIC_ECC_binary_to_bigval failed");
        ret = IFAA_ERR_SIGN;
        goto ret_handle;
    }

    // Sign
    ret = qsee_SW_GENERIC_ECDSA_sign(digest, digest_len, &private_key, &signature_data, &domain);
    if (ret != 0) {
        LOG_ERROR("qsee_SW_GENERIC_ECDSA_sign failed");
        ret = IFAA_ERR_SIGN;
        goto ret_handle;
    }

    //Convert signature_data.r Bigval to signature r binary data
    ret = qsee_SW_GENERIC_ECC_bigval_to_binary(sig_r_bin, 32, &signature_data.r, &domain, QSEE_qrlbn_tag_r);
    if (ret != 0) {
        LOG_ERROR("qsee_SW_GENERIC_ECC_bigval_to_binary failed");
        ret = IFAA_ERR_SIGN;
        goto ret_handle;
    }

    //Convert signature_data.s Bigval to signature s binary data
    ret = qsee_SW_GENERIC_ECC_bigval_to_binary(sig_s_bin, 32, &signature_data.s, &domain, QSEE_qrlbn_tag_s);
    if (ret != 0) {
        LOG_ERROR("qsee_SW_GENERIC_ECC_bigval_to_binary failed");
        ret = IFAA_ERR_SIGN;
        goto ret_handle;
    }

    memcpy(buf, sig_r_bin, 32);
    buf += 32;
    memcpy(buf, sig_s_bin, 32);
    *sig_len = 64;

ret_handle:

	return ret;
}

#elif defined(__SAMSUNG_TEEGRIS__) || defined(__SAMSUNG_Kinibi__) /*__SAMSUNG_TEEGRIS__ || __SAMSUNG_Kinibi__*/
IFAA_Result IFAA_EccSignDigest(const IFAA_EccKey* key,
                               const uint8_t* digest, uint32_t digest_len,
                               uint8_t* sig, uint32_t* sig_len)
{
    ////////////////////////////////////////////////
    ////ECC秘钥签名在GP的参考实现
    ////////////////////////////////////////////////
	TEE_Attribute attr[4];
    TEE_ObjectHandle keyobj = NULL;
    TEE_OperationHandle signop = NULL;
	uint32_t keySize = 256;

    TEE_Result ret = TEE_AllocateTransientObject(TEE_TYPE_ECDSA_KEYPAIR, keySize, &keyobj);
	if (ret != TEE_SUCCESS) {
    	LOG_E("ecc sign digest TEE_AllocateTransientObject failed: %08x", ret);
    	return IFAA_ERR_OUT_OF_MEM;
    }
	
    TEE_InitRefAttribute(&attr[0], TEE_ATTR_ECC_PUBLIC_VALUE_X, key->x.buf,key->x.len);
    TEE_InitRefAttribute(&attr[1], TEE_ATTR_ECC_PUBLIC_VALUE_Y, key->y.buf,key->y.len);
	TEE_InitRefAttribute(&attr[2], TEE_ATTR_ECC_PRIVATE_VALUE, key->p.buf,key->p.len);
    TEE_InitValueAttribute(&attr[3], TEE_ATTR_ECC_CURVE, TEE_ECC_CURVE_NIST_P256, 0);	

    LOG_D("EccSignDigest allocate transientObject ret: %08x", ret);
	ret = TEE_PopulateTransientObject(keyobj, attr, 4);
    if (ret != TEE_SUCCESS) {
		LOG_E("TEE_PopulateTransientObject failed: %08x", ret);
		ret = IFAA_ERR_UNKNOWN;
		goto bye;
    }

   	ret = TEE_AllocateOperation(&signop, TEE_ALG_ECDSA_P256, TEE_MODE_SIGN, keySize);
    if (ret != TEE_SUCCESS) {
		LOG_E("TEE_AllocateOperation failed: %08x", ret);
		ret = IFAA_ERR_UNKNOWN;
		goto bye;
    }

    TEE_SetOperationKey(signop, keyobj);
    ret = TEE_AsymmetricSignDigest(signop, NULL, 0, digest, digest_len, sig, sig_len);
    if (ret != TEE_SUCCESS) {
		LOG_E("TEE_AsymmetricSignDigest failed: %08x", ret);
		ret = IFAA_ERR_UNKNOWN;
		goto bye;
    }
bye:
	if (keyobj != NULL) {
		TEE_FreeTransientObject(keyobj);
		keyobj = NULL;
    }

    if (signop != NULL) {
		TEE_FreeOperation(signop);
		signop = NULL;
    }

    if (TEE_SUCCESS == ret) ret = IFAA_ERR_SUCCESS;
    return ret;
}
#else
#error ("TEE is not defined yet");
#endif

#if defined(__QUALCOMM__) /*__QUALCOMM__*/
IFAA_Result IFAA_EccVerifyDigest(const IFAA_EccKey* key,
                                 const uint8_t* digest, uint32_t digest_len,
                                 const uint8_t* sig, uint32_t sig_len)
{
    ////////////////////////////////////////////////
    ////ecc秘钥验签的高通的参考实现
    ////////////////////////////////////////////////

    IFAA_Result                    ret = IFAA_ERR_SUCCESS;
    QSEE_qrlbn_ECDSA_sig_t         signature_data;
    QSEE_qrlbn_ecc_affine_point_t  public_key = {0};
    QSEE_qrlbn_ecc_domain_t        domain;
    uint8_t                        *sig_r_bin = NULL;
    uint8_t                        *sig_s_bin = NULL;

    memset(&public_key, 0, sizeof(QSEE_qrlbn_ecc_affine_point_t));
    memset(&signature_data, 0, sizeof(QSEE_qrlbn_ECDSA_sig_t));

    /* Initialise the domain parameters for the Brainpool 256r1 curve */
    ret = qsee_SW_GENERIC_ECC_init(&domain, m, a, b, G_x, G_y, n, 1);
    if (ret) {
        LOG_ERROR("qsee_SW_GENERIC_ECC_init API failed.\n");
        ret = IFAA_ERR_VERIFY;
        goto ret_handle;
    }

    //Convert x binary data to public_key.x Bigval
    ret = qsee_SW_GENERIC_ECC_binary_to_bigval(&public_key.x, key->x.buf, key->x.len,
                                                &domain, QSEE_qrlbn_tag_X);
    if (ret != 0) {
        LOG_ERROR("qsee_SW_GENERIC_ECC_binary_to_bigval failed");
        ret = IFAA_ERR_VERIFY;
        goto ret_handle;
    }

    //Convert y binary data to public_key.y Bigval
    ret = qsee_SW_GENERIC_ECC_binary_to_bigval(&public_key.y, key->y.buf, key->y.len,
                                                &domain, QSEE_qrlbn_tag_Y);
    if (ret != 0) {
        LOG_ERROR("qsee_SW_GENERIC_ECC_binary_to_bigval failed");
        ret = IFAA_ERR_VERIFY;
        goto ret_handle;
    }

    sig_r_bin = sig;
    sig_s_bin = sig + 32;

    //Convert r binary data to signature_data.r Bigval
    ret = qsee_SW_GENERIC_ECC_binary_to_bigval(&signature_data.r, sig_r_bin, 32, &domain, QSEE_qrlbn_tag_r);
    if (ret != 0) {
        LOG_ERROR("qsee_SW_GENERIC_ECC_binary_to_bigval failed");
        ret = IFAA_ERR_VERIFY;
        goto ret_handle;
    }

    //Convert s binary data to signature_data.s Bigval
    ret = qsee_SW_GENERIC_ECC_binary_to_bigval(&signature_data.s, sig_s_bin, 32, &domain, QSEE_qrlbn_tag_s);
    if (ret != 0) {
        LOG_ERROR("qsee_SW_GENERIC_ECC_binary_to_bigval failed");
        ret = IFAA_ERR_VERIFY;
        goto ret_handle;
    }

    ret = qsee_SW_GENERIC_ECDSA_verify(digest, digest_len, &public_key, &signature_data, &domain);
    if (ret != 0) {
        LOG_ERROR("qsee_SW_GENERIC_ECDSA_verify failed");
        ret = IFAA_ERR_VERIFY;
        goto ret_handle;
    }

ret_handle:

	return ret;
}

#elif defined(__SAMSUNG_TEEGRIS__) || defined(__SAMSUNG_Kinibi__) /*__SAMSUNG_TEEGRIS__ || __SAMSUNG_Kinibi__*/
IFAA_Result IFAA_EccVerifyDigest(const IFAA_EccKey* key,
                                 const uint8_t* digest, uint32_t digest_len,
                                 const uint8_t* sig, uint32_t sig_len)
{
    ////////////////////////////////////////////////
    ////ecc秘钥验签的GP的参考实现
    ////////////////////////////////////////////////
	TEE_Attribute       attr[0];
    TEE_ObjectHandle    keyobj = TEE_HANDLE_NULL;
    TEE_OperationHandle verifyop = TEE_HANDLE_NULL;
	uint32_t			keySize = 256;

    TEE_Result  ret = TEE_AllocateTransientObject(TEE_TYPE_ECDSA_PUBLIC_KEY, keySize, &keyobj);
    if (ret != TEE_SUCCESS) {
		LOG_E("TEE_AllocateTransientObject failed: %08x", ret);
		return IFAA_ERR_OUT_OF_MEM;
    }

    TEE_InitRefAttribute(&attr[0], TEE_ATTR_ECC_PUBLIC_VALUE_X, key->x.buf,key->x.len);
    TEE_InitRefAttribute(&attr[1], TEE_ATTR_ECC_PUBLIC_VALUE_Y, key->y.buf,key->y.len);
    TEE_InitValueAttribute(&attr[2], TEE_ATTR_ECC_CURVE, TEE_ECC_CURVE_NIST_P256, 0);

    ret = TEE_PopulateTransientObject(keyobj, attr, 3);
    if (ret != TEE_SUCCESS) {
		LOG_E("TEE_PopulateTransientObject failed: %08x", ret);
		ret = IFAA_ERR_UNKNOWN;
		goto bye;
    }

    ret = TEE_AllocateOperation(&verifyop, TEE_ALG_ECDSA_P256, TEE_MODE_VERIFY, keySize);
    if (ret != TEE_SUCCESS) {
		LOG_E("TEE_AllocateOperation failed: %08x", ret);
		ret = IFAA_ERR_UNKNOWN;
		goto bye;
    }

    TEE_SetOperationKey(verifyop, keyobj);
 	
	ret = TEE_AsymmetricVerifyDigest(verifyop, NULL, 0, digest, digest_len, sig, sig_len);
    if (ret != TEE_SUCCESS) {
		LOG_E("TEE_AsymmetricVerifyDigest failed: %08x", ret);
		ret = IFAA_ERR_UNKNOWN;
		goto bye;
    }

bye:
    if (keyobj != NULL) {
		TEE_FreeTransientObject(keyobj);
		keyobj = NULL;
    }
    if (verifyop != NULL) {
		TEE_FreeOperation(verifyop);
		verifyop = NULL;
    }
    if (TEE_SUCCESS == ret) ret = IFAA_ERR_SUCCESS;
    return ret;
}
#else
#error ("TEE is not defined yet");
#endif


#define SHA1_HASH_LEN   20

#if defined(__QUALCOMM__) /*__QUALCOMM__*/
IFAA_Result IFAA_HmacSha1(const uint8_t *msg, uint32_t msg_len,
                          const uint8_t *key, uint32_t key_len,
                          uint8_t *mac)
{
    int ret = qsee_hmac(QSEE_HMAC_SHA1, msg, msg_len, key, key_len, mac);
    if (ret < 0) {
        LOG_ERROR("qsee_hmac failed");
        return IFAA_ERR_HASH;
    }

    return IFAA_ERR_SUCCESS;
}

#elif defined(__SAMSUNG_TEEGRIS__) || defined(__SAMSUNG_Kinibi__) /*__SAMSUNG_TEEGRIS__ || __SAMSUNG_Kinibi__*/
IFAA_Result IFAA_HmacSha1(const uint8_t *msg, uint32_t msg_len,
                          const uint8_t *key, uint32_t key_len,
                          uint8_t *mac)
{
    ////////////////////////////////////////////////
    ////hmacsha1的标准实现
    ////////////////////////////////////////////////

#define B 64
    TEE_OperationHandle op = NULL;
    uint8_t k_ipad[B + 1] = {0}; /* inner padding - key XORd with ipad */
    uint8_t k_opad[B + 1] = {0}; /* outer padding - key XORd with opad */

    /* if key is longer than 64 bytes reset it to key=SHA1(key) */
    if (key_len > B) {
        TEE_AllocateOperation(&op, TEE_ALG_SHA1, TEE_MODE_DIGEST, 0);
        TEE_DigestUpdate(op, key, key_len);
        TEE_DigestDoFinal(op, NULL, 0, (void*)key, (void*)(&key_len));
        TEE_FreeOperation(op);
    }

    memset(k_ipad, 0, sizeof(k_ipad));
    memset(k_opad, 0, sizeof(k_opad));
    memcpy(k_ipad, key, key_len);
    memcpy(k_opad, key, key_len);
    for (int i = 0; i < B; ++i) {
        k_ipad[i] ^= 0x36;
        k_opad[i] ^= 0x5c;
    }
    uint32_t mac_len = SHA1_HASH_LEN;

    // perform inner SHA1
    TEE_AllocateOperation(&op, TEE_ALG_SHA1, TEE_MODE_DIGEST, 0);
    TEE_DigestUpdate(op, k_ipad, B);
    TEE_DigestDoFinal(op, msg, msg_len, mac, &mac_len);
    TEE_FreeOperation(op);

    // perform outer SHA1
    TEE_AllocateOperation(&op, TEE_ALG_SHA1, TEE_MODE_DIGEST, 0);
    TEE_DigestUpdate(op, k_opad, B);
    TEE_DigestDoFinal(op, mac, SHA1_HASH_LEN, mac, &mac_len);
    TEE_FreeOperation(op);

    return IFAA_ERR_SUCCESS;
}
#else
#error ("TEE is not defined yet");
#endif


IFAA_Result HOTPex(uint8_t* data, size_t data_len, uint8_t* hotp, uint32_t* hotp_len)
{
#define MAX_CODE_LENGTH 8

    if (*hotp_len < 4) {
        return IFAA_ERR_BAD_PARAM;
    }

    if (*hotp_len > MAX_CODE_LENGTH) {
        *hotp_len = MAX_CODE_LENGTH;
    }

    uint8_t hash1[SHA1_HASH_LEN] = {0};
    uint8_t hash2[SHA1_HASH_LEN] = {0};
    uint8_t KEY1[] = {0x8D, 0x30, 0x16, 0x15, 0xFE, 0x43, 0xE6, 0x25,
        0xAB, 0xEC, 0x6F, 0xE2, 0xA5, 0xF3, 0x81, 0x3D,
        0x34, 0xC5, 0x99, 0x5C, 0x2F, 0xF8, 0x6C, 0x94,
        0x38, 0x1F, 0xAA, 0xBC, 0x7B, 0x88, 0xC3, 0x74,
        0x8A, 0x3C, 0x2B, 0x4E, 0x13, 0x04, 0xF8, 0x6B};
    uint8_t KEY2[] = {0xE3, 0x42, 0xA9, 0xFA, 0x17, 0x2A, 0xA6, 0x4E,
        0xC2, 0x33, 0x9B, 0x95, 0xCB, 0x55, 0x5A, 0xBF,
        0x07, 0xA7, 0x04, 0x60, 0xE0, 0xA9, 0xDE, 0x3B,
        0xD6, 0x84, 0x55, 0x81, 0xC8, 0xC0, 0xE3, 0x9B,
        0x0F, 0xDB, 0xBF, 0x9E, 0xE9, 0x6F, 0x1F, 0xA4};

    CHECK_FUNC_RET(IFAA_HmacSha1(data, data_len, KEY1, sizeof(KEY1), hash1));
    CHECK_FUNC_RET(IFAA_HmacSha1(data, data_len, KEY2, sizeof(KEY2), hash2));

    // zip and fold
    uint8_t code[MAX_CODE_LENGTH] = {0};
    int offset = hash1[SHA1_HASH_LEN - 1] & 0x0f;
    code[3] = hash1[offset + 0] & 0x7f;
    code[2] = hash1[offset + 1] & 0xff;
    code[1] = hash1[offset + 2] & 0xff;
    code[0] = hash1[offset + 3] & 0xff;

    offset = hash2[SHA1_HASH_LEN - 1] & 0x0f;
    code[4] = hash2[offset + 0] & 0x7f;
    code[5] = hash2[offset + 1] & 0xff;
    code[6] = hash2[offset + 2] & 0xff;
    code[7] = hash2[offset + 3] & 0xff;

    memcpy(hotp, code, *hotp_len);

    return IFAA_ERR_SUCCESS;
}

IFAA_Result IFAA_GetDeviceId(uint8_t* buf, uint32_t* len)
{
    ///////////////////////////////////////////////////////////////////////////
    ////获取设备ID的参考实现
    ////注:这里提供为样例，实际开发时应实现在TEE_GetDeviceId里
    ////此处仅做增加 device vendor + chip vendor + TEE vendor + sensor vendor前缀
    ///////////////////////////////////////////////////////////////////////////

#define HOTP_LEN        8
#define DEVICE_ID_LEN   40
#define PREFIX_LEN      8
#define SHA256_HASH_LEN 32

    if (buf == NULL || len == NULL || *len < DEVICE_ID_LEN) {
        LOG_ERROR("get_device_id_impl - invalid parameter");
        return IFAA_ERR_BAD_PARAM;
    }

    uint8_t *p = buf;
    write16(p, IFAA_DEVICE_VENDOR_ID);
    p += 2;
    write16(p, IFAA_CHIP_VENDOR_ID);
    p += 2;
    write16(p, IFAA_TEE_VENDOR_ID);
    p += 2;
    write16(p, IFAA_SENSOR_VENDOR_ID);
    p += 2;

    uint8_t data[DEVICE_ID_LEN] = {0};
    uint32_t data_len = sizeof(data);
    ////////////////////////////////////////////////
    ////将data里填充上硬件设备id
    ////////////////////////////////////////////////
    TEE_GetDeviceId(data, &data_len);

    uint8_t digest[SHA256_HASH_LEN];
    uint32_t digest_len = SHA256_HASH_LEN;
    IFAA_Result ret = IFAA_Sha256(data, data_len, digest, &digest_len);
    if (ret != IFAA_ERR_SUCCESS) {
        LOG_ERROR("sha256 failed: 0x%08x", ret);
        return ret;
    }

    uint8_t hotp[HOTP_LEN] = {0};
    uint32_t hotp_len = sizeof(hotp);
    HOTPex(digest, digest_len, hotp, &hotp_len);

    int otp_index[HOTP_LEN] = {17, 3, 36, 9, 22, 38, 10, 25};
    for (int i = 0, k = 0; i < SHA256_HASH_LEN; ++i) {
        for (int j = 0; j < HOTP_LEN; ++j) {
            if (k == otp_index[j]) {
                p[k] = hotp[j];
                k++;
            }
        }
        p[k] = digest[i];
        k++;
    }
    *len = DEVICE_ID_LEN + PREFIX_LEN;

    return IFAA_ERR_SUCCESS;
}

IFAA_Result IFAA_GetProtocolVersion(uint8_t *version, uint32_t *version_len)
{
    ////////////////////////////////////////////////
    ////获取TA版本，当前IFAA版本号为1
    ////////////////////////////////////////////////

    int32_t i_version = TEE_GetAuthenticatorVersion();
    LOG_DBG("Authenticator version: %d", i_version);
    write32(version, i_version);
    *version_len = sizeof(i_version);

    return IFAA_ERR_SUCCESS;
}

IFAA_Result IFAA_GetOptionalCertEncodeAlg(uint8_t *algs, uint32_t *algs_len)
{
    //////////////////////////////////////////////////////////
    ////获取TA支持的证书编码格式，至少包含CERT_ENCODE_ALG_IFAA
    //////////////////////////////////////////////////////////

    //write32(algs, CERT_ENCODE_ALG_IFAA | CERT_ENCODE_ALG_X509);
    write32(algs, CERT_ENCODE_ALG_IFAA);
    *algs_len = 4;
    return IFAA_ERR_SUCCESS;
}

IFAA_Result IFAA_CheckCert(const IFAA_Certificate *cert, IFAA_Certificate *rootcert)
{
    IFAA_Result ret;
    uint8_t digest[64] = {0};
    uint32_t digest_len = sizeof(digest);
    uint32_t msg_len = cert->body.ifaa_cert.pub_key.n.len +
    cert->body.ifaa_cert.pub_key.e.len +
                       sizeof(uint32_t) * 2;
    uint8_t *msg = (uint8_t *) tzwMalloc(msg_len);
    if (NULL == msg) {
        LOG_ERROR("malloc failed.");
        return IFAA_ERR_OUT_OF_MEM;
    }

    IFAA_RsaKey rsakey;
    if (!cert || !rootcert) {
        LOG_ERROR("Invalid parameters");
        tzwFree(msg);
        return IFAA_ERR_BAD_PARAM;
    }

    write32(msg, cert->body.ifaa_cert.pub_key.n.len);
    memcpy(msg + 4, cert->body.ifaa_cert.pub_key.n.buf, cert->body.ifaa_cert.pub_key.n.len);
    write32(msg + cert->body.ifaa_cert.pub_key.n.len + 4, cert->body.ifaa_cert.pub_key.e.len);
    memcpy(msg+cert->body.ifaa_cert.pub_key.n.len +8, cert->body.ifaa_cert.pub_key.e.buf, cert->body.ifaa_cert.pub_key.e.len);

    rsakey.n = rootcert->body.ifaa_cert.pub_key.n;
    rsakey.e = rootcert->body.ifaa_cert.pub_key.e;

    ret = IFAA_Sha256(msg, msg_len, digest, &digest_len);
    if (ret != IFAA_ERR_SUCCESS) {
        LOG_ERROR("DigestCal err!");
        tzwFree(msg);
        msg = NULL;
        return IFAA_ERR_BAD_PARAM;
    }

    ret = IFAA_RsaVerifyDigest(&rsakey, digest, digest_len,
                               cert->body.ifaa_cert.sig.buf,
                               cert->body.ifaa_cert.sig.len);
    if (ret != IFAA_ERR_SUCCESS) {
        LOG_ERROR("IFAA_RsaVerifyDigest err!");
        tzwFree(msg);
        msg = NULL;
        return IFAA_ERR_BAD_PARAM;
    }
    if (msg)
        tzwFree(msg);
    msg = NULL;

    return ret;
}


////////////////////////////////////////////////
////以下为测试IFAA根公钥(附自签名)
////////////////////////////////////////////////
#define ROOT_CERT_N (uint8_t[]){ \
    0x89,0x91,0xc3,0x0f,0x87,0x19,0xef,0xbf,0xec,0x56,0xb6,0x14,0x33,0x6f,0xd9,0x6b,0xbd,0xc8,0x06,0x09, \
    0x3a,0x42,0xa4,0x76,0xcd,0x01,0x26,0x06,0x44,0xfe,0x88,0x5c,0x59,0xc9,0xef,0x12,0xea,0xdd,0x2d,0xf3, \
    0x77,0xaa,0x0d,0xf2,0x95,0x60,0x08,0x2a,0xd7,0x75,0x3c,0x96,0x9f,0xd6,0x62,0xd8,0xe4,0xa8,0xa2,0x12, \
    0xb6,0x01,0x78,0x2a,0x55,0x82,0x4f,0x76,0x4d,0x91,0x00,0xa2,0x42,0xb6,0x8e,0x30,0xf0,0xb6,0x5c,0x5a, \
    0x5c,0x3d,0xb3,0xb0,0x93,0xb9,0xcb,0x06,0xaa,0xc0,0x29,0x5f,0x0e,0xc2,0x4a,0x23,0xca,0xbe,0x15,0xf1, \
    0x64,0x98,0xad,0xfa,0xd5,0x87,0xed,0x72,0x5b,0x03,0xec,0xb4,0xb6,0x44,0xfe,0x1c,0x35,0x0f,0x89,0xaa, \
    0xa5,0xf0,0x31,0x2a,0xb0,0x24,0xcc,0x42,0xa5,0x41,0x8e,0x9d,0xeb,0x91,0xb2,0x0e,0xf3,0xdb,0x8e,0x25, \
    0x1b,0xf5,0x72,0x35,0xa9,0x41,0xa2,0x91,0x13,0xa1,0x4d,0x74,0xe4,0xa3,0x4a,0x6c,0xa6,0x83,0xef,0xc9, \
    0x71,0x26,0x8b,0xa9,0x81,0x58,0x73,0xfe,0xf1,0x21,0x20,0x35,0x62,0x80,0x2d,0x7f,0xb3,0x50,0xbf,0x6a, \
    0x85,0x0b,0x38,0x0c,0xa9,0xa4,0xd5,0x97,0x71,0x24,0x3c,0xfd,0x6e,0x77,0x01,0x03,0xdb,0x1a,0x9d,0x5b, \
    0xa3,0xfa,0x15,0xad,0x5a,0x78,0xcd,0x4d,0x53,0xad,0xed,0x81,0x20,0x4a,0x8d,0x22,0x3d,0xfd,0xb8,0x8e, \
    0x6a,0x13,0x41,0xdb,0xe9,0xe2,0xa8,0x28,0x78,0x5c,0xf1,0x6a,0x5e,0x83,0x19,0xb4,0x0d,0xf5,0xf8,0xfe, \
    0x27,0x90,0xaf,0xbd,0x25,0xa6,0x89,0x84,0xb1,0xb9,0xdc,0xe5,0x9e,0x00,0x38,0x27 }

#define ROOT_CERT_E (uint8_t[]){ 0x1,0x0,0x1 }

#define ROOT_CERT_SIG (uint8_t[]){ \
    0x63,0x66,0xcb,0x3,0xff,0x14,0x59,0x52,0x93,0x3a,0xa9,0x24,0x9,0x21,0x8a,0xdd,0xb6,0x72,0xa2,0xbd,  \
    0x34,0x95,0x6d,0x2f,0x2e,0xf1,0x28,0x38,0xe0,0x99,0x5a,0x73,0xb6,0x71,0x97,0x80,0xe3,0x9,0x60,0xea,  \
    0xcc,0x56,0x19,0x34,0x7c,0xc8,0x2a,0xbc,0xb3,0x88,0x1b,0x14,0x8e,0xb0,0x9b,0xa7,0xcf,0xaf,0xb8,0x38, \
    0x76,0xab,0xc0,0x63,0x22,0x1c,0x5f,0x71,0x5f,0x9,0x5f,0x19,0x5,0xb7,0x61,0x5f,0xe4,0xfe,0x97,0xad,  \
    0x91,0x52,0x7e,0xbc,0x87,0x93,0x2e,0x60,0x47,0x7b,0x24,0x8d,0x25,0x40,0xce,0xf1,0x26,0xa8,0x57,0xab,    \
    0xba,0x77,0xf,0x2,0xf1,0xaf,0x6d,0xed,0xd4,0x4,0xe1,0xcb,0xb7,0x6e,0x78,0x4a,0x65,0x1,0x21,0x3e,    \
    0x54,0xe3,0x8e,0x8e,0xd1,0xb3,0x60,0xf4,0xd4,0x61,0xfa,0xa8,0x63,0x62,0x20,0xf9,0xfa,0x85,0x2d,0x2f, \
    0x1,0x33,0xa1,0x23,0xf2,0x7d,0x54,0x18,0x3e,0x52,0xd8,0x88,0x4,0x23,0xd,0x3d,0xaa,0x77,0xa0,0x55,   \
    0x37,0xa5,0xc4,0x1,0xe9,0x22,0x2d,0xef,0x36,0x98,0xa9,0xf6,0xbe,0xf3,0x7,0x89,0x40,0x88,0x16,0xb3,  \
    0x8c,0x7,0x6a,0x3e,0xb6,0xe3,0x59,0xb1,0x7a,0x84,0x17,0xa2,0x2e,0x37,0x3a,0xae,0xdf,0xa0,0xd9,0x52, \
    0xbb,0xc1,0xe5,0x82,0x4d,0x40,0x50,0xe2,0x5d,0x2,0xe0,0x3,0x44,0x68,0x18,0xcd,0xc8,0xba,0xd,0xc0,   \
    0x60,0x44,0x9e,0x72,0xad,0xc5,0x12,0x50,0x54,0x73,0xd8,0x5f,0x28,0xbb,0xae,0x1b,0xe7,0x72,0x3a,0xa8, \
    0x59,0x3d,0x8b,0xdf,0xc0,0x3a,0xb7,0x1c,0x8a,0x8f,0x6f,0xa3,0x68,0x1f,0xc0,0x2f }


////////////////////////////////////////////////
////测试环境设备秘钥
////////////////////////////////////////////////
#define PRI_N (unsigned char[]) { \
    0xc3,0x49,0x30,0xb7,0xb5,0xb2,0xdb,0xcb,0xae,0x33,0x29,0x19,0xbc,0xa7,0x51,0x1,0x7c,0xab,0xb5,0x8d, \
    0xfe,0x71,0x7a,0xd3,0x2e,0xa1,0x57,0xcb,0xf0,0x15,0x1a,0x4c,0xb1,0xc6,0xba,0x6b,0xa,0xb3,0x8c,0x56, \
    0x49,0x51,0x48,0xd,0x62,0x6d,0x1d,0x51,0xae,0xfb,0x53,0x47,0x46,0x45,0xcd,0x8e,0x58,0xb7,0x4f,0x39, \
    0xef,0x7,0x1f,0xf7,0xdb,0x4b,0xe5,0x4a,0xbd,0xdf,0xcb,0xf3,0x38,0xca,0xa8,0x6e,0xcb,0x21,0x10,0x8a, \
    0xfb,0x88,0x15,0x56,0xcc,0xe6,0x3c,0x99,0x81,0xd8,0xc7,0xe9,0xf4,0x5f,0xa1,0xd8,0xd9,0xa9,0x49,0x35, \
    0xe5,0x5b,0xae,0x2,0x76,0xee,0x8f,0x6,0x9b,0x1f,0x96,0x9a,0x83,0x29,0x44,0x6b,0xf4,0x82,0x64,0xd8, \
    0xf8,0x97,0x90,0x69,0xae,0xe5,0xd1,0x3,0xd9,0x14,0x9e,0x81,0xa7,0xc7,0xc3,0x6d,0x46,0xcb,0xb1,0xcf, \
    0x9b,0x55,0xbe,0x43,0xc3,0x5e,0xdb,0xbe,0xf6,0xcf,0xdc,0x3b,0xbb,0xb3,0xf4,0x4f,0xda,0xad,0x3e,0xc3, \
    0x55,0x3d,0x1e,0x5f,0xdf,0xb5,0xa9,0x31,0x6f,0x1d,0xc3,0xc4,0x5,0xfe,0x63,0xaf,0x86,0xe2,0x31,0xe8, \
    0xe6,0x8,0x12,0x25,0xf1,0xc5,0x47,0x3,0xd2,0xb,0x46,0x30,0x42,0x8,0xa6,0xe3,0x8c,0xba,0x13,0x35, \
    0x7,0xec,0x29,0x73,0xa5,0xf3,0xdc,0x50,0xa8,0xd4,0xf6,0x58,0x4b,0x54,0xfd,0x9,0x79,0x4f,0xaf,0x34, \
    0xe1,0xa,0xa2,0xb0,0x20,0x80,0xe7,0x48,0xee,0xfe,0x47,0x3f,0x84,0x6a,0x20,0x4e,0x7e,0x8d,0x46,0xf1, \
    0xee,0x63,0x4a,0xe7,0xd2,0x2a,0xeb,0xf7,0xb7,0x6d,0xec,0xb3,0x7c,0x6d,0xe6,0x7b }

#define PRI_E (unsigned char[]) { 0x1,0x0,0x1 }

#define PRI_D (unsigned char[]) { \
    0xb6,0x2f,0xd1,0x0,0x82,0xc5,0xf3,0x62,0x49,0x9,0x37,0xbd,0xe8,0xf,0x9c,0x76,0x2b,0xae,0x31,0xf9, \
    0xdf,0xb8,0x54,0xe3,0x32,0x2c,0x99,0xb1,0xc,0x31,0x53,0xd0,0xdb,0x45,0xd0,0x62,0xce,0xa0,0x5,0x3b, \
    0xf6,0xb8,0x9a,0xe4,0xc9,0xbf,0x8c,0x4b,0xc9,0x58,0x75,0x30,0x18,0x72,0x44,0xbc,0x19,0x2e,0x22,0xfe, \
    0xa4,0x6d,0xdc,0x38,0x2a,0xe1,0xda,0x6f,0x69,0x46,0xa1,0x8a,0x2e,0xa0,0x7a,0x94,0xaa,0x73,0x15,0x70, \
    0xe4,0xa,0xe8,0x5,0x8b,0xb0,0xfc,0x36,0x26,0x3a,0x6c,0xff,0x69,0xd9,0xd2,0x2f,0x71,0x99,0xa,0x50, \
    0xfa,0xc2,0x16,0x4b,0xfc,0x52,0xc1,0x22,0x63,0x94,0xb,0xb7,0xe8,0xc7,0x96,0x2a,0xb4,0xf8,0xf5,0x46, \
    0xaa,0x5d,0x14,0x0,0x54,0x87,0xd8,0xff,0x0,0x5e,0x86,0xf2,0x35,0x45,0x52,0x1f,0xe8,0xa2,0xb2,0x9b, \
    0xba,0xe6,0xc0,0x63,0x78,0xa5,0x60,0x6d,0x6d,0x8a,0x31,0x15,0xaf,0x28,0xf6,0xa3,0x63,0xe6,0x2,0xd5, \
    0xe6,0xbd,0x38,0xee,0x16,0x1c,0xef,0xcd,0x9e,0xc2,0x7,0x61,0x2e,0x3a,0x5f,0x76,0x6e,0x8c,0xe0,0x14, \
    0x7,0x12,0x28,0xb0,0x36,0x6e,0x9b,0x36,0xb9,0xec,0x81,0xe0,0xce,0x36,0x88,0xa,0x9,0x28,0xcd,0x3c, \
    0x38,0x4d,0xe9,0x9,0xec,0xc8,0x4c,0x8,0x24,0x27,0xaa,0x35,0x49,0xe,0x5b,0x29,0xd9,0xd0,0x83,0x52, \
    0x6,0x24,0xa8,0x74,0xae,0xcd,0x3c,0x5b,0xfe,0x53,0x86,0x88,0x10,0x42,0x4,0x4c,0x28,0x53,0x51,0xb7, \
    0x82,0xf3,0xe8,0x19,0xf,0x96,0xd6,0x48,0x13,0xf1,0x39,0x60,0x5b,0xe,0x2f,0x99 }

IFAA_Result IFAA_AuthenticatorVerifyDigest(const uint8_t *digest, uint32_t digest_len,
                                           const uint8_t *signature, uint32_t sig_len,
                                           const IFAA_Certificate *cert, uint32_t certlen)
{
    LOG_FUNC_BEGIN
    LOG_PERF_BEGIN

    ////////////////////////////////////////////////////
    ////sample仅提供2级证书验证， 实现上建议支持不定级证书链
    ////////////////////////////////////////////////////

    IFAA_Result ret = IFAA_ERR_SUCCESS;
    IFAA_RsaKey rsakey;
    IFAA_Certificate root_cert;
    root_cert.body.ifaa_cert.pub_key.n.buf  = ROOT_CERT_N;
    root_cert.body.ifaa_cert.pub_key.n.len  = sizeof(ROOT_CERT_N);
    root_cert.body.ifaa_cert.pub_key.e.buf  = ROOT_CERT_E;
    root_cert.body.ifaa_cert.pub_key.e.len  = sizeof(ROOT_CERT_E);
    root_cert.body.ifaa_cert.sig.buf        = ROOT_CERT_SIG;
    root_cert.body.ifaa_cert.sig.len        = sizeof(ROOT_CERT_SIG);

    if(!digest || !signature|| !cert || digest_len <= 0 || sig_len <= 0 || certlen <= 0) {
        LOG_ERROR("Invalid parameters");
        return IFAA_ERR_BAD_PARAM;
    }

    switch (cert->cert_enc_alg) {
        case CERT_ENCODE_ALG_IFAA: {
            ret = IFAA_CheckCert(cert, &root_cert);
            if( ret != IFAA_ERR_SUCCESS) {
                LOG_ERROR("VerifyCer err!");
                return IFAA_ERR_BAD_PARAM;
            }
            break;
        }

        default:
            return IFAA_ERR_BAD_PARAM;
    }

    rsakey.n = cert->body.ifaa_cert.pub_key.n;
    rsakey.e = cert->body.ifaa_cert.pub_key.e;
    ret = IFAA_RsaVerifyDigest(&rsakey, digest, digest_len, signature, sig_len);
    if (ret != IFAA_ERR_SUCCESS) {
        LOG_ERROR("VerifyDigest err!");
        return IFAA_ERR_BAD_PARAM;
    }

    LOG_FUNC_END
    LOG_PERF_END

    return ret;
}

MACRO_IFAA_IMPL_MARKER
IFAA_Result IFAA_AuthenticatorSignDigest(const uint8_t* digest, uint32_t digest_len,
                                         uint8_t* signature, uint32_t* sig_len)
{
    LOG_FUNC_BEGIN
    LOG_PERF_BEGIN

    ///////////////////////////////////////////////////////////////////////////////
    ////sample仅提供hard code的秘钥，实际秘钥为RPMB中
    ////注:这里提供为样例，实际开发时应实现在TEE_AuthenticatorSignDigest里
    ////此处仅做适当封装
    //////////////////////////////////////////////////////////////////////////////

    IFAA_Result ret = IFAA_ERR_SUCCESS;
    IFAA_RsaKey rsaprikey ;
    if (!digest || !signature|| digest_len <= 0) {
        LOG_ERROR("Invalid parameters");
        return IFAA_ERR_BAD_PARAM;
    }

    rsaprikey.n.buf = PRI_N;
    rsaprikey.n.len = sizeof(PRI_N);
    rsaprikey.e.buf = PRI_E;
    rsaprikey.e.len = sizeof(PRI_E);
    rsaprikey.d.buf = PRI_D;
    rsaprikey.d.len = sizeof(PRI_D);

    ret = IFAA_RsaSignDigest(&rsaprikey, digest, digest_len, signature, sig_len);
    if (ret != IFAA_ERR_SUCCESS) {
        LOG_ERROR("AuthenticatorSignDigest err!");
        return IFAA_ERR_BAD_PARAM;
    }

    LOG_FUNC_END
    LOG_PERF_END

    return ret;
}
#define MAX_PATH_LEN 256

#if defined(__QUALCOMM__) /*__QUALCOMM__*/
MACRO_IFAA_IMPL_MARKER
IFAA_Result IFAA_WriteFile(const char *path, uint32_t path_len, const uint8_t *data, uint32_t len)
{
    ////////////////////////////////////////////////
    ////写文件在高通上的参考实现
    ////////////////////////////////////////////////

    IFAA_Result ret = IFAA_ERR_SUCCESS;

    char buf_path[MAX_PATH_LEN] = {0};
    if (path_len > MAX_PATH_LEN) {
        LOG_E("IFAA_WriteFile ,can't use memcpy operation because of overflow.");
        return IFAA_ERR_BUF_TOO_SHORT;
    }
    memcpy(buf_path, path, path_len);
    LOG_DBG("write_file: %s", buf_path);

    int fd = qsee_sfs_open(buf_path, O_CREAT | O_WRONLY);
    if (fd == 0) {
        LOG_ERROR("qsee_sfs_open failed: 0x%08X", qsee_sfs_error(fd));
        return IFAA_ERR_WRITE;
    }

    if (data != NULL && len > 0) {
        int count = qsee_sfs_write(fd, (const char*)data, len);
        if (count != len) {
            LOG_ERROR("qsee_sfs_write failed: 0x%08X", qsee_sfs_error(fd));
            ret = IFAA_ERR_WRITE;
        }
    }

    int status = qsee_sfs_close(fd);
    if (status != 0) {
        LOG_ERROR("qsee_sfs_close failed: 0x%08X", qsee_sfs_error(fd));
        ret = IFAA_ERR_WRITE;
    }

    return ret;
}

#elif defined(__SAMSUNG_TEEGRIS__) || defined(__SAMSUNG_Kinibi__) /*__SAMSUNG_TEEGRIS__ || __SAMSUNG_Kinibi__*/
MACRO_IFAA_IMPL_MARKER
IFAA_Result IFAA_WriteFile(const char *path, uint32_t path_len, const uint8_t *data, uint32_t len)
{
    ////////////////////////////////////////////////
    ////写文件在GP上的参考实现
    ////////////////////////////////////////////////

    CHECK_BOOL_RET_VAL(!path && path_len > 0
                       && !data && len > 0, IFAA_ERR_BAD_PARAM);

    TEE_ObjectHandle handle = NULL;
    TEE_Result ret;
    LOG_DBG("write_file: %s", path);
    LOG_DBG("strlen(path): %d", path_len);

    ret  = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, path, path_len,
                                      /*TEE_DATA_FLAG_CREATE |*/ TEE_DATA_FLAG_ACCESS_WRITE,
                                      NULL, NULL, 0, &handle);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_CreatePersistentObject failed: 0x%08x", ret);
        return IFAA_ERR_WRITE;
    }

    ret = TEE_WriteObjectData(handle, data, len);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_WriteObjectData failed: 0x%08x", ret);
        ret = IFAA_ERR_WRITE;
    }

    TEE_CloseObject(handle);

    if (TEE_SUCCESS == ret) ret = IFAA_ERR_SUCCESS;
    return ret;
}
#else
#error ("TEE is not defined yet");
#endif

#if defined(__QUALCOMM__) /*__QUALCOMM__*/
MACRO_IFAA_IMPL_MARKER
IFAA_Result IFAA_ReadFile(const char *path, uint32_t path_len, uint8_t *data, uint32_t *len)
{
    ////////////////////////////////////////////////
    ////读文件在高通参考实现
    ////////////////////////////////////////////////

    IFAA_Result ret = IFAA_ERR_SUCCESS;
    uint32_t size = 0;
    uint8_t buf_path[MAX_PATH_LEN] = { 0  };
    memcpy(buf_path, path, path_len);
    LOG_DBG("read_file: %s", buf_path);

    int fd = qsee_sfs_open(buf_path, O_RDONLY);
    if (fd == 0) {
        LOG_ERROR("qsee_sfs_open failed: 0x%08X", qsee_sfs_error(fd));
        return IFAA_ERR_READ;
    }

    size = *len;

    if (data != NULL && size > 0) {
        int count = qsee_sfs_read(fd, (char*)data, size);
        LOG_DBG("qsee_sfs_getSize: size = %d,count = %d", size, count);
        if (count <= 0) {
            LOG_ERROR("qsee_sfs_read failed: 0x%08X\n", qsee_sfs_error(fd));
            ret = IFAA_ERR_READ;
        }
        else {
            *len = count;
        }
    }

    int status = qsee_sfs_close(fd);
    if (status != 0) {
        LOG_ERROR("qsee_sfs_close failed: 0x%08X", qsee_sfs_error(fd));
        ret = IFAA_ERR_READ;
    }

    return ret;
}

#elif defined(__SAMSUNG_TEEGRIS__) || defined(__SAMSUNG_Kinibi__) /*__SAMSUNG_TEEGRIS__ || __SAMSUNG_Kinibi__*/
MACRO_IFAA_IMPL_MARKER
IFAA_Result IFAA_ReadFile(const char *path, uint32_t path_len, uint8_t *data, uint32_t *len)
{
    ////////////////////////////////////////////////
    ////读文件在GP参考实现
    ////////////////////////////////////////////////

    CHECK_BOOL_RET_VAL(!path && path_len > 0
                       && !data && *len > 0, IFAA_ERR_BAD_PARAM);

    TEE_ObjectHandle handle = NULL;
    TEE_Result ret;
    LOG_DBG("read_file: %s", path);
    LOG_DBG("strlen(path): %d", path_len);

    ret = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, path, path_len,
                                   TEE_DATA_FLAG_ACCESS_READ, &handle);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_OpenPersistentObject failed: 0x%08x", ret);
        return IFAA_ERR_READ;
    }

    ret = TEE_ReadObjectData(handle, data, *len, (uint32_t*)len);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_ReadObjectData failed: 0x%08x", ret);
        ret = IFAA_ERR_READ;
    }

    LOG_DBG("TEE_ReadObjectData len is %d", *len);
    TEE_CloseObject(handle);

    if (TEE_SUCCESS == ret) ret = IFAA_ERR_SUCCESS;
    return ret;
}
#else
#error ("TEE is not defined yet");
#endif

#if defined(__QUALCOMM__) /*__QUALCOMM__*/
MACRO_IFAA_IMPL_MARKER
IFAA_Result IFAA_DeleteFile(const char *path, uint32_t path_len)
{
    ////////////////////////////////////////////////
    ////删除文件在gaot的参考实现
    ////////////////////////////////////////////////

    uint8_t buf_path[MAX_PATH_LEN] = { 0  };
    memcpy(buf_path, path, path_len);
    LOG_DBG("delete_file: %s", buf_path);

    int ret = qsee_sfs_rm(buf_path);
    if (ret != 0) {
        LOG_ERROR("qsee_sfs_rm failed");
        return IFAA_ERR_ERASE;
    }

    return IFAA_ERR_SUCCESS;
}

#elif defined(__SAMSUNG_TEEGRIS__) || defined(__SAMSUNG_Kinibi__) /*__SAMSUNG_TEEGRIS__ || __SAMSUNG_Kinibi__*/
MACRO_IFAA_IMPL_MARKER
IFAA_Result IFAA_DeleteFile(const char *path, uint32_t path_len)
{
    ////////////////////////////////////////////////
    ////删除文件在GP的参考实现
    ////////////////////////////////////////////////

    CHECK_BOOL_RET_VAL(!path && path_len > 0, IFAA_ERR_BAD_PARAM);

    TEE_ObjectHandle    handle = NULL;
    TEE_Result          ret;
    LOG_DBG("delete_file: %s", path);

    ret = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, path, path_len,
                                   TEE_DATA_FLAG_ACCESS_WRITE_META, &handle);
    if (ret != TEE_SUCCESS) {
        LOG_ERROR("TEE_OpenPersistentObject failed: 0x%08x", ret);
        return IFAA_ERR_ERASE;
    }

    TEE_CloseAndDeletePersistentObject(handle);

    return IFAA_ERR_SUCCESS;
}
#else
#error ("TEE is not defined yet");
#endif

