/** * @file ske_cmac.c * @brief Semidrive CRYPTO ske cmac source file. * * @copyright Copyright (c) 2021 Semidrive Semiconductor. * All rights reserved. */ #include #ifdef SUPPORT_SKE_MODE_CMAC /* function: ske_hp cmac internal init config * parameters: * ctx ------------------------ input, ske_cmac_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_cmac_init_internal(ske_cmac_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_cmac_ctx, alg, SKE_MODE_CMAC, SKE_CRYPTO_ENCRYPT, key, sp_key_idx, (uint8_t *)iv); } /* function: ske_hp cmac init(CPU style) * parameters: * ctx ------------------------ input, ske_cmac_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] 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_cmac_init(ske_cmac_ctx_t *ctx, SKE_ALG alg, uint8_t *key, uint16_t sp_key_idx) { /*check and keep ctx->left_bytes = 0*/ if (NULL == ctx) { return SKE_BUFFER_NULL; } else { ctx->left_bytes = 0; } ske_hp_set_cpu_mode(); return ske_hp_cmac_init_internal(ctx, alg, key, sp_key_idx); } /* function: ske_hp cmac update message(CPU style) * parameters: * ctx ------------------------ input, ske_cmac_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_cmac_update(ske_cmac_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 { ; } /*if one block left, process it*/ if (ctx->ske_cmac_ctx->block_bytes == ctx->left_bytes) { ret = ske_hp_update_blocks_no_output(ctx->ske_cmac_ctx, ctx->block_buf, ctx->ske_cmac_ctx->block_bytes); if (SKE_SUCCESS != ret) { return ret; } else { ctx->left_bytes = 0; } } /*padding*/ if (ctx->left_bytes) { fill_bytes = ctx->ske_cmac_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_cmac_ctx, ctx->block_buf, ctx->ske_cmac_ctx->block_bytes); if (SKE_SUCCESS != ret) { return ret; } else { ctx->left_bytes = 0; msg += fill_bytes; msg_bytes -= fill_bytes; } } } /*process some blocks*/ blocks_bytes = (msg_bytes / ctx->ske_cmac_ctx->block_bytes) * ctx->ske_cmac_ctx->block_bytes; remainder = msg_bytes % ctx->ske_cmac_ctx->block_bytes; /*process remainder*/ if (remainder) { ret = ske_hp_update_blocks_no_output(ctx->ske_cmac_ctx, msg, blocks_bytes); if (SKE_SUCCESS != ret) { return ret; } else { memcpy_(ctx->block_buf, msg + blocks_bytes, remainder); ctx->left_bytes = remainder; } } else { blocks_bytes -= ctx->ske_cmac_ctx->block_bytes; ret = ske_hp_update_blocks_no_output(ctx->ske_cmac_ctx, msg, blocks_bytes); if (SKE_SUCCESS != ret) { return ret; } else { memcpy_(ctx->block_buf, msg + blocks_bytes, ctx->ske_cmac_ctx->block_bytes); ctx->left_bytes = ctx->ske_cmac_ctx->block_bytes; } } return SKE_SUCCESS; } /* function: ske_hp cmac finish, and get the mac(CPU style) * parameters: * ctx ------------------------ input, ske_cmac_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. . */ uint32_t ske_hp_cmac_final(ske_cmac_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_cmac_ctx->block_bytes)) { return SKE_INPUT_INVALID; } else { ; } ske_hp_set_last_block(1); ske_hp_set_last_block_len(ctx->left_bytes); if (ctx->ske_cmac_ctx->block_bytes == ctx->left_bytes) { ret = ske_hp_update_blocks_internal(ctx->ske_cmac_ctx, ctx->block_buf, (uint8_t *)tmp, ctx->ske_cmac_ctx->block_bytes); if (SKE_SUCCESS != ret) { return ret; } else { ; } } else { ctx->block_buf[ctx->left_bytes] = 0x80; memset_(ctx->block_buf + ctx->left_bytes + 1, 0, ctx->ske_cmac_ctx->block_bytes - 1 - ctx->left_bytes); ret = ske_hp_update_blocks_internal(ctx->ske_cmac_ctx, ctx->block_buf, (uint8_t *)tmp, ctx->ske_cmac_ctx->block_bytes); if (SKE_SUCCESS != ret) { return ret; } else { ; } } memcpy_(mac, tmp, mac_bytes); return SKE_SUCCESS; } /* function: ske_hp cmac(CPU 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 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 could be any value(including 0). */ uint32_t ske_hp_cmac(SKE_ALG alg, uint8_t *key, uint16_t sp_key_idx, uint8_t *msg, uint32_t msg_bytes, uint8_t *mac, uint8_t mac_bytes) { ske_cmac_ctx_t ctx[1]; uint32_t ret; ret = ske_hp_cmac_init(ctx, alg, key, sp_key_idx); if (SKE_SUCCESS != ret) { return ret; } else { ; } ret = ske_hp_cmac_update(ctx, msg, msg_bytes); if (SKE_SUCCESS != ret) { return ret; } else { ; } return ske_hp_cmac_final(ctx, mac, mac_bytes); } #ifdef SKE_HP_DMA_FUNCTION /* function: ske_hp cmac dma style init * parameters: * ctx ------------------------ input, ske_cmac_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_cmac_init(ske_cmac_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_cmac_init_internal((ske_cmac_ctx_t *)ctx, alg, key, sp_key_idx); } /* function: ske cmac dma style update update message blocks(excluding the last * block, or the message tail) parameters: ctx ------------------------ input, * ske_cmac_dma_ctx_t context pointer msg ------------------------ input, * message of some blocks, excluding last block(or message tail) msg_words * ------------------ input, word length of msg, 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_cmac_update_blocks_excluding_last_block( ske_cmac_dma_ctx_t *ctx, uint32_t *msg, uint32_t msg_words) { if (NULL == ctx) { return SKE_BUFFER_NULL; } else if (msg_words & (ctx->ske_cmac_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_cmac_ctx, msg, msg_words); } /* function: ske_hp cmac dma style update message including the last block(or * message tail), and get the mac parameters: ctx ------------------------ * input, ske_cmac_dma_ctx_t context pointer msg ------------------------ input, * message including the last block(or message tail) msg_bytes * ------------------ input, byte length of msg, could be 0 mac * ------------------------ output, cmac, occupies a block return: * SKE_SUCCESS(success), other(error) caution: * 1. if the whole message length is 0, this case is supported. in this * case, msg occupies a block, and please set msg_bytes to 0. */ uint32_t ske_hp_dma_cmac_update_including_last_block(ske_cmac_dma_ctx_t *ctx, uint32_t *msg, uint32_t msg_bytes, uint32_t *mac) { uint32_t msg_words; uint32_t remainder_bytes; if ((NULL == ctx) || (NULL == msg) || (NULL == mac)) { return SKE_BUFFER_NULL; } else { ; } ske_hp_set_last_block(1); /*get last block length and pad padded by software, not hardware, do not * delete this padding action*/ if (0 == msg_bytes) { msg[0] = 0x80; msg[1] = 0; msg[2] = 0; msg[3] = 0; msg_bytes = 1; remainder_bytes = 1; } else if (msg_bytes & 0x0F) { msg[msg_bytes / 4] |= 0x80 << ((msg_bytes & 3) * 8); remainder_bytes = msg_bytes & 0x0F; } else { remainder_bytes = ctx->ske_cmac_ctx->block_bytes; } /*set the last block message length*/ ske_hp_set_last_block_len(remainder_bytes); msg_words = (msg_bytes + ctx->ske_cmac_ctx->block_bytes - 1) / ctx->ske_cmac_ctx->block_bytes; msg_words *= ctx->ske_cmac_ctx->block_words; return ske_hp_dma_operate(ctx->ske_cmac_ctx, msg, mac, msg_words, ctx->ske_cmac_ctx->block_words); } /* function: ske_hp cmac(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 message. mac * ------------------------ output, mac 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 is actual byte length of message, it could be any * value(including 0). (1). if msg_bytes is not 0, msg must have * (msg_bytes+15)/16 blocks, if the last block is not full, please pad with * zero. (2). if msg_bytes is 0, msg occupies a block. */ uint32_t ske_hp_dma_cmac(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_cmac_dma_ctx_t ctx[1]; ret = ske_hp_dma_cmac_init(ctx, alg, key, sp_key_idx); if (SKE_SUCCESS != ret) { return ret; } else { ; } return ske_hp_dma_cmac_update_including_last_block(ctx, msg, msg_bytes, mac); } #endif #endif