From 1a9aa9ad975d4f520d5b88c17eb634dfe46a2012 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Wed, 26 Dec 2018 07:31:13 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@12483 110e8d01-0319-4d1e-a829-52ad28d1bb01 --- os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c | 278 ++++++++++++++++++++++--- os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h | 98 +++++++-- 2 files changed, 339 insertions(+), 37 deletions(-) (limited to 'os/hal/ports/STM32/LLD/CRYPv1') diff --git a/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c b/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c index 60a1f88f2..645619d84 100644 --- a/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c +++ b/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c @@ -22,6 +22,8 @@ * @{ */ +#include + #include "hal.h" #if (HAL_USE_CRY == TRUE) || defined(__DOXYGEN__) @@ -30,6 +32,10 @@ /* Driver local definitions. */ /*===========================================================================*/ +#define HASH1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_CRY_HASH1_DMA_STREAM, \ + STM32_HASH1_DMA_CHN) + /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ @@ -47,6 +53,34 @@ CRYDriver CRYD1; /* Driver local functions. */ /*===========================================================================*/ +/** + * @brief Shared end-of-rx service routine. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void cry_lld_serve_hash_interrupt(CRYDriver *cryp, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_HASH_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0U) { + STM32_CRY_HASH_DMA_ERROR_HOOK(cryp); + } +#endif + + if ((flags & STM32_DMA_ISR_TCIF) != 0U) { + /* End buffer interrupt.*/ + + /* Halting processing via DMA.*/ +// HASH->CR &= ~HASH_CR_DMAE; + + /* Resuming waiting thread.*/ + osalSysLockFromISR(); + osalThreadResumeI(&cryp->hash_tr, MSG_OK); + osalSysUnlockFromISR(); + } +} + /*===========================================================================*/ /* Driver interrupt handlers. */ /*===========================================================================*/ @@ -64,13 +98,20 @@ void cry_lld_init(void) { #if STM32_CRY_ENABLED1 cryObjectInit(&CRYD1); + #if STM32_CRY_USE_CRYP1 - CRYD1.cryp = CRYP; #endif + #if STM32_CRY_USE_HASH1 - CRYD1.hash = HASH; -#endif + CRYD1.hash_tr = NULL; +#if STM32_DMA_SUPPORTS_DMAMUX + CRYD1.dma_hash = STM32_DMA_STREAM(STM32_CRY_HASH1_DMA_CHANNEL); +#else + CRYD1.dma_hash = STM32_DMA_STREAM(STM32_CRY_HASH1_DMA_STREAM); #endif +#endif /* STM32_CRY_USE_HASH1 */ + +#endif /* STM32_CRY_ENABLED1 */ } /** @@ -83,12 +124,36 @@ void cry_lld_init(void) { void cry_lld_start(CRYDriver *cryp) { if (cryp->state == CRY_STOP) { + #if STM32_CRY_ENABLED1 if (&CRYD1 == cryp) { #if STM32_CRY_USE_CRYP1 rccEnableCRYP(true); #endif + #if STM32_CRY_USE_HASH1 + bool b; + b = dmaStreamAllocate(cryp->dma_hash, + STM32_CRY_HASH1_IRQ_PRIORITY, + (stm32_dmaisr_t)cry_lld_serve_hash_interrupt, + (void *)cryp); + osalDbgAssert(!b, "stream already allocated"); + + /* Preparing the DMA channel.*/ + dmaStreamSetMode(cryp->dma_hash, + STM32_DMA_CR_CHSEL(HASH1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_CRY_HASH1_DMA_PRIORITY) | + STM32_DMA_CR_MINC | STM32_DMA_CR_DIR_M2P | +// STM32_DMA_CR_PINC | STM32_DMA_CR_DIR_M2M | + STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | + STM32_DMA_CR_TCIE); + dmaStreamSetPeripheral(cryp->dma_hash, &HASH->DIN); +// dmaStreamSetMemory0(cryp->dma_hash, &HASH->DIN); +// dmaStreamSetFIFO(cryp->dma_hash, STM32_DMA_FCR_DMDIS); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(cryp->dma_hash, STM32_DMAMUX1_HASH); +#endif rccEnableHASH(true); #endif } @@ -114,38 +179,58 @@ void cry_lld_stop(CRYDriver *cryp) { if (cryp->state == CRY_READY) { +#if STM32_CRY_ENABLED1 + if (&CRYD1 == cryp) { +#if STM32_CRY_USE_CRYP1 + rccDisableCRYP(); +#endif + +#if STM32_CRY_USE_HASH1 + dmaStreamRelease(cryp->dma_hash); + rccDisableHASH(); +#endif + } +#endif } } +#if (CRY_LLD_SUPPORTS_AES == TRUE) || defined(__DOXYGEN__) /** - * @brief Initializes the transient key for a specific algorithm. + * @brief Initializes the AES transient key. + * @note It is the underlying implementation to decide which key sizes are + * allowable. * * @param[in] cryp pointer to the @p CRYDriver object - * @param[in] algorithm the algorithm identifier * @param[in] size key size in bytes * @param[in] keyp pointer to the key data * @return The operation status. * @retval CRY_NOERROR if the operation succeeded. - * @retval CRY_ERR_INV_ALGO if the specified algorithm is unknown or - * unsupported. - * @retval CRY_ERR_INV_KEY_SIZE if the specified key size is invalid. + * @retval CRY_ERR_INV_ALGO if the algorithm is unsupported. + * @retval CRY_ERR_INV_KEY_SIZE if the specified key size is invalid for + * the specified algorithm. * * @notapi */ -cryerror_t cry_lld_loadkey(CRYDriver *cryp, - cryalgorithm_t algorithm, - size_t size, - const uint8_t *keyp) { +cryerror_t cry_lld_aes_loadkey(CRYDriver *cryp, + size_t size, + const uint8_t *keyp) { + osalDbgCheck((cryp != NULL) && (keyp != NULL)); + + +#if CRY_LLD_SUPPORTS_AES == TRUE + return cry_lld_aes_loadkey(cryp, size, keyp); +#elif HAL_CRY_USE_FALLBACK == TRUE + return cry_fallback_aes_loadkey(cryp, size, keyp); +#else (void)cryp; - (void)algorithm; (void)size; (void)keyp; - return CRY_NOERROR; + return CRY_ERR_INV_ALGO; +#endif } -#if (CRY_LLD_SUPPORTS_AES == TRUE) || defined(__DOXYGEN__) /** * @brief Encryption of a single block using AES. * @note The implementation of this function must guarantee that it can @@ -690,6 +775,42 @@ cryerror_t cry_lld_decrypt_AES_GCM(CRYDriver *cryp, #endif #if (CRY_LLD_SUPPORTS_DES == TRUE) || defined(__DOXYGEN__) +/** + * @brief Initializes the DES transient key. + * @note It is the underlying implementation to decide which key sizes are + * allowable. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] size key size in bytes + * @param[in] keyp pointer to the key data + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the algorithm is unsupported. + * @retval CRY_ERR_INV_KEY_SIZE if the specified key size is invalid for + * the specified algorithm. + * + * @notapi + */ +cryerror_t cry_lld_des_loadkey(CRYDriver *cryp, + size_t size, + const uint8_t *keyp) { + + osalDbgCheck((cryp != NULL) && (keyp != NULL)); + + +#if CRY_LLD_SUPPORTS_DES == TRUE + return cry_lld_des_loadkey(cryp, size, keyp); +#elif HAL_CRY_USE_FALLBACK == TRUE + return cry_fallback_des_loadkey(cryp, size, keyp); +#else + (void)cryp; + (void)size; + (void)keyp; + + return CRY_ERR_INV_ALGO; +#endif +} + /** * @brief Encryption of a single block using (T)DES. * @note The implementation of this function must guarantee that it can @@ -1033,9 +1154,16 @@ cryerror_t cry_lld_SHA1_final(CRYDriver *cryp, SHA1Context *sha1ctxp, cryerror_t cry_lld_SHA256_init(CRYDriver *cryp, SHA256Context *sha256ctxp) { (void)cryp; - (void)sha256ctxp; - return CRY_ERR_INV_ALGO; + /* Initializing context structure.*/ + sha256ctxp->last_data = 0U; + sha256ctxp->last_size = 0U; + + /* Initializing operation.*/ + HASH->CR = HASH_CR_MDMAT | HASH_CR_ALGO_1 | HASH_CR_ALGO_0 | + HASH_CR_DATATYPE_1 | HASH_CR_INIT; + + return CRY_NOERROR; } /** @@ -1057,12 +1185,55 @@ cryerror_t cry_lld_SHA256_init(CRYDriver *cryp, SHA256Context *sha256ctxp) { cryerror_t cry_lld_SHA256_update(CRYDriver *cryp, SHA256Context *sha256ctxp, size_t size, const uint8_t *in) { - (void)cryp; - (void)sha256ctxp; - (void)size; - (void)in; + /* This HW is unable to hash blocks that are not a multiple of 4 bytes + except for the last block in the stream which is handled in the + "final" function.*/ + if (sha256ctxp->last_size != 0U) { + return CRY_ERR_OP_FAILURE; + } - return CRY_ERR_INV_ALGO; + /* Any unaligned data is deferred to the "final" function.*/ + sha256ctxp->last_size = 8U * (size % sizeof (uint32_t)); + if (sha256ctxp->last_size > 0U) { + const uint32_t *wp = (const uint32_t *)(const void *)in; + sha256ctxp->last_data = wp[size / sizeof (uint32_t)]; + } + + /* Removing the unaligned part from the total size.*/ + size = size & ~(sizeof (uint32_t) - 1U); + + /* Data is processed in 32kB blocks because DMA size limitations.*/ + while (size > 0U) { + size_t chunk = size > 0x8000U ? 0x8000U : size; + +#if 1 + osalSysLock(); + + /* Setting up transfer.*/ + dmaStreamSetMemory0(cryp->dma_hash, in); +// dmaStreamSetPeripheral(cryp->dma_hash, in); + dmaStreamSetTransactionSize(cryp->dma_hash, chunk / sizeof (uint32_t)); + + /* Enabling DMA channel then HASH engine.*/ + dmaStreamEnable(cryp->dma_hash); + HASH->CR |= HASH_CR_DMAE; + + /* Waiting for DMA operation completion.*/ + osalThreadSuspendS(&cryp->hash_tr); + + osalSysUnlock(); +#else + const uint32_t *wp = (const uint32_t *)(const void *)in; + for (size_t i = 0; i < chunk / sizeof (uint32_t); i++) { + HASH->DIN = wp[i]; + } +#endif + + size -= chunk; + in += chunk; + } + + return CRY_NOERROR; } /** @@ -1082,12 +1253,33 @@ cryerror_t cry_lld_SHA256_update(CRYDriver *cryp, SHA256Context *sha256ctxp, */ cryerror_t cry_lld_SHA256_final(CRYDriver *cryp, SHA256Context *sha256ctxp, uint8_t *out) { + uint32_t digest[8]; (void)cryp; - (void)sha256ctxp; - (void)out; - return CRY_ERR_INV_ALGO; + if (sha256ctxp->last_size > 0U) { + HASH->DIN = sha256ctxp->last_data; + } + + /* Triggering final calculation and wait for result.*/ + HASH->SR = 0U; + HASH->STR = sha256ctxp->last_size; + HASH->STR = sha256ctxp->last_size | HASH_STR_DCAL; + while ((HASH->SR & HASH_SR_DCIS) == 0U) { + } + + /* Reading digest.*/ + digest[0] = HASH_DIGEST->HR[0]; + digest[1] = HASH_DIGEST->HR[1]; + digest[2] = HASH_DIGEST->HR[2]; + digest[3] = HASH_DIGEST->HR[3]; + digest[4] = HASH_DIGEST->HR[4]; + digest[5] = HASH_DIGEST->HR[5]; + digest[6] = HASH_DIGEST->HR[6]; + digest[7] = HASH_DIGEST->HR[7]; + memcpy((void *)out, (const void *)digest, sizeof digest); + + return CRY_NOERROR; } #endif @@ -1167,6 +1359,42 @@ cryerror_t cry_lld_SHA512_final(CRYDriver *cryp, SHA512Context *sha512ctxp, #endif #if (CRY_LLD_SUPPORTS_HMAC_SHA256 == TRUE) || defined(__DOXYGEN__) +/** + * @brief Initializes the HMAC transient key. + * @note It is the underlying implementation to decide which key sizes are + * allowable. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] size key size in bytes + * @param[in] keyp pointer to the key data + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the algorithm is unsupported. + * @retval CRY_ERR_INV_KEY_SIZE if the specified key size is invalid for + * the specified algorithm. + * + * @notapi + */ +cryerror_t cry_lld_hmac_loadkey(CRYDriver *cryp, + size_t size, + const uint8_t *keyp) { + + osalDbgCheck((cryp != NULL) && (keyp != NULL)); + +#if (CRY_LLD_SUPPORTS_HMAC_SHA256 == TRUE) || \ + (CRY_LLD_SUPPORTS_HMAC_SHA512 == TRUE) + return cry_lld_hmac_loadkey(cryp, size, keyp); +#elif HAL_CRY_USE_FALLBACK == TRUE + return cry_fallback_hmac_loadkey(cryp, size, keyp); +#else + (void)cryp; + (void)size; + (void)keyp; + + return CRY_ERR_INV_ALGO; +#endif +} + /** * @brief Hash initialization using HMAC_SHA256. * diff --git a/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h b/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h index 7ec84fc4f..46201d570 100644 --- a/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h +++ b/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h @@ -54,7 +54,28 @@ * @note The default is @p FALSE. */ #if !defined(STM32_CRY_USE_HASH1) || defined(__DOXYGEN__) -#define STM32_CRY_USE_HASH1 TRUE +#define STM32_CRY_USE_HASH1 FALSE +#endif + +/** + * @brief CRYP1 interrupt priority level setting. + */ +#if !defined(STM32_CRY_CRYP1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CRY_CRYP1_IRQ_PRIORITY 9 +#endif + +/** + * @brief HASH1 interrupt priority level setting. + */ +#if !defined(STM32_CRY_HASH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CRY_HASH1_IRQ_PRIORITY 9 +#endif + +/** + * @brief HASH1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_CRY_HASH1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CRY_HASH1_DMA_PRIORITY 0 #endif /** @} */ @@ -86,7 +107,53 @@ #endif #if !STM32_CRY_ENABLED1 -#error "CRY driver activated but no CRYP or HASH peripheral assigned" +#error "CRY driver activated but no CRYP nor HASH peripheral assigned" +#endif + +#if STM32_CRY_USE_HASH1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_CRY_HASH1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to HASH1" +#endif + +#if STM32_CRY_USE_CRYP1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_CRY_CRYP1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to CRYP1" +#endif + +/* Devices with DMAMUX require a different kind of check.*/ +#if STM32_DMA_SUPPORTS_DMAMUX + +#if STM32_CRY_USE_HASH1 +#if !defined(STM32_CRY_HASH1_DMA_CHANNEL) +#error "HASH1 DMA channel not defined" +#endif +#if !STM32_DMA_IS_VALID_CHANNEL(STM32_CRY_HASH1_DMA_CHANNEL) +#error "Invalid DMA channel assigned to HASH1" +#endif +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_CRY_HASH1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to HASH1" +#endif +#endif /* !STM32_CRY_USE_HASH1 */ + +#else /* !STM32_DMA_SUPPORTS_DMAMUX */ + +/* Sanity checks on DMA streams settings in mcuconf.h.*/ +#if STM32_CRY_USE_HASH1 +#if !defined(STM32_CRY_HASH1_DMA_STREAM) +#error "HASH1 DMA streams not defined" +#endif +#if !STM32_DMA_IS_VALID_ID(STM32_CRY_HASH1_DMA_STREAM, STM32_HASH1_DMA_MSK) +#error "invalid DMA stream associated to HASH1" +#endif +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_CRY_HASH1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to HASH1" +#endif +#endif /* !STM32_CRY_USE_HASH1 */ + +#endif /* !STM32_DMA_SUPPORTS_DMAMUX */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED #endif /** @@ -115,11 +182,11 @@ #define CRY_LLD_SUPPORTS_DES_CBC FALSE #endif #if STM32_CRY_USE_HASH1 || defined (__DOXYGEN__) -#define CRY_LLD_SUPPORTS_SHA1 TRUE +#define CRY_LLD_SUPPORTS_SHA1 FALSE #define CRY_LLD_SUPPORTS_SHA256 TRUE -#define CRY_LLD_SUPPORTS_SHA512 TRUE +#define CRY_LLD_SUPPORTS_SHA512 FALSE #define CRY_LLD_SUPPORTS_HMAC_SHA256 TRUE -#define CRY_LLD_SUPPORTS_HMAC_SHA512 TRUE +#define CRY_LLD_SUPPORTS_HMAC_SHA512 FALSE #else #define CRY_LLD_SUPPORTS_SHA1 FALSE #define CRY_LLD_SUPPORTS_SHA256 FALSE @@ -168,16 +235,16 @@ struct CRYDriver { #endif /* End of the mandatory fields.*/ #if STM32_CRY_USE_CRYP1 || defined (__DOXYGEN__) - /** - * @brief Pointer to the CRYP registers block. - */ - CRYP_TypeDef *cryp; #endif #if STM32_CRY_USE_HASH1 || defined (__DOXYGEN__) /** - * @brief Pointer to the HASH registers block. + * @brief Thread reference for hash operations. + */ + thread_reference_t hash_tr; + /** + * @brief Hash DMA stream. */ - HASH_TypeDef *hash; + const stm32_dma_stream_t *dma_hash; #endif }; @@ -195,7 +262,14 @@ typedef struct { * @brief Type of a SHA256 context. */ typedef struct { - uint32_t dummy; + /** + * @brief Last data to be hashed on finalization. + */ + uint32_t last_data; + /** + * @brief Size, in bits, of the last data. + */ + uint32_t last_size; } SHA256Context; #endif -- cgit v1.2.3