/*!
* @file tl_aes.c
* @brief Implementation of AES GCM
* @author Oleksandr Gabrilchuk (o.gabrilchuk@samsung.com)
* @version 1
* @date Created: Created: Tue Jul 24 10:20:53 2014
* @date Modified: Fri Aug  1 10:48:38 2014
* @copyright
* In Samsung Ukraine R&D Center (SURC under a contract between)
* @par
* LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
* @par
* Copyright (c) Samsung Electronics Co. Ltd 2013. All rights reserved.
*/

/*#include <comdef.h>*/
#include "common.h"
#include "tl_aes.h"
#include "tl_utils.h"
#include "tl_log.h"
#include "openssl/aes/aes.h"
#include "openssl/modes/modes.h"

int32_t softsim_aes_gcm_init(aes_ctx_t *ctx, const uint8_t *key, uint32_t keyLength, const uint8_t *IV, uint32_t IVLength, AES_MODE mode)
{
    int32_t retVal = SOFTSIM_ERR_GENERAL;

    AES_KEY         *aes_key  = &(ctx->key);
    GCM128_CONTEXT  *stCipher = &(ctx->stCipher);

    ctx->mode = mode;

    if(AES_set_encrypt_key( key, (int)(keyLength * 8), aes_key )){
        goto exit;
    }

    CRYPTO_gcm128_init (stCipher, (void *)aes_key, (block128_f)AES_encrypt);
    CRYPTO_gcm128_setiv(stCipher, IV, IVLength);

    retVal = SOFTSIM_SUCCESS;

exit:
    return retVal;

}

int32_t softsim_aes_gcm_add_aad(aes_ctx_t *ctx, const uint8_t *AAD, uint32_t AADLen)
{
    GCM128_CONTEXT  *stCipher = &(ctx->stCipher);

    if(AAD){
        if(CRYPTO_gcm128_aad(stCipher, AAD, AADLen)){
            return SOFTSIM_ERR_GENERAL;
        }
    }
    return SOFTSIM_SUCCESS;
}

int32_t softsim_aes_gcm_update(aes_ctx_t *ctx, const uint8_t *inDataBlock, uint32_t dataBlockLen, uint8_t *outDataBlock)
{
    int32_t retVal = SOFTSIM_ERR_GENERAL;
    GCM128_CONTEXT  *stCipher = &(ctx->stCipher);

    if(ctx->mode == SOFTSIM_CC_AES_ENCRYPT){
        if(CRYPTO_gcm128_encrypt(stCipher, inDataBlock, outDataBlock, dataBlockLen)){
            goto exit;
        }
    }

    if(ctx->mode == SOFTSIM_CC_AES_DECRYPT){
        if(CRYPTO_gcm128_decrypt(stCipher, inDataBlock, outDataBlock, dataBlockLen)){
            goto exit;
        }
    }

    retVal = SOFTSIM_SUCCESS;

exit:
    return retVal;
}

int32_t softsim_aes_gcm_finish(aes_ctx_t *ctx, uint8_t *AT, uint32_t ATLen)
{
    int32_t retVal = SOFTSIM_ERR_GENERAL;
    GCM128_CONTEXT  *stCipher = &(ctx->stCipher);

    if(ctx->mode == SOFTSIM_CC_AES_ENCRYPT){
        CRYPTO_gcm128_tag(stCipher, AT, ATLen);
        retVal = SOFTSIM_SUCCESS;
    }

    if(ctx->mode == SOFTSIM_CC_AES_DECRYPT){
        if(!CRYPTO_gcm128_finish(stCipher, AT, ATLen)){
            retVal = SOFTSIM_SUCCESS;
        }
#ifndef _NDEBUG_
        dump_bytes("attached tag", AT, ATLen);
        dump_bytes("actual tag", stCipher->Xi.c, ATLen);
#endif
    }
    return retVal;
}
