Files
base/drivers/source/crypto/cacc/ske/ske_cbc_mac.c
2025-11-07 09:57:14 +08:00

513 lines
19 KiB
C

/**
* @file ske_cbc_mac.c
* @brief Semidrive CRYPTO ske cbc mac source file.
*
* @copyright Copyright (c) 2021 Semidrive Semiconductor.
* All rights reserved.
*/
#include <ske_cbc_mac.h>
#include <stdio.h>
#ifdef SUPPORT_SKE_MODE_CBC_MAC
/* function: ske_hp cbc mac internal init config
* parameters:
* ctx ------------------------ input, ske_cbc_mac_ctx_t context pointer
* alg ------------------------ input, ske_hp algorithm
* key ------------------------ input, key in byte buffer style
* sp_key_idx ----------------- input, index of secure port key, (sp_key_idx
* & 0x7FFF) must be in [1,MAX_KEY_IDX], if the MSB(sp_key_idx) is 1, that means
* using low 128bit of the 256bit key return: SKE_SUCCESS(success), other(error)
* caution:
* 1. if key is from user input, please make sure key is not NULL(now
* sp_key_idx is useless), otherwise, key is from secure port, and (sp_key_idx &
* 0x7FFF) must be in [1,MAX_KEY_IDX]
*/
uint32_t ske_hp_cbc_mac_init_internal(ske_cbc_mac_ctx_t *ctx, SKE_ALG alg,
uint8_t *key, uint16_t sp_key_idx)
{
uint32_t iv[4];
uint32_clear(iv, 4);
return ske_hp_init_internal(ctx->ske_cbc_mac_ctx, alg, SKE_MODE_CBC_MAC,
SKE_CRYPTO_ENCRYPT, key, sp_key_idx,
(uint8_t *)iv);
}
/* function: ske_hp cbc mac init(CPU style)
* parameters:
* ctx ------------------------ input, ske_cbc_mac_ctx_t context pointer
* alg ------------------------ input, ske_hp algorithm
* padding -------------------- input, ske_hp cbc mac padding scheme, like
* SKE_NO_PADDING,SKE_ZERO_PADDING. key ------------------------ input, key in
* byte buffer style sp_key_idx ----------------- input, index of secure port
* key, (sp_key_idx & 0x7FFF) must be in [1,MAX_KEY_IDX] return:
* SKE_SUCCESS(success), other(error) caution:
* 1. if key is from user input, please make sure key is not NULL(now
* sp_key_idx is useless), otherwise, key is from secure port, and (sp_key_idx &
* 0x7FFF) must be in [1,MAX_KEY_IDX]
*/
uint32_t ske_hp_cbc_mac_init(ske_cbc_mac_ctx_t *ctx, SKE_ALG alg,
SKE_PADDING padding, uint8_t *key,
uint16_t sp_key_idx)
{
/*check and keep the padding scheme and ctx->left_bytes = 0*/
if (NULL == ctx) {
return SKE_BUFFER_NULL;
} else if (padding > SKE_ZERO_PADDING) {
return SKE_INPUT_INVALID;
} else {
ctx->is_updated = 0;
ctx->padding = padding;
ctx->left_bytes = 0;
}
ske_hp_set_cpu_mode();
return ske_hp_cbc_mac_init_internal(ctx, alg, key, sp_key_idx);
}
/* function: ske_hp cbc_mac update message(CPU style)
* parameters:
* ctx ------------------------ input, ske_cbc_mac_ctx_t context pointer
* msg ------------------------ input, message
* msg_bytes ------------------ input, byte length of message.
* return: SKE_SUCCESS(success), other(error)
* caution:
* 1. msg_bytes could be any value.
*/
uint32_t ske_hp_cbc_mac_update(ske_cbc_mac_ctx_t *ctx, uint8_t *msg,
uint32_t msg_bytes)
{
uint32_t blocks_bytes;
uint32_t ret;
uint8_t fill_bytes, remainder;
if (NULL == ctx) {
return SKE_BUFFER_NULL;
} else {
;
}
if ((NULL == msg) || (0 == msg_bytes)) {
return SKE_SUCCESS;
} else {
ctx->is_updated = 1;
}
if (ctx->left_bytes) {
fill_bytes = ctx->ske_cbc_mac_ctx->block_bytes - ctx->left_bytes;
if (msg_bytes < fill_bytes) {
memcpy_(ctx->block_buf + ctx->left_bytes, msg, msg_bytes);
ctx->left_bytes += msg_bytes;
return SKE_SUCCESS;
} else {
memcpy_(ctx->block_buf + ctx->left_bytes, msg, fill_bytes);
ret = ske_hp_update_blocks_no_output(
ctx->ske_cbc_mac_ctx, ctx->block_buf,
ctx->ske_cbc_mac_ctx->block_bytes);
if (SKE_SUCCESS != ret) {
return ret;
} else {
ctx->left_bytes = 0;
msg += fill_bytes;
msg_bytes -= fill_bytes;
}
}
}
/*update blocks*/
blocks_bytes = (msg_bytes / ctx->ske_cbc_mac_ctx->block_bytes) *
ctx->ske_cbc_mac_ctx->block_bytes;
ret =
ske_hp_update_blocks_no_output(ctx->ske_cbc_mac_ctx, msg, blocks_bytes);
if (SKE_SUCCESS != ret) {
return ret;
} else {
;
}
/*hold the remainder*/
remainder = msg_bytes % ctx->ske_cbc_mac_ctx->block_bytes;
if (remainder) {
memcpy_(ctx->block_buf, msg + blocks_bytes, remainder);
ctx->left_bytes = remainder;
} else {
;
}
return SKE_SUCCESS;
}
/* function: ske_hp cbc_mac finish, and get the mac(CPU style)
* parameters:
* ctx ------------------------ input, ske_cbc_mac_ctx_t context pointer
* mac ------------------------ output, mac
* mac_bytes ------------------ input, mac byte length, must be bigger than
* 1, and not bigger than block length return: SKE_SUCCESS(success),
* other(error) caution:
* 1. for the case that padding is SKE_NO_PADDING, if the total length of
* message is not a multiple of block length, it will return error.
*/
uint32_t ske_hp_cbc_mac_final(ske_cbc_mac_ctx_t *ctx, uint8_t *mac,
uint8_t mac_bytes)
{
uint32_t tmp[4];
uint32_t ret;
if (NULL == ctx || NULL == mac) {
return SKE_BUFFER_NULL;
} else if ((0 == mac_bytes) ||
(mac_bytes > ctx->ske_cbc_mac_ctx->block_bytes)) {
return SKE_INPUT_INVALID;
} else if (0 == ctx->is_updated) {
/*no input, it is not valid*/
return SKE_INPUT_INVALID;
} else {
;
}
if (0 == ctx->left_bytes) {
ske_hp_simple_get_output_block(tmp, ctx->ske_cbc_mac_ctx->block_words);
} else {
if (SKE_NO_PADDING == ctx->padding) {
return SKE_ERROR;
} else if (SKE_ZERO_PADDING == ctx->padding) {
memset_(ctx->block_buf + ctx->left_bytes, 0,
ctx->ske_cbc_mac_ctx->block_bytes - ctx->left_bytes);
ret = ske_hp_update_blocks_internal(
ctx->ske_cbc_mac_ctx, ctx->block_buf, (uint8_t *)tmp,
ctx->ske_cbc_mac_ctx->block_bytes);
if (SKE_SUCCESS != ret) {
return ret;
} else {
;
}
} else {
return SKE_ERROR;
}
}
memcpy_(mac, tmp, mac_bytes);
return SKE_SUCCESS;
}
/* function: ske_hp cbc mac(CPU style, one-off style)
* parameters:
* alg ------------------------ input, ske_hp algorithm
* padding -------------------- input, ske_hp cbc mac padding scheme, like
* SKE_NO_PADDING,SKE_ZERO_PADDING. key ------------------------ input, key in
* byte buffer style sp_key_idx ----------------- input, index of secure port
* key, (sp_key_idx & 0x7FFF) must be in [1,MAX_KEY_IDX], if the MSB(sp_key_idx)
* is 1, that means using low 128bit of the 256bit key msg
* ------------------------ input, message msg_bytes ------------------ input,
* byte length of message. mac ------------------------ output, mac mac_bytes
* ------------------ input, mac byte length, must be bigger than 1, and not
* bigger than block length return: SKE_SUCCESS(success), other(error) caution:
* 1. if key is from user input, please make sure key is not NULL(now
* sp_key_idx is useless), otherwise, key is from secure port, and (sp_key_idx &
* 0x7FFF) must be in [1,MAX_KEY_IDX]
* 2. msg_bytes can not be 0
* 3. for the case that padding is SKE_NO_PADDING, if the total length of
* message is not a multiple of block length, it will return error.
*/
uint32_t ske_hp_cbc_mac(SKE_ALG alg, SKE_PADDING padding, uint8_t *key,
uint16_t sp_key_idx, uint8_t *msg, uint32_t msg_bytes,
uint8_t *mac, uint8_t mac_bytes)
{
uint32_t ret;
ske_cbc_mac_ctx_t ctx[1];
ret = ske_hp_cbc_mac_init(ctx, alg, padding, key, sp_key_idx);
if (SKE_SUCCESS != ret) {
return ret;
} else {
;
}
ret = ske_hp_cbc_mac_update(ctx, msg, msg_bytes);
if (SKE_SUCCESS != ret) {
return ret;
} else {
;
}
return ske_hp_cbc_mac_final(ctx, mac, mac_bytes);
}
#ifdef SKE_HP_DMA_FUNCTION
/* function: ske_hp cbc mac dma style init
* parameters:
* ctx ------------------------ input, ske_cbc_mac_dma_ctx_t context pointer
* alg ------------------------ input, ske_hp algorithm
* key ------------------------ input, key in byte buffer style
* sp_key_idx ----------------- input, index of secure port key, (sp_key_idx
* & 0x7FFF) must be in [1,MAX_KEY_IDX], if the MSB(sp_key_idx) is 1, that means
* using low 128bit of the 256bit key return: SKE_SUCCESS(success), other(error)
* caution:
* 1. if key is from user input, please make sure key is not NULL(now
* sp_key_idx is useless), otherwise, key is from secure port, and (sp_key_idx &
* 0x7FFF) must be in [1,MAX_KEY_IDX]
*/
uint32_t ske_hp_dma_cbc_mac_init(ske_cbc_mac_dma_ctx_t *ctx, SKE_ALG alg,
uint8_t *key, uint16_t sp_key_idx)
{
if (NULL == ctx) {
return SKE_BUFFER_NULL;
} else {
;
}
ske_hp_set_dma_mode();
ske_hp_disable_dma_linked_list();
return ske_hp_cbc_mac_init_internal((ske_cbc_mac_ctx_t *)ctx, alg, key,
sp_key_idx);
}
/* function: ske_hp cbc mac dma style update message blocks(excluding the last
* block, or the message tail) parameters: ctx ------------------------ input,
* ske_cbc_mac_dma_ctx_t context pointer msg ------------------------ input,
* message of some blocks, excluding last block(or message tail) msg_words
* ------------------ input, word length of in, must be a multiple of block word
* length return: SKE_SUCCESS(success), other(error) caution:
* 1. the input msg must be some blocks, and excludes the last block(or
* message tail)
*/
uint32_t ske_hp_dma_cbc_mac_update_blocks_excluding_last_block(
ske_cbc_mac_dma_ctx_t *ctx, uint32_t *msg, uint32_t msg_words)
{
if (NULL == ctx) {
return SKE_BUFFER_NULL;
} else if (msg_words & (ctx->ske_cbc_mac_ctx->block_words - 1)) {
return SKE_INPUT_INVALID;
} else if ((NULL == msg) || (0 == msg_words)) {
return SKE_SUCCESS;
} else {
;
}
return ske_hp_dma_operate_without_output(ctx->ske_cbc_mac_ctx, msg,
msg_words);
}
/* function: ske_hp cbc mac dma style update message including the last block(or
* message tail), and get the mac parameters: ctx ------------------------
* input, ske_cbc_mac_dma_ctx_t context pointer msg ------------------------
* input, message including the last block(or message tail) msg_bytes
* ------------------ input, byte length of msg, can not be 0 mac
* ------------------------ output, cbc mac, occupies a block return:
* SKE_SUCCESS(success), other(error) caution:
* 1. if the actual message length msg_bytes is not a multiple of block
* length, please make sure the last block(or message tail) is padded already.
*/
uint32_t ske_hp_dma_cbc_mac_update_including_last_block(
ske_cbc_mac_dma_ctx_t *ctx, uint32_t *msg, uint32_t msg_bytes,
uint32_t *mac)
{
uint32_t msg_words;
if ((NULL == ctx) || (NULL == msg) || (NULL == mac)) {
return SKE_BUFFER_NULL;
} else if (0 == msg_bytes) {
return SKE_INPUT_INVALID;
} else {
;
}
msg_words = (msg_bytes + ctx->ske_cbc_mac_ctx->block_bytes - 1) /
ctx->ske_cbc_mac_ctx->block_bytes;
msg_words *= ctx->ske_cbc_mac_ctx->block_words;
ske_hp_set_last_block(1);
return ske_hp_dma_operate(ctx->ske_cbc_mac_ctx, msg, mac, msg_words,
ctx->ske_cbc_mac_ctx->block_words);
}
/* function: ske_hp cbc mac, dma style(DMA style, one-off style)
* parameters:
* alg ------------------------ input, ske_hp algorithm
* key ------------------------ input, key in byte buffer style
* sp_key_idx ----------------- input, index of secure port key, (sp_key_idx
* & 0x7FFF) must be in [1,MAX_KEY_IDX], if the MSB(sp_key_idx) is 1, that means
* using low 128bit of the 256bit key msg ------------------------ input,
* message msg_bytes ------------------ input, byte length of msg mac
* ------------------------ output, mac, occupies a block return:
* SKE_SUCCESS(success), other(error) caution:
* 1. if key is from user input, please make sure key is not NULL(now
* sp_key_idx is useless), otherwise, key is from secure port, and (sp_key_idx &
* 0x7FFF) must be in [1,MAX_KEY_IDX]
* 2. msg_bytes can not be 0
* 3. if the actual message length msg_bytes is not a multiple of block
* length, please make sure the last block is padded already
*/
uint32_t ske_hp_dma_cbc_mac(SKE_ALG alg, uint8_t *key, uint16_t sp_key_idx,
uint32_t *msg, uint32_t msg_bytes, uint32_t *mac)
{
uint32_t ret;
ske_cbc_mac_dma_ctx_t ctx[1];
ret = ske_hp_dma_cbc_mac_init(ctx, alg, key, sp_key_idx);
if (SKE_SUCCESS != ret) {
return ret;
} else {
;
}
return ske_hp_dma_cbc_mac_update_including_last_block(ctx, msg, msg_bytes,
mac);
}
#endif
#ifdef SKE_HP_DMA_LL_FUNCTION
/* function: ske_hp cbc mac dma style init
* parameters:
* ctx ------------------------ input, ske_cbc_mac_dma_ctx_t context pointer
* alg ------------------------ input, ske_hp algorithm
* key ------------------------ input, key in bytes
* sp_key_idx ----------------- input, index of secure port key, (sp_key_idx
* & 0x7FFF) must be in [1,MAX_KEY_IDX] mac_bytes ------------------ input, mac
* byte length, must be bigger than 1, and not bigger than block length return:
* SKE_SUCCESS(success), other(error) caution:
* 1. if key is from user input, please make sure key is not NULL(now
* sp_key_idx is useless), otherwise, key is from secure port, and (sp_key_idx &
* 0x7FFF) must be in [1,MAX_KEY_IDX]
*/
uint32_t ske_hp_dma_ll_cbc_mac_init(ske_cbc_mac_dma_ctx_t *ctx, SKE_ALG alg,
uint8_t *key, uint16_t sp_key_idx,
uint8_t mac_bytes)
{
if (NULL == ctx) {
return SKE_BUFFER_NULL;
} else {
ctx->is_updated = 0;
}
ske_hp_set_dma_mode();
ske_hp_enable_dma_linked_list();
return ske_hp_cbc_mac_init_internal((ske_cbc_mac_ctx_t *)ctx, alg, key,
sp_key_idx, mac_bytes);
}
/* function: ske_hp cbc mac dma style update message in blocks
* parameters:
* ctx ------------------------ input, ske_cbc_mac_dma_ctx_t context pointer
* in ------------------------- input, message in blocks
* out ------------------------ output, must has the same length as in
* words ---------------------- input, word length of in or out, must be a
* multiple of block word length llp ------------------------ input, DMA linked
* list node return: SKE_SUCCESS(success), other(error) caution:
* 1. here the length unit is ske block length, so please make sure input
* are some blocks, if the actual message length is not a multiple of block
* length, please make sure the last block is padded.
*/
uint32_t ske_hp_dma_ll_cbc_mac_update_blocks(ske_cbc_mac_dma_ctx_t *ctx,
uint32_t *in, uint32_t *out,
uint32_t words, dma_ll_node_t *llp)
{
if ((NULL == ctx) || (NULL == in) || (NULL == out)) {
return SKE_BUFFER_NULL;
} else if (words & (ctx->ske_cbc_mac_ctx->block_words - 1)) {
return SKE_INPUT_INVALID;
} else {
ctx->is_updated = 1;
}
ske_hp_dma_ll_operate(in, out, words, llp);
while (0 != llp->next_llp) {
llp = (dma_ll_node_t *)(llp->next_llp);
}
/*keep the last output block*/
uint32_copy(ctx->tmp_output_block,
((uint32_t *)(llp->dst_addr)) +
(((llp->last_len) & 0x7FFFFFFF) >> 5) -
ctx->ske_cbc_mac_ctx->block_words,
ctx->ske_cbc_mac_ctx->block_words);
return SKE_SUCCESS;
}
/* function: ske_hp cbc mac dma ll style finish, and get the mac
* parameters:
* ctx ------------------------ input, ske_cbc_mac_dma_ctx_t context pointer
* mac ------------------------ output, mac
* return: SKE_SUCCESS(success), other(error)
* caution:
* 1.
*/
uint32_t ske_hp_dma_ll_cbc_mac_final(ske_cbc_mac_dma_ctx_t *ctx, uint8_t *mac)
{
return ske_hp_dma_cbc_mac_final(ctx, mac);
}
/* function: ske cbc mac, dma ll style(one-off)
* parameters:
* alg ------------------------ input, ske algorithm
* key ------------------------ input, key in bytes
* sp_key_idx ----------------- input, index of secure port key, (sp_key_idx
* & 0x7FFF) must be in [1,MAX_KEY_IDX] in ------------------------- input,
* message out ------------------------ just for temporary output, must have the
* same length as in in_words ------------------- input, word length of in and
* out, must be a multiple of block length. llp ------------------------ input,
* DMA linked list node mac ------------------------ output, mac mac_bytes
* ------------------ input, mac byte length, must be bigger than 1, and not
* bigger than block length return: SKE_SUCCESS(success), other(error) caution:
* 1. if key is from user input, please make sure key is not NULL(now
* sp_key_idx is useless), otherwise, key is from secure port, and (sp_key_idx &
* 0x7FFF) must be in [1,MAX_KEY_IDX]
* 2. in_words must be a multiple of block length
* 3. if the actual message length is not a multiple of block length, please
* make sure the last block is padded
*/
uint32_t ske_hp_dma_ll_cbc_mac(SKE_ALG alg, uint8_t *key, uint16_t sp_key_idx,
uint32_t *in, uint32_t *out, uint32_t in_words,
dma_ll_node_t *llp, uint8_t *mac,
uint8_t mac_bytes)
{
uint32_t ret;
ske_cbc_mac_dma_ctx_t ctx[1];
ret = ske_hp_dma_ll_cbc_mac_init(ctx, alg, key, sp_key_idx, mac_bytes);
if (SKE_SUCCESS != ret) {
return ret;
} else {
;
}
ret = ske_hp_dma_ll_cbc_mac_update_blocks(ctx, in, out, in_words, llp);
if (SKE_SUCCESS != ret) {
return ret;
} else {
;
}
ret = ske_hp_dma_ll_cbc_mac_final(ctx, mac);
if (SKE_SUCCESS != ret) {
return ret;
} else {
return SKE_SUCCESS;
}
}
#endif
#endif