559 lines
14 KiB
C
559 lines
14 KiB
C
/**
|
|
* @file hash_basic.c
|
|
* @brief Semidrive CRYPTO hash basic source file.
|
|
*
|
|
* @copyright Copyright (c) 2021 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include "hash_basic.h"
|
|
|
|
/* hash register pointer */
|
|
volatile static hash_reg_t *const g_hash_reg = (hash_reg_t *)HASH_BASE_ADDR;
|
|
|
|
/* function: get hash IP version
|
|
* parameters: none
|
|
* return: hash IP version
|
|
* caution:
|
|
*/
|
|
uint32_t hash_get_version(void) { return g_hash_reg->hash_version; }
|
|
|
|
/* function: set hash to be CPU mode
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_set_cpu_mode(void)
|
|
{
|
|
g_hash_reg->hash_cfg &= (~((0x1) << HASH_DMA_OFFSET));
|
|
}
|
|
|
|
/* function: set hash to be DMA mode
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_set_dma_mode(void)
|
|
{
|
|
g_hash_reg->hash_cfg |= ((0x1) << HASH_DMA_OFFSET);
|
|
}
|
|
|
|
/* function: set hash mode
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_set_hash_mode(void)
|
|
{
|
|
g_hash_reg->hash_cfg &= (~(((uint32_t)1) << HASH_HMAC_OFFSET));
|
|
}
|
|
|
|
/* function: set hmac mode
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_set_hmac_mode(void)
|
|
{
|
|
g_hash_reg->hash_cfg |= (((uint32_t)1) << HASH_HMAC_OFFSET);
|
|
}
|
|
|
|
/* function: set hmac key mode
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_set_hmac_key_mode(void) { g_hash_reg->hash_mdin_cr |= 0x1; }
|
|
|
|
/* function: clear hmac key mode
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_clear_hmac_key_mode(void) { g_hash_reg->hash_mdin_cr &= ~0x1; }
|
|
|
|
/* function: clear hash risp regist
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_clear_risp(void) { g_hash_reg->hash_risr &= ~0x3; }
|
|
|
|
/* function: set opreated hmac key bitlen to regist
|
|
* parameters:
|
|
* cnt ------------------- input, operated key bitlen
|
|
* return: none
|
|
* caution:none
|
|
*/
|
|
void hash_set_hmac_key_cnt(uint32_t bitlen)
|
|
{
|
|
g_hash_reg->hash_key_cnt = bitlen;
|
|
}
|
|
|
|
/* function: set total hmac key bitlen to regist
|
|
* parameters:
|
|
* bitlen ------------------- input, key bitlen
|
|
* return: none
|
|
* caution:none
|
|
*/
|
|
void hash_set_hmac_key_len(uint32_t bitlen)
|
|
{
|
|
g_hash_reg->hash_key_len = bitlen;
|
|
}
|
|
|
|
/* function: hmac key opr for one block
|
|
* parameters:none
|
|
* return: none
|
|
* caution:none
|
|
*/
|
|
void hash_hmac_key_opr_one_block(uint32_t *key, uint32_t block_byte_len)
|
|
{
|
|
uint32_t i;
|
|
uint32_t block_words_len;
|
|
|
|
block_words_len = block_byte_len >> 2;
|
|
|
|
hash_set_hmac_key_len(block_byte_len << 3);
|
|
hash_set_hmac_key_cnt(0);
|
|
hash_set_last_block(1);
|
|
hash_start();
|
|
|
|
for (i = 0; i < block_words_len; i++) {
|
|
g_hash_reg->hash_m_din = key[i];
|
|
}
|
|
|
|
hash_wait_till_done();
|
|
}
|
|
|
|
/* function: hmac key opr
|
|
* parameters:none
|
|
* return: none
|
|
* caution:none
|
|
*/
|
|
void hash_hmac_key_opr(uint8_t *key, uint32_t key_bytes)
|
|
{
|
|
hash_set_hmac_key_len(key_bytes << 3);
|
|
hash_set_hmac_key_cnt(0);
|
|
hash_set_last_block(1);
|
|
hash_start();
|
|
hash_input_msg_u8(key, key_bytes);
|
|
hash_wait_till_done();
|
|
}
|
|
|
|
/* function: hmac secure port key opr for one block
|
|
* parameters:none
|
|
* return: none
|
|
* caution:none
|
|
*/
|
|
void hash_hmac_sp_key_opr(uint32_t key_bits)
|
|
{
|
|
hash_set_hmac_key_len(key_bits);
|
|
hash_set_hmac_key_cnt(0);
|
|
hash_set_last_block(1);
|
|
hash_start();
|
|
hash_wait_till_done();
|
|
}
|
|
|
|
/* function: set the specific hash algorithm
|
|
* parameters:
|
|
* hash_alg ------------------- input, specific hash algorithm
|
|
* return: none
|
|
* caution:
|
|
* 1. please make sure hash_alg is valid
|
|
*/
|
|
void hash_set_alg(HASH_ALG hash_alg)
|
|
{
|
|
g_hash_reg->hash_cfg &= (~0x0000000F);
|
|
g_hash_reg->hash_cfg |= hash_alg;
|
|
}
|
|
|
|
/* function: check whether hash_alg is SHA3
|
|
* parameters:
|
|
* hash_alg ------------------- input, specific hash algorithm
|
|
* return: 1(yes), 0(no)
|
|
* caution:
|
|
* 1. please make sure hash_alg is valid
|
|
*/
|
|
uint32_t hash_check_whether_sha3_alg(HASH_ALG hash_alg)
|
|
{
|
|
if (hash_alg < HASH_SHA3_224) {
|
|
return 0;
|
|
} else if (hash_alg <= HASH_SHA3_512) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* function: update hash config
|
|
* parameters:none
|
|
* return: none
|
|
* caution: none
|
|
*/
|
|
void hash_update_config(void)
|
|
{
|
|
g_hash_reg->hash_cfg |= (0x00001000);
|
|
g_hash_reg->hash_ctrl |= 0x1;
|
|
hash_wait_till_done();
|
|
g_hash_reg->hash_cfg &= (~0x00001000);
|
|
}
|
|
|
|
/* function: enable hash interruption in CPU mode
|
|
* parameters: none
|
|
* return: none
|
|
* caution: none
|
|
*/
|
|
void hash_enable_cpu_interruption(void) { g_hash_reg->hash_imcr |= 0x1; }
|
|
|
|
/* function: disable hash interruption in CPU mode
|
|
* parameters: none
|
|
* return: none
|
|
* caution: none
|
|
*/
|
|
void hash_disable_cpu_interruption(void) { g_hash_reg->hash_imcr &= (~0x1); }
|
|
|
|
/* function: enable hash interruption in DMA mode
|
|
* parameters: none
|
|
* return: none
|
|
* caution: none
|
|
*/
|
|
void hash_enable_dma_interruption(void)
|
|
{
|
|
g_hash_reg->hash_imcr |= ((0x1) << 1);
|
|
}
|
|
|
|
/* function: disable hash interruption in DMA mode
|
|
* parameters: none
|
|
* return: none
|
|
* caution: none
|
|
*/
|
|
void hash_disable_dma_interruption(void)
|
|
{
|
|
g_hash_reg->hash_imcr &= (~((0x1) << 1));
|
|
}
|
|
|
|
/* function: set dma wlen
|
|
* parameters:
|
|
* wlen ------------------------ input, byte length of write back data
|
|
* return: none
|
|
* caution: none
|
|
*/
|
|
void hash_set_dma_wlen(uint32_t wlen) { g_hash_reg->dma_wlen = wlen; }
|
|
|
|
/* function: clear dma_sa and dma_da
|
|
* parameters:none
|
|
* return: none
|
|
* caution: none
|
|
*/
|
|
void hash_clear_dma_sa_da(void)
|
|
{
|
|
g_hash_reg->dma_sa_l = 0x0;
|
|
g_hash_reg->dma_sa_h = 0x0;
|
|
|
|
g_hash_reg->dma_da_l = 0x0;
|
|
g_hash_reg->dma_da_h = 0x0;
|
|
}
|
|
|
|
/* function: set the tag whether current block is the last message block or not
|
|
* parameters:
|
|
* tag ------------------------ input, 0(no), other(yes)
|
|
* return: none
|
|
* caution:
|
|
* 1. if it is the last block, please config hash_reg->hash_msg_len,
|
|
* then the hardware will do the padding and post-processing.
|
|
*/
|
|
void hash_set_last_block(uint8_t tag)
|
|
{
|
|
if (tag) { /* current block is the last one of the message */
|
|
g_hash_reg->hash_mdin_cr |= (((uint32_t)1) << HASH_LAST_BLOCK_OFFSET);
|
|
} else { /* current block is not the last one of the message */
|
|
g_hash_reg->hash_mdin_cr &=
|
|
(~(((uint32_t)1) << HASH_LAST_BLOCK_OFFSET));
|
|
}
|
|
}
|
|
|
|
/* function: set the hash endian
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_set_endian_uint32(void)
|
|
{
|
|
/* clear bit[9:8], and now CPU is big-endian */
|
|
g_hash_reg->hash_cfg &=
|
|
(~(((uint32_t)3) << HASH_REVERSE_BYTE_ORDER_IN_WORD_OFFSET));
|
|
|
|
#ifndef HASH_CPU_BIG_ENDIAN
|
|
/* CPU is little-endian, input and output reversed by hardware----hash IP */
|
|
g_hash_reg->hash_cfg |=
|
|
((((uint32_t)2) << HASH_REVERSE_BYTE_ORDER_IN_WORD_OFFSET));
|
|
#endif
|
|
}
|
|
|
|
/* function: enable hmac secure port
|
|
* parameters:
|
|
* sp_key_idx ----------------- input, index of secure port key
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_hmac_enable_secure_port(uint16_t sp_key_idx)
|
|
{
|
|
#ifdef HMAC_SECURE_PORT_FUNCTION
|
|
|
|
g_hash_reg->hash_cfg |= ((0x1) << 5);
|
|
|
|
sp_key_idx -= 1;
|
|
OTP_KEY_CTRL = ((uint32_t)(sp_key_idx & 0x7FFF)) << 16;
|
|
|
|
OTP_KEY_CTRL |= 0x1;
|
|
|
|
#endif
|
|
}
|
|
|
|
/* function: disable hmac secure port
|
|
* parameters:
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_hmac_disable_secure_port(void)
|
|
{
|
|
g_hash_reg->hash_cfg &= (~(((uint32_t)1) << 5));
|
|
}
|
|
|
|
/* function: get current HASH iterator value
|
|
* parameters:
|
|
* iterator ------------------- output, current hash iterator
|
|
* hash_iterator_words -------- input, iterator word length
|
|
* return: none
|
|
* caution:
|
|
* 1.
|
|
*/
|
|
void hash_get_iterator(uint8_t *iterator, uint8_t hash_iterator_words)
|
|
{
|
|
uint32_t temp;
|
|
uint32_t i;
|
|
|
|
/* for the case that iterator is not aligned by word */
|
|
if (((uint32_t)iterator) & 3) {
|
|
for (i = 0; i < hash_iterator_words; i++) {
|
|
temp = g_hash_reg->hash_out[i];
|
|
memcpy_(iterator + (i << 2), &temp, 4);
|
|
}
|
|
} else {
|
|
for (i = 0; i < hash_iterator_words; i++) {
|
|
((uint32_t *)iterator)[i] = g_hash_reg->hash_out[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
/* function: input current iterator value
|
|
* parameters:
|
|
* iterator ------------------- input, hash iterator value
|
|
* hash_iterator_words -------- input, iterator word length
|
|
* return: none
|
|
* caution:
|
|
* 1. iterator must be word aligned
|
|
*/
|
|
void hash_set_iterator(uint32_t *iterator, uint8_t hash_iterator_words)
|
|
{
|
|
uint32_t i;
|
|
|
|
if (iterator != NULL) {
|
|
for (i = 0; i < hash_iterator_words; i++) {
|
|
g_hash_reg->hash_in[i] = iterator[i];
|
|
}
|
|
} else {
|
|
/*for SHA3 init, iv is zero of 1600 bits*/
|
|
for (i = 0; i < hash_iterator_words; i++) {
|
|
g_hash_reg->hash_in[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* function: set hash_msg_len and hash_msg_cnt
|
|
* parameters:
|
|
* bytelen ------------------- input, msg byte length
|
|
* return: none
|
|
* caution:none
|
|
*/
|
|
void hash_set_msg_len(uint32_t bytelen)
|
|
{
|
|
volatile uint32_t flag = 0;
|
|
|
|
g_hash_reg->hash_msg_len[0] = bytelen << 3;
|
|
g_hash_reg->hash_msg_len[1] = bytelen >> (32 - 3);
|
|
g_hash_reg->hash_msg_len[2] = flag;
|
|
g_hash_reg->hash_msg_len[3] = flag;
|
|
|
|
g_hash_reg->hash_msg_cnt[0] = flag;
|
|
g_hash_reg->hash_msg_cnt[1] = flag;
|
|
g_hash_reg->hash_msg_cnt[2] = flag;
|
|
g_hash_reg->hash_msg_cnt[3] = flag;
|
|
}
|
|
|
|
/* function: clear hash_msg_len and hash_msg_cnt
|
|
* parameters:none
|
|
* return: none
|
|
* caution:none
|
|
*/
|
|
void hash_clear_msg_len(void)
|
|
{
|
|
volatile uint32_t flag = 0;
|
|
|
|
g_hash_reg->hash_msg_len[0] = flag;
|
|
g_hash_reg->hash_msg_len[1] = flag;
|
|
g_hash_reg->hash_msg_len[2] = flag;
|
|
g_hash_reg->hash_msg_len[3] = flag;
|
|
|
|
g_hash_reg->hash_msg_cnt[0] = flag;
|
|
g_hash_reg->hash_msg_cnt[1] = flag;
|
|
g_hash_reg->hash_msg_cnt[2] = flag;
|
|
g_hash_reg->hash_msg_cnt[3] = flag;
|
|
}
|
|
|
|
/* function: set the total bit length of the whole message
|
|
* parameters:
|
|
* msg_total_bits ------------- input, total bit length of the whole message
|
|
* words ---------------------- input, word length of array msg_total_bits
|
|
* return: none
|
|
* caution:
|
|
* 1.
|
|
*/
|
|
void hash_set_msg_total_bit_len(uint32_t *msg_total_bits,
|
|
uint32_t block_byte_len)
|
|
{
|
|
uint32_t words = HASH_BLOCK_MAX_WORD_LEN / 8;
|
|
|
|
while (words--) {
|
|
g_hash_reg->hash_msg_len[words] = msg_total_bits[words];
|
|
g_hash_reg->hash_msg_cnt[words] = msg_total_bits[words];
|
|
}
|
|
|
|
if (block_byte_len == 64) {
|
|
g_hash_reg->hash_msg_cnt[0] &= 0xFFFFFE00;
|
|
} else {
|
|
g_hash_reg->hash_msg_cnt[0] &= 0xFFFFFC00;
|
|
}
|
|
}
|
|
|
|
/* function: start HASH iteration calc
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_start(void)
|
|
{
|
|
g_hash_reg->hash_risr = 0x0;
|
|
g_hash_reg->hash_ctrl |= 0x1;
|
|
}
|
|
|
|
/* function: wait till done
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_wait_till_done(void)
|
|
{
|
|
while ((g_hash_reg->hash_ctrl & 0x1)) {
|
|
;
|
|
}
|
|
}
|
|
|
|
/* function: DMA wait till done
|
|
* parameters:
|
|
* callback ------------------- callback function pointer
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void hash_dma_wait_till_done(HASH_CALLBACK callback)
|
|
{
|
|
while ((g_hash_reg->hash_ctrl & 0x1)) {
|
|
|
|
if (callback) {
|
|
callback();
|
|
} else {
|
|
;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* function: input message
|
|
* parameters:
|
|
* msg ------------------------ input, message
|
|
* msg_words ------------------ input, word length of msg
|
|
* return: none
|
|
* caution:
|
|
* 1. if msg does not contain the last block, please make sure msg_words is
|
|
* a multiple of the hash block word length.
|
|
*/
|
|
void hash_input_msg(uint8_t *msg, uint32_t msg_words)
|
|
{
|
|
uint32_t tmp;
|
|
|
|
if (((uint32_t)msg) & 3) {
|
|
while (msg_words--) {
|
|
memcpy_(&tmp, msg, 4);
|
|
g_hash_reg->hash_m_din = tmp;
|
|
msg += 4;
|
|
}
|
|
} else {
|
|
while (msg_words--) {
|
|
g_hash_reg->hash_m_din = *((uint32_t *)msg);
|
|
msg += 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* function: input message
|
|
* parameters:
|
|
* msg ------------------------ input, message
|
|
* msg_words ------------------ input, byte length of msg
|
|
* return: none
|
|
* caution:
|
|
* 1. if msg does not contain the last block, please make sure msg_words is
|
|
* a multiple of the hash block word length.
|
|
*/
|
|
void hash_input_msg_u8(uint8_t *msg, uint32_t msg_bytes)
|
|
{
|
|
uint32_t tmp1, tmp2;
|
|
hash_input_msg(msg, msg_bytes >> 2);
|
|
tmp1 = msg_bytes & 0x00000003;
|
|
|
|
if (0 != tmp1) {
|
|
tmp2 = 0;
|
|
memcpy_((uint8_t *)&tmp2, msg + (msg_bytes & 0xFFFFFFFC), tmp1);
|
|
hash_input_msg((uint8_t *)&tmp2, 1);
|
|
} else {
|
|
;
|
|
}
|
|
}
|
|
|
|
#ifdef HASH_DMA_FUNCTION
|
|
|
|
/* function: basic HASH DMA operation
|
|
* parameters:
|
|
* msg ------------------------ input, message of some blocks, or message
|
|
* including the last byte(last block) iterator ------------------- output,
|
|
* temporary iterator or hash digest msgBitLen ------------------ input, actual
|
|
* bit length of msg callback ------------------- callback function pointer
|
|
* return: none
|
|
* caution:
|
|
* 1. for DMA operation, the unit of input and output is 4 words, so, please
|
|
* make sure the buffer iterator is sufficient.
|
|
*/
|
|
void hash_dma_operate(uint32_t *msg, uint32_t *iterator, uint32_t msgBitLen,
|
|
HASH_CALLBACK callback)
|
|
{
|
|
g_hash_reg->dma_sa_l = (uint32_t)msg;
|
|
g_hash_reg->dma_sa_h = 0x0;
|
|
|
|
g_hash_reg->dma_da_l = (uint32_t)iterator;
|
|
g_hash_reg->dma_da_h = 0x0;
|
|
|
|
g_hash_reg->dma_rlen = msgBitLen;
|
|
|
|
hash_start();
|
|
hash_dma_wait_till_done(callback);
|
|
}
|
|
#endif
|