/** ****************************************************************************** * @file stm32h5xx_hal_hash.c * @author MCD Application Team * @brief HASH HAL module driver. * This file provides firmware functions to manage HASH peripheral * ****************************************************************************** * @attention * * Copyright (c) 2022 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** @verbatim =============================================================================== ##### How to use this driver ##### =============================================================================== [..] The HASH HAL driver can be used as follows: (#)Initialize the HASH low level resources by implementing the HAL_HASH_MspInit(): (##) Enable the HASH interface clock using __HAL_RCC_HASH_CLK_ENABLE() (##) When resorting to interrupt-based APIs (e.g. HAL_HASH_Start_IT()) (+++) Configure the HASH interrupt priority using HAL_NVIC_SetPriority() (+++) Enable the HASH IRQ handler using HAL_NVIC_EnableIRQ() (+++) In HASH IRQ handler, call HAL_HASH_IRQHandler() API (##) When resorting to DMA-based APIs (e.g. HAL_HASH_Start_DMA()) (+++) Enable the DMA interface clock (+++) Configure and enable one DMA to manage data transfer from memory to peripheral (input DMA). Managing data transfer from peripheral to memory can be performed only using CPU. (+++) Associate the initialized DMA handle to the HASH DMA handle using __HAL_LINKDMA() (+++) Configure the priority and enable the NVIC for the transfer complete interrupt on the DMA: use HAL_NVIC_SetPriority() and HAL_NVIC_EnableIRQ() (#)Initialize the HASH HAL using HAL_HASH_Init(). This function: (##) resorts to HAL_HASH_MspInit() for low-level initialization, (##) configures the data type: no swap, half word swap, bit swap or byte swap, (##) configures the Algorithm : MD5, SHA1 or SHA2 (#)Three processing schemes are available: (##) Polling mode: processing APIs are blocking functions i.e. they process the data and wait till the digest computation is finished, e.g. HAL_HASH_Start() for HASH or HAL_HMAC_Start() for HMAC (##) Interrupt mode: processing APIs are not blocking functions i.e. they process the data under interrupt, e.g. HAL_HASH_Start_IT() for HASH or HAL_HMAC_Start_IT() for HMAC (##) DMA mode: processing APIs are not blocking functions and the CPU is not used for data transfer i.e. the data transfer is ensured by DMA, e.g. HAL_HASH_Start_DMA() for HASH or HAL_HMAC_Start_DMA() for HMAC. (#)When the processing function is called after HAL_HASH_Init(), the HASH peripheral is initialized and processes the buffer fed in input. When the input data have all been fed to the Peripheral, the digest computation can start. (#)Multi-buffer processing HASH and HMAC are possible in polling, interrupt and DMA modes. (##) In polling mode, API HAL_HASH_Accumulate()/HAL_HASH_HMAC_Accumulate() must be called for each input buffer, except for the last one. User must resort to HAL_HASH_AccumulateLast()/HAL_HASH_HMAC_AccumulateLast() to enter the last one and retrieve as well the computed digest. (##) In interrupt mode, API HAL_HASH_Accumulate_IT()/HAL_HASH_HMAC_Accumulate_IT() must be called for each input buffer, except for the last one. User must resort to HAL_HASH_AccumulateLast_IT()/HAL_HASH_HMAC_AccumulateLast_IT() to enter the last one and retrieve as well the computed digest. (##) In DMA mode, once initialization is done, MDMAT bit must be set through __HAL_HASH_SET_MDMAT() macro. From that point, each buffer can be fed to the Peripheral through HAL_HASH_Start_DMA() API for HASH and HAL_HASH_HMAC_Start_DMA() API for HMAC . Before entering the last buffer, reset the MDMAT bit with __HAL_HASH_RESET_MDMAT() macro then wrap-up the HASH processing in feeding the last input buffer through the same API HAL_HASH_Start_DMA()for HASH and HAL_HASH_HMAC_Start_DMA() API for HMAC and retrieve as well the computed digest. (#)To use this driver (version 2.0.0) with application developed with old driver (version 1.0.0) user have to: (##) Add Algorithm as parameter like DataType or KeySize. (##) Use new API HAL_HASH_Start() for HASH and HAL_HASH_HMAC_Start() for HMAC processing instead of old API like HAL_HASH_SHA1_Start and HAL_HMAC_SHA1_Start. @endverbatim ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32h5xx_hal.h" /** @addtogroup STM32H5xx_HAL_Driver * @{ */ #if defined (HASH) /** @defgroup HASH HASH * @brief HASH HAL module driver. * @{ */ #ifdef HAL_HASH_MODULE_ENABLED /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /** @defgroup HASH_Private_Defines HASH Private Defines * @{ */ #define HASH_TIMEOUTVALUE 1000U /*!< Time-out value */ /** * @} */ /** @defgroup HASH_Number_Of_CSR_Registers HASH Number of Context Swap Registers * @{ */ #if defined(HASH_ALGOSELECTION_SHA512) #define HASH_NUMBER_OF_CSR_REGISTERS 103U /*!< Number of Context Swap Registers */ #else #define HASH_NUMBER_OF_CSR_REGISTERS 54U /*!< Number of Context Swap Registers */ #endif /* HASH_ALGOSELECTION_SHA512 */ /** * @} */ /* Private Constants ---------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ /** @defgroup HASH_Private_Functions HASH Private Functions * @{ */ static void HASH_GetDigest(HASH_HandleTypeDef *hhash, uint8_t *pMsgDigest, uint8_t Size); static void HASH_WriteData(HASH_HandleTypeDef *hhash, const uint8_t *pInBuffer, uint32_t Size); static HAL_StatusTypeDef HASH_WriteData_IT(HASH_HandleTypeDef *hhash); static void HASH_DMAXferCplt(DMA_HandleTypeDef *hdma); static void HASH_DMAError(DMA_HandleTypeDef *hdma); static HAL_StatusTypeDef HASH_WaitOnFlagUntilTimeout(HASH_HandleTypeDef *hhash, uint32_t Flag, FlagStatus Status, uint32_t Timeout); /** * @} */ /* Exported functions ---------------------------------------------------------*/ /** @defgroup HASH_Exported_Functions HASH Exported Functions * @{ */ /** @defgroup HASH_Exported_Functions_Group1 Initialization and de-initialization functions * @brief Initialization and configuration functions. * @verbatim =============================================================================== ##### Initialization and de-initialization functions ##### =============================================================================== [..] This section provides functions allowing to: (+) Initialize the HASH according to the specified parameters in the HASH_InitTypeDef and create the associated handle (+) DeInitialize the HASH peripheral (+) Initialize the HASH MCU Specific Package (MSP) (+) DeInitialize the HASH MSP (+) Configure HASH (HAL_HASH_SetConfig) with the specified parameters in the HASH_ConfigTypeDef Parameters which are configured in This section are : (+) Data Type : no swap, half word swap, bit swap or byte swap (+) Algorithm : MD5,SHA1 or SHA2 (+) Get HASH configuration (HAL_HASH_GetConfig) from the specified parameters in the HASH_HandleTypeDef @endverbatim * @{ */ /** * @brief Initializes the HASH according to the specified parameters in the HASH_HandleTypeDef and create the associated handle. * @note Only Algorithm and DATATYPE bits of HASH Peripheral are set by HAL_HASH_Init(), * other configuration bits are set by HASH or HMAC processing APIs. * @param hhash pointer to a HASH_HandleTypeDef structure that contains * the configuration information for HASH module. * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_Init(HASH_HandleTypeDef *hhash) { uint32_t cr_value; /* Check the hash handle allocation */ if (hhash == NULL) { return HAL_ERROR; } /* Check the parameters */ assert_param(IS_HASH_DATATYPE(hhash->Init.DataType)); assert_param(IS_HASH_ALGORITHM(hhash->Init.Algorithm)); #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) if (hhash->State == HAL_HASH_STATE_RESET) { /* Allocate lock resource and initialize it */ hhash->Lock = HAL_UNLOCKED; /* Reset Callback pointers in HAL_HASH_STATE_RESET only */ hhash->InCpltCallback = HAL_HASH_InCpltCallback; /* Legacy weak InCpltCallback */ hhash->DgstCpltCallback = HAL_HASH_DgstCpltCallback; /* Legacy weak DgstCpltCallback */ hhash->ErrorCallback = HAL_HASH_ErrorCallback; /* Legacy weak ErrorCallback */ if (hhash->MspInitCallback == NULL) { hhash->MspInitCallback = HAL_HASH_MspInit; } /* Init the low level hardware */ hhash->MspInitCallback(hhash); } #else if (hhash->State == HAL_HASH_STATE_RESET) { /* Allocate lock resource and initialize it */ hhash->Lock = HAL_UNLOCKED; /* Init the low level hardware */ HAL_HASH_MspInit(hhash); } #endif /* (USE_HAL_HASH_REGISTER_CALLBACKS) */ /* Set the key size, data type and Algorithm */ cr_value = (uint32_t)(hhash->Init.DataType | hhash->Init.Algorithm); /* Set the key size, data type, algorithm and mode */ MODIFY_REG(hhash->Instance->CR, HASH_CR_DATATYPE | HASH_CR_ALGO | HASH_CR_INIT, cr_value); /* Change HASH phase to Ready */ hhash->Phase = HAL_HASH_PHASE_READY; /* Change HASH state to Ready */ hhash->State = HAL_HASH_STATE_READY; /* Reset error code field */ hhash->ErrorCode = HAL_HASH_ERROR_NONE; #if (USE_HAL_HASH_SUSPEND_RESUME == 1U) /* Reset suspension request flag */ hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; #endif /* (USE_HAL_HASH_SUSPEND_RESUME) */ /* Return function status */ return HAL_OK; } /** * @brief DeInitialize the HASH peripheral. * @param hhash pointer to a HASH_HandleTypeDef structure that contains * the configuration information for HASH module. * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_DeInit(HASH_HandleTypeDef *hhash) { /* Check the HASH handle allocation */ if (hhash == NULL) { return HAL_ERROR; } /* Change the default HASH phase */ hhash->Phase = HAL_HASH_PHASE_READY; /* Reset HashInCount */ hhash->HashInCount = 0U; /* Reset multi buffers accumulation flag */ hhash->Accumulation = 0U; #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) if (hhash->MspDeInitCallback == NULL) { hhash->MspDeInitCallback = HAL_HASH_MspDeInit; } /* DeInit the low level hardware */ hhash->MspDeInitCallback(hhash); #else /* DeInit the low level hardware: CLOCK, NVIC */ HAL_HASH_MspDeInit(hhash); #endif /* (USE_HAL_HASH_REGISTER_CALLBACKS) */ /* Set the HASH state to Ready */ hhash->State = HAL_HASH_STATE_RESET; __HAL_UNLOCK(hhash); return HAL_OK; } /** * @brief Configure the HASH according to the specified * parameters in the HASH_ConfigTypeDef * @param hcryp pointer to a HASH_HandleTypeDef structure * @param pConf pointer to a HASH_ConfigTypeDef structure that contains * the configuration information for HASH module * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_SetConfig(HASH_HandleTypeDef *hhash, HASH_ConfigTypeDef *pConf) { uint32_t cr_value; /* Check the HASH handle allocation */ if ((hhash == NULL) || (pConf == NULL)) { return HAL_ERROR; } /* Check parameters */ assert_param(IS_HASH_DATATYPE(pConf->DataType)); assert_param(IS_HASH_ALGORITHM(pConf->Algorithm)); if (hhash->State == HAL_HASH_STATE_READY) { /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; __HAL_LOCK(hhash); /* Set HASH parameters */ hhash->Init.DataType = pConf->DataType; hhash->Init.pKey = pConf->pKey; hhash->Init.Algorithm = pConf->Algorithm; hhash->Init.KeySize = pConf->KeySize; /* Set the key size, data type and Algorithm */ cr_value = (uint32_t)(hhash->Init.DataType | hhash->Init.Algorithm); /* Set the key size, data type, algorithm and mode */ MODIFY_REG(hhash->Instance->CR, HASH_CR_DATATYPE | HASH_CR_ALGO | HASH_CR_INIT, cr_value); /* Change HASH phase to Ready */ hhash->Phase = HAL_HASH_PHASE_READY; /* Change HASH state to Ready */ hhash->State = HAL_HASH_STATE_READY; /* Reset error code field */ hhash->ErrorCode = HAL_HASH_ERROR_NONE; __HAL_UNLOCK(hhash); return HAL_OK; } else { /* Busy error code field */ hhash->ErrorCode |= HAL_HASH_ERROR_BUSY; return HAL_ERROR; } } /** * @brief Get HASH Configuration parameters in associated handle * @param pConf pointer to a HASH_HandleTypeDef structure * @param hhash pointer to a HASH_ConfigTypeDef structure that contains * the configuration information for HASH module * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_GetConfig(HASH_HandleTypeDef *hhash, HASH_ConfigTypeDef *pConf) { /* Check the HASH handle allocation */ if ((hhash == NULL) || (pConf == NULL)) { return HAL_ERROR; } if (hhash->State == HAL_HASH_STATE_READY) { /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; __HAL_LOCK(hhash); /* Set HASH parameters */ pConf->DataType = hhash->Init.DataType; pConf->pKey = hhash->Init.pKey; pConf->Algorithm = hhash->Init.Algorithm; pConf->KeySize = hhash->Init.KeySize; /* Change HASH state to Ready */ hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); return HAL_OK; } else { /* Busy error code field */ hhash->ErrorCode |= HAL_HASH_ERROR_BUSY; return HAL_ERROR; } } /** * @brief Initialize the HASH MSP. * @param hhash pointer to a HASH_HandleTypeDef structure that contains * the configuration information for HASH module. * @retval None */ __weak void HAL_HASH_MspInit(HASH_HandleTypeDef *hhash) { /* Prevent unused argument(s) compilation warning */ UNUSED(hhash); /* NOTE : This function should not be modified; when the callback is needed, HAL_HASH_MspInit() can be implemented in the user file. */ } /** * @brief DeInitialize the HASH MSP. * @param hhash pointer to a HASH_HandleTypeDef structure that contains * the configuration information for HASH module. * @retval None */ __weak void HAL_HASH_MspDeInit(HASH_HandleTypeDef *hhash) { /* Prevent unused argument(s) compilation warning */ UNUSED(hhash); /* NOTE : This function should not be modified; when the callback is needed, HAL_HASH_MspDeInit() can be implemented in the user file. */ } #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) /** * @brief Register a User HASH Callback * To be used instead of the weak (surcharged) predefined callback * @param hhash HASH handle * @param CallbackID ID of the callback to be registered * This parameter can be one of the following values: * @arg HAL_HASH_INPUTCPLT_CB_ID input completion callback ID * @arg HAL_HASH_DGSTCPLT_CB_ID digest computation completion callback ID * @arg HAL_HASH_ERROR_CB_ID error callback ID * @arg HAL_HASH_MSPINIT_CB_ID MspInit callback ID * @arg HAL_HASH_MSPDEINIT_CB_ID MspDeInit callback ID * @param pCallback pointer to the Callback function * @retval status */ HAL_StatusTypeDef HAL_HASH_RegisterCallback(HASH_HandleTypeDef *hhash, HAL_HASH_CallbackIDTypeDef CallbackID, pHASH_CallbackTypeDef pCallback) { HAL_StatusTypeDef status = HAL_OK; if (pCallback == NULL) { /* Update the error code */ hhash->ErrorCode |= HAL_HASH_ERROR_INVALID_CALLBACK; return HAL_ERROR; } if (hhash->State == HAL_HASH_STATE_READY) { switch (CallbackID) { case HAL_HASH_INPUTCPLT_CB_ID : hhash->InCpltCallback = pCallback; break; case HAL_HASH_DGSTCPLT_CB_ID : hhash->DgstCpltCallback = pCallback; break; case HAL_HASH_ERROR_CB_ID : hhash->ErrorCallback = pCallback; break; case HAL_HASH_MSPINIT_CB_ID : hhash->MspInitCallback = pCallback; break; case HAL_HASH_MSPDEINIT_CB_ID : hhash->MspDeInitCallback = pCallback; break; default : /* Update the error code */ hhash->ErrorCode |= HAL_HASH_ERROR_INVALID_CALLBACK; /* update return status */ status = HAL_ERROR; break; } } else if (hhash->State == HAL_HASH_STATE_RESET) { switch (CallbackID) { case HAL_HASH_MSPINIT_CB_ID : hhash->MspInitCallback = pCallback; break; case HAL_HASH_MSPDEINIT_CB_ID : hhash->MspDeInitCallback = pCallback; break; default : /* Update the error code */ hhash->ErrorCode |= HAL_HASH_ERROR_INVALID_CALLBACK; /* update return status */ status = HAL_ERROR; break; } } else { /* Update the error code */ hhash->ErrorCode |= HAL_HASH_ERROR_INVALID_CALLBACK; /* update return status */ status = HAL_ERROR; } return status; } /** * @brief Unregister a HASH Callback * HASH Callback is redirected to the weak (surcharged) predefined callback * @param hhash HASH handle * @param CallbackID ID of the callback to be unregistered * This parameter can be one of the following values: * @arg HAL_HASH_INPUTCPLT_CB_ID HASH input completion Callback ID * @arg HAL_HASH_DGSTCPLT_CB_ID HASH digest computation completion Callback ID * @arg HAL_HASH_ERROR_CB_ID HASH error Callback ID * @arg HAL_HASH_MSPINIT_CB_ID HASH MspInit callback ID * @arg HAL_HASH_MSPDEINIT_CB_ID HASH MspDeInit callback ID * @retval status */ HAL_StatusTypeDef HAL_HASH_UnRegisterCallback(HASH_HandleTypeDef *hhash, HAL_HASH_CallbackIDTypeDef CallbackID) { HAL_StatusTypeDef status = HAL_OK; if (hhash->State == HAL_HASH_STATE_READY) { switch (CallbackID) { case HAL_HASH_INPUTCPLT_CB_ID : hhash->InCpltCallback = HAL_HASH_InCpltCallback; /* Legacy weak input completion callback */ break; case HAL_HASH_DGSTCPLT_CB_ID : hhash->DgstCpltCallback = HAL_HASH_DgstCpltCallback; /* Legacy weak digest computation completion callback */ break; case HAL_HASH_ERROR_CB_ID : hhash->ErrorCallback = HAL_HASH_ErrorCallback; /* Legacy weak error callback */ break; case HAL_HASH_MSPINIT_CB_ID : hhash->MspInitCallback = HAL_HASH_MspInit; /* Legacy weak MspInit Callback */ break; case HAL_HASH_MSPDEINIT_CB_ID : hhash->MspDeInitCallback = HAL_HASH_MspDeInit; /* Legacy weak MspDeInit Callback */ break; default : /* Update the error code */ hhash->ErrorCode |= HAL_HASH_ERROR_INVALID_CALLBACK; /* update return status */ status = HAL_ERROR; break; } } else if (hhash->State == HAL_HASH_STATE_RESET) { switch (CallbackID) { case HAL_HASH_MSPINIT_CB_ID : hhash->MspInitCallback = HAL_HASH_MspInit; /* Legacy weak MspInit Callback */ break; case HAL_HASH_MSPDEINIT_CB_ID : hhash->MspDeInitCallback = HAL_HASH_MspDeInit; /* Legacy weak MspDeInit Callback */ break; default : /* Update the error code */ hhash->ErrorCode |= HAL_HASH_ERROR_INVALID_CALLBACK; /* update return status */ status = HAL_ERROR; break; } } else { /* Update the error code */ hhash->ErrorCode |= HAL_HASH_ERROR_INVALID_CALLBACK; /* update return status */ status = HAL_ERROR; } return status; } #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ #if (USE_HAL_HASH_SUSPEND_RESUME == 1U) /** * @brief Save the HASH context in case of processing suspension. * @param hhash HASH handle. * @param pMemBuffer pointer to the memory buffer where the HASH context * is saved. * @note The IMR, STR, CR then all the CSR registers are saved * in that order. Only the r/w bits are read to be restored later on. * @note By default, all the context swap registers (there are * HASH_NUMBER_OF_CSR_REGISTERS of those) are saved. * @note pMemBuffer points to a buffer allocated by the user. The buffer size * must be at least (HASH_NUMBER_OF_CSR_REGISTERS + 3) * 4 uint8 long. * @retval None */ void HAL_HASH_Suspend(HASH_HandleTypeDef *hhash, uint8_t *pMemBuffer) { uint32_t mem_ptr = (uint32_t)pMemBuffer; uint32_t csr_ptr = (uint32_t)(hhash->Instance->CSR); uint32_t i; /* Prevent unused argument(s) compilation warning */ UNUSED(hhash); /* Save IMR register content */ *(uint32_t *)(mem_ptr) = READ_BIT(hhash->Instance->IMR, HASH_IT_DINI | HASH_IT_DCI); mem_ptr += 4U; /* Save STR register content */ *(uint32_t *)(mem_ptr) = READ_BIT(hhash->Instance->STR, HASH_STR_NBLW); mem_ptr += 4U; /* Save CR register content */ *(uint32_t *)(mem_ptr) = READ_BIT(hhash->Instance->CR, HASH_CR_DMAE | HASH_CR_DATATYPE | HASH_CR_MODE | HASH_CR_ALGO | HASH_CR_LKEY | HASH_CR_MDMAT); mem_ptr += 4U; /* By default, save all CSRs registers */ for (i = HASH_NUMBER_OF_CSR_REGISTERS; i > 0U; i--) { *(uint32_t *)(mem_ptr) = *(uint32_t *)(csr_ptr); mem_ptr += 4U; csr_ptr += 4U; } /* Save low-priority block HASH handle parameters */ hhash->Init_saved = hhash->Init; hhash->pHashOutBuffPtr_saved = hhash->pHashOutBuffPtr; hhash->HashInCount_saved = hhash->HashInCount; hhash->Size_saved = hhash->Size; hhash->pHashInBuffPtr_saved = hhash->pHashInBuffPtr; hhash->Phase_saved = hhash->Phase; hhash->pHashKeyBuffPtr_saved = hhash->pHashKeyBuffPtr; } /** * @brief Restore the HASH context in case of processing resumption. * @param hhash HASH handle. * @param pMemBuffer pointer to the memory buffer where the HASH context * is stored. * @note The IMR, STR, CR then all the CSR registers are restored * in that order. Only the r/w bits are restored. * @note By default, all the context swap registers (HASH_NUMBER_OF_CSR_REGISTERS * of those) are restored (all of them have been saved by default * beforehand). * @retval None */ void HAL_HASH_Resume(HASH_HandleTypeDef *hhash, uint8_t *pMemBuffer) { uint32_t mem_ptr = (uint32_t)pMemBuffer; uint32_t csr_ptr = (uint32_t)(hhash->Instance->CSR); uint32_t i; /* Prevent unused argument(s) compilation warning */ UNUSED(hhash); /* Restore IMR register content */ WRITE_REG(hhash->Instance->IMR, (*(uint32_t *)(mem_ptr))); mem_ptr += 4U; /* Restore STR register content */ WRITE_REG(hhash->Instance->STR, (*(uint32_t *)(mem_ptr))); mem_ptr += 4U; /* Restore CR register content */ WRITE_REG(hhash->Instance->CR, (*(uint32_t *)(mem_ptr))); mem_ptr += 4U; /* Reset the HASH processor before restoring the Context Swap Registers (CSR) */ SET_BIT(hhash->Instance->CR, HASH_CR_INIT); /* By default, restore all CSR registers */ for (i = HASH_NUMBER_OF_CSR_REGISTERS; i > 0U; i--) { WRITE_REG((*(uint32_t *)(csr_ptr)), (*(uint32_t *)(mem_ptr))); mem_ptr += 4U; csr_ptr += 4U; } /* Restore low-priority block HASH handle parameters */ hhash->Init = hhash->Init_saved; hhash->pHashOutBuffPtr = hhash->pHashOutBuffPtr_saved; hhash->HashInCount = hhash->HashInCount_saved; hhash->Size = hhash->Size_saved; hhash->pHashInBuffPtr = hhash->pHashInBuffPtr_saved; hhash->Phase = hhash->Phase_saved; hhash->State = HAL_HASH_STATE_SUSPENDED; hhash->pHashKeyBuffPtr = hhash->pHashKeyBuffPtr_saved; } /** * @brief Initiate HASH processing suspension when in interruption mode. * @param hhash HASH handle. * @note Set the handle field SuspendRequest to the appropriate value so that * the on-going HASH processing is suspended as soon as the required * conditions are met. Note that the actual suspension is carried out * by the functions HASH_WriteData() in polling mode and HASH_IT() in * interruption mode. * @retval None */ HAL_StatusTypeDef HAL_HASH_ProcessSuspend(HASH_HandleTypeDef *hhash) { uint32_t remainingwords; /*remaining number in of source block to be transferred.*/ uint32_t nbbytePartialHash = (((hhash->Instance->SR) >> 16U) * 4U); /* Nb byte to enter in HASH fifo to trig a partial HASH computation*/ uint32_t sizeinwords;/* number in word of source block to be transferred.*/ /* suspension in DMA mode*/ if (__HAL_HASH_GET_FLAG(hhash, HASH_FLAG_DMAS) != RESET) { if (hhash->State == HAL_HASH_STATE_READY) { return HAL_ERROR; } else { /* Clear the DMAE bit to disable the DMA interface */ CLEAR_BIT(HASH->CR, HASH_CR_DMAE); /* Wait until the last DMA transfer is complete (DMAS = 0 in the HASH_SR register) */ if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_DMAS, SET, HASH_TIMEOUTVALUE) != HAL_OK) { return HAL_TIMEOUT; } /* At this point, DMA interface is disabled and no transfer is on-going */ /* Retrieve from the DMA handle how many words remain to be written */ /* DMA3 used, DMA_CBR1_BNDT in bytes, DMA_CSR_FIFOL in words */ remainingwords = ((((DMA_Channel_TypeDef *)hhash->hdmain->Instance)->CBR1) \ & DMA_CBR1_BNDT) / 4U; remainingwords += ((((DMA_Channel_TypeDef *)hhash->hdmain->Instance)->CSR) \ & DMA_CSR_FIFOL) >> DMA_CSR_FIFOL_Pos; if (remainingwords <= nbbytePartialHash) { /* No suspension attempted since almost to the end of the transferred data. */ /* Best option for user code is to wrap up low priority message hashing */ return HAL_ERROR; } /* Disable DMA channel */ /* Note that the Abort function will - Clear the transfer error flags - Unlock - Set the State */ if (HAL_DMA_Abort(hhash->hdmain) != HAL_OK) { return HAL_ERROR; } if (__HAL_HASH_GET_FLAG(hhash, HASH_FLAG_DCIS) != RESET) { return HAL_ERROR; } /* Wait until the hash processor is ready (no block is being processed), that is wait for DINIS=1 in HASH_SR */ if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_DINIS, RESET, HASH_TIMEOUTVALUE) != HAL_OK) { return HAL_TIMEOUT; } /* Compute how many words were supposed to be transferred by DMA */ sizeinwords = (((hhash->Size % 4U) != 0U) ? \ ((hhash->Size + 3U) / 4U) : (hhash->Size / 4U)); /* Accordingly, update the input pointer that points at the next word to be transferred to the Peripheral by DMA */ hhash->pHashInBuffPtr += 4U * (sizeinwords - remainingwords) ; /* And store in HashInCount the remaining size to transfer (in bytes) */ hhash->HashInCount = 4U * remainingwords; hhash->State = HAL_HASH_STATE_SUSPENDED; __HAL_UNLOCK(hhash); return HAL_OK; } } else /* suspension when in interruption mode*/ { /* Set Handle Suspend Request field */ hhash->SuspendRequest = HAL_HASH_SUSPEND; return HAL_OK; } } #endif /* USE_HAL_HASH_SUSPEND_RESUME */ /** * @} */ /** @defgroup HASH_Exported_Functions_Group2 HASH processing functions * @brief HASH processing functions using different mode. * @verbatim =============================================================================== ##### HASH processing functions ##### =============================================================================== [..] This section provides API allowing to calculate the hash value using one of the HASH algorithms supported by the peripheral. [..] For a single buffer to be hashed, user can resort to one of three processing functions available . (+) Polling mode : HAL_HASH_Start() (+) Interrupt mode : HAL_HASH_Start_IT() (+) DMA mode : HAL_HASH_Start_DMA() [..] In case of multi-buffer HASH processing (a single digest is computed while several buffers are fed to the Peripheral), the user can resort to successive calls to : (+) Polling mode : HAL_HASH_Accumulate() and wrap-up the digest computation by a call to HAL_HASH_AccumulateLast() (+) Interrupt mode : HAL_HASH_Accumulate_IT() and wrap-up the digest computation by a call to HAL_HASH_AccumulateLast_IT() (+) DMA mode : HAL_HASH_Start_DMA(), MDMAT bit must be set through __HAL_HASH_SET_MDMAT() macro, before entering the last buffer, reset the MDMAT bit with __HAL_HASH_RESET_MDMAT() macro then wrap-up the HASH processing in feeding the last input buffer through the same API HAL_HASH_Start_DMA() @endverbatim * @{ */ /** * @brief HASH peripheral processes in polling mode pInBuffer then reads the computed digest. * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes. * @param pOutBuffer pointer to the computed digest. * @param Timeout specify timeout value * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_Start(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size, uint8_t *const pOutBuffer, uint32_t Timeout) { /* Check the hash handle allocation */ if (hhash == NULL) { return HAL_ERROR; } /* Check if peripheral is ready to start process */ if (hhash->State == HAL_HASH_STATE_READY) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Reset HashInCount and Initialize Size, pHashInBuffPtr and pHashOutBuffPtr parameters */ hhash->pHashInBuffPtr = pInBuffer; hhash->pHashOutBuffPtr = pOutBuffer; hhash->HashInCount = 0U; hhash->Size = Size; /* Set HASH mode */ CLEAR_BIT(hhash->Instance->CR, HASH_CR_MODE); /* Reset the HASH processor core */ MODIFY_REG(hhash->Instance->CR, HASH_CR_INIT, HASH_CR_INIT); /* Configure the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * (Size % 4U)); /* Set the phase */ hhash->Phase = HAL_HASH_PHASE_PROCESS; HASH_WriteData(hhash, pInBuffer, Size); /* Start the message padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for digest calculation completion status(DCIS) flag to be set */ if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_DCIS, RESET, Timeout) != HAL_OK) { return HAL_ERROR; } /* Read the message digest */ HASH_GetDigest(hhash, pOutBuffer, HASH_DIGEST_LENGTH(hhash)); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_READY; /* Reset HASH state machine */ hhash->Phase = HAL_HASH_PHASE_READY; /* Process Unlocked */ __HAL_UNLOCK(hhash); /* Return function status */ return HAL_OK; } else { return HAL_BUSY; } } /** * @brief HASH peripheral processes in interrupt mode pInBuffer then reads the computed digest. * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes. * @param pOutBuffer pointer to the computed digest. * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_Start_IT(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size, uint8_t *const pOutBuffer) { HAL_StatusTypeDef status; HAL_HASH_StateTypeDef temp_state; /* Check the hash handle allocation */ if (hhash == NULL) { return HAL_ERROR; } /* Check if peripheral is ready to start process or suspended */ temp_state = hhash->State; if ((temp_state == HAL_HASH_STATE_READY) || (temp_state == HAL_HASH_STATE_SUSPENDED)) { /* Process Locked */ __HAL_LOCK(hhash); if (hhash->State == HAL_HASH_STATE_READY) { /* Reset HashInCount and Initialize Size, pHashInBuffPtr and pHashOutBuffPtr parameters */ hhash->HashInCount = 0U; hhash->pHashInBuffPtr = pInBuffer; hhash->pHashOutBuffPtr = pOutBuffer; hhash->Size = Size; /* Set HASH mode */ CLEAR_BIT(hhash->Instance->CR, HASH_CR_MODE); /* Reset the HASH processor core */ MODIFY_REG(hhash->Instance->CR, HASH_CR_INIT, HASH_CR_INIT); /* Configure the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * (Size % 4U)); } /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Set the phase */ hhash->Phase = HAL_HASH_PHASE_PROCESS; /* Enable the specified HASH interrupt*/ __HAL_HASH_ENABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); status = HASH_WriteData_IT(hhash); } else { status = HAL_BUSY; } /* Return function status */ return status; } /** * @brief HASH peripheral processes in DMA mode pInBuffer then reads the computed digest. * @note Multi-buffer HASH processing is possible, consecutive calls to HAL_HASH_Start_DMA * (MDMAT bit must be set) can be used to feed several input buffers * back-to-back to the Peripheral that will yield a single * HASH signature once all buffers have been entered. Wrap-up of input * buffers feeding and retrieval of digest is done by a call to * HAL_HASH_Start_DMA (MDMAT bit must be reset). * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes (must be a multiple of 4 in * case of Multi-buffer and not last buffer). * @param pOutBuffer pointer to the computed digest. * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_Start_DMA(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size, uint8_t *const pOutBuffer) { HAL_StatusTypeDef status; HAL_HASH_StateTypeDef temp_state; /* Check the hash handle allocation */ if (hhash == NULL) { return HAL_ERROR; } /* Check if peripheral is ready to start process or suspended */ temp_state = hhash->State; if ((temp_state == HAL_HASH_STATE_READY) || (temp_state == HAL_HASH_STATE_SUSPENDED)) { /* Process Locked */ __HAL_LOCK(hhash); /* Check if initialization phase has not been already performed */ if (hhash->State == HAL_HASH_STATE_READY) { /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Reset HashInCount and Initialize Size, pHashInBuffPtr and pHashOutBuffPtr parameters */ hhash->HashInCount = 0U; hhash->pHashInBuffPtr = pInBuffer; hhash->pHashOutBuffPtr = pOutBuffer; hhash->HashInCount = 0U; hhash->Size = Size; /* Check if initialization phase has already been performed. If Phase is already set to HAL_HASH_PHASE_PROCESS, this means the API is processing a new input data message in case of multi-buffer HASH computation. */ if (hhash->Phase == HAL_HASH_PHASE_READY) { /* Set HASH mode */ CLEAR_BIT(hhash->Instance->CR, HASH_CR_MODE); /* Reset the HASH processor core */ MODIFY_REG(hhash->Instance->CR, HASH_CR_INIT, HASH_CR_INIT); /* Set the phase */ hhash->Phase = HAL_HASH_PHASE_PROCESS; } /* Configure the number of valid bits in last word of the message */ if ((hhash->Instance->CR & HASH_CR_MDMAT) == 0U) { /* Configure the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * ((hhash->Size) % 4U)); } else { /* Configure the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 0U); } } else /* HAL_HASH_STATE_SUSPENDED */ { /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /*only part not yet hashed to compute */ hhash->Size = hhash->HashInCount; } /* Set the HASH DMA transfer complete callback */ hhash->hdmain->XferCpltCallback = HASH_DMAXferCplt; /* Set the DMA error callback */ hhash->hdmain->XferErrorCallback = HASH_DMAError; if ((hhash->hdmain->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST) { if ((hhash->hdmain->LinkedListQueue != NULL) && (hhash->hdmain->LinkedListQueue->Head != NULL)) { /* Enable the DMA channel */ hhash->hdmain->LinkedListQueue->Head->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET]\ = ((((hhash->Size) % 4U) != 0U) ? ((hhash->Size) + (4U - ((hhash->Size) % 4U))) : (hhash->Size)); hhash->hdmain->LinkedListQueue->Head->LinkRegisters[NODE_CSAR_DEFAULT_OFFSET]\ = (uint32_t)(hhash->pHashInBuffPtr); /* Set DMA source address */ hhash->hdmain->LinkedListQueue->Head->LinkRegisters[NODE_CDAR_DEFAULT_OFFSET]\ = (uint32_t)&hhash->Instance->DIN; /* Set DMA destination address */ status = HAL_DMAEx_List_Start_IT(hhash->hdmain); } else { /* Return error status */ status = HAL_ERROR; } } else { status = HAL_DMA_Start_IT(hhash->hdmain, (uint32_t)pInBuffer, (uint32_t)&hhash->Instance->DIN, \ ((((hhash->Size) % 4U) != 0U) ? ((hhash->Size) + (4U - ((hhash->Size) % 4U))) : \ (hhash->Size))); } if (status != HAL_OK) { /* DMA error code field */ hhash->ErrorCode |= HAL_HASH_ERROR_DMA; /* Return error */ #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1U) /*Call registered error callback*/ hhash->ErrorCallback(hhash); #else /*Call legacy weak error callback*/ HAL_HASH_ErrorCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ } else { /* Enable DMA requests */ SET_BIT(hhash->Instance->CR, HASH_CR_DMAE); } } else { status = HAL_BUSY; } /* Return function status */ return status; } /** * @brief HASH peripheral processes in polling mode several input buffers. * @note Consecutive calls to HAL_HASH_Accumulate() can be used to feed * several input buffers back-to-back to the Peripheral that will yield a single * HASH signature once all buffers have been entered. Wrap-up of input * buffers feeding and retrieval of digest is done by a call to * HAL_HASH_AccumulateLast() * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes and a multiple of 4. * @param Timeout specify timeout value * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_Accumulate(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size, uint32_t Timeout) { HAL_HASH_StateTypeDef temp_state; /* Check the hash handle allocation and buffer length multiple of 4 */ if ((hhash == NULL) || ((Size % 4U) != 0U)) { return HAL_ERROR; } /* Check if peripheral is ready to start process or suspended */ temp_state = hhash->State; if ((temp_state == HAL_HASH_STATE_READY) || (temp_state == HAL_HASH_STATE_SUSPENDED)) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Reset HashInCount and Initialize Size, pHashInBuffPtr and pHashOutBuffPtr parameters */ hhash->pHashInBuffPtr = pInBuffer; hhash->HashInCount = 0U; hhash->Size = Size; if (hhash->Phase == HAL_HASH_PHASE_READY) { /* Set HASH mode */ CLEAR_BIT(hhash->Instance->CR, HASH_CR_MODE); /* Reset the HASH processor core */ MODIFY_REG(hhash->Instance->CR, HASH_CR_INIT, HASH_CR_INIT); /* Set the phase */ hhash->Phase = HAL_HASH_PHASE_PROCESS; } HASH_WriteData(hhash, pInBuffer, Size); /* Wait for BUSY flag to be cleared */ if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, Timeout) != HAL_OK) { return HAL_ERROR; } /* Change the HASH state */ hhash->State = HAL_HASH_STATE_READY; /* Process Unlocked */ __HAL_UNLOCK(hhash); return HAL_OK; } else { return HAL_BUSY; } } /** * @brief End computation of a single HASH signature after several calls to HAL_HASH_Accumulate() API. * @note Digest is available in pOutBuffer * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes. * @param pOutBuffer pointer to the computed digest. * @param Timeout specify timeout value * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_AccumulateLast(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size, uint8_t *const pOutBuffer, uint32_t Timeout) { HAL_HASH_StateTypeDef temp_state; /* Check the hash handle allocation */ if (hhash == NULL) { return HAL_ERROR; } /* Check if peripheral is ready to start process or suspended */ temp_state = hhash->State; if ((temp_state == HAL_HASH_STATE_READY) || (temp_state == HAL_HASH_STATE_SUSPENDED)) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Reset HashInCount and Initialize Size, pHashInBuffPtr and pHashOutBuffPtr parameters */ hhash->pHashInBuffPtr = pInBuffer; hhash->pHashOutBuffPtr = pOutBuffer; hhash->HashInCount = 0U; hhash->Size = Size; if (hhash->Phase == HAL_HASH_PHASE_READY) { /* Set HASH mode */ CLEAR_BIT(hhash->Instance->CR, HASH_CR_MODE); /* Reset the HASH processor core */ MODIFY_REG(hhash->Instance->CR, HASH_CR_INIT, HASH_CR_INIT); /* Set the phase */ hhash->Phase = HAL_HASH_PHASE_PROCESS; } /* Configure the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * (Size % 4U)); HASH_WriteData(hhash, pInBuffer, Size); /* Start the message padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for digest calculation completion status(DCIS) flag to be set */ if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_DCIS, RESET, Timeout) != HAL_OK) { return HAL_ERROR; } /* Read the message digest */ HASH_GetDigest(hhash, pOutBuffer, HASH_DIGEST_LENGTH(hhash)); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_READY; /* Reset HASH state machine */ hhash->Phase = HAL_HASH_PHASE_READY; hhash->Accumulation = 0; /* Process Unlocked */ __HAL_UNLOCK(hhash); return HAL_OK; } else { return HAL_BUSY; } } /** * @brief HASH peripheral processes in interrupt mode several input buffers. * @note Consecutive calls to HAL_HASH_Accumulate_IT() can be used to feed * several input buffers back-to-back to the Peripheral that will yield a single * HASH signature once all buffers have been entered. Wrap-up of input * buffers feeding and retrieval of digest is done by a call to * HAL_HASH_AccumulateLast_IT() * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes and a multiple of 4. * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_Accumulate_IT(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size) { HAL_StatusTypeDef status; /* Check the hash handle allocation */ if ((hhash == NULL) || ((Size % 4U) != 0U)) { return HAL_ERROR; } /* Check if peripheral is ready to start process */ if (hhash->State == HAL_HASH_STATE_READY) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Reset HashInCount and Initialize Size and pHashInBuffPtr parameters */ hhash->pHashInBuffPtr = pInBuffer; hhash->HashInCount = 0U; hhash->Size = Size; /* Set multi buffers accumulation flag */ hhash->Accumulation = 1U; if (hhash->Phase == HAL_HASH_PHASE_READY) { /* Set HASH mode */ CLEAR_BIT(hhash->Instance->CR, HASH_CR_MODE); /* Reset the HASH processor core */ MODIFY_REG(hhash->Instance->CR, HASH_CR_INIT, HASH_CR_INIT); /* Set the phase */ hhash->Phase = HAL_HASH_PHASE_PROCESS; } /* Enable the specified HASH interrupt*/ __HAL_HASH_ENABLE_IT(hhash, HASH_IT_DINI); status = HASH_WriteData_IT(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_READY; /* Process Unlocked */ __HAL_UNLOCK(hhash); } else { status = HAL_BUSY; } /* Return function status */ return status; } /** * @brief End computation of a single HASH signature after several calls to HAL_HASH_Accumulate_IT() API. * @note Digest is available in pOutBuffer * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes. * @param pOutBuffer pointer to the computed digest. * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_AccumulateLast_IT(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size, uint8_t *const pOutBuffer) { HAL_StatusTypeDef status; /* Check the hash handle allocation */ if (hhash == NULL) { return HAL_ERROR; } /* Check if peripheral is ready to start process */ if (hhash->State == HAL_HASH_STATE_READY) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Reset HashInCount and Initialize Size, pHashInBuffPtr and pHashOutBuffPtr parameters */ hhash->pHashInBuffPtr = pInBuffer; hhash->pHashOutBuffPtr = pOutBuffer; hhash->HashInCount = 0U; hhash->Size = Size; if (hhash->Phase == HAL_HASH_PHASE_READY) { /* Set HASH mode */ CLEAR_BIT(hhash->Instance->CR, HASH_CR_MODE); /* Reset the HASH processor core */ MODIFY_REG(hhash->Instance->CR, HASH_CR_INIT, HASH_CR_INIT); /* Set the phase */ hhash->Phase = HAL_HASH_PHASE_PROCESS; } /* Configure the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * (Size % 4U)); /* Enable the specified HASH interrupt*/ __HAL_HASH_ENABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); status = HASH_WriteData_IT(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_READY; /* Reset HASH state machine */ hhash->Phase = HAL_HASH_PHASE_READY; /* Process Unlocked */ __HAL_UNLOCK(hhash); } else { status = HAL_BUSY; } /* Return function status */ return status; } /** * @} */ /** @defgroup HASH_Exported_Functions_Group3 HMAC processing functions * @brief HMAC processing functions using different mode. * @verbatim =============================================================================== ##### HMAC processing functions ##### =============================================================================== [..] This section provides API allowing to calculate the HMAC (keyed-hash message authentication code) value using: (+) one of the algorithms supported by the peripheral (+) Key selection (++) Long key : HMAC key is longer than the block size (++) Short key : HMAC key is shorter or equal to the block size [..] To calculate the HMAC for a single buffer, user can resort to one of three processing functions available . (+) Polling mode : HAL_HASH_HMAC_Start() (+) Interrupt mode : HAL_HASH_HMAC_Start_IT() (+) DMA mode : HAL_HASH_HMAC_Start_DMA() [..] In case of multi-buffer HMAC processing (a single digest is computed while several buffers are fed to the Peripheral), the user can resort to successive calls to : (+) Polling mode : HAL_HASH_HMAC_Accumulate() and wrap-up the digest computation by a call to HAL_HASH_HMAC_AccumulateLast() (+) Interrupt mode : HAL_HASH_HMAC_Accumulate_IT() and wrap-up the digest computation by a call to HAL_HASH_HMAC_AccumulateLast_IT() (+) DMA mode : HAL_HASH_HMAC_Start_DMA(),MDMAT bit must be set through __HAL_HASH_SET_MDMAT() macro, before entering the last buffer, reset the MDMAT bit with __HAL_HASH_RESET_MDMAT() macro then wrap-up the HMAC processing in feeding the last input buffer through the same API HAL_HASH_HMAC_Start_DMA() @endverbatim * @{ */ /** * @brief HMAC in polling mode, HASH peripheral processes Key then pInBuffer then reads the computed digest. * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes. * @param pOutBuffer pointer to the computed digest. * @param Timeout specify timeout value * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_HMAC_Start(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size, uint8_t *const pOutBuffer, uint32_t Timeout) { uint32_t blocksize; /* Block size in bytes */ /* Check the hash handle allocation */ if (hhash == NULL) { return HAL_ERROR; } /* Check if peripheral is ready to start process */ if (hhash->State == HAL_HASH_STATE_READY) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Reset HASH Phase */ hhash->Phase = HAL_HASH_PHASE_READY; /* Reset HashInCount and Initialize Size, pHashKeyBuffPtr, pHashInBuffPtr and pHashOutBuffPtr parameters */ hhash->pHashInBuffPtr = pInBuffer; hhash->pHashOutBuffPtr = pOutBuffer; hhash->pHashKeyBuffPtr = hhash->Init.pKey; hhash->HashInCount = 0U; hhash->Size = Size; /* Check if key size is larger than block size of the algorithm, accordingly set LKEY and the other setting bits */ if ((hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA1) || (hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA224) || (hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA256)) { blocksize = 64U; } else { blocksize = 128U; } if (hhash->Init.KeySize > blocksize) { MODIFY_REG(hhash->Instance->CR, HASH_CR_LKEY | HASH_CR_MODE | HASH_CR_INIT, HASH_ALGOMODE_HMAC | HASH_LONGKEY | HASH_CR_INIT); } else { MODIFY_REG(hhash->Instance->CR, HASH_CR_LKEY | HASH_CR_MODE | HASH_CR_INIT, HASH_ALGOMODE_HMAC | HASH_CR_INIT); } /* Configure the number of valid bits in last word of the Key */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * ((hhash->Init.KeySize) % 4U)); /* Set the phase */ hhash->Phase = HAL_HASH_PHASE_PROCESS; /* Write Key */ HASH_WriteData(hhash, hhash->Init.pKey, hhash->Init.KeySize); /* Start the Key padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for BUSY flag to be cleared */ if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, Timeout) != HAL_OK) { return HAL_ERROR; } /* Configure the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * (Size % 4U)); /* Write message */ HASH_WriteData(hhash, pInBuffer, Size); /* Start the message padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for BUSY flag to be cleared */ if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, Timeout) != HAL_OK) { return HAL_ERROR; } /* Configure the number of valid bits in last word of the Key */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * ((hhash->Init.KeySize) % 4U)); /* Write Key */ HASH_WriteData(hhash, hhash->Init.pKey, hhash->Init.KeySize); /* Start the Key padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for digest calculation completion status(DCIS) flag to be set */ if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_DCIS, RESET, Timeout) != HAL_OK) { return HAL_ERROR; } /* Read the message digest */ HASH_GetDigest(hhash, pOutBuffer, HASH_DIGEST_LENGTH(hhash)); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_READY; /* Change the HASH phase */ hhash->Phase = HAL_HASH_PHASE_READY; /* Process Unlocked */ __HAL_UNLOCK(hhash); /* Return function status */ return HAL_OK; } else { return HAL_BUSY; } } /** * @brief HMAC accumulate mode, HASH peripheral processes Key then several input buffers. * @note Consecutive calls to HAL_HASH_HMAC_Accumulate() can be used to feed * several input buffers back-to-back to the Peripheral that will yield a single * HASH signature once all buffers have been entered. Wrap-up of input * buffers feeding and retrieval of digest is done by a call to * HAL_HASH_HMAC_AccumulateLast() * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes and a multiple of 4 * @param Timeout specify timeout value * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_HMAC_Accumulate(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size, uint32_t Timeout) { uint32_t blocksize; /* Block size in bytes */ /* Check the hash handle allocation and buffer length multiple of 4 */ if ((hhash == NULL) || ((Size % 4U) != 0U)) { return HAL_ERROR; } /* Check if peripheral is ready to start process */ if (hhash->State == HAL_HASH_STATE_READY) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Initialize Size, pHashInBuffPtr and pHashKeyBuffPtr parameters */ hhash->pHashInBuffPtr = pInBuffer; hhash->pHashKeyBuffPtr = hhash->Init.pKey; hhash->Size = Size; if (hhash->Phase == HAL_HASH_PHASE_READY) { /* Reset HashInCount parameter */ hhash->HashInCount = 0U; /* Check if key size is larger than 64 bytes, accordingly set LKEY and the other setting bits */ /* Check if key size is larger than block size of the algorithm, accordingly set LKEY and the other setting */ if ((hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA1) || (hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA224) || (hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA256)) { blocksize = 64U; } else { blocksize = 128U; } if (hhash->Init.KeySize > blocksize) { MODIFY_REG(hhash->Instance->CR, HASH_CR_LKEY | HASH_CR_MODE | HASH_CR_INIT, HASH_ALGOMODE_HMAC | HASH_LONGKEY | HASH_CR_INIT); } else { MODIFY_REG(hhash->Instance->CR, HASH_CR_LKEY | HASH_CR_MODE | HASH_CR_INIT, HASH_ALGOMODE_HMAC | HASH_CR_INIT); } /* Set phase process */ hhash->Phase = HAL_HASH_PHASE_PROCESS; /* Configure the number of valid bits in last word of the Key */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * ((hhash->Init.KeySize) % 4U)); /* Write Key */ HASH_WriteData(hhash, hhash->Init.pKey, hhash->Init.KeySize); /* Start the Key padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for BUSY flag to be cleared */ if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, Timeout) != HAL_OK) { return HAL_ERROR; } } /* Change the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 0U); /* Write message */ HASH_WriteData(hhash, pInBuffer, Size); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_READY; /* Process Unlocked */ __HAL_UNLOCK(hhash); /* Return function status */ return HAL_OK; } else { return HAL_BUSY; } } /** * @brief End computation of a single HMAC signature after several calls to HAL_HASH_HMAC_Accumulate() API. * @note Digest is available in pOutBuffer * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes. * @param pOutBuffer pointer to the computed digest. * @param Timeout specify timeout value * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_HMAC_AccumulateLast(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size, uint8_t *const pOutBuffer, uint32_t Timeout) { /* Check the hash handle allocation */ if (hhash == NULL) { return HAL_ERROR; } /* Check if peripheral is ready to start process */ if (hhash->State == HAL_HASH_STATE_READY) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Initialize Size, pHashInBuffPtr, pHashKeyBuffPtr and pHashOutBuffPtr parameters */ hhash->pHashInBuffPtr = pInBuffer; hhash->pHashOutBuffPtr = pOutBuffer; hhash->pHashKeyBuffPtr = hhash->Init.pKey; hhash->Size = Size; if (hhash->Phase != HAL_HASH_PHASE_PROCESS) { return HAL_ERROR; } else { /* Configure the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * (Size % 4U)); /* Write message */ HASH_WriteData(hhash, pInBuffer, Size); /* Start the message padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for BUSY flag to be cleared */ if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, Timeout) != HAL_OK) { return HAL_ERROR; } /* Configure the number of valid bits in last word of the Key */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * ((hhash->Init.KeySize) % 4U)); /* Write Key */ HASH_WriteData(hhash, hhash->Init.pKey, hhash->Init.KeySize); /* Start the Key padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for digest calculation completion status(DCIS) flag to be set */ if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_DCIS, RESET, Timeout) != HAL_OK) { return HAL_ERROR; } /* Read the message digest */ HASH_GetDigest(hhash, pOutBuffer, HASH_DIGEST_LENGTH(hhash)); } /* Change the HASH state */ hhash->State = HAL_HASH_STATE_READY; /* Reset HASH state machine */ hhash->Phase = HAL_HASH_PHASE_READY; /* Process Unlocked */ __HAL_UNLOCK(hhash); /* Return function status */ return HAL_OK; } else { return HAL_BUSY; } } /** * @brief HMAC in interrupt mode, HASH peripheral process Key then pInBuffer then read the computed digest. * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes. * @param pOutBuffer pointer to the computed digest. * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_HMAC_Start_IT(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size, uint8_t *const pOutBuffer) { HAL_StatusTypeDef status; uint32_t blocksize; /* Block size in bytes */ /* Check the hash handle allocation */ if (hhash == NULL) { return HAL_ERROR; } /* Check if peripheral is ready to start process */ if (hhash->State == HAL_HASH_STATE_READY) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Reset HASH Phase */ hhash->Phase = HAL_HASH_PHASE_READY; /* Reset HashInCount and Initialize Size, pHashKeyBuffPtr, pHashInBuffPtr and pHashOutBuffPtr parameters */ hhash->pHashInBuffPtr = pInBuffer; hhash->pHashOutBuffPtr = pOutBuffer; hhash->pHashKeyBuffPtr = hhash->Init.pKey; hhash->HashInCount = 0U; hhash->Size = Size; /* Check if key size is larger than block size of the algorithm, accordingly set LKEY and the other setting bits */ if ((hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA1) || (hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA224) || (hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA256)) { blocksize = 64U; } else { blocksize = 128U; } if (hhash->Init.KeySize > blocksize) { MODIFY_REG(hhash->Instance->CR, HASH_CR_LKEY | HASH_CR_MODE | HASH_CR_INIT, HASH_ALGOMODE_HMAC | HASH_LONGKEY | HASH_CR_INIT); } else { MODIFY_REG(hhash->Instance->CR, HASH_CR_LKEY | HASH_CR_MODE | HASH_CR_INIT, HASH_ALGOMODE_HMAC | HASH_CR_INIT); } /* Configure the number of valid bits in last word of the Key */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * ((hhash->Init.KeySize) % 4U)); /* Set the phase */ hhash->Phase = HAL_HASH_PHASE_PROCESS; } else if (hhash->State == HAL_HASH_STATE_SUSPENDED) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; } else { return HAL_BUSY; } /* Enable the specified HASH interrupt*/ __HAL_HASH_ENABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); status = HASH_WriteData_IT(hhash); /* Return function status */ return status; } /** * @brief HMAC accumulate in interrupt mode, HASH peripheral processes Key then several input buffers. * @note Consecutive calls to HAL_HASH_HMAC_Accumulate_IT() can be used to feed * several input buffers back-to-back to the Peripheral that will yield a single * HASH signature once all buffers have been entered. Wrap-up of input * buffers feeding and retrieval of digest is done by a call to * HAL_HASH_HMAC_AccumulateLast_IT() * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes and a multiple of 4. * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_HMAC_Accumulate_IT(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size) { HAL_StatusTypeDef status; uint32_t blocksize; /* Block size in bytes */ /* Check the hash handle allocation and buffer length multiple of 4 */ if ((hhash == NULL) || ((Size % 4U) != 0U)) { return HAL_ERROR; } /* Check if peripheral is ready to start process */ if (hhash->State == HAL_HASH_STATE_READY) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Reset HashInCount and Initialize Size, pHashInBuffPtr and pHashOutBuffPtr parameters */ hhash->pHashInBuffPtr = pInBuffer; hhash->pHashKeyBuffPtr = hhash->Init.pKey; hhash->HashInCount = 0U; hhash->Size = Size; /* Set multi buffers accumulation flag */ hhash->Accumulation = 1U; if (hhash->Phase == HAL_HASH_PHASE_READY) { /* Check if key size is larger than block size of the algorithm, accordingly set LKEY and the other setting */ if ((hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA1) || (hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA224) || (hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA256)) { blocksize = 64U; } else { blocksize = 128U; } if (hhash->Init.KeySize > blocksize) { MODIFY_REG(hhash->Instance->CR, HASH_CR_LKEY | HASH_CR_MODE | HASH_CR_INIT, HASH_ALGOMODE_HMAC | HASH_LONGKEY | HASH_CR_INIT); } else { MODIFY_REG(hhash->Instance->CR, HASH_CR_LKEY | HASH_CR_MODE | HASH_CR_INIT, HASH_ALGOMODE_HMAC | HASH_CR_INIT); } /* Configure the number of valid bits in last word of the Key */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * ((hhash->Init.KeySize) % 4U)); /* Set the phase */ hhash->Phase = HAL_HASH_PHASE_PROCESS; } /* Enable the specified HASH interrupt*/ __HAL_HASH_ENABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); status = HASH_WriteData_IT(hhash); } else { status = HAL_BUSY; } /* Return function status */ return status; } /** * @brief End computation of a single HMAC signature in interrupt mode, after * several calls to HAL_HASH_HMAC_Accumulate() API. * @note Digest is available in pOutBuffer * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes. * @param pOutBuffer pointer to the computed digest. * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_HMAC_AccumulateLast_IT(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size, uint8_t *const pOutBuffer) { HAL_StatusTypeDef status; /* Check the hash handle allocation */ if (hhash == NULL) { return HAL_ERROR; } /* Check if peripheral is ready to start process*/ if (hhash->State == HAL_HASH_STATE_READY) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Reset HashInCount and Initialize Size, pHashInBuffPtr and pHashOutBuffPtr parameters */ hhash->pHashInBuffPtr = pInBuffer; hhash->pHashOutBuffPtr = pOutBuffer; hhash->pHashKeyBuffPtr = hhash->Init.pKey; hhash->HashInCount = 0U; hhash->Size = Size; /* Set multi buffers accumulation flag */ hhash->Accumulation = 0U; /* Enable the specified HASH interrupt*/ __HAL_HASH_ENABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); status = HASH_WriteData_IT(hhash); } else { status = HAL_BUSY; } /* Return function status */ return status; } /** * @brief HMAC in DMA mode,HASH peripheral processes Key then pInBuffer in DMA mode * then read the computed digest. * @note Multi-buffer HMAC processing is possible, consecutive calls to HAL_HASH_HMAC_Start_DMA * (MDMAT bit must be set) can be used to feed several input buffers * back-to-back to the Peripheral that will yield a single * HASH signature once all buffers have been entered. Wrap-up of input * buffers feeding and retrieval of digest is done by a call to * HAL_HASH_HMAC_Start_DMA (MDMAT bit must be reset). * @param hhash HASH handle. * @param pInBuffer pointer to the input buffer (buffer to be hashed). * @param Size length of the input buffer in bytes. * @param pOutBuffer pointer to the computed digest. * @retval HAL status */ HAL_StatusTypeDef HAL_HASH_HMAC_Start_DMA(HASH_HandleTypeDef *hhash, const uint8_t *const pInBuffer, uint32_t Size, uint8_t *const pOutBuffer) { HAL_StatusTypeDef status; uint32_t count; uint32_t blocksize; /* Block size in bytes */ /* Check the hash handle allocation */ if (hhash == NULL) { return HAL_ERROR; } /* Check if peripheral is ready to start process*/ if (hhash->State == HAL_HASH_STATE_READY) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /* Reset HashInCount and Initialize Size, pHashInBuffPtr and pHashOutBuffPtr parameters */ hhash->pHashInBuffPtr = pInBuffer; hhash->pHashOutBuffPtr = pOutBuffer; hhash->pHashKeyBuffPtr = hhash->Init.pKey; hhash->HashInCount = 0U; hhash->Size = Size; /* Set the phase */ if (hhash->Phase == HAL_HASH_PHASE_READY) { /* Check if key size is larger than block size of the algorithm, accordingly set LKEY and the other setting */ if ((hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA1) || (hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA224) || (hhash->Init.Algorithm == HASH_ALGOSELECTION_SHA256)) { blocksize = 64U; } else { blocksize = 128U; } if (hhash->Init.KeySize > blocksize) { MODIFY_REG(hhash->Instance->CR, HASH_CR_LKEY | HASH_CR_MODE | HASH_CR_INIT, HASH_ALGOMODE_HMAC | HASH_LONGKEY | HASH_CR_INIT); } else { MODIFY_REG(hhash->Instance->CR, HASH_CR_LKEY | HASH_CR_MODE | HASH_CR_INIT, HASH_ALGOMODE_HMAC | HASH_CR_INIT); } /* Set the phase */ hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_1; /* Configure the number of valid bits in last word of the Key */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * ((hhash->Init.KeySize) % 4U)); /* Write Key */ HASH_WriteData(hhash, hhash->Init.pKey, hhash->Init.KeySize); /* Start the Key padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for DCIS flag to be set */ count = HASH_TIMEOUTVALUE; do { count--; if (count == 0U) { /* Change state */ hhash->ErrorCode |= HAL_HASH_ERROR_TIMEOUT; hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); return HAL_ERROR; } } while (HAL_IS_BIT_CLR(hhash->Instance->SR, HASH_FLAG_BUSY)); } hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_2; if ((hhash->Instance->CR & HASH_CR_MDMAT) == 0U) { /* Configure the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * ((hhash->Size) % 4U)); } else { /* Configure the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 0U); } } else if (hhash->State == HAL_HASH_STATE_SUSPENDED) { /* Process Locked */ __HAL_LOCK(hhash); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_BUSY; /*only part not yet hashed to compute */ hhash->Size = hhash->HashInCount; } else { /* Return busy status */ return HAL_BUSY; } /* Set the HASH DMA transfer complete callback */ hhash->hdmain->XferCpltCallback = HASH_DMAXferCplt; /* Set the DMA error callback */ hhash->hdmain->XferErrorCallback = HASH_DMAError; if ((hhash->hdmain->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST) { if ((hhash->hdmain->LinkedListQueue != NULL) && (hhash->hdmain->LinkedListQueue->Head != NULL)) { /* Enable the DMA channel */ hhash->hdmain->LinkedListQueue->Head->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET]\ = ((((hhash->Size) % 4U) != 0U) ? ((hhash->Size) + (4U - ((hhash->Size) % 4U))) : ((hhash->Size))); hhash->hdmain->LinkedListQueue->Head->LinkRegisters[NODE_CSAR_DEFAULT_OFFSET]\ = (uint32_t)(hhash->pHashInBuffPtr); /* Set DMA source address */ hhash->hdmain->LinkedListQueue->Head->LinkRegisters[NODE_CDAR_DEFAULT_OFFSET]\ = (uint32_t)&hhash->Instance->DIN; /* Set DMA destination address */ status = HAL_DMAEx_List_Start_IT(hhash->hdmain); } else { /* Return error status */ status = HAL_ERROR; } } else { status = HAL_DMA_Start_IT(hhash->hdmain, (uint32_t)(hhash->pHashInBuffPtr), (uint32_t)&hhash->Instance->DIN, \ ((((hhash->Size) % 4U) != 0U) ? ((hhash->Size) + (4U - ((hhash->Size) % 4U))) : \ ((hhash->Size)))); } if (status != HAL_OK) { /* DMA error code field */ hhash->ErrorCode |= HAL_HASH_ERROR_DMA; /* Return error */ #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1U) /*Call registered error callback*/ hhash->ErrorCallback(hhash); #else /*Call legacy weak error callback*/ HAL_HASH_ErrorCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ } else { /* Enable DMA requests */ SET_BIT(hhash->Instance->CR, HASH_CR_DMAE); } /* Return function status */ return status; } /** * @} */ /** @defgroup HASH_Exported_Functions_Group4 HASH IRQ handler management * @brief HASH IRQ handler. * @verbatim ============================================================================== ##### HASH IRQ handler management ##### ============================================================================== [..] This section provides HASH IRQ handler and callback functions. (+) HAL_HASH_IRQHandler HASH interrupt request (+) HAL_HASH_InCpltCallback input data transfer complete callback (+) HAL_HASH_DgstCpltCallback digest computation complete callback (+) HAL_HASH_ErrorCallback HASH error callback (+) HAL_HASH_GetState return the HASH state (+) HAL_HASH_GetError return the HASH error code @endverbatim * @{ */ /** * @brief Handle HASH interrupt request. * @param hhash HASH handle. * @note HAL_HASH_IRQHandler() handles interrupts in HMAC processing as well. * @retval None */ void HAL_HASH_IRQHandler(HASH_HandleTypeDef *hhash) { HAL_StatusTypeDef status; uint32_t itsource = hhash->Instance->IMR; uint32_t itflag = hhash->Instance->SR; /* If digest is ready */ if ((itflag & HASH_FLAG_DCIS) == HASH_FLAG_DCIS) { /* Read the digest */ HASH_GetDigest(hhash, hhash->pHashOutBuffPtr, HASH_DIGEST_LENGTH(hhash)); /* Disable Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_READY; /* Reset HASH state machine */ hhash->Phase = HAL_HASH_PHASE_READY; /* Process Unlocked */ __HAL_UNLOCK(hhash); /* Call digest computation complete call back */ #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) hhash->DgstCpltCallback(hhash); #else HAL_HASH_DgstCpltCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ } /* If Peripheral ready to accept new data */ if ((itflag & HASH_FLAG_DINIS) == HASH_FLAG_DINIS) { if ((itsource & HASH_IT_DINI) == HASH_IT_DINI) { status = HASH_WriteData_IT(hhash); if (status != HAL_OK) { /* Call error callback */ #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) hhash->ErrorCallback(hhash); #else HAL_HASH_ErrorCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ } } } } /** * @brief Input data transfer complete call back. * @note HAL_HASH_InCpltCallback() is called when the complete input message * has been fed to the Peripheral. This API is invoked only when input data are * entered under interruption or through DMA. * @note In case of HASH or HMAC multi-buffer DMA feeding case (MDMAT bit set), * HAL_HASH_InCpltCallback() is called at the end of each buffer feeding * to the Peripheral. * @param hhash pointer to a HASH_HandleTypeDef structure that contains * the configuration information for HASH module. * @retval None */ __weak void HAL_HASH_InCpltCallback(HASH_HandleTypeDef *hhash) { /* Prevent unused argument(s) compilation warning */ UNUSED(hhash); /* NOTE : This function should not be modified; when the callback is needed, HAL_HASH_InCpltCallback() can be implemented in the user file. */ } /** * @brief Digest computation complete call back. * @note HAL_HASH_DgstCpltCallback() is used under interruption, is not * relevant with DMA. * @param hhash pointer to a HASH_HandleTypeDef structure that contains * the configuration information for HASH module. * @retval None */ __weak void HAL_HASH_DgstCpltCallback(HASH_HandleTypeDef *hhash) { /* Prevent unused argument(s) compilation warning */ UNUSED(hhash); /* NOTE : This function should not be modified; when the callback is needed, HAL_HASH_DgstCpltCallback() can be implemented in the user file. */ } /** * @brief HASH error callback. * @note Code user can resort to hhash->Status (HAL_ERROR, HAL_TIMEOUT,...) * to retrieve the error type. * @param hhash pointer to a HASH_HandleTypeDef structure that contains * the configuration information for HASH module. * @retval None */ __weak void HAL_HASH_ErrorCallback(HASH_HandleTypeDef *hhash) { /* Prevent unused argument(s) compilation warning */ UNUSED(hhash); /* NOTE : This function should not be modified; when the callback is needed, HAL_HASH_ErrorCallback() can be implemented in the user file. */ } /** * @brief Return the HASH handle state. * @note The API yields the current state of the handle (BUSY, READY,...). * @param hhash HASH handle. * @retval HAL HASH state */ HAL_HASH_StateTypeDef HAL_HASH_GetState(HASH_HandleTypeDef *hhash) { return hhash->State; } /** * @brief Return the HASH handle error code. * @param hhash pointer to a HASH_HandleTypeDef structure. * @retval HASH Error Code */ uint32_t HAL_HASH_GetError(HASH_HandleTypeDef *hhash) { /* Return HASH Error Code */ return hhash->ErrorCode; } /** * @} */ /** * @} */ /* Private functions ---------------------------------------------------------*/ /** @addtogroup HASH_Private_Functions * @{ */ /** * @brief DMA HASH Input Data transfer completion callback. * @param hdma DMA handle. * @retval None */ static void HASH_DMAXferCplt(DMA_HandleTypeDef *hdma) { HASH_HandleTypeDef *hhash = (HASH_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; uint32_t count; if (READ_BIT(hhash->Instance->CR, HASH_CR_MODE) == 0U) { if ((hhash->Instance->CR & HASH_CR_MDMAT) == 0U) { /* Disable the DMA transfer */ CLEAR_BIT(hhash->Instance->CR, HASH_CR_DMAE); /* Wait for DCIS flag to be set */ count = HASH_TIMEOUTVALUE; do { count--; if (count == 0U) { /* Change state */ hhash->ErrorCode |= HAL_HASH_ERROR_TIMEOUT; hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) hhash->ErrorCallback(hhash); #else HAL_HASH_ErrorCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ } } while (HAL_IS_BIT_CLR(hhash->Instance->SR, HASH_FLAG_DCIS)); /* Call Input data transfer complete call back */ #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) hhash->InCpltCallback(hhash); #else HAL_HASH_InCpltCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ /* Read the message digest */ HASH_GetDigest(hhash, hhash->pHashOutBuffPtr, HASH_DIGEST_LENGTH(hhash)); /* Change the HASH state to ready */ hhash->State = HAL_HASH_STATE_READY; /* Reset HASH state machine */ hhash->Phase = HAL_HASH_PHASE_READY; /* Process UnLock */ __HAL_UNLOCK(hhash); /* Call digest complete call back */ #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) hhash->DgstCpltCallback(hhash); #else HAL_HASH_DgstCpltCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ } else { hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); } } else /*HMAC DMA*/ { if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_2) { if ((hhash->Instance->CR & HASH_CR_MDMAT) == 0U) { /* Set the phase */ hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_3; /* Configure the number of valid bits in last word of the Key */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * ((hhash->Init.KeySize) % 4U)); /* Write Key */ HASH_WriteData(hhash, hhash->Init.pKey, hhash->Init.KeySize); /* Start the Key padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for DCIS flag to be set */ count = HASH_TIMEOUTVALUE; do { count--; if (count == 0U) { /* Disable the DMA transfer */ CLEAR_BIT(hhash->Instance->CR, HASH_CR_DMAE); /* Change state */ hhash->ErrorCode |= HAL_HASH_ERROR_DMA; hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) hhash->ErrorCallback(hhash); #else HAL_HASH_ErrorCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ } } while (HAL_IS_BIT_CLR(hhash->Instance->SR, HASH_FLAG_DCIS)); /* Read the message digest */ HASH_GetDigest(hhash, hhash->pHashOutBuffPtr, HASH_DIGEST_LENGTH(hhash)); /* Change the HASH state to ready */ hhash->State = HAL_HASH_STATE_READY; /* Reset HASH state machine */ hhash->Phase = HAL_HASH_PHASE_READY; /* Process UnLock */ __HAL_UNLOCK(hhash); /* Call digest complete call back */ #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) hhash->DgstCpltCallback(hhash); #else HAL_HASH_DgstCpltCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ } else { hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); hhash->Accumulation = 1; } } } } /** * @brief DMA HASH communication error callback. * @param hdma DMA handle. * @retval None */ static void HASH_DMAError(DMA_HandleTypeDef *hdma) { HASH_HandleTypeDef *hhash = (HASH_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; hhash->ErrorCode |= HAL_HASH_ERROR_DMA; /* Set HASH state to ready to prevent any blocking issue in user code present in HAL_HASH_ErrorCallback() */ hhash->State = HAL_HASH_STATE_READY; #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) hhash->ErrorCallback(hhash); #else HAL_HASH_ErrorCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ } /** * @brief Feed the input buffer to the HASH peripheral in polling. * @param hhash HASH handle. * @param pInBuffer pointer to input buffer. * @param Size the size of input buffer in bytes. * @retval HAL status */ static void HASH_WriteData(HASH_HandleTypeDef *hhash, const uint8_t *pInBuffer, uint32_t Size) { uint32_t buffercounter; __IO uint32_t inputaddr = (uint32_t) pInBuffer; for (buffercounter = 0U; buffercounter < Size ; buffercounter += 4U) { /* Write input data 4 bytes at a time */ hhash->Instance->DIN = *(uint32_t *)inputaddr; inputaddr += 4U; hhash->HashInCount += 4U; } } /** * @brief Feed the input buffer to the HASH peripheral in interruption mode. * @param hhash HASH handle. * @retval HAL status */ static HAL_StatusTypeDef HASH_WriteData_IT(HASH_HandleTypeDef *hhash) { uint32_t buffercounter; uint32_t count; __IO uint32_t keyaddr = (uint32_t)(hhash->pHashKeyBuffPtr); __IO uint32_t inputaddr = (uint32_t)(hhash->pHashInBuffPtr); uint32_t nbbytePartialHash = (((hhash->Instance->SR) >> 16U) * 4U); /* Nb byte to enter in HASH fifo to trig a partial HASH computation*/ if (hhash->State == HAL_HASH_STATE_BUSY) { if ((hhash->Instance->CR & HASH_CR_MODE) == 0U) { #if (USE_HAL_HASH_SUSPEND_RESUME == 1U) /* If suspension flag has been raised, suspend processing */ if (hhash->SuspendRequest == HAL_HASH_SUSPEND) { /* reset SuspendRequest */ hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; /* Disable Computation Complete Flag and Errors Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_SUSPENDED; __HAL_UNLOCK(hhash); } else { #endif /* USE_HAL_HASH_SUSPEND_RESUME */ if (((hhash->HashInCount) + nbbytePartialHash) < (hhash->Size)) { for (buffercounter = 0U; buffercounter < nbbytePartialHash ; buffercounter += 4U) { /* Write input data 4 bytes at a time */ hhash->Instance->DIN = *(uint32_t *)inputaddr; inputaddr += 4U; hhash->HashInCount += 4U; hhash->pHashInBuffPtr += 4U; } /* Wait for HASH_IT_DINI flag to be set */ count = HASH_TIMEOUTVALUE; do { count--; if (count == 0U) { /* Disable Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); /* Change state */ hhash->ErrorCode |= HAL_HASH_ERROR_TIMEOUT; hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); return HAL_ERROR; } } while (HAL_IS_BIT_CLR(hhash->Instance->SR, HASH_FLAG_DINIS)); } else { while ((hhash->HashInCount) < hhash->Size) { /* Write input data 4 bytes at a time */ hhash->Instance->DIN = *(uint32_t *)inputaddr; inputaddr += 4U; hhash->HashInCount += 4U; hhash->pHashInBuffPtr += 4U; } /* Call Input transfer complete callback */ #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1U) /*Call registered Input complete callback*/ hhash->InCpltCallback(hhash); #else /*Call legacy weak Input complete callback*/ HAL_HASH_InCpltCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ if (hhash->Accumulation == 0U) { if (__HAL_HASH_GET_IT_SOURCE(hhash, HASH_IT_DINI)) { /* Start the message padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for HASH_FLAG_DCIS flag to be set */ count = HASH_TIMEOUTVALUE; do { count--; if (count == 0U) { /* Disable Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); /* Change state */ hhash->ErrorCode |= HAL_HASH_ERROR_TIMEOUT; hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); return HAL_ERROR; } } while (HAL_IS_BIT_CLR(hhash->Instance->SR, HASH_FLAG_DCIS)); } } else { /* Reset multi buffers accumulation flag */ hhash->Accumulation = 0U; /* Disable Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI); } } #if (USE_HAL_HASH_SUSPEND_RESUME == 1U) } #endif /* USE_HAL_HASH_SUSPEND_RESUME */ } else /*HMAC */ { if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_2) /* loading input*/ { #if (USE_HAL_HASH_SUSPEND_RESUME == 1U) /* If suspension flag has been raised, suspend processing */ if (hhash->SuspendRequest == HAL_HASH_SUSPEND) { /* reset SuspendRequest */ hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; /* Disable Computation Complete Flag and Errors Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); /* Change the HASH state */ hhash->State = HAL_HASH_STATE_SUSPENDED; __HAL_UNLOCK(hhash); } else { #endif /* USE_HAL_HASH_SUSPEND_RESUME */ if (hhash->Accumulation == 1U) { /* Configure the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 0U); } else { /* Configure the number of valid bits in last word of the message */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * (hhash->Size % 4U)); } if (((hhash->HashInCount) + nbbytePartialHash) < (hhash->Size)) { for (buffercounter = 0U; buffercounter < nbbytePartialHash ; buffercounter += 4U) { /* Write input data 4 bytes at a time */ hhash->Instance->DIN = *(uint32_t *)inputaddr; inputaddr += 4U; hhash->HashInCount += 4U; hhash->pHashInBuffPtr += 4U; } /* Wait for HASH_IT_DINI flag to be set */ count = HASH_TIMEOUTVALUE; do { count--; if (count == 0U) { /* Disable Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); /* Change state */ hhash->ErrorCode |= HAL_HASH_ERROR_TIMEOUT; hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); return HAL_ERROR; } } while (HAL_IS_BIT_CLR(hhash->Instance->SR, HASH_FLAG_DINIS)); } else { while ((hhash->HashInCount) < hhash->Size) { /* Write input data 4 bytes at a time */ hhash->Instance->DIN = *(uint32_t *)inputaddr; inputaddr += 4U; hhash->HashInCount += 4U; hhash->pHashInBuffPtr += 4U; } /* Call Input transfer complete callback */ #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1U) /*Call registered Input complete callback*/ hhash->InCpltCallback(hhash); #else /*Call legacy weak Input complete callback*/ HAL_HASH_InCpltCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ if (hhash->Accumulation == 0U) { if (__HAL_HASH_GET_IT_SOURCE(hhash, HASH_IT_DINI)) { /* Start the message padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for HASH_FLAG_BUSY flag to be set */ count = HASH_TIMEOUTVALUE; do { count--; if (count == 0U) { /* Disable Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); /* Change state */ hhash->ErrorCode |= HAL_HASH_ERROR_TIMEOUT; hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); return HAL_ERROR; } } while (HAL_IS_BIT_SET(hhash->Instance->SR, HASH_FLAG_BUSY)); hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_3; hhash->HashInCount = 0U; hhash->pHashKeyBuffPtr = hhash->Init.pKey; } } else { /* Disable Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); return HAL_OK; } } #if (USE_HAL_HASH_SUSPEND_RESUME == 1U) } #endif /* USE_HAL_HASH_SUSPEND_RESUME */ } else if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_3)/* loading Key*/ { /* Configure the number of valid bits in last word of the Key */ MODIFY_REG(hhash->Instance->STR, HASH_STR_NBLW, 8U * ((hhash->Init.KeySize) % 4U)); if (((hhash->HashInCount) + nbbytePartialHash) < (hhash->Init.KeySize)) { for (buffercounter = 0U; buffercounter < nbbytePartialHash ; buffercounter += 4U) { /* Write input data 4 bytes at a time */ hhash->Instance->DIN = *(uint32_t *)keyaddr; keyaddr += 4U; hhash->HashInCount += 4U; hhash->pHashKeyBuffPtr += 4U; } /* Wait for HASH_IT_DINI flag to be set */ count = HASH_TIMEOUTVALUE; do { count--; if (count == 0U) { /* Disable Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); /* Change state */ hhash->ErrorCode |= HAL_HASH_ERROR_TIMEOUT; hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); return HAL_ERROR; } } while (HAL_IS_BIT_CLR(hhash->Instance->SR, HASH_FLAG_DINIS)); } else { while ((hhash->HashInCount) < (hhash->Init.KeySize)) { /* Write input data 4 bytes at a time */ hhash->Instance->DIN = *(uint32_t *)keyaddr; keyaddr += 4U; hhash->HashInCount += 4U; } /* Start the message padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for HASH_FLAG_DCIS flag to be set */ count = HASH_TIMEOUTVALUE; do { count--; if (count == 0U) { /* Disable Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); /* Change state */ hhash->ErrorCode |= HAL_HASH_ERROR_TIMEOUT; hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); return HAL_ERROR; } } while (HAL_IS_BIT_CLR(hhash->Instance->SR, HASH_FLAG_DCIS)); } } else /*first step , loading key*/ { hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_1; if (((hhash->HashInCount) + nbbytePartialHash) < (hhash->Init.KeySize)) { for (buffercounter = 0U; buffercounter < nbbytePartialHash ; buffercounter += 4U) { /* Write input data 4 bytes at a time */ hhash->Instance->DIN = *(uint32_t *)keyaddr; keyaddr += 4U; hhash->HashInCount += 4U; hhash->pHashKeyBuffPtr += 4U; } /* Wait for HASH_IT_DINI flag to be set */ count = HASH_TIMEOUTVALUE; do { count--; if (count == 0U) { /* Disable Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); /* Change state */ hhash->ErrorCode |= HAL_HASH_ERROR_TIMEOUT; hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); return HAL_ERROR; } } while (HAL_IS_BIT_CLR(hhash->Instance->SR, HASH_FLAG_DINIS)); } else { while ((hhash->HashInCount) < (hhash->Init.KeySize)) { /* Write input data 4 bytes at a time */ hhash->Instance->DIN = *(uint32_t *)keyaddr; keyaddr += 4U; hhash->HashInCount += 4U; hhash->pHashKeyBuffPtr += 4U; } /* Start the message padding then the Digest calculation */ SET_BIT(hhash->Instance->STR, HASH_STR_DCAL); /* Wait for HASH_FLAG_BUSY flag to be set */ count = HASH_TIMEOUTVALUE; do { count--; if (count == 0U) { /* Disable Interrupts */ __HAL_HASH_DISABLE_IT(hhash, HASH_IT_DINI | HASH_IT_DCI); /* Change state */ hhash->ErrorCode |= HAL_HASH_ERROR_TIMEOUT; hhash->State = HAL_HASH_STATE_READY; __HAL_UNLOCK(hhash); return HAL_ERROR; } } while (HAL_IS_BIT_SET(hhash->Instance->SR, HASH_FLAG_BUSY)); /*change Phase to step 2*/ hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_2; hhash->HashInCount = 0U; } } } } else if ((hhash->State == HAL_HASH_STATE_SUSPENDED)) { return HAL_OK; } else { /* Busy error code field */ hhash->ErrorCode |= HAL_HASH_ERROR_BUSY; #if (USE_HAL_HASH_REGISTER_CALLBACKS == 1U) /*Call registered error callback*/ hhash->ErrorCallback(hhash); #else /*Call legacy weak error callback*/ HAL_HASH_ErrorCallback(hhash); #endif /* USE_HAL_HASH_REGISTER_CALLBACKS */ } return HAL_OK; } /** * @brief Retrieve the message digest. * @param hhash HASH handle * @param pMsgDigest pointer to the computed digest. * @param Size message digest size in bytes. * @retval None */ static void HASH_GetDigest(HASH_HandleTypeDef *hhash, uint8_t *pMsgDigest, uint8_t Size) { uint32_t msgdigest = (uint32_t)pMsgDigest; switch (Size) { case 20: /* SHA1 */ *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[0]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[1]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[2]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[3]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[4]); break; case 28: /* SHA224 */ *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[0]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[1]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[2]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[3]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[4]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[5]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[6]); break; case 32: /* SHA256 */ *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[0]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[1]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[2]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[3]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[4]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[5]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[6]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[7]); break; #if defined(HASH_ALGOSELECTION_SHA512) case 48: /* SHA384 */ *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[0]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[1]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[2]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[3]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[4]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[5]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[6]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[7]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[8]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[9]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[10]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[11]); break; case 64: /* SHA 512 */ *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[0]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[1]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[2]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[3]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(hhash->Instance->HR[4]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[5]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[6]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[7]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[8]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[9]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[10]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[11]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[12]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[13]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[14]); msgdigest += 4U; *(uint32_t *)(msgdigest) = __REV(HASH_DIGEST->HR[15]); break; #endif /* defined(HASH_ALGOSELECTION_SHA512)*/ default: break; } } /** * @brief Handle HASH processing Timeout. * @param hhash HASH handle. * @param Flag specifies the HASH flag to check. * @param Status the Flag status (SET or RESET). * @param Timeout Timeout duration. * @retval HAL status */ static HAL_StatusTypeDef HASH_WaitOnFlagUntilTimeout(HASH_HandleTypeDef *hhash, uint32_t Flag, FlagStatus Status, uint32_t Timeout) { uint32_t tickstart = HAL_GetTick(); /* Wait until flag is set */ if (Status == RESET) { while (__HAL_HASH_GET_FLAG(hhash, Flag) == RESET) { /* Check for the Timeout */ if (Timeout != HAL_MAX_DELAY) { if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U)) { /* Set State to Ready to be able to restart later on */ hhash->State = HAL_HASH_STATE_READY; hhash->ErrorCode |= HAL_HASH_ERROR_TIMEOUT; /* Process Unlocked */ __HAL_UNLOCK(hhash); return HAL_ERROR; } } } } else { while (__HAL_HASH_GET_FLAG(hhash, Flag) != RESET) { /* Check for the Timeout */ if (Timeout != HAL_MAX_DELAY) { if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U)) { /* Set State to Ready to be able to restart later on */ hhash->State = HAL_HASH_STATE_READY; hhash->ErrorCode |= HAL_HASH_ERROR_TIMEOUT; /* Process Unlocked */ __HAL_UNLOCK(hhash); return HAL_ERROR; } } } } return HAL_OK; } /** * @} */ #endif /* HAL_HASH_MODULE_ENABLED */ #endif /* HASH*/ /** * @} */ /** * @} */