/* stm32.c * * Copyright (C) 2006-2026 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ /* Generic STM32 Hashing Function */ /* Supports CubeMX HAL or Standard Peripheral Library */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifdef NO_INLINE #include #else #define WOLFSSL_MISC_INCLUDED #include #endif #ifndef NO_AES #include #endif #ifdef WOLFSSL_STM32_PKA #include #if defined(WOLFSSL_STM32L5) #include #include #elif defined(WOLFSSL_STM32U5) #include #include #elif defined(WOLFSSL_STM32WB) #include #include #elif defined(WOLFSSL_STM32WL) #include #include #elif defined(WOLFSSL_STM32MP13) #include #include #elif defined(WOLFSSL_STM32H7S) #include #include #elif defined(WOLFSSL_STM32WBA) #include #include #elif defined(WOLFSSL_STM32N6) #include #include #elif defined(WOLFSSL_STM32H5) #include #include #else #error Please add the hal_pk.h include #endif extern PKA_HandleTypeDef hpka; #if !defined(WOLFSSL_STM32_PKA_V2) && defined(PKA_ECC_SCALAR_MUL_IN_B_COEFF) /* PKA hardware like in U5 added coefB and primeOrder */ #define WOLFSSL_STM32_PKA_V2 #endif #ifdef HAVE_ECC #include #ifndef WOLFSSL_HAVE_ECC_KEY_GET_PRIV /* FIPS build has replaced ecc.h. */ #define wc_ecc_key_get_priv(key) (&((key)->k)) #define WOLFSSL_HAVE_ECC_KEY_GET_PRIV #endif #endif /* HAVE_ECC */ #endif /* WOLFSSL_STM32_PKA */ #ifdef STM32_HASH /* #define DEBUG_STM32_HASH */ /* User can override STM32_HASH_CLOCK_ENABLE and STM32_HASH_CLOCK_DISABLE */ #ifndef STM32_HASH_CLOCK_ENABLE static WC_INLINE void wc_Stm32_Hash_Clock_Enable(STM32_HASH_Context* stmCtx) { #ifdef WOLFSSL_STM32_CUBEMX __HAL_RCC_HASH_CLK_ENABLE(); #else RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_HASH, ENABLE); #endif (void)stmCtx; } #define STM32_HASH_CLOCK_ENABLE(ctx) wc_Stm32_Hash_Clock_Enable(ctx) #endif #ifndef STM32_HASH_CLOCK_DISABLE static WC_INLINE void wc_Stm32_Hash_Clock_Disable(STM32_HASH_Context* stmCtx) { #ifdef WOLFSSL_STM32_CUBEMX __HAL_RCC_HASH_CLK_DISABLE(); #else RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_HASH, DISABLE); #endif (void)stmCtx; } #define STM32_HASH_CLOCK_DISABLE(ctx) wc_Stm32_Hash_Clock_Disable(ctx) #endif /* STM32 Port Internal Functions */ static void wc_Stm32_Hash_NumValidBits(word32 len) { /* calculate number of valid bits in last word */ /* NBLW = 0x00 (all 32-bits are valid) */ word32 nbvalidbytesdata = (len % STM32_HASH_REG_SIZE); HASH->STR &= ~HASH_STR_NBW; HASH->STR |= (8 * nbvalidbytesdata) & HASH_STR_NBW; #ifdef DEBUG_STM32_HASH printf("STM Valid Last bits (%d)\n", 8 * nbvalidbytesdata); #endif } static void wc_Stm32_Hash_SaveContext(STM32_HASH_Context* ctx) { int i; /* save context registers */ ctx->HASH_IMR = HASH->IMR; ctx->HASH_STR = HASH->STR; ctx->HASH_CR = HASH->CR; #ifdef STM32_HASH_SHA3 ctx->SHA3CFGR = HASH->SHA3CFGR; #endif for (i=0; iHASH_CSR[i] = HASH->CSR[i]; } #ifdef DEBUG_STM32_HASH printf("STM Save CR %lx, IMR %lx, STR %lx\n", HASH->CR, HASH->IMR, HASH->STR); #endif } static void wc_Stm32_Hash_RestoreContext(STM32_HASH_Context* ctx, word32 algo, word32 mode) { int i; if (ctx->HASH_CR == 0) { /* init context */ #if defined(HASH_IMR_DINIE) && defined(HASH_IMR_DCIE) /* Disable IRQ's - wolfSSL does not use the HASH/RNG IRQ * If using the HAL hashing API's directly it will re-enable the IRQs */ HASH->IMR &= ~(HASH_IMR_DINIE | HASH_IMR_DCIE); #endif /* Configure algorithm, mode, data type and initialize HASH processor. * INIT must be written in the same register write as ALGO because * setting INIT resets ALGO bits to their default value (MD5). */ HASH->CR = (algo | mode | HASH_DATATYPE_8B | HASH_CR_INIT); /* by default mark all bits valid */ wc_Stm32_Hash_NumValidBits(0); #ifdef DEBUG_STM32_HASH printf("STM Init algo %x, mode %x, CR %lx, SR %lx\n", (unsigned int)algo, (unsigned int)mode, HASH->CR, HASH->SR); #endif } else { /* restore context registers */ HASH->IMR = ctx->HASH_IMR; HASH->STR = ctx->HASH_STR; #ifdef STM32_HASH_SHA3 HASH->SHA3CFGR = ctx->SHA3CFGR; #endif /* Restore CR with INIT in a single write - setting INIT resets ALGO * bits, so we must include the saved CR value in the same write. */ HASH->CR = ctx->HASH_CR | HASH_CR_INIT; /* continue restoring context registers */ for (i=0; iCSR[i] = ctx->HASH_CSR[i]; } #ifdef DEBUG_STM32_HASH printf("STM Restore CR %lx, IMR %lx, STR %lx\n", HASH->CR, HASH->IMR, HASH->STR); #endif } } static void wc_Stm32_Hash_GetDigest(byte* hash, int digestSize) { word32 digest[HASH_MAX_DIGEST/sizeof(word32)]; int i = 0, sz; if (digestSize > HASH_MAX_DIGEST) digestSize = HASH_MAX_DIGEST; sz = digestSize; while (sz > 0) { /* first 20 bytes come from instance HR */ if (i < 5) { digest[i] = HASH->HR[i]; } #ifdef HASH_DIGEST /* reset comes from HASH_DIGEST */ else { digest[i] = HASH_DIGEST->HR[i]; } #endif i++; sz -= 4; } ByteReverseWords(digest, digest, digestSize); XMEMCPY(hash, digest, digestSize); #ifdef DEBUG_STM32_HASH { word32 ii; printf("STM Digest %d\n", digestSize); for (ii=0; iiSR & HASH_SR_BUSY) #ifdef HASH_IMR_DINIE || (HASH->SR & HASH_SR_DINIS) == 0 #endif ) && ++timeout < STM32_HASH_TIMEOUT) { }; #ifdef DEBUG_STM32_HASH printf("STM Wait Data %d, HASH->SR %lx\n", timeout, HASH->SR); #endif /* verify timeout did not occur */ if (timeout >= STM32_HASH_TIMEOUT) { return WC_TIMEOUT_E; } return 0; } static int wc_Stm32_Hash_WaitCalcComp(STM32_HASH_Context* stmCtx) { int timeout = 0; (void)stmCtx; /* wait until not busy and hash digest calculation complete */ while (((HASH->SR & HASH_SR_BUSY) #ifdef HASH_IMR_DCIE || (HASH->SR & HASH_SR_DCIS) == 0 #endif ) && ++timeout < STM32_HASH_TIMEOUT) { }; #ifdef DEBUG_STM32_HASH printf("STM Wait Calc %d, HASH->SR %lx\n", timeout, HASH->SR); #endif /* verify timeout did not occur */ if (timeout >= STM32_HASH_TIMEOUT) { return WC_TIMEOUT_E; } return 0; } static void wc_Stm32_Hash_Data(STM32_HASH_Context* stmCtx, word32 len) { word32 i, blocks; if (len > stmCtx->buffLen) len = stmCtx->buffLen; /* calculate number of 32-bit blocks - round up */ blocks = ((len + STM32_HASH_REG_SIZE-1) / STM32_HASH_REG_SIZE); #ifdef DEBUG_STM32_HASH printf("STM DIN %d blocks\n", blocks); #endif for (i=0; ibuffer[i]); #endif HASH->DIN = stmCtx->buffer[i]; } stmCtx->loLen += len; /* total */ stmCtx->buffLen -= len; if (stmCtx->buffLen > 0) { XMEMMOVE(stmCtx->buffer, (byte*)stmCtx->buffer+len, stmCtx->buffLen); } } /* STM32 Port Exposed Functions */ void wc_Stm32_Hash_Init(STM32_HASH_Context* stmCtx) { /* clear context */ /* this also gets called after finish */ XMEMSET(stmCtx, 0, sizeof(STM32_HASH_Context)); } int wc_Stm32_Hash_Update(STM32_HASH_Context* stmCtx, word32 algo, const byte* data, word32 len, word32 blockSize) { int ret = 0; byte* local = (byte*)stmCtx->buffer; int wroteToFifo = 0; word32 chunkSz; #ifdef DEBUG_STM32_HASH printf("STM Hash Update: algo %x, len %d, buffLen %d, fifoBytes %d\n", algo, len, stmCtx->buffLen, stmCtx->fifoBytes); #endif (void)blockSize; /* check that internal buffLen is valid */ if (stmCtx->buffLen > (word32)sizeof(stmCtx->buffer)) { return BUFFER_E; } /* turn on hash clock */ STM32_HASH_CLOCK_ENABLE(stmCtx); /* restore hash context or init as new hash */ wc_Stm32_Hash_RestoreContext(stmCtx, algo, HASH_ALGOMODE_HASH); /* write blocks to FIFO */ while (len) { word32 add; chunkSz = blockSize; /* fill the FIFO plus one additional to flush the first block */ if (!stmCtx->fifoBytes) { chunkSz += STM32_HASH_REG_SIZE; } add = min(len, chunkSz - stmCtx->buffLen); XMEMCPY(&local[stmCtx->buffLen], data, add); stmCtx->buffLen += add; data += add; len -= add; if (stmCtx->buffLen == chunkSz) { wc_Stm32_Hash_Data(stmCtx, stmCtx->buffLen); wroteToFifo = 1; stmCtx->fifoBytes += chunkSz; } } if (wroteToFifo) { /* make sure hash operation is done */ ret = wc_Stm32_Hash_WaitDataReady(stmCtx); /* save hash state for next operation */ wc_Stm32_Hash_SaveContext(stmCtx); } /* turn off hash clock */ STM32_HASH_CLOCK_DISABLE(stmCtx); return ret; } int wc_Stm32_Hash_Final(STM32_HASH_Context* stmCtx, word32 algo, byte* hash, word32 digestSize) { int ret = 0; #ifdef DEBUG_STM32_HASH printf("STM Hash Final: algo %x, digestSz %d, buffLen %d, fifoBytes %d\n", algo, digestSize, stmCtx->buffLen, stmCtx->fifoBytes); #endif /* turn on hash clock */ STM32_HASH_CLOCK_ENABLE(stmCtx); /* restore hash context or init as new hash */ wc_Stm32_Hash_RestoreContext(stmCtx, algo, HASH_ALGOMODE_HASH); /* finish reading any trailing bytes into FIFO */ if (stmCtx->buffLen > 0) { /* send remainder of data */ wc_Stm32_Hash_Data(stmCtx, stmCtx->buffLen); } /* calculate number of valid bits in last word */ wc_Stm32_Hash_NumValidBits(stmCtx->loLen + stmCtx->buffLen); /* start hash processor */ HASH->STR |= HASH_STR_DCAL; /* wait for hash done */ ret = wc_Stm32_Hash_WaitCalcComp(stmCtx); if (ret == 0) { /* read message digest */ wc_Stm32_Hash_GetDigest(hash, digestSize); } /* turn off hash clock */ STM32_HASH_CLOCK_DISABLE(stmCtx); return ret; } #if defined(STM32_HMAC) && !defined(NO_HMAC) /* STM32 Port HMAC Functions */ #include int wc_Stm32_Hmac_GetAlgoInfo(int macType, word32* algo, word32* blockSize, word32* digestSize) { int ret = 0; switch (macType) { #if !defined(NO_MD5) && !defined(STM32_NOMD5) case WC_MD5: if (algo) *algo = HASH_AlgoSelection_MD5; if (blockSize) *blockSize = WC_MD5_BLOCK_SIZE; if (digestSize) *digestSize = WC_MD5_DIGEST_SIZE; break; #endif #ifndef NO_SHA case WC_SHA: if (algo) *algo = HASH_AlgoSelection_SHA1; if (blockSize) *blockSize = WC_SHA_BLOCK_SIZE; if (digestSize) *digestSize = WC_SHA_DIGEST_SIZE; break; #endif #ifdef WOLFSSL_SHA224 case WC_SHA224: if (algo) *algo = HASH_AlgoSelection_SHA224; if (blockSize) *blockSize = WC_SHA224_BLOCK_SIZE; if (digestSize) *digestSize = WC_SHA224_DIGEST_SIZE; break; #endif #ifndef NO_SHA256 case WC_SHA256: if (algo) *algo = HASH_AlgoSelection_SHA256; if (blockSize) *blockSize = WC_SHA256_BLOCK_SIZE; if (digestSize) *digestSize = WC_SHA256_DIGEST_SIZE; break; #endif #if defined(STM32_HASH_SHA384) && defined(WOLFSSL_SHA384) case WC_SHA384: if (algo) *algo = HASH_ALGOSELECTION_SHA384; if (blockSize) *blockSize = WC_SHA384_BLOCK_SIZE; if (digestSize) *digestSize = WC_SHA384_DIGEST_SIZE; break; #endif #if defined(STM32_HASH_SHA512) && defined(WOLFSSL_SHA512) case WC_SHA512: if (algo) *algo = HASH_ALGOSELECTION_SHA512; if (blockSize) *blockSize = WC_SHA512_BLOCK_SIZE; if (digestSize) *digestSize = WC_SHA512_DIGEST_SIZE; break; #endif default: ret = BAD_FUNC_ARG; break; } return ret; } static void wc_Stm32_Hmac_FeedKey(const byte* key, word32 keySz) { word32 i, blocks; word32 tmp; /* feed key words into HASH->DIN */ blocks = keySz / STM32_HASH_REG_SIZE; for (i = 0; i < blocks; i++) { XMEMCPY(&tmp, key + (i * STM32_HASH_REG_SIZE), STM32_HASH_REG_SIZE); HASH->DIN = tmp; } /* handle remaining bytes in last partial word */ if (keySz % STM32_HASH_REG_SIZE) { tmp = 0; XMEMCPY(&tmp, key + (blocks * STM32_HASH_REG_SIZE), keySz % STM32_HASH_REG_SIZE); HASH->DIN = tmp; } ForceZero(&tmp, sizeof(tmp)); #ifdef DEBUG_STM32_HASH printf("STM HMAC FeedKey %d bytes\n", (int)keySz); #endif } /* STM32 HMAC Exposed Functions */ int wc_Stm32_Hmac_SetKey(STM32_HASH_Context* stmCtx, int macType, const byte* key, word32 keySz) { int ret; word32 algo, blockSize, digestSize; word32 mode; if (stmCtx == NULL || key == NULL) return BAD_FUNC_ARG; ret = wc_Stm32_Hmac_GetAlgoInfo(macType, &algo, &blockSize, &digestSize); if (ret != 0) return ret; #ifdef DEBUG_STM32_HASH printf("STM HMAC SetKey: macType %d, keySz %d\n", macType, (int)keySz); #endif /* clear context for fresh HMAC */ wc_Stm32_Hash_Init(stmCtx); /* turn on hash clock */ STM32_HASH_CLOCK_ENABLE(stmCtx); /* initialize hardware for HMAC mode. * Keys are always pre-hashed in software before reaching this point * (see hmac.c), so keySz will always be <= blockSize here. */ mode = HASH_ALGOMODE_HMAC; wc_Stm32_Hash_RestoreContext(stmCtx, algo, mode); /* Phase 1: Feed key into HASH->DIN */ wc_Stm32_Hmac_FeedKey(key, keySz); /* set number of valid bits in last word and trigger DCAL */ wc_Stm32_Hash_NumValidBits(keySz); HASH->STR |= HASH_STR_DCAL; /* wait for data input ready (phase 1 complete) */ ret = wc_Stm32_Hash_WaitDataReady(stmCtx); if (ret == 0) { /* save context for context switching */ wc_Stm32_Hash_SaveContext(stmCtx); } /* turn off hash clock */ STM32_HASH_CLOCK_DISABLE(stmCtx); return ret; } int wc_Stm32_Hmac_Final(STM32_HASH_Context* stmCtx, word32 algo, const byte* key, word32 keySz, byte* hash, word32 digestSize) { int ret; if (stmCtx == NULL || key == NULL || hash == NULL) return BAD_FUNC_ARG; #ifdef DEBUG_STM32_HASH printf("STM HMAC Final: algo %x, keySz %d, buffLen %d, fifoBytes %d\n", (unsigned int)algo, (int)keySz, (int)stmCtx->buffLen, (int)stmCtx->fifoBytes); #endif /* turn on hash clock */ STM32_HASH_CLOCK_ENABLE(stmCtx); /* restore HMAC context */ wc_Stm32_Hash_RestoreContext(stmCtx, algo, HASH_ALGOMODE_HMAC); /* finish reading any trailing bytes into FIFO */ if (stmCtx->buffLen > 0) { wc_Stm32_Hash_Data(stmCtx, stmCtx->buffLen); } /* Phase 2 complete: set valid bits and trigger DCAL */ wc_Stm32_Hash_NumValidBits(stmCtx->loLen + stmCtx->buffLen); HASH->STR |= HASH_STR_DCAL; /* wait for data input ready (phase 2 complete, ready for phase 3) */ ret = wc_Stm32_Hash_WaitDataReady(stmCtx); if (ret != 0) { STM32_HASH_CLOCK_DISABLE(stmCtx); return ret; } /* Phase 3: Feed key again into HASH->DIN */ wc_Stm32_Hmac_FeedKey(key, keySz); /* set valid bits for key and trigger DCAL */ wc_Stm32_Hash_NumValidBits(keySz); HASH->STR |= HASH_STR_DCAL; /* wait for hash done (digest computation complete) */ ret = wc_Stm32_Hash_WaitCalcComp(stmCtx); if (ret == 0) { /* read message digest */ wc_Stm32_Hash_GetDigest(hash, digestSize); } /* turn off hash clock */ STM32_HASH_CLOCK_DISABLE(stmCtx); return ret; } #endif /* STM32_HMAC && !NO_HMAC */ #endif /* STM32_HASH */ #ifdef STM32_CRYPTO #ifndef NO_AES #ifdef WOLFSSL_STM32_CUBEMX #if defined(WOLFSSL_STM32U5_DHUK) /* Set the DHUK IV to be used when unwrapping an AES key * return 0 on success */ int wc_Stm32_Aes_SetDHUK_IV(struct Aes* aes, const byte* iv, int ivSz) { if (ivSz != sizeof(aes->dhukIV)) { return BAD_FUNC_ARG; } XMEMCPY(aes->dhukIV, iv, ivSz); aes->dhukIVLen = ivSz; return 0; } /* Wrap an AES key using the DHUK */ int wc_Stm32_Aes_Wrap(struct Aes* aes, const byte* in, word32 inSz, byte* out, word32* outSz, const byte* iv, int ivSz) { CRYP_HandleTypeDef hcryp; int ret = 0; byte key[AES_256_KEY_SIZE]; /* SAES requires use of the RNG -- HAL_RNG_DeInit() calls from random.c turn off the RNG clock -- re-enable the clock here */ __HAL_RCC_RNG_CLK_ENABLE(); ByteReverseWords((word32*)key, (word32*)in, inSz); XMEMSET(&hcryp, 0, sizeof(CRYP_HandleTypeDef)); if (ret == 0) { hcryp.Instance = SAES; hcryp.Init.DataType = CRYP_DATATYPE_8B; hcryp.Init.KeySize = CRYP_KEYSIZE_256B; hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_BYTE; hcryp.Init.KeySelect = CRYP_KEYSEL_HW; /* use DHUK to unwrap with use */ hcryp.Init.KeyMode = CRYP_KEYMODE_WRAPPED; if (iv != NULL) { hcryp.Init.pInitVect = (uint32_t *)iv; hcryp.Init.Algorithm = CRYP_AES_CBC; } else { hcryp.Init.Algorithm = CRYP_AES_ECB; } ret = HAL_CRYP_Init(&hcryp); } if (ret == HAL_OK) { ret = HAL_CRYPEx_WrapKey(&hcryp, (uint32_t*)key, (uint32_t*)out, 100); HAL_CRYP_DeInit(&hcryp); } ForceZero(key, sizeof(key)); ByteReverseWords((word32*)out, (word32*)out, inSz); *outSz = inSz; (void)aes; return ret; } int wc_Stm32_Aes_UnWrap(struct Aes* aes, CRYP_HandleTypeDef* hcryp, const byte* in, word32 inSz, const byte* iv, int ivSz) { int ret = 0; /* SAES requires use of the RNG -- HAL_RNG_DeInit() calls from random.c turn off the RNG clock -- re-enable the clock here */ __HAL_RCC_RNG_CLK_ENABLE(); /* setup for key unwrapping */ XMEMSET(hcryp, 0, sizeof(CRYP_HandleTypeDef)); hcryp->Instance = SAES; hcryp->Init.DataType = CRYP_DATATYPE_8B; hcryp->Init.KeySize = CRYP_KEYSIZE_256B; hcryp->Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_BYTE; if (ivSz > 0 && iv != NULL) { hcryp->Init.pInitVect = (uint32_t *)iv; hcryp->Init.Algorithm = CRYP_AES_CBC; } else { hcryp->Init.Algorithm = CRYP_AES_ECB; } hcryp->Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS; hcryp->Init.KeySelect = CRYP_KEYSEL_HW; /* use DHUK to unwrap with use */ hcryp->Init.KeyMode = CRYP_KEYMODE_WRAPPED; ret = HAL_CRYP_Init(hcryp); if (ret == HAL_OK) { /* On success the key is placed into a location where the next encrypt/decrypt * calls using hcryp make use of the key */ ret = HAL_CRYPEx_UnwrapKey(hcryp, (uint32_t*)in, 100); } return ret; } #endif int wc_Stm32_Aes_Init(Aes* aes, CRYP_HandleTypeDef* hcryp, int useSaes) { int ret; word32 keySize; #ifdef STM32_HW_CLOCK_AUTO /* enable the peripheral clock */ __HAL_RCC_CRYP_CLK_ENABLE(); #endif ret = wc_AesGetKeySize(aes, &keySize); if (ret != 0) return ret; XMEMSET(hcryp, 0, sizeof(CRYP_HandleTypeDef)); switch (keySize) { case 16: /* 128-bit key */ hcryp->Init.KeySize = CRYP_KEYSIZE_128B; break; #ifdef CRYP_KEYSIZE_192B case 24: /* 192-bit key */ hcryp->Init.KeySize = CRYP_KEYSIZE_192B; break; #endif case 32: /* 256-bit key */ hcryp->Init.KeySize = CRYP_KEYSIZE_256B; break; default: break; } #ifdef WOLFSSL_STM32U5_DHUK /* Use hardware key */ if (useSaes && (aes->devId == WOLFSSL_STM32U5_DHUK_DEVID || aes->devId == WOLFSSL_STM32U5_SAES_DEVID)) { /* SAES requires use of the RNG -- HAL_RNG_DeInit() calls from random.c turn off the RNG clock -- re-enable the clock here */ __HAL_RCC_RNG_CLK_ENABLE(); hcryp->Instance = SAES; hcryp->Init.DataType = CRYP_DATATYPE_8B; /* Key select (HW, or Normal) */ if (aes->devId == WOLFSSL_STM32U5_DHUK_DEVID) { hcryp->Init.KeySelect = CRYP_KEYSEL_HW; } else { hcryp->Init.KeySelect = CRYP_KEYSEL_NORMAL; hcryp->Init.KeyMode = CRYP_KEYMODE_NORMAL; hcryp->Init.pKey = (uint32_t*)aes->key; } } else #endif { hcryp->Instance = CRYP; hcryp->Init.DataType = CRYP_DATATYPE_8B; hcryp->Init.pKey = (STM_CRYPT_TYPE*)aes->key; } #ifdef STM32_HAL_V2 hcryp->Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_BYTE; #if defined(CRYP_HEADERWIDTHUNIT_BYTE) && defined(STM_CRYPT_HEADER_WIDTH) hcryp->Init.HeaderWidthUnit = (STM_CRYPT_HEADER_WIDTH == 4) ? CRYP_HEADERWIDTHUNIT_WORD : CRYP_HEADERWIDTHUNIT_BYTE; #endif #endif return 0; } void wc_Stm32_Aes_Cleanup(void) { #ifdef STM32_HW_CLOCK_AUTO /* disable the peripheral clock */ __HAL_RCC_CRYP_CLK_DISABLE(); #endif } #else /* Standard Peripheral Library */ int wc_Stm32_Aes_Init(Aes* aes, CRYP_InitTypeDef* cryptInit, CRYP_KeyInitTypeDef* keyInit) { int ret; word32 keySize; word32* aes_key; ret = wc_AesGetKeySize(aes, &keySize); if (ret != 0) return ret; aes_key = aes->key; /* crypto structure initialization */ CRYP_KeyStructInit(keyInit); CRYP_StructInit(cryptInit); /* load key into correct registers */ switch (keySize) { case 16: /* 128-bit key */ cryptInit->CRYP_KeySize = CRYP_KeySize_128b; keyInit->CRYP_Key2Left = aes_key[0]; keyInit->CRYP_Key2Right = aes_key[1]; keyInit->CRYP_Key3Left = aes_key[2]; keyInit->CRYP_Key3Right = aes_key[3]; break; case 24: /* 192-bit key */ cryptInit->CRYP_KeySize = CRYP_KeySize_192b; keyInit->CRYP_Key1Left = aes_key[0]; keyInit->CRYP_Key1Right = aes_key[1]; keyInit->CRYP_Key2Left = aes_key[2]; keyInit->CRYP_Key2Right = aes_key[3]; keyInit->CRYP_Key3Left = aes_key[4]; keyInit->CRYP_Key3Right = aes_key[5]; break; case 32: /* 256-bit key */ cryptInit->CRYP_KeySize = CRYP_KeySize_256b; keyInit->CRYP_Key0Left = aes_key[0]; keyInit->CRYP_Key0Right = aes_key[1]; keyInit->CRYP_Key1Left = aes_key[2]; keyInit->CRYP_Key1Right = aes_key[3]; keyInit->CRYP_Key2Left = aes_key[4]; keyInit->CRYP_Key2Right = aes_key[5]; keyInit->CRYP_Key3Left = aes_key[6]; keyInit->CRYP_Key3Right = aes_key[7]; break; default: break; } cryptInit->CRYP_DataType = CRYP_DataType_8b; return 0; } void wc_Stm32_Aes_Cleanup(void) { } #endif /* WOLFSSL_STM32_CUBEMX */ #endif /* !NO_AES */ #endif /* STM32_CRYPTO */ #ifdef WOLFSSL_STM32_PKA /* Reverse array in memory (in place) */ #ifdef HAVE_ECC /* convert from mp_int to STM32 PKA HAL integer, as array of bytes of size sz. * if mp_int has less bytes than sz, add zero bytes at most significant byte * positions. * This is when for example modulus is 32 bytes (P-256 curve) * and mp_int has only 31 bytes, we add leading zeros * so that result array has 32 bytes, same as modulus (sz). */ static int stm32_get_from_mp_int(uint8_t *dst, const mp_int *a, int sz) { int res, szbin, offset; if (dst == NULL || a == NULL || sz < 0) return BAD_FUNC_ARG; /* check how many bytes are in the mp_int */ szbin = mp_unsigned_bin_size(a); if (szbin < 0 || szbin > sz) return BUFFER_E; /* compute offset from dst */ offset = sz - szbin; if (offset < 0) offset = 0; if (offset > sz) offset = sz; /* add leading zeroes */ if (offset) XMEMSET(dst, 0, offset); /* convert mp_int to array of bytes */ res = mp_to_unsigned_bin(a, dst + offset); return res; } static int stm32_getabs_from_mp_int(uint8_t *dst, const mp_int *a, int sz, uint32_t* abs_sign) { int res; mp_int x; if (dst == NULL || a == NULL || sz < 0 || abs_sign == NULL) return BAD_FUNC_ARG; res = mp_init(&x); if (res == MP_OKAY) { /* make abs(x) and capture sign */ #if defined(USE_FAST_MATH) || defined(USE_INTEGER_HEAP_MATH) || \ ((defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)) && \ defined(WOLFSSL_SP_INT_NEGATIVE)) *abs_sign = x.sign; #else *abs_sign = 1; /* default to negative */ #endif res = mp_abs((mp_int*)a, &x); if (res == MP_OKAY) res = stm32_get_from_mp_int(dst, &x, sz); mp_clear(&x); } return res; } /* convert hex string to unsigned char */ static int stm32_getabs_from_hexstr(const char* hex, uint8_t* dst, int sz, uint32_t *abs_sign) { int res; mp_int x; if (hex == NULL || dst == NULL || sz < 0) return BAD_FUNC_ARG; res = mp_init(&x); if (res == MP_OKAY) { res = mp_read_radix(&x, hex, MP_RADIX_HEX); /* optionally make abs(x) and capture sign */ if (res == MP_OKAY && abs_sign != NULL) { #if defined(USE_FAST_MATH) || defined(USE_INTEGER_HEAP_MATH) || \ ((defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)) && \ defined(WOLFSSL_SP_INT_NEGATIVE)) *abs_sign = x.sign; #else *abs_sign = 1; /* default to negative */ #endif res = mp_abs(&x, &x); } if (res == MP_OKAY) res = stm32_get_from_mp_int(dst, &x, sz); mp_clear(&x); } return res; } static int stm32_get_from_hexstr(const char* hex, uint8_t* dst, int sz) { return stm32_getabs_from_hexstr(hex, dst, sz, NULL); } /* STM32 PKA supports up to 640-bit numbers */ #define STM32_MAX_ECC_SIZE (80) #ifdef WOLFSSL_STM32_PKA_V2 /* find curve based on prime/modulus and return order/coefB */ static int stm32_get_curve_params(mp_int* modulus, uint8_t* order, uint8_t* coefB) { int res, i, found = 0; mp_int modulusChk; res = mp_init(&modulusChk); if (res != MP_OKAY) return res; for (i = 0; ecc_sets[i].size != 0 && ecc_sets[i].name != NULL; i++) { const ecc_set_type* curve = &ecc_sets[i]; /* match based on curve prime */ if ((res = mp_read_radix(&modulusChk, curve->prime, MP_RADIX_HEX)) == MP_OKAY && (mp_cmp(modulus, &modulusChk) == MP_EQ)) { found = 1; if (order) { res = stm32_get_from_hexstr(curve->order, order, curve->size); } if (coefB) { res = stm32_get_from_hexstr(curve->Bf, coefB, curve->size); } break; } } mp_clear(&modulusChk); if (!found && res == MP_OKAY) { res = MP_RANGE; } return res; } #endif /* WOLFSSL_STM32_PKA_V2 */ /** Perform a point multiplication (timing resistant) k The scalar to multiply by G The base point R [out] Destination for kG a ECC curve parameter a modulus The modulus of the field the ECC curve is in order curve order rng Random Generator struct (not used) map Boolean whether to map back to affine or not (1==map, 0 == leave in projective) return MP_OKAY on success */ int wc_ecc_mulmod_ex2(const mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, mp_int* modulus, mp_int* o, WC_RNG* rng, int map, void* heap) { PKA_ECCMulInTypeDef pka_mul; PKA_ECCMulOutTypeDef pka_mul_res; int szModulus; int status; int res; uint8_t Gxbin[STM32_MAX_ECC_SIZE]; uint8_t Gybin[STM32_MAX_ECC_SIZE]; uint8_t kbin[STM32_MAX_ECC_SIZE]; uint8_t PtXbin[STM32_MAX_ECC_SIZE]; uint8_t PtYbin[STM32_MAX_ECC_SIZE]; uint8_t prime[STM32_MAX_ECC_SIZE]; uint8_t coefA[STM32_MAX_ECC_SIZE]; #ifdef WOLFSSL_STM32_PKA_V2 uint8_t coefB[STM32_MAX_ECC_SIZE]; uint8_t order[STM32_MAX_ECC_SIZE]; #endif uint32_t coefA_sign = 1; (void)rng; XMEMSET(&pka_mul, 0x00, sizeof(PKA_ECCMulInTypeDef)); XMEMSET(&pka_mul_res, 0x00, sizeof(PKA_ECCMulOutTypeDef)); pka_mul_res.ptX = PtXbin; pka_mul_res.ptY = PtYbin; if (k == NULL || G == NULL || R == NULL || modulus == NULL) { return ECC_BAD_ARG_E; } szModulus = mp_unsigned_bin_size(modulus); res = stm32_get_from_mp_int(kbin, k, szModulus); if (res == MP_OKAY) res = stm32_get_from_mp_int(Gxbin, G->x, szModulus); if (res == MP_OKAY) res = stm32_get_from_mp_int(Gybin, G->y, szModulus); if (res == MP_OKAY) res = stm32_get_from_mp_int(prime, modulus, szModulus); if (res == MP_OKAY) res = stm32_getabs_from_mp_int(coefA, a, szModulus, &coefA_sign); #ifdef WOLFSSL_STM32_PKA_V2 XMEMSET(order, 0, sizeof(order)); XMEMSET(coefB, 0, sizeof(coefB)); if (res == MP_OKAY) { if (o != NULL) { /* use provided order and get coefB */ res = stm32_get_from_mp_int(order, o, szModulus); if (res == MP_OKAY) { res = stm32_get_curve_params(modulus, NULL, coefB); } } else { /* get order and coefB for matching prime */ res = stm32_get_curve_params(modulus, order, coefB); } } #endif if (res != MP_OKAY) { ForceZero(kbin, sizeof(kbin)); return res; } pka_mul.modulusSize = szModulus; pka_mul.coefSign = coefA_sign; pka_mul.coefA = coefA; pka_mul.modulus = prime; pka_mul.pointX = Gxbin; pka_mul.pointY = Gybin; pka_mul.scalarMulSize = szModulus; pka_mul.scalarMul = kbin; #ifdef WOLFSSL_STM32_PKA_V2 pka_mul.coefB = coefB; pka_mul.primeOrder = order; #endif status = HAL_PKA_ECCMul(&hpka, &pka_mul, HAL_MAX_DELAY); if (status != HAL_OK) { ForceZero(kbin, sizeof(kbin)); HAL_PKA_RAMReset(&hpka); return WC_HW_E; } pka_mul_res.ptX = Gxbin; pka_mul_res.ptY = Gybin; HAL_PKA_ECCMul_GetResult(&hpka, &pka_mul_res); ForceZero(kbin, sizeof(kbin)); res = mp_read_unsigned_bin(R->x, Gxbin, szModulus); if (res == MP_OKAY) { res = mp_read_unsigned_bin(R->y, Gybin, szModulus); #if defined(USE_FAST_MATH) || defined(USE_INTEGER_HEAP_MATH) || \ ((defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)) && \ defined(WOLFSSL_SP_INT_NEGATIVE)) /* if k is negative, we compute the multiplication with abs(-k) * with result (x, y) and modify the result to (x, -y) */ R->y->sign = k->sign; #endif } if (res == MP_OKAY) res = mp_set(R->z, 1); HAL_PKA_RAMReset(&hpka); (void)heap; return res; } int wc_ecc_mulmod_ex(const mp_int *k, ecc_point *G, ecc_point *R, mp_int* a, mp_int *modulus, int map, void* heap) { return wc_ecc_mulmod_ex2(k, G, R, a, modulus, NULL, NULL, map, heap); } int ecc_map_ex(ecc_point* P, mp_int* modulus, mp_digit mp, int ct) { /* this is handled in hardware, so no projective mapping needed */ (void)P; (void)modulus; (void)mp; (void)ct; return MP_OKAY; } int stm32_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, word32 hashlen, int* res, ecc_key* key) { PKA_ECDSAVerifInTypeDef pka_ecc; int size; int status; uint8_t Rbin[STM32_MAX_ECC_SIZE]; uint8_t Sbin[STM32_MAX_ECC_SIZE]; uint8_t Qxbin[STM32_MAX_ECC_SIZE]; uint8_t Qybin[STM32_MAX_ECC_SIZE]; uint8_t Hashbin[STM32_MAX_ECC_SIZE]; uint8_t prime[STM32_MAX_ECC_SIZE]; uint8_t coefA[STM32_MAX_ECC_SIZE]; uint8_t gen_x[STM32_MAX_ECC_SIZE]; uint8_t gen_y[STM32_MAX_ECC_SIZE]; uint8_t order[STM32_MAX_ECC_SIZE]; uint32_t coefA_sign = 1; XMEMSET(&pka_ecc, 0x00, sizeof(PKA_ECDSAVerifInTypeDef)); if (r == NULL || s == NULL || hash == NULL || res == NULL || key == NULL || key->dp == NULL) { return ECC_BAD_ARG_E; } *res = 0; /* default to failure */ size = wc_ecc_size(key); /* get key size in bytes */ /* load R/S and public X/Y using key size */ status = stm32_get_from_mp_int(Rbin, r, size); if (status == MP_OKAY) status = stm32_get_from_mp_int(Sbin, s, size); if (status == MP_OKAY) status = stm32_get_from_mp_int(Qxbin, key->pubkey.x, size); if (status == MP_OKAY) status = stm32_get_from_mp_int(Qybin, key->pubkey.y, size); if (status != MP_OKAY) return status; /* find parameters for the selected curve */ status = stm32_get_from_hexstr(key->dp->prime, prime, size); if (status == MP_OKAY) status = stm32_get_from_hexstr(key->dp->order, order, size); if (status == MP_OKAY) status = stm32_get_from_hexstr(key->dp->Gx, gen_x, size); if (status == MP_OKAY) status = stm32_get_from_hexstr(key->dp->Gy, gen_y, size); if (status == MP_OKAY) status = stm32_getabs_from_hexstr(key->dp->Af, coefA, size, &coefA_sign); if (status != MP_OKAY) return status; pka_ecc.primeOrderSize = size; pka_ecc.modulusSize = size; pka_ecc.coefSign = coefA_sign; pka_ecc.coef = coefA; pka_ecc.modulus = prime; pka_ecc.basePointX = gen_x; pka_ecc.basePointY = gen_y; pka_ecc.primeOrder = order; pka_ecc.pPubKeyCurvePtX = Qxbin; pka_ecc.pPubKeyCurvePtY = Qybin; pka_ecc.RSign = Rbin; pka_ecc.SSign = Sbin; XMEMSET(Hashbin, 0, STM32_MAX_ECC_SIZE); if (hashlen > STM32_MAX_ECC_SIZE) { return ECC_BAD_ARG_E; } else if ((int)hashlen > size) { /* in the case that hashlen is larger than key size place hash at * beginning of buffer */ XMEMCPY(Hashbin, hash, size); } else { /* in all other cases where hashlen is equal to or less than the key * size pad the Hashbin buffer with leading zero's */ XMEMCPY(Hashbin + (size - hashlen), hash, hashlen); } pka_ecc.hash = Hashbin; status = HAL_PKA_ECDSAVerif(&hpka, &pka_ecc, HAL_MAX_DELAY); if (status != HAL_OK) { HAL_PKA_RAMReset(&hpka); return WC_HW_E; } *res = HAL_PKA_ECDSAVerif_IsValidSignature(&hpka); HAL_PKA_RAMReset(&hpka); return status; } int stm32_ecc_sign_hash_ex(const byte* hash, word32 hashlen, WC_RNG* rng, ecc_key* key, mp_int *r, mp_int *s) { PKA_ECDSASignInTypeDef pka_ecc; PKA_ECDSASignOutTypeDef pka_ecc_out; int size; int status; mp_int gen_k; mp_int order_mp; uint8_t Keybin[STM32_MAX_ECC_SIZE]; uint8_t Intbin[STM32_MAX_ECC_SIZE]; uint8_t Rbin[STM32_MAX_ECC_SIZE]; uint8_t Sbin[STM32_MAX_ECC_SIZE]; uint8_t Hashbin[STM32_MAX_ECC_SIZE]; uint8_t prime[STM32_MAX_ECC_SIZE]; uint8_t coefA[STM32_MAX_ECC_SIZE]; #ifdef WOLFSSL_STM32_PKA_V2 uint8_t coefB[STM32_MAX_ECC_SIZE]; #endif uint8_t gen_x[STM32_MAX_ECC_SIZE]; uint8_t gen_y[STM32_MAX_ECC_SIZE]; uint8_t order[STM32_MAX_ECC_SIZE]; uint32_t coefA_sign = 1; XMEMSET(&pka_ecc, 0x00, sizeof(PKA_ECDSASignInTypeDef)); XMEMSET(&pka_ecc_out, 0x00, sizeof(PKA_ECDSASignOutTypeDef)); if (r == NULL || s == NULL || hash == NULL || key == NULL || key->dp == NULL) { return ECC_BAD_ARG_E; } size = wc_ecc_size(key); /* find parameters for the selected curve */ status = stm32_get_from_hexstr(key->dp->prime, prime, size); if (status == MP_OKAY) status = stm32_get_from_hexstr(key->dp->order, order, size); if (status == MP_OKAY) status = stm32_get_from_hexstr(key->dp->Gx, gen_x, size); if (status == MP_OKAY) status = stm32_get_from_hexstr(key->dp->Gy, gen_y, size); if (status == MP_OKAY) status = stm32_getabs_from_hexstr(key->dp->Af, coefA, size, &coefA_sign); #ifdef WOLFSSL_STM32_PKA_V2 if (status == MP_OKAY) status = stm32_get_from_hexstr(key->dp->Bf, coefB, size); #endif if (status != MP_OKAY) return status; /* generate random part of "k" */ mp_init(&gen_k); mp_init(&order_mp); status = mp_read_unsigned_bin(&order_mp, order, size); if (status == MP_OKAY) status = wc_ecc_gen_k(rng, size, &gen_k, &order_mp); if (status == MP_OKAY) status = stm32_get_from_mp_int(Intbin, &gen_k, size); mp_clear(&gen_k); mp_clear(&order_mp); if (status != MP_OKAY) { ForceZero(Intbin, sizeof(Intbin)); return status; } /* get private part of "k" */ status = stm32_get_from_mp_int(Keybin, wc_ecc_key_get_priv(key), size); if (status != MP_OKAY) { ForceZero(Keybin, sizeof(Keybin)); ForceZero(Intbin, sizeof(Intbin)); return status; } pka_ecc.primeOrderSize = size; pka_ecc.modulusSize = size; pka_ecc.coefSign = coefA_sign; pka_ecc.coef = coefA; #ifdef WOLFSSL_STM32_PKA_V2 pka_ecc.coefB = coefB; #endif pka_ecc.modulus = prime; pka_ecc.basePointX = gen_x; pka_ecc.basePointY = gen_y; pka_ecc.primeOrder = order; XMEMSET(Hashbin, 0, STM32_MAX_ECC_SIZE); if (hashlen > STM32_MAX_ECC_SIZE) { ForceZero(Keybin, sizeof(Keybin)); ForceZero(Intbin, sizeof(Intbin)); return ECC_BAD_ARG_E; } else if ((int)hashlen > size) { /* in the case that hashlen is larger than key size place hash at * beginning of buffer */ XMEMCPY(Hashbin, hash, size); } else { /* in all other cases where hashlen is equal to or less than the key * size pad the Hashbin buffer with leading zero's */ XMEMCPY(Hashbin + (size - hashlen), hash, hashlen); } pka_ecc.hash = Hashbin; pka_ecc.integer = Intbin; pka_ecc.privateKey = Keybin; /* Assign R, S static buffers */ pka_ecc_out.RSign = Rbin; pka_ecc_out.SSign = Sbin; status = HAL_PKA_ECDSASign(&hpka, &pka_ecc, HAL_MAX_DELAY); if (status != HAL_OK) { ForceZero(Keybin, sizeof(Keybin)); ForceZero(Intbin, sizeof(Intbin)); HAL_PKA_RAMReset(&hpka); return WC_HW_E; } HAL_PKA_ECDSASign_GetResult(&hpka, &pka_ecc_out, NULL); ForceZero(Keybin, sizeof(Keybin)); ForceZero(Intbin, sizeof(Intbin)); status = mp_read_unsigned_bin(r, pka_ecc_out.RSign, size); if (status == MP_OKAY) status = mp_read_unsigned_bin(s, pka_ecc_out.SSign, size); HAL_PKA_RAMReset(&hpka); return status; } #endif /* HAVE_ECC */ #endif /* WOLFSSL_STM32_PKA */