/**
 * \file CryptoPlatformBF.c
 * \brief BlowFish TZ related high level crypto functions.
 * \author Andrey Nastenko (a.nastenko@samsung.com)
 * \version 0.1
 * \date Created Jan 23, 2014
 * \par In Samsung Ukraine R&D Center (SURC) under a contract between
 * \par LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine) and
 * \par "Samsung Elecrtronics Co", Ltd (Seoul, Republic of Korea)
 * \par Copyright: (c) Samsung Electronics Co, Ltd 2012. All rights reserved.
 **/

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <tee_internal_api.h>

#include "CryptoPlatform.h"
#include "CommLayerData.h"
#include "blowfish_utils.h"
#include "log.h"
#include "DebugPrint.h"

int32_t getSHA1Digest(uint8_t* data, uint32_t len, uint8_t* digest)
{
	int32_t status = PLATFORM_INTERNAL_ERROR;
	uint8_t tmp_digest[SHA1_DIGEST_LEN] = {0};
	size_t  tmp_digest_len = sizeof(tmp_digest);
	TEE_OperationHandle hndl = 0;

	if (TEE_AllocateOperation( &hndl, TEE_ALG_SHA1, TEE_MODE_DIGEST, 0) == TEE_SUCCESS ) {
		if (TEE_DigestDoFinal(hndl, data, len, tmp_digest, &tmp_digest_len) == TEE_SUCCESS) {
			memcpy( digest, tmp_digest, SHA1_DIGEST_LEN );
			memset( tmp_digest, 0, sizeof(tmp_digest) );
			status = NO_ERROR;
		}
		TEE_FreeOperation(hndl);
	}

	return status;
}

int32_t getSHA256Digest(uint8_t* data, uint32_t len, uint8_t* digest)
{
	int32_t status = PLATFORM_INTERNAL_ERROR;
	uint8_t tmp_digest[SHA256_DIGEST_LEN] = {0};
	size_t  tmp_digest_len = sizeof(tmp_digest);
	TEE_OperationHandle hndl;

	if (TEE_AllocateOperation(&hndl, TEE_ALG_SHA256, TEE_MODE_DIGEST, 0) == TEE_SUCCESS) {
		if (TEE_DigestDoFinal(hndl, data, len, tmp_digest, &tmp_digest_len) == TEE_SUCCESS) {
			memcpy(digest, tmp_digest, SHA256_DIGEST_LEN);
			memset(tmp_digest, 0, sizeof(tmp_digest));
			status = NO_ERROR;
		}
		TEE_FreeOperation(hndl);
	}

	return status;
}

int32_t getSHA512Digest(uint8_t* data, uint32_t len, uint8_t* digest)
{
	int32_t status = PLATFORM_INTERNAL_ERROR;
	int32_t ret = PLATFORM_INTERNAL_ERROR;
	uint8_t tmp_digest[SHA512_DIGEST_LEN] = {0};
	size_t  tmp_digest_len = sizeof(tmp_digest);
	TEE_OperationHandle hndl;

	ret = TEE_AllocateOperation(&hndl, TEE_ALG_SHA512, TEE_MODE_DIGEST, 0);
	if (ret == TEE_SUCCESS) {
		ret = TEE_DigestDoFinal(hndl, data, len, tmp_digest, &tmp_digest_len);
		if (ret == TEE_SUCCESS) {
			memcpy(digest, tmp_digest, SHA512_DIGEST_LEN);
			memset(tmp_digest, 0, sizeof(tmp_digest));
			status = NO_ERROR;
		} else {
			LOGE("TEE_DigestDoFinal failed with return value %d\n", ret);
		}
		TEE_FreeOperation(hndl);
	} else {
		LOGE("TEE_AllocateOperation failed with return value %d\n", ret);
	}

	return status;
}

int32_t getRandBlock(uint8_t *buf, uint32_t len)
{
	TEE_GenerateRandom(buf, len);
	LOGD("Random bytes generated\n");
	return NO_ERROR;
}

int32_t loadMLDAPKeyBlob(uint8_t* wrapped, uint32_t wrappedLen, KeyInfo_t* keyInfo, uint8_t* keyBlob, uint32_t* keyBlobLen)
{
	(void)keyInfo;

	if (NO_ERROR != unwrap(wrapped, wrappedLen, keyBlob, keyBlobLen)) {
		LOGE("unwrap failed\n");
		return PLATFORM_INTERNAL_ERROR;
	}

	return NO_ERROR;
}

int32_t loadSKMKeyBlob(uint8_t* wrapped, uint32_t wrappedLen, KeyInfo_t* keyInfo, uint8_t* keyBlob, uint32_t* keyBlobLen)
{
	return loadMLDAPKeyBlob(wrapped, wrappedLen, keyInfo, keyBlob, keyBlobLen);
}

int32_t saveKeyBlob(uint8_t* keyBlob, uint32_t keyBlobLen, KeyInfo_t* keyInfo, uint8_t* wrappedOut, uint32_t* wrappedOutLen, uint8_t* TID, uint32_t TIDLen)
{
	(void)keyInfo;

	if (NO_ERROR != wrap(keyBlob, keyBlobLen, wrappedOut, wrappedOutLen, TID, TIDLen)) {
		LOGE("wrap failed\n");
		return PLATFORM_INTERNAL_ERROR;
	}

	return NO_ERROR;
}

/* Get OEM flag for integrity check */
int32_t getOemFlag(void)
{
	return NO_ERROR;
}