523 lines
16 KiB
C
523 lines
16 KiB
C
/*****************************************************************************
|
|
*
|
|
*
|
|
*Copyright (c) 2021-2029 Semidrive Incorporated. All rights reserved.
|
|
*Software License Agreement
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
#include <hash.h>
|
|
#include <hmac.h>
|
|
|
|
/* function: init HMAC
|
|
* parameters:
|
|
* ctx ------------------------ input, hmac_ctx_t context pointer
|
|
* key_flag ------------------- input, whether key byte length bigger than
|
|
* block byte length return: HASH_SUCCESS(success), other(error) caution:
|
|
* 1. please make sure hash_alg is valid
|
|
*/
|
|
static void hmac_key_state_recover(hmac_ctx_t *ctx, uint32_t key_flag)
|
|
{
|
|
hash_set_cpu_mode();
|
|
hash_set_hmac_mode();
|
|
hash_set_endian_uint32();
|
|
hash_disable_cpu_interruption();
|
|
hash_set_alg(ctx->hash_alg);
|
|
hash_set_hmac_key_mode();
|
|
hash_update_config();
|
|
|
|
if (1 == key_flag) {
|
|
hash_set_IV(ctx->hash_alg, ctx->hash_ctx->iterator_word_len);
|
|
hash_hmac_key_opr_one_block(ctx->K0, ctx->hash_ctx->block_byte_len);
|
|
} else if (2 == key_flag) {
|
|
hash_set_iterator(ctx->K0, ctx->hash_ctx->iterator_word_len);
|
|
hash_set_hmac_key_len(0);
|
|
hash_set_hmac_key_cnt(0);
|
|
hash_set_last_block(1);
|
|
hash_start();
|
|
hash_wait_till_done();
|
|
} else {
|
|
;
|
|
}
|
|
|
|
hash_clear_hmac_key_mode();
|
|
}
|
|
|
|
/* function: init HMAC
|
|
* parameters:
|
|
* ctx ------------------------ input, hmac_ctx_t context pointer
|
|
* hash_alg ------------------- input, specific hash algorithm
|
|
* key ------------------------ input, key
|
|
* sp_key_idx ----------------- input, index of secure port key
|
|
* key_bytes ------------------ input, byte length of key, it could be 0
|
|
* return: HASH_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure hash_alg is valid
|
|
*/
|
|
uint32_t hmac_init(hmac_ctx_t *ctx, HASH_ALG hash_alg, uint8_t *key,
|
|
uint16_t sp_key_idx, uint32_t key_bytes)
|
|
{
|
|
if (NULL == ctx) {
|
|
return HASH_BUFFER_NULL;
|
|
} else if (HASH_SUCCESS != check_hash_alg(hash_alg)) {
|
|
return HASH_INPUT_INVALID;
|
|
} else if (key_bytes & 0xE0000000) {
|
|
/*bit length overflow*/
|
|
return HASH_INPUT_INVALID;
|
|
} else if (NULL == key) {
|
|
#ifdef HMAC_SECURE_PORT_FUNCTION
|
|
if ((0 == sp_key_idx) || (sp_key_idx > HMAC_MAX_KEY_IDX) ||
|
|
(0 == key_bytes) || (key_bytes > HMAC_MAX_SP_KEY_SIZE)) {
|
|
return HASH_INPUT_INVALID;
|
|
} else if ((sp_key_idx == HMAC_MAX_KEY_IDX) &&
|
|
(key_bytes > HMAC_MAX_SP_KEY_SIZE / 2)) {
|
|
return HASH_INPUT_INVALID;
|
|
} else {
|
|
;
|
|
}
|
|
#else
|
|
key_bytes = 0;
|
|
#endif
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*set hash_ctx config*/
|
|
memset_(ctx, 0, sizeof(hmac_ctx_t));
|
|
|
|
if (key) {
|
|
/*key is from user input*/
|
|
hash_hmac_disable_secure_port();
|
|
} else {
|
|
/*key is from secure port*/
|
|
hash_hmac_enable_secure_port(sp_key_idx);
|
|
hash_hmac_enable_secure_port(sp_key_idx + 1);
|
|
}
|
|
|
|
hash_set_cpu_mode();
|
|
hash_set_hmac_mode();
|
|
hash_set_hmac_key_mode();
|
|
hash_set_endian_uint32();
|
|
hash_disable_cpu_interruption();
|
|
hash_set_alg(hash_alg);
|
|
hash_update_config();
|
|
|
|
ctx->hash_alg = hash_alg;
|
|
ctx->hash_ctx->hash_alg = hash_alg;
|
|
ctx->hash_ctx->block_byte_len = hash_get_block_word_len(hash_alg) << 2;
|
|
ctx->hash_ctx->iterator_word_len = hash_get_iterator_word_len(hash_alg);
|
|
ctx->hash_ctx->digest_byte_len = hash_get_digest_word_len(hash_alg) << 2;
|
|
ctx->hash_ctx->status.busy = 0;
|
|
ctx->hash_ctx->first_update_flag = 1;
|
|
ctx->hash_ctx->finish_flag = 0;
|
|
|
|
if (key) {
|
|
/*key is from user input*/
|
|
hash_set_IV(hash_alg, ctx->hash_ctx->iterator_word_len);
|
|
|
|
/*get K0*/
|
|
if (key_bytes <= ctx->hash_ctx->block_byte_len) {
|
|
/*K0 = (key)||000..00*/
|
|
ctx->key_flag = 1;
|
|
memcpy_((uint8_t *)(ctx->K0), key, key_bytes);
|
|
memset_(((uint8_t *)(ctx->K0)) + key_bytes, 0,
|
|
ctx->hash_ctx->block_byte_len - key_bytes);
|
|
hash_hmac_key_opr_one_block(ctx->K0, ctx->hash_ctx->block_byte_len);
|
|
} else {
|
|
ctx->key_flag = 2;
|
|
hash_hmac_key_opr(key, key_bytes);
|
|
hash_get_iterator(((uint8_t *)(ctx->K0)),
|
|
ctx->hash_ctx->digest_byte_len >> 2);
|
|
memset_(((uint8_t *)(ctx->K0)) + ctx->hash_ctx->digest_byte_len, 0,
|
|
ctx->hash_ctx->block_byte_len -
|
|
ctx->hash_ctx->digest_byte_len);
|
|
}
|
|
} else {
|
|
/*key is from secure port*/
|
|
hash_hmac_sp_key_opr(key_bytes << 3);
|
|
}
|
|
|
|
hash_clear_hmac_key_mode();
|
|
return HASH_SUCCESS;
|
|
}
|
|
|
|
/* function: hash iterate calc with some blocks
|
|
* parameters:
|
|
* ctx ------------------------ input, hash_ctx_t context pointer
|
|
* msg ------------------------ input, message of some blocks
|
|
* block_count ---------------- input, count of blocks
|
|
* return: none
|
|
* caution:
|
|
* 1. please make sure the three parameters is valid
|
|
*/
|
|
static void hash_hmac_calc_blocks(hash_ctx_t *ctx, const uint8_t *msg,
|
|
uint32_t block_count)
|
|
{
|
|
uint8_t block_word_len = (ctx->block_byte_len) >> 2;
|
|
|
|
#if CONFIG_HASH_SUPPORT_MUL_THREAD
|
|
/*set the input iterator data*/
|
|
if (1 != ctx->first_update_flag) {
|
|
hash_set_iterator(ctx->iterator, ctx->iterator_word_len);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*set the bit length of the input blocks*/
|
|
hash_set_tx_bit_len(ctx, block_count);
|
|
|
|
hash_set_last_block(0);
|
|
|
|
ctx->first_update_flag = 0;
|
|
|
|
hash_start_calculate(ctx);
|
|
|
|
while (block_count--) {
|
|
/*input the block message*/
|
|
hash_input_msg((uint8_t *)msg, block_word_len);
|
|
msg += ctx->block_byte_len;
|
|
}
|
|
|
|
hash_wait_till_done();
|
|
|
|
#if CONFIG_HASH_SUPPORT_MUL_THREAD
|
|
/*if message update not done, get the new iterator hash value*/
|
|
if (1 != ctx->finish_flag) {
|
|
hash_get_iterator((uint8_t *)(ctx->iterator), ctx->iterator_word_len);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
/* function: hmac update message
|
|
* parameters:
|
|
* ctx ------------------------ input, hmac_ctx_t context pointer
|
|
* msg ------------------------ input, message
|
|
* msg_bytes ------------------ input, byte length of the input message
|
|
* return: HASH_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure the three parameters are valid, and ctx is
|
|
* initialized
|
|
*/
|
|
uint32_t hmac_update(hmac_ctx_t *ctx, const uint8_t *msg, uint32_t msg_bytes)
|
|
{
|
|
uint32_t count;
|
|
uint8_t left, fill;
|
|
|
|
if (NULL == ctx) {
|
|
return HASH_BUFFER_NULL;
|
|
} else if ((NULL == msg) || (0 == msg_bytes)) {
|
|
return HASH_SUCCESS;
|
|
} else {
|
|
;
|
|
}
|
|
/*start to update processing*/
|
|
ctx->hash_ctx->status.busy = 1;
|
|
|
|
#if CONFIG_HASH_SUPPORT_MUL_THREAD
|
|
hmac_key_state_recover(ctx, ctx->key_flag);
|
|
#endif
|
|
/*byte length of valid message left in block buffer*/
|
|
/*byte length that block buffer need to fill a block*/
|
|
left = ctx->hash_ctx->total[0] % (ctx->hash_ctx->block_byte_len);
|
|
fill = (ctx->hash_ctx->block_byte_len) - left;
|
|
|
|
/*update total byte length*/
|
|
if (hash_total_len_add_uint32(ctx->hash_ctx->total,
|
|
ctx->hash_ctx->block_byte_len / 32,
|
|
msg_bytes)) {
|
|
return HASH_LEN_OVERFLOW;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
if (left) {
|
|
if (msg_bytes >= fill) {
|
|
memcpy_(ctx->hash_ctx->hash_buffer + left, (uint8_t *)msg, fill);
|
|
hash_hmac_calc_blocks(ctx->hash_ctx, ctx->hash_ctx->hash_buffer, 1);
|
|
msg_bytes -= fill;
|
|
msg += fill;
|
|
} else {
|
|
memcpy_(ctx->hash_ctx->hash_buffer + left, (uint8_t *)msg,
|
|
msg_bytes);
|
|
goto end;
|
|
}
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*process some blocks*/
|
|
count = msg_bytes / (ctx->hash_ctx->block_byte_len);
|
|
|
|
if (count) {
|
|
hash_hmac_calc_blocks(ctx->hash_ctx, msg, count);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*process the remainder*/
|
|
msg += (ctx->hash_ctx->block_byte_len) * count;
|
|
msg_bytes = msg_bytes % (ctx->hash_ctx->block_byte_len);
|
|
|
|
if (msg_bytes) {
|
|
memcpy_(ctx->hash_ctx->hash_buffer, (uint8_t *)msg, msg_bytes);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
end:
|
|
/*update end, status becomes idle*/
|
|
ctx->hash_ctx->status.busy = 0;
|
|
|
|
return HASH_SUCCESS;
|
|
}
|
|
|
|
/* function: message update done, get the mac
|
|
* parameters:
|
|
* ctx ------------------------ input, hmac_ctx_t context pointer
|
|
* mac ------------------------ output, mac
|
|
* return: HASH_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure the ctx is valid and initialized
|
|
* 2. please make sure the mac buffer is sufficient
|
|
*/
|
|
uint32_t hmac_final(hmac_ctx_t *ctx, uint8_t *mac)
|
|
{
|
|
uint8_t tmp;
|
|
|
|
if (NULL == ctx || NULL == mac) {
|
|
return HASH_BUFFER_NULL;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
#if CONFIG_HASH_SUPPORT_MUL_THREAD
|
|
hmac_key_state_recover(ctx, ctx->key_flag);
|
|
|
|
if (0 == ctx->hash_ctx->first_update_flag) {
|
|
hash_set_iterator((uint8_t *)(ctx->hash_ctx->iterator),
|
|
ctx->hash_ctx->iterator_word_len);
|
|
}
|
|
/*set not the last block*/
|
|
hash_set_last_block(0);
|
|
#endif
|
|
/*the last block calc*/
|
|
ctx->hash_ctx->finish_flag = 1;
|
|
|
|
/*get the byte length of the remainder msg(less than one block)*/
|
|
tmp = ctx->hash_ctx->total[0] % (ctx->hash_ctx->block_byte_len);
|
|
|
|
/*set total msg bit length*/
|
|
hash_total_bytelen_2_bitlen(ctx->hash_ctx->total,
|
|
(ctx->hash_ctx->block_byte_len) / 32);
|
|
|
|
hash_set_msg_total_bit_len(ctx->hash_ctx->total,
|
|
ctx->hash_ctx->block_byte_len);
|
|
|
|
hash_set_last_block(1);
|
|
|
|
hash_start();
|
|
|
|
hash_input_msg((uint8_t *)ctx->hash_ctx->hash_buffer, (tmp + 3) / 4);
|
|
|
|
hash_wait_till_done();
|
|
|
|
/*get the hash result*/
|
|
hash_get_iterator(mac, (ctx->hash_ctx->digest_byte_len) >> 2);
|
|
|
|
memset_(ctx, 0, sizeof(hmac_ctx_t));
|
|
|
|
return HASH_SUCCESS;
|
|
}
|
|
|
|
/* function: input key and whole message, get the mac
|
|
* parameters:
|
|
* hash_alg ------------------- input, specific hash algorithm
|
|
* key ------------------------ input, key
|
|
* sp_key_idx ----------------- input, index of secure port key
|
|
* key_bytes ------------------ input, byte length of the key
|
|
* msg ------------------------ input, message
|
|
* msg_bytes ------------------ input, byte length of the input message
|
|
* mac ------------------------ output, mac
|
|
* return: HASH_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure the mac buffer is sufficient
|
|
*/
|
|
uint32_t hmac(HASH_ALG hash_alg, uint8_t *key, uint16_t sp_key_idx,
|
|
uint32_t key_bytes, uint8_t *msg, uint32_t msg_bytes,
|
|
uint8_t *mac)
|
|
{
|
|
hmac_ctx_t ctx[1];
|
|
uint32_t ret;
|
|
|
|
ret = hmac_init(ctx, hash_alg, key, sp_key_idx, key_bytes);
|
|
|
|
if (HASH_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = hmac_update(ctx, msg, msg_bytes);
|
|
|
|
if (HASH_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
return hmac_final(ctx, mac);
|
|
}
|
|
|
|
#ifdef HASH_DMA_FUNCTION
|
|
/* function: init dma hmac
|
|
* parameters:
|
|
* ctx ------------------------ input, hmac_dma_ctx_t context pointer
|
|
* hash_alg ------------------- input, specific hash algorithm
|
|
* key ------------------------ input, key
|
|
* sp_key_idx ----------------- input, index of secure port key
|
|
* key_bytes ------------------ input, key byte length
|
|
* callback ------------------- callback function pointer
|
|
* return: HASH_SUCCESS(success), other(error)
|
|
* caution:
|
|
*/
|
|
uint32_t hmac_dma_init(hmac_dma_ctx_t *ctx, HASH_ALG hash_alg,
|
|
const uint8_t *key, uint16_t sp_key_idx,
|
|
uint32_t key_bytes, HASH_CALLBACK callback)
|
|
{
|
|
uint32_t ret;
|
|
|
|
if (NULL == ctx || NULL == callback) {
|
|
return HASH_BUFFER_NULL;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = hmac_init(ctx->hmac_ctx, hash_alg, (uint8_t *)key, sp_key_idx,
|
|
key_bytes);
|
|
|
|
if (HASH_SUCCESS == ret) {
|
|
hash_clear_dma_sa_da();
|
|
|
|
hash_set_dma_wlen(hash_get_digest_word_len(hash_alg) << 5);
|
|
|
|
hash_set_dma_mode();
|
|
hash_set_last_block(0);
|
|
|
|
ctx->hash_dma_ctx->block_word_len = hash_get_block_word_len(hash_alg);
|
|
ctx->hash_dma_ctx->callback = callback;
|
|
uint32_clear(ctx->hash_dma_ctx->total,
|
|
ctx->hash_dma_ctx->block_word_len / 8);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* function: dma hmac update message
|
|
* parameters:
|
|
* ctx ------------------------ input, hmac_dma_ctx_t context pointer
|
|
* msg ------------------------ input, message
|
|
* msg_words ------------------ input, word length of the input message,
|
|
* must be multiple of block word length of HASH tmp_iterator ---------------
|
|
* output, temporary hash iterator return: HASH_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure the four parameters are valid, and ctx is initialized
|
|
*/
|
|
uint32_t hmac_dma_update_blocks(hmac_dma_ctx_t *ctx, uint32_t *msg,
|
|
uint32_t msg_words, uint32_t *tmp_iterator)
|
|
{
|
|
if (NULL == ctx) {
|
|
return HASH_BUFFER_NULL;
|
|
} else {
|
|
return hash_dma_update_blocks(ctx->hash_dma_ctx, msg, msg_words,
|
|
tmp_iterator);
|
|
}
|
|
}
|
|
|
|
/* function: dma hmac message update done, get the mac
|
|
* parameters:
|
|
* ctx ------------------------ input, hmac_dma_ctx_t context pointer
|
|
* remainder_msg -------------- input, message
|
|
* remainder_bytes ------------ input, byte length of the last message, must
|
|
* be in [0, BLOCK_BYTE_LEN-1], here BLOCK_BYTE_LEN is block byte length of HASH
|
|
* tmp_iterator --------------- output, temporary hash iterator
|
|
* mac ------------------------ output, mac
|
|
* return: HASH_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure the three parameters are valid, and ctx is
|
|
* initialized
|
|
*/
|
|
uint32_t hmac_dma_final(hmac_dma_ctx_t *ctx, uint32_t *remainder_msg,
|
|
uint32_t remainder_bytes, uint32_t *tmp_iterator,
|
|
uint8_t *mac)
|
|
{
|
|
uint32_t ret;
|
|
|
|
if ((NULL == ctx) || (NULL == tmp_iterator) || (NULL == mac)) {
|
|
return HASH_BUFFER_NULL;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = hash_dma_final(ctx->hash_dma_ctx, remainder_msg, remainder_bytes,
|
|
tmp_iterator);
|
|
|
|
if (HASH_SUCCESS == ret) {
|
|
memcpy_(mac, (uint8_t *)tmp_iterator,
|
|
ctx->hmac_ctx->hash_ctx->digest_byte_len);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* function: dma hmac input key and message, get the mac
|
|
* parameters:
|
|
* hash_alg ------------------- input, specific hash algorithm
|
|
* key ------------------------ input, key
|
|
* sp_key_idx ----------------- input, index of secure port key
|
|
* key_bytes ------------------ input, key byte length
|
|
* msg ------------------------ input, message
|
|
* msg_bytes ------------------ input, byte length of the input message
|
|
* tmp_iterator --------------- output, for temporary hash iterator or
|
|
* digest(DMA) mac ------------------------ output, mac callback
|
|
* ------------------- callback function pointer return: HASH_SUCCESS(success),
|
|
* other(error) caution:
|
|
*/
|
|
uint32_t hmac_dma(HASH_ALG hash_alg, uint8_t *key, uint16_t sp_key_idx,
|
|
uint32_t key_bytes, uint32_t *msg, uint32_t msg_bytes,
|
|
uint32_t *tmp_iterator, uint8_t *mac, HASH_CALLBACK callback)
|
|
{
|
|
uint32_t blocks_words, remainder_bytes;
|
|
uint32_t ret;
|
|
hmac_dma_ctx_t ctx[1];
|
|
|
|
ret = hmac_dma_init(ctx, hash_alg, key, sp_key_idx, key_bytes, callback);
|
|
|
|
if (HASH_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
remainder_bytes = msg_bytes % ctx->hmac_ctx->hash_ctx->block_byte_len;
|
|
blocks_words = (msg_bytes - remainder_bytes) / 4;
|
|
ret = hash_dma_update_blocks(ctx->hash_dma_ctx, msg, blocks_words,
|
|
tmp_iterator);
|
|
|
|
if (HASH_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
return hmac_dma_final(ctx, (uint32_t *)(msg + blocks_words),
|
|
remainder_bytes, tmp_iterator, mac);
|
|
}
|
|
#endif
|