/** * @file ske.c * @brief Semidrive CRYPTO ske source file. * * @copyright Copyright (c) 2021 Semidrive Semiconductor. * All rights reserved. */ #include static ske_ctx_t ske_ctx[1]; /* function: check whether the ske algorithm is valid or not * parameters: * ske_alg -------------------- input, specific ske algorithm * return: SKE_SUCCESS(valid), other(invalid) * caution: * 1. */ uint8_t ske_hp_check_alg(SKE_ALG ske_alg) { uint8_t ret; switch (ske_alg) { #ifdef SUPPORT_SKE_DES case SKE_ALG_DES: #endif #ifdef SUPPORT_SKE_TDES_128 case SKE_ALG_TDES_128: #endif #ifdef SUPPORT_SKE_TDES_192 case SKE_ALG_TDES_192: #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 #ifdef SUPPORT_SKE_AES_128 case SKE_ALG_AES_128: #endif #ifdef SUPPORT_SKE_AES_192 case SKE_ALG_AES_192: #endif #ifdef SUPPORT_SKE_AES_256 case SKE_ALG_AES_256: #endif #ifdef SUPPORT_SKE_SM4 case SKE_ALG_SM4: #endif ret = SKE_SUCCESS; break; default: ret = SKE_INPUT_INVALID; break; } return ret; } /* function: check whether the ske algorithm mode is valid or not * parameters: * ske_alg -------------------- input, specific ske algorithm * ske_mode ------------------- input, specific ske algorithm mode * return: SKE_SUCCESS(valid), other(invalid) * caution: * 1. */ uint8_t ske_hp_check_mode(SKE_ALG ske_alg, SKE_MODE ske_mode) { uint8_t ret; switch (ske_mode) { #ifdef SUPPORT_SKE_MODE_ECB case SKE_MODE_ECB: #endif #ifdef SUPPORT_SKE_MODE_CBC case SKE_MODE_CBC: #endif #ifdef SUPPORT_SKE_MODE_CFB case SKE_MODE_CFB: #endif #ifdef SUPPORT_SKE_MODE_OFB case SKE_MODE_OFB: #endif #ifdef SUPPORT_SKE_MODE_CTR case SKE_MODE_CTR: #endif #ifdef SUPPORT_SKE_MODE_CBC_MAC case SKE_MODE_CBC_MAC: #endif ret = SKE_SUCCESS; break; /*for DES/3DES, CAMC is not supported at present*/ #ifdef SUPPORT_SKE_MODE_CMAC case SKE_MODE_CMAC: switch (ske_alg) { #ifdef SUPPORT_SKE_AES_128 case SKE_ALG_AES_128: #endif #ifdef SUPPORT_SKE_AES_192 case SKE_ALG_AES_192: #endif #ifdef SUPPORT_SKE_AES_256 case SKE_ALG_AES_256: #endif #ifdef SUPPORT_SKE_SM4 case SKE_ALG_SM4: #endif #if (defined(SUPPORT_SKE_AES_128) || defined(SUPPORT_SKE_AES_192) || \ defined(SUPPORT_SKE_AES_256) || defined(SUPPORT_SKE_SM4)) ret = SKE_SUCCESS; break; #endif default: ret = SKE_INPUT_INVALID; } break; #endif /*for DES/3DES, XTS, CCM and GCM mode are not supported due to the * definition or standard*/ #ifdef SUPPORT_SKE_MODE_XTS case SKE_MODE_XTS: #endif #ifdef SUPPORT_SKE_MODE_CCM case SKE_MODE_CCM: #endif #ifdef SUPPORT_SKE_MODE_GCM case SKE_MODE_GCM: #endif #if (defined(SUPPORT_SKE_MODE_XTS) || defined(SUPPORT_SKE_MODE_CCM) || \ defined(SUPPORT_SKE_MODE_GCM)) switch (ske_alg) { #ifdef SUPPORT_SKE_AES_128 case SKE_ALG_AES_128: #endif #ifdef SUPPORT_SKE_AES_192 case SKE_ALG_AES_192: #endif #ifdef SUPPORT_SKE_AES_256 case SKE_ALG_AES_256: #endif #ifdef SUPPORT_SKE_SM4 case SKE_ALG_SM4: #endif #if (defined(SUPPORT_SKE_AES_128) || defined(SUPPORT_SKE_AES_192) || \ defined(SUPPORT_SKE_AES_256) || defined(SUPPORT_SKE_SM4)) ret = SKE_SUCCESS; break; #endif default: ret = SKE_INPUT_INVALID; break; } break; #endif default: ret = SKE_INPUT_INVALID; break; } return ret; } /* function: get block byte length for spcific ske_hp alg * parameters: * ske_alg -------------------- input, ske_hp algorithm * return: block byte length for ske_hp alg * caution: * 1. please make sure ske_alg is valid */ uint8_t ske_hp_get_block_byte_len(SKE_ALG ske_alg) { uint8_t byteLen; switch (ske_alg) { #ifdef SUPPORT_SKE_DES case SKE_ALG_DES: #endif #ifdef SUPPORT_SKE_TDES_128 case SKE_ALG_TDES_128: #endif #ifdef SUPPORT_SKE_TDES_192 case SKE_ALG_TDES_192: #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_DES) || defined(SUPPORT_SKE_TDES_128) || \ defined(SUPPORT_SKE_TDES_192) || defined(SUPPORT_SKE_TDES_EEE_128) || \ defined(SUPPORT_SKE_TDES_EEE_192)) byteLen = 8; break; #endif #ifdef SUPPORT_SKE_AES_128 case SKE_ALG_AES_128: #endif #ifdef SUPPORT_SKE_AES_192 case SKE_ALG_AES_192: #endif #ifdef SUPPORT_SKE_AES_256 case SKE_ALG_AES_256: #endif #ifdef SUPPORT_SKE_SM4 case SKE_ALG_SM4: #endif #if (defined(SUPPORT_SKE_AES_128) || defined(SUPPORT_SKE_AES_192) || \ defined(SUPPORT_SKE_AES_256) || defined(SUPPORT_SKE_SM4)) byteLen = 16; break; #endif default: byteLen = 16; } return byteLen; } /* function: get key byte length for spcific ske_hp alg * parameters: * ske_alg -------------------- input, ske_hp algorithm * return: key byte length for ske_hp alg * caution: * 1. please make sure ske_alg is valid */ uint8_t ske_hp_get_key_byte_len(SKE_ALG ske_alg) { uint8_t byte_len; switch (ske_alg) { #ifdef SUPPORT_SKE_DES case SKE_ALG_DES: byte_len = 8; break; #endif #ifdef SUPPORT_SKE_TDES_128 case SKE_ALG_TDES_128: #endif #ifdef SUPPORT_SKE_TDES_EEE_128 case SKE_ALG_TDES_EEE_128: #endif #ifdef SUPPORT_SKE_AES_128 case SKE_ALG_AES_128: #endif #ifdef SUPPORT_SKE_SM4 case SKE_ALG_SM4: #endif #if (defined(SUPPORT_SKE_TDES_128) || defined(SUPPORT_SKE_TDES_EEE_128) || \ defined(SUPPORT_SKE_AES_128) || defined(SUPPORT_SKE_SM4)) byte_len = 16; break; #endif #ifdef SUPPORT_SKE_TDES_192 case SKE_ALG_TDES_192: #endif #ifdef SUPPORT_SKE_TDES_EEE_192 case SKE_ALG_TDES_EEE_192: #endif #ifdef SUPPORT_SKE_AES_192 case SKE_ALG_AES_192: #endif #if (defined(SUPPORT_SKE_TDES_192) || defined(SUPPORT_SKE_TDES_EEE_192) || \ defined(SUPPORT_SKE_AES_192)) byte_len = 24; break; #endif #ifdef SUPPORT_SKE_AES_256 case SKE_ALG_AES_256: byte_len = 32; break; #endif default: byte_len = 16; } return byte_len; } /* function: set ske_hp iv * parameters: * iv ------------------------- input, initial vector * block_bytes ---------------- input, byte length of current ske_hp block * return: none * caution: * 1. please make sure the inputs are valid */ void ske_hp_set_iv(uint8_t *iv, uint32_t block_bytes) { uint32_t tmp[4]; if (((uint32_t)iv) & 3) { memcpy_(tmp, iv, block_bytes); ske_hp_set_iv_uint32(tmp, block_bytes / 4); } else { ske_hp_set_iv_uint32((uint32_t *)iv, block_bytes / 4); } } /* function: set ske_hp key * parameters: * alg ------------------------ input, ske_hp algorithm * key ------------------------ input, key * key_bytes ------------------ input, byte length of key * key_idx -------------------- input, key index, only 1 and 2 are valid * return: none * caution: * 1. please make sure the inputs are valid */ void ske_hp_set_key(SKE_ALG alg, uint8_t *key, uint16_t key_bytes, uint16_t key_idx) { uint32_t tmp[8]; memcpy_(tmp, key, key_bytes); /*for 3DES-2key, set key3=key1*/ switch (alg) { #ifdef SUPPORT_SKE_TDES_128 case SKE_ALG_TDES_128: #endif #ifdef SUPPORT_SKE_TDES_EEE_128 case SKE_ALG_TDES_EEE_128: #endif #if (defined(SUPPORT_SKE_TDES_128) || defined(SUPPORT_SKE_TDES_EEE_128)) memcpy_(tmp + 4, key, 8); key_bytes += 8; break; #endif default: break; } ske_hp_set_key_uint32(tmp, key_idx, key_bytes / 4); } /* function: ske_hp init config * parameters: * ctx ------------------------ input, ske_ctx_t context pointer * alg ------------------------ input, ske_hp algorithm * mode ----------------------- input, ske_hp algorithm operation mode, like * ECB,CBC,OFB,etc. crypto --------------------- input, encrypting or decrypting * 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], if the MSB(sp_key_idx) is 1, that means * using low 128bit of the 256bit key iv ------------------------- input, iv in * bytes, must be a block return: SKE_SUCCESS(success), other(error) caution: * 1. this function is common for CPU/DMA/DMA-LL * 2. if mode is ECB, then there is no iv, in this case iv could be NULL * 3. if mode is CMAC/CBC-MAC, the iv must be a block of all zero * 4. if key is from user input, please make sure the argument 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_init_internal(ske_ctx_t *ctx, SKE_ALG alg, SKE_MODE mode, SKE_CRYPTO crypto, uint8_t *key, uint16_t sp_key_idx, uint8_t *iv) { uint32_t key_bytes; if (NULL == ctx) { return SKE_BUFFER_NULL; } else if (SKE_SUCCESS != ske_hp_check_alg(alg)) { return SKE_INPUT_INVALID; } else if (SKE_SUCCESS != ske_hp_check_mode(alg, mode)) { return SKE_INPUT_INVALID; } else if (crypto > SKE_CRYPTO_DECRYPT) { return SKE_INPUT_INVALID; } else if (NULL == key) { /*secure port key idx is from 1 to MAX_KEY_IDX*/ #ifdef SKE_SECURE_PORT_FUNCTION key_bytes = sp_key_idx & (0x7FFF); if ((0 == key_bytes) || (key_bytes > SKE_MAX_KEY_IDX)) { return SKE_INPUT_INVALID; } #else return SKE_INPUT_INVALID; #endif } else { ; } if (SKE_MODE_ECB == mode) { iv = NULL; } else if (NULL == iv) { return SKE_BUFFER_NULL; } else { ; } /*keep the block length*/ ctx->block_bytes = ske_hp_get_block_byte_len(alg); ctx->block_words = ctx->block_bytes / 4; /*config*/ ske_hp_set_endian_uint32(); ske_hp_set_alg(alg); ske_hp_set_mode(mode); ske_hp_set_crypto(crypto); ske_hp_set_last_block(0); /*set iv or nonce*/ if (NULL != iv) { ske_hp_set_iv(iv, ctx->block_bytes); } if (NULL != key) { /*key is from user input*/ ske_hp_disable_secure_port(); key_bytes = ske_hp_get_key_byte_len(alg); ske_hp_set_key(alg, key, key_bytes, 1); #if defined(SUPPORT_SKE_MODE_XTS) if (SKE_MODE_XTS == mode) { ske_hp_set_key(alg, key + key_bytes, key_bytes, 2); } #endif } else { /*key is from secure port*/ #if defined(SUPPORT_SKE_MODE_XTS) if (SKE_MODE_XTS == mode) { ske_hp_enable_secure_port(sp_key_idx + 1); ske_hp_expand_key(); } #endif ske_hp_enable_secure_port(sp_key_idx); } return ske_hp_expand_key(); } /* function: ske_hp init config(CPU style) * parameters: * alg ------------------------ input, ske_hp algorithm * mode ----------------------- input, ske_hp algorithm operation mode, like * ECB,CBC,OFB,etc. crypto --------------------- input, encrypting or decrypting * 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], if the MSB(sp_key_idx) is 1, that means * using low 128bit of the 256bit key iv ------------------------- input, iv in * bytes, must be a block return: SKE_SUCCESS(success), other(error) caution: * 1. if mode is ECB, then there is no iv, in this case iv could be NULL * 2. this function is designed for ECB/CBC/CFB/OFB/CTR/XTS modes, and * input/output unit must be a block * 3. 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_init(SKE_ALG alg, SKE_MODE mode, SKE_CRYPTO crypto, uint8_t *key, uint16_t sp_key_idx, uint8_t *iv) { ske_hp_set_cpu_mode(); ske_hp_set_c_len_uint32(0); return ske_hp_init_internal(ske_ctx, alg, mode, crypto, key, sp_key_idx, iv); } /* function: ske_hp encryption or decryption(CPU style) * parameters: * in ------------------------- input, plaintext or ciphertext * out ------------------------ output, ciphertext or plaintext * bytes ---------------------- input, byte length of input or output. * return: SKE_SUCCESS(success), other(error) * caution: * 1. this function is designed for ECB/CBC/CFB/OFB/CTR/XTS modes, and * input/output unit must be a block * 2. to save memory, in and out could be the same buffer, in this case, the * output will cover the input. * 3. bytes must be a multiple of block byte length. */ uint32_t ske_hp_update_blocks(uint8_t *in, uint8_t *out, uint32_t bytes) { if ((NULL == in) || (NULL == out)) { return SKE_BUFFER_NULL; } else if (bytes & (ske_ctx->block_bytes - 1)) { return SKE_INPUT_INVALID; } ske_hp_update_blocks_internal(ske_ctx, in, out, bytes); return SKE_SUCCESS; } /* function: ske_hp finish * parameters: none * return: SKE_SUCCESS(success), other(error) * caution: * 1. if encryption or decryption is done, please call this(optional) */ uint32_t ske_hp_final(void) { memset_(ske_ctx, 0, sizeof(ske_ctx_t)); return SKE_SUCCESS; } /* function: ske_hp encrypting or decrypting(CPU style, one-off style) * parameters: * alg ------------------------ input, ske_hp algorithm * mode ----------------------- input, ske_hp algorithm operation mode, like * ECB,CBC,OFB,etc. crypto --------------------- input, encrypting or decrypting * 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], if the MSB(sp_key_idx) is 1, that means * using low 128bit of the 256bit key iv ------------------------- input, iv in * bytes, must be a block in ------------------------- input, plaintext or * ciphertext out ------------------------ output, ciphertext or plaintext bytes * ---------------------- input, byte length of input or output. return: * SKE_SUCCESS(success), other(error) caution: * 1. if mode is ECB, then there is no iv, in this case iv could be NULL * 2. this function is designed for ECB/CBC/CFB/OFB/CTR/XTS modes, and * input/output unit is a block * 3. 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] * 4. to save memory, in and out could be the same buffer, in this case, the * output will cover the input. * 5. bytes must be a multiple of block byte length. */ uint32_t ske_hp_crypto(SKE_ALG alg, SKE_MODE mode, SKE_CRYPTO crypto, uint8_t *key, uint16_t sp_key_idx, uint8_t *iv, uint8_t *in, uint8_t *out, uint32_t bytes) { uint32_t ret; ske_hp_set_cpu_mode(); ske_hp_set_c_len_uint32(0); ret = ske_hp_init_internal(ske_ctx, alg, mode, crypto, key, sp_key_idx, iv); if (SKE_SUCCESS != ret) { return ret; } else { return ske_hp_update_blocks(in, out, bytes); } } #ifdef SKE_HP_DMA_FUNCTION /* function: ske_hp init config(DMA style) * parameters: * alg ------------------------ input, ske_hp algorithm * mode ----------------------- input, ske_hp algorithm operation mode, like * ECB,CBC,OFB,etc. crypto --------------------- input, encrypting or decrypting * key ------------------------ input, key in bytes, must be a block * 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 iv ------------------------- input, iv in * bytes return: SKE_SUCCESS(success), other(error) caution: * 1. if mode is ECB, then there is no iv, in this case iv could be NULL * 2. this function is designed for ECB/CBC/CFB/OFB/CTR/XTS modes, and * input/output unit is a block * 3. 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_init(SKE_ALG alg, SKE_MODE mode, SKE_CRYPTO crypto, uint8_t *key, uint16_t sp_key_idx, uint8_t *iv) { ske_hp_set_dma_mode(); ske_hp_set_c_len_uint32(0); ske_hp_disable_dma_linked_list(); return ske_hp_init_internal(ske_ctx, alg, mode, crypto, key, sp_key_idx, iv); } /* function: ske_hp encryption or decryption(DMA style) * parameters: * in ------------------------- input, plaintext or ciphertext * out ------------------------ output, ciphertext or plaintext * words ---------------------- input, word length of input or output, must * be multiples of 4(128bits) return: SKE_SUCCESS(success), other(error) * caution: * 1. this function is designed for ECB/CBC/CFB/OFB/CTR/XTS modes, and * input/output unit is a block * 2. to save memory, in and out could be the same buffer, in this case, the * output will cover the input. * 3. words must be a multiple of block word length. */ uint32_t ske_hp_dma_update_blocks(uint32_t *in, uint32_t *out, uint32_t words) { if (0 == words) { return SKE_SUCCESS; } else if (words & (ske_ctx->block_words - 1)) { return SKE_INPUT_INVALID; } else { return ske_hp_dma_operate(ske_ctx, in, out, words, words); } } /* function: ske_hp finish(DMA style) * parameters: none * return: SKE_SUCCESS(success), other(error) * caution: * 1. if encryption or decryption is done, please call this(optional) */ uint32_t ske_hp_dma_final(void) { memset_(ske_ctx, 0, sizeof(ske_ctx_t)); return SKE_SUCCESS; } /* function: ske_hp encrypting or decrypting(DMA style, one-off style) * parameters: * alg ------------------------ input, ske_hp algorithm * mode ----------------------- input, ske_hp algorithm operation mode, like * ECB,CBC,OFB,etc. crypto --------------------- input, encrypting or decrypting * 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], if the MSB(sp_key_idx) is 1, that means * using low 128bit of the 256bit key iv ------------------------- input, iv in * bytes, must be a block in ------------------------- input, plaintext or * ciphertext out ------------------------ output, ciphertext or plaintext words * ---------------------- input, word length of input or output. return: * SKE_SUCCESS(success), other(error) caution: * 1. if mode is ECB, then there is no iv, in this case iv could be NULL * 2. this function is designed for ECB/CBC/CFB/OFB/CTR/XTS modes, and * input/output unit is a block * 3. 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] * 4. to save memory, in and out could be the same buffer, in this case, the * output will cover the input. * 5. words must be a multiple of block word length. */ uint32_t ske_hp_dma_crypto(SKE_ALG alg, SKE_MODE mode, SKE_CRYPTO crypto, uint8_t *key, uint16_t sp_key_idx, uint8_t *iv, uint32_t *in, uint32_t *out, uint32_t words) { uint32_t ret; ske_hp_set_dma_mode(); ske_hp_set_c_len_uint32(0); ske_hp_disable_dma_linked_list(); ret = ske_hp_init_internal(ske_ctx, alg, mode, crypto, key, sp_key_idx, iv); if (SKE_SUCCESS != ret) { return ret; } else { return ske_hp_dma_update_blocks(in, out, words); } } #endif #ifdef SKE_HP_DMA_LL_FUNCTION uint32_t ske_hp_dma_ll_init(SKE_ALG alg, SKE_MODE mode, SKE_CRYPTO crypto, uint8_t *key, uint16_t sp_key_idx, uint8_t *iv) { ske_hp_set_dma_mode(); ske_hp_enable_dma_linked_list(); return ske_hp_init_internal(ske_ctx, alg, mode, crypto, key, sp_key_idx, iv); } uint32_t ske_hp_dma_ll_crypto(uint32_t *in, uint32_t *out, uint32_t wordLen, dma_ll_node_t *llp) { ske_hp_dma_ll_operate(in, out, wordLen, llp); return SKE_SUCCESS; } /* function: ske_hp finish(DMA style) * parameters: none * return: SKE_SUCCESS(success), other(error) * caution: * 1. if encryption or decryption is done, please call this(optional) */ uint32_t ske_hp_dma_ll_final() { memset_(ske_ctx, 0, sizeof(ske_ctx_t)); return SKE_SUCCESS; } #endif