Files
test/drivers/source/crypto/cacc/ral/ske_basic.c
2025-11-07 20:19:23 +08:00

792 lines
20 KiB
C

/**
* @file ske_basic.c
* @brief Semidrive CRYPTO ske basic source file.
*
* @copyright Copyright (c) 2021 Semidrive Semiconductor.
* All rights reserved.
*/
#include <stdio.h>
#include "ske_basic.h"
#include "sdrv_crypto_utility.h"
#include "trng.h"
/* ske_hp register pointer */
volatile static ske_hp_reg_t *const g_ske_hp_reg =
(ske_hp_reg_t *)(SKE_HP_BASE_ADDR);
/* function: get ske IP version
* parameters: none
* return: ske IP version
* caution:
*/
uint32_t ske_get_version(void) { return g_ske_hp_reg->ske_version; }
/* function: set ske_hp to be CPU mode
* parameters: none
* return: none
* caution:
*/
void ske_hp_set_cpu_mode(void)
{
g_ske_hp_reg->cfg &= (~((0x1) << SKE_HP_DMA_OFFSET));
}
/* function: set ske_hp to be DMA mode
* parameters: none
* return: none
* caution:
*/
void ske_hp_set_dma_mode(void)
{
g_ske_hp_reg->cfg |= (0x1) << SKE_HP_DMA_OFFSET;
}
/* function: enable ske_hp DMA linked list function
* parameters: none
* return: none
* caution:
* 1. this works when DMA mode is enabled
*/
void ske_hp_enable_dma_linked_list(void)
{
g_ske_hp_reg->cfg |= (0x1) << SKE_HP_DMA_LL_OFFSET;
}
/* function: disable ske_hp DMA linked list function
* parameters: none
* return: none
* caution:
*/
void ske_hp_disable_dma_linked_list(void)
{
g_ske_hp_reg->cfg &= ~((0x1) << SKE_HP_DMA_LL_OFFSET);
}
/* function: set the ske_hp endian
* parameters: none
* return: none
* caution:
* 1. actually, this config works for only CPU mode now
*/
void ske_hp_set_endian_uint32(void)
{
/* clear bit[25:24], and now CPU is big-endian */
g_ske_hp_reg->cfg &=
~(((uint32_t)3) << SKE_HP_REVERSE_BYTE_ORDER_IN_WORD_OFFSET);
/* CPU is little-endian, input and output reversed by hardware----ske IP */
#ifndef SKE_HP_CPU_BIG_ENDIAN
g_ske_hp_reg->cfg |=
(((uint32_t)2) << SKE_HP_REVERSE_BYTE_ORDER_IN_WORD_OFFSET);
#endif
}
/* function: enable ske_hp secure port
* parameters:
* 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: none caution:
*/
void ske_hp_enable_secure_port(uint16_t sp_key_idx)
{
#ifdef SKE_SECURE_PORT_FUNCTION
g_ske_hp_reg->sp |= 0x1;
OTP_KEY_CTRL = 0x0;
/* use the low 128bit of the 256bit key */
if (sp_key_idx & 0x8000) {
OTP_KEY_CTRL = (0x1 << 24);
}
/* set key idx */
if (sp_key_idx == 9) {
OTP_KEY_CTRL |= 0x100000;
} else {
sp_key_idx -= 1;
OTP_KEY_CTRL |= ((uint32_t)(sp_key_idx & 0x7FFF)) << 16;
}
OTP_KEY_CTRL |= 0x1;
#endif
}
/* function: disable ske_hp secure port
* parameters: none
* return: none
* caution:
*/
void ske_hp_disable_secure_port(void) { g_ske_hp_reg->sp &= ~(0x1); }
/* function: set ske_hp encrypting or decrypting
* parameters:
* crypto --------------------- input, SKE_CRYPTO_ENCRYPT or
* SKE_CRYPTO_DECRYPT return: none caution:
* 1. please make sure crypto is valid
*/
void ske_hp_set_crypto(SKE_CRYPTO crypto)
{
g_ske_hp_reg->cfg &= ~(((uint32_t)1) << SKE_HP_CRYPTO_OFFSET);
g_ske_hp_reg->cfg |= (((uint32_t)crypto) << SKE_HP_CRYPTO_OFFSET);
}
/* function: set ske_hp alg
* parameters:
* ske_alg -------------------- input, ske_hp algorithm
* return: none
* caution:
* 1. please make sure ske_alg is valid
*/
void ske_hp_set_alg(SKE_ALG ske_alg)
{
uint32_t cfg;
switch (ske_alg) {
#ifdef SUPPORT_SKE_DES
case SKE_ALG_DES:
cfg = 3;
break;
#endif
#ifdef SUPPORT_SKE_TDES_128
case SKE_ALG_TDES_128:
#endif
#ifdef SUPPORT_SKE_TDES_192
case SKE_ALG_TDES_192:
#endif
#if (defined(SUPPORT_SKE_TDES_128) || defined(SUPPORT_SKE_TDES_192))
cfg = 4;
break;
#endif
#ifdef SUPPORT_SKE_TDES_EEE_128
case SKE_ALG_TDES_EEE_128:
#endif
#ifdef SUPPORT_SKE_TDES_EEE_192
case SKE_ALG_TDES_EEE_192:
#endif
#if (defined(SUPPORT_SKE_TDES_EEE_128) || defined(SUPPORT_SKE_TDES_EEE_192))
cfg = 5;
break;
#endif
#ifdef SUPPORT_SKE_AES_128
case SKE_ALG_AES_128:
cfg = (1 << 6) | (1 << 4) | (1);
break;
#endif
#ifdef SUPPORT_SKE_AES_192
case SKE_ALG_AES_192:
cfg = (2 << 6) | (2 << 4) | (1);
break;
#endif
#ifdef SUPPORT_SKE_AES_256
case SKE_ALG_AES_256:
cfg = (3 << 6) | (3 << 4) | (1);
break;
#endif
#ifdef SUPPORT_SKE_SM4
case SKE_ALG_SM4:
cfg = 2;
break;
#endif
default:
cfg = 2;
}
g_ske_hp_reg->cfg &= (~(0x000000FFU));
g_ske_hp_reg->cfg |= cfg;
}
/* function: set ske_hp alg operation mode
* parameters:
* mode ----------------------- input, operation mode
* return: none
* caution:
* 1. please make sure mode is valid
*/
void ske_hp_set_mode(SKE_MODE mode)
{
g_ske_hp_reg->cfg &= (~(0x0000000F << SKE_HP_MODE_OFFSET));
g_ske_hp_reg->cfg |= (((uint32_t)mode) << SKE_HP_MODE_OFFSET);
}
/* function: set whether ske_hp current input data is the last data or not
* parameters:
* is_last_block -------------- input, 0:no, other:yes
* return: none
* caution:
* 1. just for CMAC/CCM/GCM/XTS mode
*/
void ske_hp_set_last_block(uint32_t is_last_block)
{
if (is_last_block) {
g_ske_hp_reg->m_din_cr |= (((uint32_t)1) << SKE_HP_LAST_DATA_OFFSET);
} else {
g_ske_hp_reg->m_din_cr &= ~(((uint32_t)1) << SKE_HP_LAST_DATA_OFFSET);
}
}
/* function: set ske_hp current input data bit length
* parameters:
* bytes ---------------------- input, byte length of current input data
* return: none
* caution:
* 1. just for CMAC
*/
void ske_hp_set_last_block_len(uint32_t bytes)
{
g_ske_hp_reg->m_din_cr &= ~0x000000FF;
g_ske_hp_reg->m_din_cr |= (bytes << 3);
}
/* function: set ske_hp seed
* parameters: none
* return: SKE_SUCCESS(success), other(error)
* caution:
* 1.
*/
uint32_t ske_hp_set_seed(void)
{
if (TRNG_SUCCESS != get_rand((uint8_t *)(g_ske_hp_reg->ske_seed),
sizeof(g_ske_hp_reg->ske_seed))) {
return SKE_ERROR;
} else {
return SKE_SUCCESS;
}
}
/* function: ske_hp start to expand key or calc
* parameters:none
* return: none
* caution:
*/
void ske_hp_start(void)
{
g_ske_hp_reg->risr = 0x0;
g_ske_hp_reg->ctrl |= 0x1;
}
uint32_t ske_hp_check_attack_state(void)
{
if (g_ske_hp_reg->ske_alarm & 0x1) {
return SKE_ATTACK_ALARM;
} else {
return SKE_SUCCESS;
}
}
/* function: wait till ske_hp expanding key is done
* parameters:
* return: none
* caution:
*/
uint32_t ske_hp_expand_key_wait_till_done()
{
uint32_t state_val;
while (!(g_ske_hp_reg->sr & 0x1)) {
state_val = ske_hp_check_attack_state();
if (SKE_SUCCESS == state_val) {
continue;
} else {
return state_val;
}
}
return SKE_SUCCESS;
}
/* function: wait till ske_hp is waiting to input
* parameters:
* return: none
* caution:
*/
uint32_t ske_hp_wait_till_input()
{
uint32_t state_val;
while (!(g_ske_hp_reg->sr & (1 << 16))) {
state_val = ske_hp_check_attack_state();
if (SKE_SUCCESS == state_val) {
continue;
} else {
return state_val;
}
}
return SKE_SUCCESS;
}
/* function: wait till ske_hp output is ready
* parameters:
* return: SKE_SUCCESS(success), other(error)
* caution:
*/
uint32_t ske_hp_wait_till_output()
{
uint32_t state_val;
while (!(g_ske_hp_reg->sr & (1 << 17))) {
state_val = ske_hp_check_attack_state();
if (SKE_SUCCESS == state_val) {
continue;
} else {
return state_val;
}
}
return SKE_SUCCESS;
}
/* function: wait till ske_hp calculating is done
* parameters:
* return: SKE_SUCCESS(success), other(error)
* caution:
*/
uint32_t ske_hp_calc_wait_till_done(void)
{
uint32_t state_val;
while (!(g_ske_hp_reg->risr & 0x7)) {
state_val = ske_hp_check_attack_state();
if (SKE_SUCCESS == state_val) {
continue;
} else {
return state_val;
}
}
return SKE_SUCCESS;
}
/* function: set ske_hp key
* parameters:
* key ------------------------ input, key in word buffer
* idx ------------------------ input, key index, only 1 and 2 are valid
* key_words ------------------ input, word length of key
* return: none
* caution:
* 1. if idx is 1, set key1 register, else if idx is 2, set key2 register,
* please make sure idx is valid
*/
void ske_hp_set_key_uint32(uint32_t *key, uint32_t idx, uint32_t key_words)
{
volatile uint32_t *key_reg;
int32_t i;
if (1 == idx) {
key_reg = g_ske_hp_reg->key1;
} else {
key_reg = g_ske_hp_reg->key2;
}
for (i = key_words; i > 0; i--) {
key_reg[i - 1] = key[key_words - i];
}
}
/* function: set ske_hp iv
* parameters:
* iv ------------------------- input, iv in word buffer
* block_words ---------------- input, word length of ske_hp block
* return: none
* caution:
* 1. please make sure the three parameters are valid
*/
void ske_hp_set_iv_uint32(uint32_t *iv, uint32_t block_words)
{
int32_t i;
for (i = block_words; i > 0; i--) {
g_ske_hp_reg->iv[i - 1] = iv[block_words - i];
}
}
#if (defined(SUPPORT_SKE_MODE_GCM) || defined(SUPPORT_SKE_MODE_CCM))
/* function: set aad bits(just for ske_hp ccm/gcm mode)
* parameters:
* aad_bytes ------------------ input, byte length of aad
* return: none
* caution:
* 1. this function is just for CCM/GCM mode
*/
void ske_hp_set_aad_len_uint32(uint32_t aad_bytes)
{
g_ske_hp_reg->ske_a_len_l = ((aad_bytes) << 3) & 0xFFFFFFFF;
g_ske_hp_reg->ske_a_len_h = aad_bytes >> (32 - 3);
}
#endif
#if (defined(SUPPORT_SKE_MODE_GCM) || defined(SUPPORT_SKE_MODE_CCM) || \
defined(SUPPORT_SKE_MODE_XTS))
/* function: set plaintext/ciphertext bits(just for ske_hp ccm/gcm/xts mode)
* parameters:
* c_bytes -------------------- input, byte length of plaintext/ciphertext
* return: none
* caution:
* 1. this function is just for CCM/GCM/XTS mode
*/
void ske_hp_set_c_len_uint32(uint32_t c_bytes)
{
g_ske_hp_reg->ske_c_len_l = ((c_bytes) << 3) & 0xFFFFFFFF;
g_ske_hp_reg->ske_c_len_h = c_bytes >> (32 - 3);
}
#endif
/* function: input one block
* parameters:
* in ------------------------- input, plaintext or ciphertext in word
* buffer block_words ---------------- input, word length of ske_hp block
* return: none
* caution:
* 1. in is a word buffer of only one block.
*/
void ske_hp_simple_set_input_block(uint32_t *in, uint32_t block_words)
{
int32_t i;
for (i = block_words; i > 0; i--) {
g_ske_hp_reg->m_din[i - 1] = in[block_words - i];
}
}
/* function: output one block
* parameters:
* out ------------------------ output, one block output of ske_hp in word
* buffer block_words ---------------- input, word length of ske_hp block
* return: none
* caution:
*/
void ske_hp_simple_get_output_block(uint32_t *out, uint32_t block_words)
{
int32_t i;
/* trigger to pop */
g_ske_hp_reg->ctrl |= 0x02;
for (i = block_words; i > 0; i--) {
out[block_words - i] = g_ske_hp_reg->m_dout[i - 1];
}
}
/* function: ske_hp expand key
* parameters: none
* return: none
* caution: 1. must be called after ske_hp_set_crypto() and ske_hp_set_alg(),
* and the key is set already.
*/
uint32_t ske_hp_expand_key(void)
{
uint32_t ret;
g_ske_hp_reg->cfg |= ((0x1) << SKE_HP_UP_CFG_OFFSET);
ske_hp_start();
ret = ske_hp_expand_key_wait_till_done();
if (SKE_SUCCESS != ret) {
return ret;
}
g_ske_hp_reg->cfg &= ~((0x1) << SKE_HP_UP_CFG_OFFSET);
return SKE_SUCCESS;
}
/************************* DMA *************************/
void dma_set_time_out_threshold(uint16_t cycle_threshold)
{
g_ske_hp_reg->dma_to = cycle_threshold;
}
#ifdef SKE_HP_DMA_FUNCTION
/* function: basic ske_hp DMA operation
* parameters:
* ctx ------------------------ input, ske_ctx_t context pointer
* in ------------------------- input, plaintext or ciphertext
* out ------------------------ output, ciphertext or plaintext
* in_words ------------------- input, word length of in, must be multiples
* of block word length out_words ------------------ input, word length of out,
* must be multiples of block word length return: SKE_SUCCESS(success),
* other(error) caution:
* 1. in_words & out_words must be multiples of block words.
* 2. it could be without output, namely, out can be NULL, out_words can be
* 0(for CBC_MAC/CMAC)
*/
uint32_t ske_hp_dma_operate(ske_ctx_t *ctx, uint32_t *in, uint32_t *out,
uint32_t in_words, uint32_t out_words)
{
uint32_t ret;
if (NULL == in) {
return SKE_BUFFER_NULL;
}
/* src & dst addr low 32bits */
g_ske_hp_reg->dma_sa_l = (uint32_t)in;
g_ske_hp_reg->dma_da_l = (uint32_t)out;
/* src & dst addr high 32bits */
if (4 == (sizeof(uint32_t *))) {
/* in this case, if using (((uint64_t)in)>>32), you may get 0xFFFFFFFF,
* not 0 you expected! */
g_ske_hp_reg->dma_sa_h = 0x0;
g_ske_hp_reg->dma_da_h = 0x0;
} else {
/* g_ske_hp_reg->dma_sa_h = (((uint64_t)in)>>32); */
/* g_ske_hp_reg->dma_da_h = (((uint64_t)out)>>32); */
}
/* data word length */
g_ske_hp_reg->dma_rlen = in_words * 32;
g_ske_hp_reg->dma_wlen = out_words * 32;
ske_hp_start();
ret = ske_hp_calc_wait_till_done();
if (SKE_SUCCESS != ret) {
uint32_clear(out, out_words);
} else {
}
return ret;
}
#if (defined(SUPPORT_SKE_MODE_CMAC) || defined(SUPPORT_SKE_MODE_CMAC))
/* function: basic ske_hp DMA operation without output(for CBC_MAC/CMAC)
* parameters:
* ctx ------------------------ input, ske_ctx_t context pointer
* in ------------------------- input, plaintext or ciphertext
* in_words ------------------- input, word length of in, must be multiples
* of block word length return: SKE_SUCCESS(success), other(error) caution:
* 1. in_words must be a multiple of block words.
*/
uint32_t ske_hp_dma_operate_without_output(ske_ctx_t *ctx, uint32_t *in,
uint32_t in_words)
{
volatile uint32_t flag_0 = 0;
/* src addr low 32bits */
g_ske_hp_reg->dma_sa_l = (uint32_t)in;
/* src addr high 32bits */
if (4 == (sizeof(uint32_t *))) {
/* in this case, if using (((uint64_t)in)>>32), you may get 0xFFFFFFFF,
* not 0 you expected! */
g_ske_hp_reg->dma_sa_h = flag_0;
} else {
/* g_ske_hp_reg->dma_sa_h = (((uint64_t)in)>>32); */
}
/* data word length */
g_ske_hp_reg->dma_rlen = in_words * 32;
g_ske_hp_reg->dma_wlen = flag_0;
ske_hp_start();
return ske_hp_calc_wait_till_done();
}
#endif
#ifdef SKE_HP_DMA_LL_FUNCTION
void ske_hp_dma_ll_operate(uint32_t *in, uint32_t *out, uint32_t wordLen,
dma_ll_node_t *llp)
{
/* ll addr */
g_ske_hp_reg->dma_llp_l = ((uint64_t)llp) & 0xFFFFFFFF;
g_ske_hp_reg->dma_llp_h = ((uint64_t)llp) >> 32;
/* src addr */
g_ske_hp_reg->dma_sa_l = ((uint64_t)in) & 0xFFFFFFFF;
g_ske_hp_reg->dma_sa_h = ((uint64_t)in) >> 32;
/* dst addr */
g_ske_hp_reg->dma_da_l = ((uint64_t)out) & 0xFFFFFFFF;
g_ske_hp_reg->dma_da_h = ((uint64_t)out) >> 32;
/* data word length */
g_ske_hp_reg->dma_rlen = wordLen * 32;
ske_hp_start();
ske_hp_calc_wait_till_done();
}
#endif
#endif
/* function: update ske_hp some blocks without output
* parameters:
* ctx ------------------------ input, ske_ctx_t context pointer
* in ------------------------- input, some blocks
* bytes ---------------------- input, byte length of in
* return: SKE_SUCCESS(success), other(error)
* caution:
* 1. please make sure the bytes is a multiple of block byte length
* ctx->block_bytes
* 2. this function is called by CCM(input aad)/GCM(input aad)/CMAC/CBC-MAC
* mode
*/
uint32_t ske_hp_update_blocks_no_output(ske_ctx_t *ctx, uint8_t *in,
uint32_t bytes)
{
uint32_t in_word_align, is_ccm_gcm_mode = 0;
uint32_t tmp_in[4];
uint32_t i;
uint32_t ret;
if (((uint32_t)in) & 3) {
in_word_align = 0;
} else {
in_word_align = 1;
}
i = (g_ske_hp_reg->cfg & 0xF0000000) >> 28;
switch (i) {
#if (defined(SUPPORT_SKE_MODE_GCM))
case SKE_MODE_GCM:
#endif
#if (defined(SUPPORT_SKE_MODE_CCM))
case SKE_MODE_CCM:
#endif
#if (defined(SUPPORT_SKE_MODE_GCM) || defined(SUPPORT_SKE_MODE_CCM))
is_ccm_gcm_mode = 1;
break;
#endif
default:
is_ccm_gcm_mode = 0;
}
/* input one block ---> calculating ---> output one block */
for (i = 0; i < bytes; i += ctx->block_bytes) {
if (in_word_align) {
ske_hp_simple_set_input_block((uint32_t *)in, ctx->block_words);
} else {
memcpy_(tmp_in, in, ctx->block_bytes);
ske_hp_simple_set_input_block((uint32_t *)tmp_in, ctx->block_words);
}
ske_hp_start();
if (is_ccm_gcm_mode) {
ret = ske_hp_wait_till_input();
if (SKE_SUCCESS != ret) {
return ret;
} else {
;
}
} else {
ret = ske_hp_calc_wait_till_done();
if (SKE_SUCCESS != ret) {
return ret;
} else {
/* trigger to pop, this can not be deleted */
g_ske_hp_reg->ctrl |= 0x2;
}
}
in += ctx->block_bytes;
}
return SKE_SUCCESS;
}
/* function: update ske_hp some blocks and get the same number of blocks
* parameters:
* ctx ------------------------ input, ske_ctx_t context pointer
* in ------------------------- input, some blocks
* out ------------------------ output, the same number of blocks
* bytes ---------------------- input, byte length of in
* return: SKE_SUCCESS(success), other(error)
* caution:
* 1. please make sure the bytes is a multiple of block byte length
* ctx->block_bytes
*/
uint32_t ske_hp_update_blocks_internal(ske_ctx_t *ctx, uint8_t *in,
uint8_t *out, uint32_t bytes)
{
uint8_t *out_bak = out;
uint32_t in_word_align, out_word_align;
uint32_t tmp_in[4];
uint32_t i;
uint32_t ret;
if (((uint32_t)in) & 3) {
in_word_align = 0;
} else {
in_word_align = 1;
}
if (((uint32_t)out) & 3) {
out_word_align = 0;
} else {
out_word_align = 1;
}
/* input one block ---> calculating ---> output one block */
for (i = 0; i < bytes; i += ctx->block_bytes) {
if (in_word_align) {
ske_hp_simple_set_input_block((uint32_t *)in, ctx->block_words);
} else {
memcpy_(tmp_in, in, ctx->block_bytes);
ske_hp_simple_set_input_block((uint32_t *)tmp_in, ctx->block_words);
}
ske_hp_start();
ret = ske_hp_wait_till_output();
if (SKE_SUCCESS != ret) {
if (out_word_align) {
uint32_clear((uint32_t *)out_bak, bytes / 4);
} else {
memset_(out_bak, 0, bytes);
}
return ret;
} else {
;
}
if (out_word_align) {
ske_hp_simple_get_output_block((uint32_t *)out, ctx->block_words);
} else {
ske_hp_simple_get_output_block((uint32_t *)tmp_in,
ctx->block_words);
memcpy_(out, tmp_in, ctx->block_bytes);
}
in += ctx->block_bytes;
out += ctx->block_bytes;
}
return SKE_SUCCESS;
}