/**
 * @file tc_tm_lib_common.c
 *
 * @brief This file contain functionalities that are common to tele command
 *        tele data and telemetry.
 *
 * @copyright Copyright 2023 Antaris, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
/*********************************************************************/
#include "tc_tm_lib_common.h"
#include "exo_io_al_sos_timer.h"
#include "hmac_sha256.h"
#include "mbedtls/aes.h"

/**
 * @brief api that returns epoch utc time
 */
time_t get_utc_epoch(void)
{
    time_t seconds;

#ifdef LINUX_TEMP_PORT
    seconds = time(NULL);

#else
    seconds = get_crnt_time_date_in_epoch();

#endif
    return seconds;
}

/**
 * @brief Copies 1 or 2 bytes from the src buffer to dst depending on the
 *        src data. If data is greater than 127, the extension bit (7th bit)
 *        is set and 2 bytes of data is copied to the destination.
 */
uint16 set_extnd_val_16(const uint16 *src, uint8 *dst, size_t size)
{
    uint16 status;
    uint16 tmp = 0;
    uint16 num = *src;

    if((NULL != src) && (NULL != dst))
    {
        if(num > 127)
        {
            tmp = (num & EXT_BIT_MASK);
            tmp = tmp >> EXT_BIT_POS;
            if(tmp)
            {
                num = num | (1 << 15);
            }
            else
            {
                num = num | (1 << EXT_BIT_POS);
                num = num & ~(1 << 15);
            }

            os_memcpy(dst, &num, size);
            status = size;
        }
        else
        {
            os_memcpy(dst, src, 1);
            status = 1;
        }
    }
    else
    {
        status = TC_TM_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief Copies 1 or 2 bytes from the src buffer to dst depending on the
 *        src data. If the extension bit (7th bit) is set, 2 bytes of data
 *        is copied to the destination.
 */
uint16 get_extnd_val_16(const uint8 *src, uint16 *dst, size_t size)
{
    uint8 ext_bit = 0;
    uint16 tmp = 0;
    uint16 status = 0;
    uint16 num = 0;

    bzero(dst, sizeof(uint16));

    os_memcpy(&num, src, size);

    tmp = num;

    ext_bit = (tmp & EXT_BIT_MASK) >> EXT_BIT_POS;

    if(ext_bit)
    {
        tmp = (num & 0x8000);
        tmp = tmp >> 15;
        if(tmp)
        {
            num = num & ~(1 << 15);
        }
        else
        {
            num = num & ~(1 << 7);
        }
        os_memcpy(dst, &num, size);
        status = size;
    }
    else
    {

        os_memcpy(dst, src, 1);

        status = 1;
    }

    return status;
}

/**
 * @brief This API calculates hmac for the passed in data buffer
 */
size_t compute_hmac(const uint8 *data, const uint8 *key, const uint32 keysize,
                    const uint32 datasize, void *out)
{

    size_t outlen = 32;

    if((NULL != data) && (NULL != key) && (NULL != out))
    {
        outlen = hmac_sha256((const int8 *)key, keysize, (const int8 *)data,
                             datasize, out, outlen);
    }
    else
    {
        outlen = TC_TM_LIB_NULL_PTR;
    }

    return outlen;
}

/**
 * @brief This API encrypts the passed in data buffer
 */
int32 aes_encrypt_data(s_crypt_params *param, const uint8 *buf, int32 length,
                       uint8 *output)
{
    int32 status;
    mbedtls_aes_context aes;
    // TBD: Fix the segmentation fault in encryption for Target environment
    if((NULL != param) && (NULL != buf) && (NULL != param->key) &&
       (NULL != output))
    {
        mbedtls_aes_init(&aes);
        mbedtls_aes_setkey_enc(&aes, param->key, param->key_size);

        switch(param->encrypt_mode)
        {
            case CRYPT_AES_CFB8:
                status = mbedtls_aes_crypt_cfb8(&aes, MBEDTLS_AES_ENCRYPT,
                                                length, param->iv, buf, output);
                break;

            default:
                status = TC_TM_LIB_CRYPT_UNSUPPORTED;
        }
    }
    else
    {
        status = TC_TM_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API decrypts the passed in data buffer
 */

int32 aes_decrypt_data(s_crypt_params *param, const uint8 *buf, int32 length,
                       uint8 *output)
{
    int32 status;
    mbedtls_aes_context aes;
    uint8 iv[16] = {0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

    if((NULL != param) && (NULL != buf) && (NULL != param->key) &&
       (NULL != output))
    {
        mbedtls_aes_init(&aes);
        mbedtls_aes_setkey_enc(&aes, param->key, param->key_size);

        switch(param->encrypt_mode)
        {
            case CRYPT_AES_CFB8:
                status = mbedtls_aes_crypt_cfb8(&aes, MBEDTLS_AES_DECRYPT,
                                                length, iv, buf, output);
                break;

            default:
                status = TC_TM_LIB_CRYPT_UNSUPPORTED;
        }
    }
    else
    {
        status = TC_TM_LIB_NULL_PTR;
    }

    return status;
}
