#include "atca_basic.h"
#include "atca_execution.h"
typedef struct
{
uint32_t total_msg_size; uint32_t block_size; uint8_t block[ATCA_SHA256_BLOCK_SIZE * 2]; } hw_sha256_ctx;
ATCA_STATUS atcab_sha_base(uint8_t mode, uint16_t length, const uint8_t* message, uint8_t* data_out, uint16_t* data_out_size)
{
ATCAPacket packet;
ATCACommand ca_cmd = _gDevice->mCommands;
ATCA_STATUS status = ATCA_GEN_FAIL;
uint8_t cmd_mode = (mode & SHA_MODE_MASK);
if (cmd_mode != SHA_MODE_SHA256_PUBLIC && cmd_mode != SHA_MODE_HMAC_START && length > 0 && message == NULL)
{
return ATCA_BAD_PARAM; }
if (data_out != NULL && data_out_size == NULL)
{
return ATCA_BAD_PARAM;
}
do
{
packet.param1 = mode;
packet.param2 = length;
if (cmd_mode != SHA_MODE_SHA256_PUBLIC && cmd_mode != SHA_MODE_HMAC_START)
{
memcpy(packet.data, message, length);
}
if ((status = atSHA(ca_cmd, &packet, length)) != ATCA_SUCCESS)
{
break;
}
if ((status = atca_execute_command(&packet, _gDevice)) != ATCA_SUCCESS)
{
break;
}
if ((data_out != NULL) && (packet.data[ATCA_COUNT_IDX] > 4))
{
if (packet.data[ATCA_COUNT_IDX] - ATCA_PACKET_OVERHEAD > *data_out_size)
{
status = ATCA_SMALL_BUFFER;
break;
}
*data_out_size = packet.data[ATCA_COUNT_IDX] - ATCA_PACKET_OVERHEAD;
memcpy(data_out, &packet.data[ATCA_RSP_DATA_IDX], *data_out_size);
}
}
while (0);
return status;
}
ATCA_STATUS atcab_sha_start(void)
{
return atcab_sha_base(SHA_MODE_SHA256_START, 0, NULL, NULL, NULL);
}
ATCA_STATUS atcab_sha_update(const uint8_t *message)
{
return atcab_sha_base(SHA_MODE_SHA256_UPDATE, 64, message, NULL, NULL);
}
ATCA_STATUS atcab_sha_end(uint8_t *digest, uint16_t length, const uint8_t *message)
{
uint16_t digest_size = 32;
return atcab_sha_base(SHA_MODE_SHA256_END, length, message, digest, &digest_size);
}
ATCA_STATUS atcab_sha_read_context(uint8_t* context, uint16_t* context_size)
{
return atcab_sha_base(SHA_MODE_READ_CONTEXT, 0, NULL, context, context_size);
}
ATCA_STATUS atcab_sha_write_context(const uint8_t* context, uint16_t context_size)
{
return atcab_sha_base(SHA_MODE_WRITE_CONTEXT, context_size, context, NULL, NULL);
}
ATCA_STATUS atcab_sha(uint16_t length, const uint8_t *message, uint8_t *digest)
{
return atcab_hw_sha2_256(message, length, digest);
}
ATCA_STATUS atcab_hw_sha2_256_init(atca_sha256_ctx_t* ctx)
{
memset(ctx, 0, sizeof(*ctx));
return atcab_sha_start();
}
ATCA_STATUS atcab_hw_sha2_256_update(atca_sha256_ctx_t* ctx, const uint8_t* data, size_t data_size)
{
ATCA_STATUS status = ATCA_SUCCESS;
uint32_t block_count;
uint32_t rem_size = ATCA_SHA256_BLOCK_SIZE - ctx->block_size;
uint32_t copy_size = data_size > rem_size ? rem_size : (uint32_t)data_size;
uint32_t i = 0;
memcpy(&ctx->block[ctx->block_size], data, copy_size);
if (ctx->block_size + data_size < ATCA_SHA256_BLOCK_SIZE)
{
ctx->block_size += (uint32_t)data_size;
return ATCA_SUCCESS;
}
status = atcab_sha_update(ctx->block);
if (status != ATCA_SUCCESS)
{
return status;
}
data_size -= copy_size; block_count = (uint32_t)(data_size / ATCA_SHA256_BLOCK_SIZE);
for (i = 0; i < block_count; i++)
{
status = atcab_sha_update(&data[copy_size + i * ATCA_SHA256_BLOCK_SIZE]);
if (status != ATCA_SUCCESS)
{
return status;
}
}
ctx->total_msg_size += (block_count + 1) * ATCA_SHA256_BLOCK_SIZE;
ctx->block_size = data_size % ATCA_SHA256_BLOCK_SIZE;
memcpy(ctx->block, &data[copy_size + block_count * ATCA_SHA256_BLOCK_SIZE], ctx->block_size);
return ATCA_SUCCESS;
}
ATCA_STATUS atcab_hw_sha2_256_finish(atca_sha256_ctx_t* ctx, uint8_t* digest)
{
ATCA_STATUS status = ATCA_SUCCESS;
uint32_t msg_size_bits;
uint32_t pad_zero_count;
uint16_t digest_size;
if (_gDevice->mIface->mIfaceCFG->devtype == ATSHA204A)
{
ctx->total_msg_size += ctx->block_size;
msg_size_bits = (ctx->total_msg_size * 8);
pad_zero_count = (ATCA_SHA256_BLOCK_SIZE - ((ctx->block_size + 9) % ATCA_SHA256_BLOCK_SIZE)) % ATCA_SHA256_BLOCK_SIZE;
ctx->block[ctx->block_size++] = 0x80;
memset(&ctx->block[ctx->block_size], 0, pad_zero_count + 4);
ctx->block_size += pad_zero_count + 4;
ctx->block[ctx->block_size++] = (uint8_t)(msg_size_bits >> 24);
ctx->block[ctx->block_size++] = (uint8_t)(msg_size_bits >> 16);
ctx->block[ctx->block_size++] = (uint8_t)(msg_size_bits >> 8);
ctx->block[ctx->block_size++] = (uint8_t)(msg_size_bits >> 0);
digest_size = 32;
status = atcab_sha_base(SHA_MODE_SHA256_UPDATE, ATCA_SHA256_BLOCK_SIZE, ctx->block, digest, &digest_size);
if (status != ATCA_SUCCESS)
{
return status;
}
if (ctx->block_size > ATCA_SHA256_BLOCK_SIZE)
{
digest_size = 32;
status = atcab_sha_base(SHA_MODE_SHA256_UPDATE, ATCA_SHA256_BLOCK_SIZE, &ctx->block[ATCA_SHA256_BLOCK_SIZE], digest, &digest_size);
if (status != ATCA_SUCCESS)
{
return status;
}
}
}
else
{
status = atcab_sha_end(digest, ctx->block_size, ctx->block);
if (status != ATCA_SUCCESS)
{
return status;
}
}
return ATCA_SUCCESS;
}
ATCA_STATUS atcab_hw_sha2_256(const uint8_t * data, size_t data_size, uint8_t* digest)
{
ATCA_STATUS status = ATCA_SUCCESS;
atca_sha256_ctx_t ctx;
status = atcab_hw_sha2_256_init(&ctx);
if (status != ATCA_SUCCESS)
{
return status;
}
status = atcab_hw_sha2_256_update(&ctx, data, data_size);
if (status != ATCA_SUCCESS)
{
return status;
}
status = atcab_hw_sha2_256_finish(&ctx, digest);
if (status != ATCA_SUCCESS)
{
return status;
}
return ATCA_SUCCESS;
}
ATCA_STATUS atcab_sha_hmac_init(atca_hmac_sha256_ctx_t* ctx, uint16_t key_slot)
{
memset(ctx, 0, sizeof(*ctx));
return atcab_sha_base(SHA_MODE_HMAC_START, key_slot, NULL, NULL, NULL);
}
ATCA_STATUS atcab_sha_hmac_update(atca_hmac_sha256_ctx_t* ctx, const uint8_t* data, size_t data_size)
{
ATCA_STATUS status = ATCA_SUCCESS;
uint32_t block_count;
uint32_t rem_size = ATCA_SHA256_BLOCK_SIZE - ctx->block_size;
uint32_t copy_size = data_size > rem_size ? rem_size : (uint32_t)data_size;
uint32_t i = 0;
memcpy(&ctx->block[ctx->block_size], data, copy_size);
if (ctx->block_size + data_size < ATCA_SHA256_BLOCK_SIZE)
{
ctx->block_size += (uint32_t)data_size;
return ATCA_SUCCESS;
}
status = atcab_sha_base(SHA_MODE_HMAC_UPDATE, ATCA_SHA256_BLOCK_SIZE, ctx->block, NULL, NULL);
if (status != ATCA_SUCCESS)
{
return status;
}
data_size -= copy_size; block_count = (uint32_t)(data_size / ATCA_SHA256_BLOCK_SIZE);
for (i = 0; i < block_count; i++)
{
status = atcab_sha_base(SHA_MODE_HMAC_UPDATE, ATCA_SHA256_BLOCK_SIZE, &data[copy_size + i * ATCA_SHA256_BLOCK_SIZE], NULL, NULL);
if (status != ATCA_SUCCESS)
{
return status;
}
}
ctx->total_msg_size += (block_count + 1) * ATCA_SHA256_BLOCK_SIZE;
ctx->block_size = data_size % ATCA_SHA256_BLOCK_SIZE;
memcpy(ctx->block, &data[copy_size + block_count * ATCA_SHA256_BLOCK_SIZE], ctx->block_size);
return ATCA_SUCCESS;
}
ATCA_STATUS atcab_sha_hmac_finish(atca_hmac_sha256_ctx_t *ctx, uint8_t* digest, uint8_t target)
{
uint8_t mode = SHA_MODE_HMAC_END;
uint16_t digest_size = 32;
if (ATECC608A == _gDevice->mIface->mIfaceCFG->devtype)
{
mode = SHA_MODE_608_HMAC_END;
}
else if (target != SHA_MODE_TARGET_TEMPKEY)
{
return ATCA_BAD_PARAM;
}
mode |= target;
return atcab_sha_base(mode, ctx->block_size, ctx->block, digest, &digest_size);
}
ATCA_STATUS atcab_sha_hmac(const uint8_t * data, size_t data_size, uint16_t key_slot, uint8_t* digest, uint8_t target)
{
ATCA_STATUS status = ATCA_SUCCESS;
atca_hmac_sha256_ctx_t ctx;
status = atcab_sha_hmac_init(&ctx, key_slot);
if (status != ATCA_SUCCESS)
{
return status;
}
status = atcab_sha_hmac_update(&ctx, data, data_size);
if (status != ATCA_SUCCESS)
{
return status;
}
status = atcab_sha_hmac_finish(&ctx, digest, target);
if (status != ATCA_SUCCESS)
{
return status;
}
return ATCA_SUCCESS;
}