/**************************************************************************//** * @file keystore.c * @version V3.01 * @brief Key store driver source file * * @copyright SPDX-License-Identifier: Apache-2.0 * @copyright Copyright (C) 2022 Nuvoton Technology Corp. All rights reserved. *****************************************************************************/ #include "NuMicro.h" /** @addtogroup Standard_Driver Standard Driver @{ */ /** @addtogroup KS_Driver Key Store Driver @{ */ int32_t g_KS_i32ErrCode = 0; /*!< KS global error code */ /** @addtogroup KS_EXPORTED_FUNCTIONS Key Store Exported Functions @{ */ /** * @brief Initial key store * @retval 0 Successful * @retval others Fail * @details This function is used to initial the key store. * It is necessary to be called before using other APIs of Key Store. */ int32_t KS_Open(void) { uint32_t u32TimeOutCount; uint32_t au32Key[8] = {0}; CLK->AHBCLK0 |= CLK_AHBCLK0_KSCKEN_Msk; /* Key store initial */ if ((KS->STS & KS_STS_INITDONE_Msk) == 0) { /* Waiting for busy */ u32TimeOutCount = KS_TIMEOUT; while (KS->STS & KS_STS_BUSY_Msk) { if (--u32TimeOutCount == 0) { return KS_ERR_TIMEOUT; } } /* Start Key Store Initial */ KS->CTL = KS_CTL_INIT_Msk | KS_CTL_START_Msk; /* Waiting for initilization */ u32TimeOutCount = KS_TIMEOUT; while ((KS->STS & KS_STS_INITDONE_Msk) == 0) { if (--u32TimeOutCount == 0) { return KS_ERR_TIMEOUT; } } } /* Waiting busy to make sure KS is ready. */ u32TimeOutCount = KS_TIMEOUT; while (KS->STS & KS_STS_BUSY_Msk) { if (--u32TimeOutCount == 0) { return KS_ERR_TIMEOUT; } } /* Create dummy key for KS Flash and KS SRAM */ if (KS_Read(KS_FLASH, 0, au32Key, 8) < 0) { if (KS_Write(KS_FLASH, KS_META_CPU | KS_META_READABLE | KS_META_256, au32Key) != 0) { return KS_ERR_INIT; } } if (KS_Read(KS_SRAM, 0, au32Key, 8) < 0) { if (KS_Write(KS_SRAM, KS_META_CPU | KS_META_READABLE | KS_META_256, au32Key) != 0) { return KS_ERR_INIT; } } return KS_OK; } /** * @brief Read key from key store * @param[in] eType The memory type. It could be: \ref KS_SRAM \ref KS_FLASH \ref KS_OTP * @param[in] i32KeyIdx The key index to read * @param[out] au32Key The buffer to store the key * @param[in] u32WordCnt The word (32-bit) count of the key buffer size * @retval 0 Successful * @retval -1 Fail * @details This function is used to read the key. */ int32_t KS_Read(KS_MEM_Type eType, int32_t i32KeyIdx, uint32_t au32Key[], uint32_t u32WordCnt) { int32_t i32Cnt; uint32_t u32Cont; int32_t offset, i, cnt; uint32_t u32TimeOutCount; /* Just return when key store is in busy */ if (KS->STS & KS_STS_BUSY_Msk) return KS_ERR_BUSY; /* Specify the key address */ KS->METADATA = ((uint32_t)eType << KS_METADATA_DST_Pos) | KS_TOMETAKEY(i32KeyIdx); /* Clear error flag */ KS->STS = KS_STS_EIF_Msk; offset = 0; u32Cont = 0; i32Cnt = (int32_t)u32WordCnt; do { /* Clear Status */ KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk; /* Trigger to read the key */ KS->CTL = u32Cont | KS_OP_READ | KS_CTL_START_Msk; /* Waiting for key store processing */ u32TimeOutCount = KS_TIMEOUT; while (KS->STS & KS_STS_BUSY_Msk) { if (--u32TimeOutCount == 0) return KS_ERR_TIMEOUT; } /* Read the key to key buffer */ cnt = i32Cnt; if (cnt > 8) cnt = 8; for (i = 0; i < cnt; i++) { au32Key[offset + i] = KS->KEY[i]; } u32Cont = KS_CTL_CONT_Msk; i32Cnt -= 8; offset += 8; } while (i32Cnt > 0); /* Check error flag */ if (KS->STS & KS_STS_EIF_Msk) return KS_ERR_FAIL; return KS_OK; } /** * @brief Get the word count of the specified Metadata key length * @param[in] u32Meta The metadata define of the key length. It could be \ref KS_META_128 \ref KS_META_163 \ref KS_META_192 \ref KS_META_224 \ref KS_META_233 \ref KS_META_255 \ref KS_META_256 \ref KS_META_283 \ref KS_META_384 \ref KS_META_409 \ref KS_META_512 \ref KS_META_521 \ref KS_META_571 \ref KS_META_1024 \ref KS_META_2048 \ref KS_META_4096 * @return The word (32-bit) count of the key * @details This function is used to get word counts of the specified metadata key length. * It could be used to know how may words needs to allocate for the key. */ uint32_t KS_GetKeyWordCnt(uint32_t u32Meta) { const uint16_t au8CntTbl[21] = { 4, 6, 6, 7, 8, 8, 8, 9, 12, 13, 16, 17, 18, 0, 0, 0, 32, 48, 64, 96, 128 }; return au8CntTbl[((u32Meta & KS_METADATA_SIZE_Msk) >> KS_METADATA_SIZE_Pos)]; } /** * @brief Write key to key store * @param[in] eType The memory type. It could be: \ref KS_SRAM \ref KS_FLASH * @param[in] u32Meta The metadata of the key. It could be the combine of \ref KS_META_AES \ref KS_META_HMAC \ref KS_META_RSA_EXP \ref KS_META_RSA_MID \ref KS_META_ECC \ref KS_META_CPU \ref KS_META_128 \ref KS_META_163 \ref KS_META_192 \ref KS_META_224 \ref KS_META_233 \ref KS_META_255 \ref KS_META_256 \ref KS_META_283 \ref KS_META_384 \ref KS_META_409 \ref KS_META_512 \ref KS_META_521 \ref KS_META_571 \ref KS_META_1024 \ref KS_META_2048 \ref KS_META_4096 \ref KS_META_BOOT \ref KS_META_READABLE \ref KS_META_PRIV \ref KS_META_NONPRIV \ref KS_META_SECURE \ref KS_META_NONSECUR * @param[out] au32Key The buffer to store the key * @param[in] u32WordCnt The word (32-bit) count of the key buffer size * @return Index of the key. Failed when index < 0. * @details This function is used to write a key to key store. */ int32_t KS_Write(KS_MEM_Type eType, uint32_t u32Meta, uint32_t au32Key[]) { int32_t i32Cnt; uint32_t u32Cont; int32_t i, cnt; volatile int32_t offset; uint32_t u32TimeOutCount; /* Just return when key store is in busy */ if (KS->STS & KS_STS_BUSY_Msk) return KS_ERR_BUSY; /* Specify the key address */ KS->METADATA = (eType << KS_METADATA_DST_Pos) | u32Meta; /* Get size index */ i32Cnt = (int32_t)KS_GetKeyWordCnt(u32Meta); /* Invalid key length */ if (i32Cnt == 0) return KS_ERR_PARAMETER; /* OTP only support maximum 256 bits */ if ((eType == KS_OTP) && (i32Cnt > 8)) return KS_ERR_PARAMETER; /* Check size limit of KS FLASH */ if (eType == KS_FLASH) { if ((int32_t)KS_GetRemainSize(KS_FLASH) - i32Cnt * 4 < 4) return KS_ERR_FAIL; } /* Check key count limit of KS SRAM */ if (eType == KS_SRAM) { if (KS_GetRemainKeyCount(KS_SRAM) == 1) return KS_ERR_FAIL; } /* Clear error flag */ KS->STS = KS_STS_EIF_Msk; offset = 0; u32Cont = 0; do { /* Prepare the key to write */ cnt = i32Cnt; if (cnt > 8) cnt = 8; for (i = 0; i < cnt; i++) { KS->KEY[i] = au32Key[offset + i]; } /* Clear Status */ KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk; /* Write the key */ KS->CTL = u32Cont | KS_OP_WRITE | KS_CTL_START_Msk; u32Cont = KS_CTL_CONT_Msk; i32Cnt -= 8; offset += 8; /* Waiting for key store processing */ u32TimeOutCount = KS_TIMEOUT; while (KS->STS & KS_STS_BUSY_Msk) { if (--u32TimeOutCount == 0) return KS_ERR_TIMEOUT; } } while (i32Cnt > 0); /* Check error flag */ if (KS->STS & KS_STS_EIF_Msk) { return KS_ERR_FAIL; } return KS_TOKEYIDX(KS->METADATA); } /** * @brief Erase a key from key store SRAM * @param[in] i32KeyIdx The key index to read * @retval 0 Successful * @retval -1 Fail * @details This function is used to erase a key from SRAM of key store. */ int32_t KS_EraseKey(int32_t i32KeyIdx) { uint32_t u32TimeOutCount = KS_TIMEOUT; /* Just return when key store is in busy */ if (KS->STS & KS_STS_BUSY_Msk) return KS_ERR_BUSY; /* Clear error flag */ KS->STS = KS_STS_EIF_Msk; /* Specify the key address */ KS->METADATA = (KS_SRAM << KS_METADATA_DST_Pos) | KS_TOMETAKEY(i32KeyIdx); /* Clear Status */ KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk; /* Erase the key */ KS->CTL = KS_OP_ERASE | KS_CTL_START_Msk; /* Waiting for processing */ while (KS->STS & KS_STS_BUSY_Msk) { if (--u32TimeOutCount == 0) return KS_ERR_TIMEOUT; } /* Check error flag */ if (KS->STS & KS_STS_EIF_Msk) return KS_ERR_FAIL; return KS_OK; } /** * @brief Erase a key from key store OTP * @param[in] i32KeyIdx The key index to erase * @retval 0 Successful * @retval -1 Fail * @details This function is used to erase a key from key store OTP. */ int32_t KS_EraseOTPKey(int32_t i32KeyIdx) { uint32_t u32TimeOutCount = KS_TIMEOUT; /* 1 second time-out */ /* Just return when key store is in busy */ if (KS->STS & KS_STS_BUSY_Msk) return KS_ERR_BUSY; /* Clear error flag */ KS->STS = KS_STS_EIF_Msk; /* Specify the key address */ KS->METADATA = ((uint32_t)KS_OTP << KS_METADATA_DST_Pos) | KS_TOMETAKEY(i32KeyIdx); /* Clear Status */ KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk; /* Erase the key */ KS->CTL = KS_OP_ERASE | KS_CTL_START_Msk; /* Waiting for processing */ while (KS->STS & KS_STS_BUSY_Msk) { if (--u32TimeOutCount == 0) return KS_ERR_TIMEOUT; } /* Check error flag */ if (KS->STS & KS_STS_EIF_Msk) return KS_ERR_FAIL; return KS_OK; } /** * @brief Lock the OTP key * @param[in] i32KeyIdx The key index to lock * @retval 0 Successful * @retval -1 Fail * @details This function is used to lock a key of KS OTP. */ int32_t KS_LockOTPKey(int32_t i32KeyIdx) { uint32_t u32TimeOutCount = KS_TIMEOUT; /* Just return when key store is in busy */ if (KS->STS & KS_STS_BUSY_Msk) return KS_ERR_BUSY; /* Clear error flag */ KS->STS = KS_STS_EIF_Msk; /* Specify the key address */ KS->METADATA = ((uint32_t)KS_OTP << KS_METADATA_DST_Pos) | KS_TOMETAKEY(i32KeyIdx); /* Clear Status */ KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk; /* Erase the key */ KS->CTL = KS_OP_LOCK | KS_CTL_START_Msk; /* Waiting for processing */ while (KS->STS & KS_STS_BUSY_Msk) { if (--u32TimeOutCount == 0) return KS_ERR_TIMEOUT; } /* Check error flag */ if (KS->STS & KS_STS_EIF_Msk) return KS_ERR_FAIL; return KS_OK; } /** * @brief Erase all keys from key store * @param[in] eType The memory type. It could be: \ref KS_SRAM \ref KS_FLASH \ref KS_OTP * @param[in] i32KeyIdx The key index to read * @retval 0 Successful * @retval -1 Fail * @details This function is used to erase all keys in SRAM or Flash of key store. */ int32_t KS_EraseAll(KS_MEM_Type eType) { uint32_t au32Key[8] = { 0 }; uint32_t u32TimeOutCount = KS_TIMEOUT; /* Just return when key store is in busy */ if (KS->STS & KS_STS_BUSY_Msk) return KS_ERR_BUSY; /* Clear error flag */ KS->STS = KS_STS_EIF_Msk; /* Specify the key address */ KS->METADATA = (eType << KS_METADATA_DST_Pos); /* Clear Status */ KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk; /* Erase the key */ KS->CTL = KS_OP_ERASE_ALL | KS_CTL_START_Msk; /* Waiting for processing */ while (KS->STS & KS_STS_BUSY_Msk) { if (--u32TimeOutCount == 0) return KS_ERR_TIMEOUT; } /* Check error flag */ if (KS->STS & KS_STS_EIF_Msk) return KS_ERR_FAIL; /* Create dummy key for KS Flash and KS SRAM */ if (KS_Read(KS_FLASH, 0, au32Key, 8) < 0) { if (KS_Write(KS_FLASH, KS_META_CPU | KS_META_READABLE | KS_META_256, au32Key) != 0) { return KS_ERR_FAIL; } } if (KS_Read(KS_SRAM, 0, au32Key, 8) < 0) { if (KS_Write(KS_SRAM, KS_META_CPU | KS_META_READABLE | KS_META_256, au32Key) != 0) { return KS_ERR_FAIL; } } return KS_OK; } /** * @brief Revoke a key in key store * @param[in] eType The memory type. It could be: \ref KS_SRAM \ref KS_FLASH \ref KS_OTP * @param[in] i32KeyIdx The key index to read * @retval 0 Successful * @retval -1 Fail * @details This function is used to revoke a key in key store. */ int32_t KS_RevokeKey(KS_MEM_Type eType, int32_t i32KeyIdx) { uint32_t u32TimeOutCount = KS_TIMEOUT; /* Just return when key store is in busy */ if (KS->STS & KS_STS_BUSY_Msk) return KS_ERR_BUSY; /* Clear error flag */ KS->STS = KS_STS_EIF_Msk; /* Specify the key address */ KS->METADATA = (eType << KS_METADATA_DST_Pos) | KS_TOMETAKEY(i32KeyIdx); /* Clear Status */ KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk; /* Erase the key */ KS->CTL = KS_OP_REVOKE | KS_CTL_START_Msk; /* Waiting for processing */ while (KS->STS & KS_STS_BUSY_Msk) { if (--u32TimeOutCount == 0) return KS_ERR_TIMEOUT; } /* Check error flag */ if (KS->STS & KS_STS_EIF_Msk) return KS_ERR_FAIL; return KS_OK; } /** * @brief Get remain size of specified Key Store memory * @param[in] eType The memory type. It could be: \ref KS_SRAM \ref KS_FLASH * @retval remain size of specified Key Store memory * @details This function is used to get remain size of Key Store. */ uint32_t KS_GetRemainSize(KS_MEM_Type mem) { uint32_t u32Reg; uint32_t u32SramRemain, u32FlashRemain; u32Reg = KS->REMAIN; //printf("KS Remain 0x%08x\n", u32Reg); //printf("SRAM remain %lu bytes, Flash remain %lu bytes\n",(u32Reg&KS_REMAIN_RRMNG_Msk) >> KS_REMAIN_RRMNG_Pos, (u32Reg&KS_REMAIN_FRMNG_Msk) >> KS_REMAIN_FRMNG_Pos); u32SramRemain = (u32Reg & KS_REMAIN_RRMNG_Msk) >> KS_REMAIN_RRMNG_Pos; u32FlashRemain = (u32Reg & KS_REMAIN_FRMNG_Msk) >> KS_REMAIN_FRMNG_Pos; if (mem == KS_SRAM) return u32SramRemain; else return u32FlashRemain; } /** * @brief Get remain key count of specified Key Store memory * @param[in] eType The memory type. It could be: \ref KS_SRAM \ref KS_FLASH * @retval Remain key count in the specified key store memory * @details This function is used to get remain key count in specified key store memory. */ uint32_t KS_GetRemainKeyCount(KS_MEM_Type mem) { uint32_t u32Reg; uint32_t u32SramRemain, u32FlashRemain; u32Reg = KS->REMKCNT; u32SramRemain = (u32Reg & KS_REMKCNT_RRMKCNT_Msk) >> KS_REMKCNT_RRMKCNT_Pos; u32FlashRemain = (u32Reg & KS_REMKCNT_FRMKCNT_Msk) >> KS_REMKCNT_FRMKCNT_Pos; if (mem == KS_SRAM) return u32SramRemain; else return u32FlashRemain; } /** * @brief Write OTP key to key store * @param[in] i32KeyIdx The OTP key index to store the key. It could be 0~7. OTP key index 0 is default for ROTPK. * @param[in] u32Meta The metadata of the key. It could be the combine of \ref KS_META_AES \ref KS_META_HMAC \ref KS_META_RSA_EXP \ref KS_META_RSA_MID \ref KS_META_ECC \ref KS_META_CPU \ref KS_META_128 \ref KS_META_163 \ref KS_META_192 \ref KS_META_224 \ref KS_META_233 \ref KS_META_255 \ref KS_META_256 \ref KS_META_BOOT \ref KS_META_READABLE \ref KS_META_PRIV \ref KS_META_NONPRIV \ref KS_META_SECURE \ref KS_META_NONSECUR * @param[out] au32Key The buffer to store the key * @param[in] u32WordCnt The word (32-bit) count of the key buffer size * @retval 0 Successful * @retval -1 Fail * @details This function is used to write a key to OTP key store. */ int32_t KS_WriteOTP(int32_t i32KeyIdx, uint32_t u32Meta, uint32_t au32Key[]) { const uint16_t au8CntTbl[7] = {4, 6, 6, 7, 8, 8, 8}; int32_t i32Cnt; uint32_t u32Cont; int32_t offset, i, cnt, sidx; uint32_t u32TimeOutCount; /* Just return when key store is in busy */ if (KS->STS & KS_STS_BUSY_Msk) return KS_ERR_BUSY; /* Specify the key address */ KS->METADATA = ((uint32_t)KS_OTP << KS_METADATA_DST_Pos) | u32Meta | KS_TOMETAKEY(i32KeyIdx); /* Get size index */ sidx = (u32Meta >> KS_METADATA_SIZE_Pos) & 0xful; /* OTP only support maximum 256 bits */ if (sidx >= 7) return KS_ERR_PARAMETER; i32Cnt = au8CntTbl[sidx]; /* Clear error flag */ KS->STS = KS_STS_EIF_Msk; offset = 0; u32Cont = 0; do { /* Prepare the key to write */ cnt = i32Cnt; if (cnt > 8) cnt = 8; for (i = 0; i < cnt; i++) { KS->KEY[i] = au32Key[offset + i]; } /* Clear Status */ KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk; /* Write the key */ KS->CTL = u32Cont | KS_OP_WRITE | KS_CTL_START_Msk; u32Cont = KS_CTL_CONT_Msk; i32Cnt -= 8; offset += 8; /* Waiting for key store processing */ u32TimeOutCount = KS_TIMEOUT; while (KS->STS & KS_STS_BUSY_Msk) { if (--u32TimeOutCount == 0) return KS_ERR_TIMEOUT; } } while (i32Cnt > 0); /* Check error flag */ if (KS->STS & KS_STS_EIF_Msk) { return KS_ERR_FAIL; } return i32KeyIdx; } /** * @brief Trigger to inverse the date in KS_SRAM. * @retval 1 The data in KS SRAM is inverted. * @retval 0 The data in KS SRAM is non-inverted. * @retval -1 Fail to invert the date in KS SRAM. * @details This function is used to trigger anti-remanence procedure by inverse the data in SRAM. * This won't change the reading key. */ int32_t KS_ToggleSRAM(void) { uint32_t u32TimeOutCount = KS_TIMEOUT; /* Just return when key store is in busy */ if (KS->STS & KS_STS_BUSY_Msk) return KS_ERR_BUSY; /* Specify the key address */ KS->METADATA = ((uint32_t)KS_SRAM << KS_METADATA_DST_Pos); /* Clear error flag */ KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk; /* Trigger to do anti-remanence procedure */ KS->CTL = KS_OP_REMAN | KS_CTL_START_Msk; /* Waiting for key store processing */ while (KS->STS & KS_STS_BUSY_Msk) { if (--u32TimeOutCount == 0) return KS_ERR_TIMEOUT; } /* Check error flag */ if (KS->STS & KS_STS_EIF_Msk) return KS_ERR_FAIL; return ((KS->STS & KS_STS_RAMINV_Msk) > 0); } /**@}*/ /* end of group KS_EXPORTED_FUNCTIONS */ /**@}*/ /* end of group KS_Driver */ /**@}*/ /* end of group Standard_Driver */