/*
 * =====================================================================================
 *
 *       Filename:  pebble_platform_interface.c
 *
 *    Description:  PEBBLE wrap/unwrap manipulation
 *
 *        Version:  1.0
 *        Created:  08/16/2020
 *       Revision:  none
 *       Compiler:  gcc
 *
 *        Company:  Samsung Electronics
 *        Copyright (c) 2020 by Samsung Electronics, All rights reserved.
 *
 * =====================================================================================
 */

/** Includes */
#include "pebble_platform_interface.h"
#include "qsee_message.h"
#include "TZ_Vendor_tl.h"

/**
 * @brief
 * decapsulate
 *
 * @param[in]  *decapsulate_ptr     - decapsulate object
 * @param[in]  decapsulate_ptr_len  - decapsulate object length
 * @param[out] *unwrap_ptr          - unwrap_ptr object
 * @param[out] *unwrap_ptr_len      - unwrap_ptr object length
 *
 * @return PEBBLE status code
 */
pebble_return_code_t decapsulate(uint8_t *decapsulate_ptr, uint32_t decapsulate_ptr_len, uint8_t *unwrap_ptr, uint32_t *unwrap_ptr_len) {
    pebble_return_code_t ret = PEBBLE_STATUS_SUCCESS;
    char src_app[32] = {0};
    char skm_app_name[32] = "skm";

    PEBBLE_LOG("decapsulate()");

    if (decapsulate_ptr_len == 0 || decapsulate_ptr_len > PEBBLE_DRK_MAX_BUF_LEN) {
        PEBBLE_LOG("decapsulate - Abnormal key length");
        ret = PEBBLE_UNWRAP_KEY_LENGTH_FAILED;
        goto error;
    }

    PEBBLE_LOG_DEBUG("decapsulate - Before decapsulate");
    ret = qsee_decapsulate_inter_app_message(
              src_app,
              decapsulate_ptr,
              decapsulate_ptr_len,
              unwrap_ptr,
              unwrap_ptr_len);
    PEBBLE_LOG_DEBUG("decapsulate - After decapsulate: ret: %d src_app: %s decapsulate_ptr_len: %d unwrapped_ptr_len: %d", ret, src_app, decapsulate_ptr_len, *unwrap_ptr_len);
    if (ret != QSEE_MESSAGE_SUCESS) {
        PEBBLE_LOG("decapsulate - qsee_decapsulate_inter_app_message() FAILED : %x", ret);
        ret = PEBBLE_UNWRAP_DECAPSULATE_ERROR;
        goto error;
    } else if (strncmp(src_app, skm_app_name, strlen(skm_app_name) + 1)) {
        PEBBLE_LOG_DEBUG("decapsulate - source app name \"%s\" was not \"%s\"", src_app, skm_app_name);
        ret = PEBBLE_UNWRAP_APP_NAME_FAILED;
        goto error;
    }
    PEBBLE_LOG_DEBUG("wrap - Decapsulate successful, proceeding to wrap");
error:
    return ret;
}

/**
 * @brief
 * wrap
 *
 * @param[in]   *unwrapped_ptr      - wrapped object
 * @param[in]   unwrapped_ptr_len   - wrapped object length
 * @param[out]  *wrapped_ptr        - wrapped object
 * @param[out]  *wrapped_ptr_len    - wrapped object length
 *
 * @return PEBBLE status code
 */
pebble_return_code_t wrap(uint8_t *unwrapped_ptr, uint32_t unwrapped_ptr_len, uint8_t *wrapped_ptr, uint32_t *wrapped_ptr_len) {
    pebble_return_code_t ret = PEBBLE_STATUS_SUCCESS;
    uint32_t wrap_ret;

    PEBBLE_LOG("wrap()");

    PEBBLE_LOG_DEBUG("wrap - Before wrap: unwrapped_ptr_len: %d MAX wrap_len: %d", unwrapped_ptr_len, *wrapped_ptr_len);
    wrap_ret = TZ_wrap_persist_data(
                   (uint8_t *)"pebble",
                   strlen("pebble"),
                   unwrapped_ptr,
                   unwrapped_ptr_len,
                   wrapped_ptr,
                   wrapped_ptr_len);
    PEBBLE_LOG_DEBUG("wrap - After wrap: unwrapped_ptr_len: %d wrap_len: %d", unwrapped_ptr_len, *wrapped_ptr_len);
    if (wrap_ret != TZ_API_OK) {
        PEBBLE_LOG("wrap - TZ_wrap_data FAILED: %d", wrap_ret);
        ret = PEBBLE_UNWRAP_FAILED_WRAP;
    }

    return ret;
}

/**
 * @brief
 * unwrap
 *
 * @param[in]  *wrapped_ptr         - wrapped object
 * @param[in]  *wrapped_ptr_len     - wrapped object length
 * @param[in]  is_wrapped_key       - is wrapped object (only for QC)
 * @param[out] *unwrapped_ptr       - unwrapped object
 * @param[out] *unwrapped_ptr_len   - unwrapped object length
 *
 * @return PEBBLE status code
 */
pebble_return_code_t unwrap(uint8_t *wrapped_ptr, uint32_t *wrapped_ptr_len, uint32_t is_wrapped_key, uint8_t *unwrapped_ptr, uint32_t *unwrapped_ptr_len) {
    uint32_t wrap_ret;

    if (*wrapped_ptr_len == 0 || *wrapped_ptr_len > PEBBLE_DRK_MAX_BUF_LEN) {
        PEBBLE_LOG("unwrap - Abnormal key length");
        return PEBBLE_UNWRAP_KEY_LENGTH_FAILED;
    }

    if (is_wrapped_key == 0) {
        wrap_ret = decapsulate(wrapped_ptr, *wrapped_ptr_len, unwrapped_ptr, unwrapped_ptr_len);

        if(wrap_ret != PEBBLE_STATUS_SUCCESS) {
            PEBBLE_LOG_DEBUG("decapsulate Fail");
            return wrap_ret;
        }

        TEE_MemFill(wrapped_ptr, 0, PEBBLE_DRK_MAX_BUF_LEN);
        *wrapped_ptr_len = PEBBLE_DRK_MAX_BUF_LEN;
        wrap_ret = wrap(unwrapped_ptr, *unwrapped_ptr_len, wrapped_ptr, wrapped_ptr_len);
        if(wrap_ret != PEBBLE_STATUS_SUCCESS) {
            PEBBLE_LOG_DEBUG("wrap Fail");
            return wrap_ret;
        }
    } else {
        PEBBLE_LOG("unwrap()");
        PEBBLE_LOG("unwrap - Before unwrap - wrapped_ptr_len: %d unwrapped_ptr_len: %d", *wrapped_ptr_len, *unwrapped_ptr_len);
        wrap_ret = TZ_unwrap_persist_data(
                       (uint8_t *)"pebble",
                       strlen("pebble"),
                       wrapped_ptr,
                       *wrapped_ptr_len,
                       unwrapped_ptr,
                       unwrapped_ptr_len);
        PEBBLE_LOG("unwrap - After unwrap - wrapped_ptr_len: %d unwrapped_ptr_len: %d", *wrapped_ptr_len, *unwrapped_ptr_len);
        if (wrap_ret == TZ_API_ERROR_NO_KEY) {
            PEBBLE_LOG("unwrap - TZ_unwrap_data FAILED with no key: %d", wrap_ret);
            return PEBBLE_UNWRAP_FAILED_NO_KEY;
        } else if (wrap_ret == TZ_API_ERROR_VERSION_MISMATCH) {
            PEBBLE_LOG("unwrap - TZ_unwrap_data FAILED with version mismatch error: %d", wrap_ret);
            return PEBBLE_UNWRAP_VERSION_MISMATCH;
        }
        if (wrap_ret != TZ_API_OK) {
            PEBBLE_LOG("unwrap - TZ_unwrap_data FAILED: %d", wrap_ret);
            return PEBBLE_UNWRAP_FAILED;
        }
    }

    return PEBBLE_STATUS_SUCCESS;
}


/**
 * @brief
 * aes_encrypt_with_params - QSEE interface to
 * TZ_Vendor_tl.c: TZ_aes_encrypt_with_params
 *
 * @param[in]   *encKey         - key
 * @param[in]   encKeyLen       - key length
 * @param[in]   *plaintext      - data to be encrypted
 * @param[in]   plaintextLen    - data length
 * @param[out]  *ciphertext     - encrypted data
 * @param[out]  *pCiphertextLen - length of encrypted data
 * @param[in]   mode            - cipher mode (EBC/CBC)
 * @param[in]   pad             - padding scheme (ISO10126/PKCS7/NO PAD)
 * @param[in]   *piv            - initial vector
 * @param[in]   iv_size         - length of initial vector
 *
 * @return  status code
 */
uint32_t aes_encrypt_with_params(
    uint8_t * encKey,
    uint32_t encKeyLen,
    uint8_t * plaintext,
    uint32_t plaintextLen,
    uint8_t * ciphertext,
    uint32_t * pCiphertextLen,
    CIPHER_MODE_ET mode,
    CIPHER_PAD_ET pad,
    uint8_t * piv,
    uint32_t iv_size
) {
    return TZ_aes_encrypt_with_params(encKey, encKeyLen, plaintext, plaintextLen, ciphertext, pCiphertextLen, mode, pad, piv, iv_size);
}


/**
 * @brief
 * aes_decrypt_with_params - QSEE interface to
 * TZ_Vendor_tl.c: TZ_aes_decrypt_with_params
 *
 * @param[in]   *decKey         - key
 * @param[in]   decKeyLen       - key length
 * @param[in]   *ciphertext     - data to be decrypted
 * @param[in]   *pCiphertextLen - lenght of data to be decrypted
 * @param[out]  *plaintext      - decrypted data
 * @param[out]  * plaintextLen  - length of decrypted data
 * @param[in]   mode            - cipher mode (EBC/CBC)
 * @param[in]   pad             - padding scheme (ISO10126/PKCS7/NO PAD)
 * @param[in]   *piv            - initial vector
 * @param[in]   iv_size         - length of initial vector
 *
 * @return  status code
 */
uint32_t aes_decrypt_with_params(
    uint8_t * decKey,
    uint32_t decKeyLen,
    uint8_t * ciphertext,
    uint32_t ciphertextLen,
    uint8_t * plaintext,
    uint32_t * pPlaintextLen,
    CIPHER_MODE_ET mode,
    CIPHER_PAD_ET pad,
    uint8_t * piv,
    uint32_t iv_size
) {
    return TZ_aes_decrypt_with_params(decKey, decKeyLen, ciphertext, ciphertextLen, plaintext, pPlaintextLen, mode, pad, piv, iv_size);
}

