/*
 * =====================================================================================
 *
 *       Filename:  pebble_hmac.c
 *
 *    Description:  PEBBLE definitions for HMAC-SHA256
 *
 *        Version:  1.0
 *        Created:  08/14/2020
 *       Revision:  none
 *       Compiler:  gcc
 *
 *        Company:  Samsung Electronics
 *        Copyright (c) 2020 by Samsung Electronics, All rights reserved.
 *
 * =====================================================================================
 */

#include "TZ_Vendor_tl.h"
#include "pebble_hmac.h"

#define TLAPI_ALG_HMAC_SHA_256_SIZE     0x20
#define TLAPI_ALG_HASH_SHA256_SIZE      0x20
#define HMAC_SHA256_OBJ_SIZE            128

#ifdef TAG
#undef TAG
#endif
#define TAG "pebble_hmac"

void TZ_bzero(void *s, size_t n) {
    volatile unsigned char *p = s;

    if (s == NULL || n == 0) {
        PEBBLE_LOG("%s s == NULL or n == 0", TAG);
        return;
    }
    TEE_MemFill(s, 0, n);

    while (n--) {
        if (*p++) {
            PEBBLE_LOG("%s error to clear memory", TAG);
            return;
        }
    }
}

uint32_t hmac_sha256_sign(const uint8_t *key, uint32_t key_len,
                          const uint8_t *msg, uint32_t msg_len,
                          uint8_t *digest, uint32_t *digest_len) {
    uint32_t ret = TZ_API_ERROR;
    TEE_Result tee_ret = TEE_SUCCESS;
    TEE_OperationHandle op_hndl;
    TEE_ObjectHandle obj_hndl;
    TEE_OBJECT_TYPES obj_type;
    uint32_t objSiz = 0;
    TEE_CRYPTO_ALGORITHMS t_algo;
    TEE_Attribute params[1];
    uint32_t paramCount = 1;
    uint8_t aes_iv[32] = {0, };
    uint8_t i = 0;

    if (!msg || !msg_len || !key || !key_len ||
            !digest || !digest_len || !*digest_len) {
        PEBBLE_LOG("%s %s() : Invalid input params", TAG, __func__);
        return ret;
    }

    TZ_bzero(digest, *digest_len);
    if (*digest_len < TLAPI_ALG_HASH_SHA256_SIZE) {
        PEBBLE_LOG("%s %s() : Insufficient output digest buffer", TAG, __func__);
        return ret;
    }
    obj_type = TEE_TYPE_HMAC_SHA256;
    t_algo = TEE_ALG_HMAC_SHA256;
    objSiz = HMAC_SHA256_OBJ_SIZE;

    tee_ret = TEE_AllocateTransientObject(obj_type, objSiz * 8, &obj_hndl);
    if (TEE_SUCCESS != tee_ret) {
        PEBBLE_LOG("%s %s() : AllocateTransientObject failed=0x%08x", TAG, __func__, tee_ret);
        goto EXIT;
    }

    TEE_InitRefAttribute(&params[0], TEE_ATTR_SECRET_VALUE, key, key_len);
    tee_ret = TEE_PopulateTransientObject(obj_hndl, params, paramCount);
    if (TEE_SUCCESS != tee_ret) {
        PEBBLE_LOG("%s %s() : PopulateTransientObject failed=0x%08x", TAG, __func__, tee_ret);
        goto EXIT;
    }

    tee_ret = TEE_AllocateOperation(&op_hndl, t_algo, TEE_MODE_MAC, objSiz * 8);
    if (TEE_SUCCESS != tee_ret) {
        PEBBLE_LOG("%s %s() : AllocateOperation failed=0x%08x", TAG, __func__, tee_ret);
        goto EXIT;
    }

    tee_ret = TEE_SetOperationKey(op_hndl, obj_hndl);
    if (TEE_SUCCESS != tee_ret) {
        PEBBLE_LOG("%s %s() : SetOperationKey failed=0x%08x", TAG, __func__, tee_ret);
        goto EXIT;
    }

    TEE_MACInit(op_hndl, aes_iv, sizeof(aes_iv));
    tee_ret = TEE_MACComputeFinal(op_hndl, msg, msg_len, digest, digest_len);
    if (TEE_SUCCESS != tee_ret) {
        PEBBLE_LOG("%s %s() : MACComputeFinal failed=0x%08x", TAG, __func__, tee_ret);
        TZ_bzero(digest, *digest_len);
        goto EXIT;
    }

    PEBBLE_LOG_DEBUG("%s %s() : Disgest is: ", TAG, __func__);
    ret = TZ_API_OK;

EXIT:

    if(obj_hndl)
        TEE_FreeTransientObject(obj_hndl);

    if(op_hndl)
        TEE_FreeOperation(op_hndl);

    PEBBLE_LOG_DEBUG("%s %s() : End.", TAG, __func__);
    return ret;
}
