From 1d9e0974f37ba15bfc948229d5246d38dc8c87f3 Mon Sep 17 00:00:00 2001 From: Peter Barada Date: Mon, 20 Jul 2026 13:46:09 -0400 Subject: [PATCH] arch/arm/src/stm32h7: Extend crypto interface to support HW HASH Add stm32h7 support for HASH HW accelerator for MD5, SHA1, SHA2-224, and SHA2-256 as well as their HMAC variants. Signed-off-by: Peter Barada --- arch/arm/src/stm32h7/Kconfig | 39 +- .../src/stm32h7/hardware/stm32h7xxxx_hash.h | 180 ++++++ arch/arm/src/stm32h7/stm32_crypto.c | 576 ++++++++++++++++-- arch/arm/src/stm32h7/stm32h7x3xx_rcc.c | 6 + .../nucleo-h753zi/configs/crypto/defconfig | 6 +- 5 files changed, 757 insertions(+), 50 deletions(-) create mode 100644 arch/arm/src/stm32h7/hardware/stm32h7xxxx_hash.h diff --git a/arch/arm/src/stm32h7/Kconfig b/arch/arm/src/stm32h7/Kconfig index 90ec8b7febf03..8712d4e652c75 100644 --- a/arch/arm/src/stm32h7/Kconfig +++ b/arch/arm/src/stm32h7/Kconfig @@ -280,9 +280,10 @@ config ARCH_CHIP_STM32H750VB select STM32H7_IO_CONFIG_V select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7+M4, 128 Kb FLASH, 1024K Kb SRAM, - with cryptographic accelerator, LQFP100 + with cryptographic & hash accelerator, LQFP100 config ARCH_CHIP_STM32H750ZB bool "STM32H750ZB" @@ -291,9 +292,10 @@ config ARCH_CHIP_STM32H750ZB select STM32H7_IO_CONFIG_Z select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7+M4, 128 Kb FLASH, 1024K Kb SRAM, - with cryptographic accelerator, LQFP144 + with cryptographic & hash accelerator, LQFP144 config ARCH_CHIP_STM32H750IB bool "STM32H750IB" @@ -302,9 +304,10 @@ config ARCH_CHIP_STM32H750IB select STM32H7_IO_CONFIG_I select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7+M4, 128 Kb FLASH, 1024K Kb SRAM, - with cryptographic accelerator, LQFP176 or UFBGA176+25 + with cryptographic & hash accelerator, LQFP176 or UFBGA176+25 config ARCH_CHIP_STM32H750XB bool "STM32H750XB" @@ -313,9 +316,10 @@ config ARCH_CHIP_STM32H750XB select STM32H7_IO_CONFIG_X select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7+M4, 128 Kb FLASH, 1024K Kb SRAM, - with cryptographic accelerator, TFBGA240+25 + with cryptographic & hash accelerator, TFBGA240+25 config ARCH_CHIP_STM32H753AI bool "STM32H753AI" @@ -324,9 +328,10 @@ config ARCH_CHIP_STM32H753AI select STM32H7_IO_CONFIG_A select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, - with cryptographic accelerator, UFBGA169 + with cryptographic & hash accelerator, UFBGA169 config ARCH_CHIP_STM32H753BI bool "STM32H753BI" @@ -335,9 +340,10 @@ config ARCH_CHIP_STM32H753BI select STM32H7_IO_CONFIG_B select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, - with cryptographic accelerator, LQFP208 + with cryptographic & hash accelerator, LQFP208 config ARCH_CHIP_STM32H753II bool "STM32H753II" @@ -346,9 +352,10 @@ config ARCH_CHIP_STM32H753II select STM32H7_IO_CONFIG_I select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, - with cryptographic accelerator, LQFP176/UFBGA176 + with cryptographic & hash accelerator, LQFP176/UFBGA176 config ARCH_CHIP_STM32H753VI bool "STM32H753VI" @@ -357,9 +364,10 @@ config ARCH_CHIP_STM32H753VI select STM32H7_IO_CONFIG_V select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, - with cryptographic accelerator, LQFP100/TFBGA100 + with cryptographic & hash accelerator, LQFP100/TFBGA100 config ARCH_CHIP_STM32H753XI bool "STM32H753XI" @@ -368,9 +376,10 @@ config ARCH_CHIP_STM32H753XI select STM32H7_IO_CONFIG_X select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, - with cryptographic accelerator, TFBGA240 + with cryptographic & hash accelerator, TFBGA240 config ARCH_CHIP_STM32H753ZI bool "STM32H753ZI" @@ -379,9 +388,10 @@ config ARCH_CHIP_STM32H753ZI select STM32H7_IO_CONFIG_Z select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, - with cryptographic accelerator, LQFP144 + with cryptographic & hash accelerator, LQFP144 config ARCH_CHIP_STM32H7B3LI bool "STM32H7B3LI" @@ -391,9 +401,10 @@ config ARCH_CHIP_STM32H7B3LI select STM32_HAVE_SMPS select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1376 Kb SRAM, - with cryptographic accelerator, TFBGA225 + with cryptographic & hash accelerator, TFBGA225 config ARCH_CHIP_STM32H755II bool "STM32H755II" @@ -404,9 +415,10 @@ config ARCH_CHIP_STM32H755II select STM32_HAVE_FDCAN2 select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, - with cryptographic accelerator, LQFP176/UFBGA176 + with cryptographic & hash accelerator, LQFP176/UFBGA176 config ARCH_CHIP_STM32H755XI bool "STM32H755XI" @@ -417,9 +429,10 @@ config ARCH_CHIP_STM32H755XI select STM32_HAVE_FDCAN2 select STM32_HAVE_CRYP select STM32_HAVE_IP_CRYPTO_H7 + select STM32_HAVE_HASH ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, - with cryptographic accelerator, TFBGA240 + with cryptographic & hash accelerator, TFBGA240 endchoice # STM32 H7 Chip Selection diff --git a/arch/arm/src/stm32h7/hardware/stm32h7xxxx_hash.h b/arch/arm/src/stm32h7/hardware/stm32h7xxxx_hash.h new file mode 100644 index 0000000000000..df2e3e33da2d8 --- /dev/null +++ b/arch/arm/src/stm32h7/hardware/stm32h7xxxx_hash.h @@ -0,0 +1,180 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/hardware/stm32h7xxxx_hash.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32H7XXXX_HASH_H +#define __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32H7XXXX_HASH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "chip.h" + +/* The following STM32H7 devices have a cryptographic accelerator that + * support AES, DES/TDES: + * + * STM32H735ZO, STM32H750XX, STM32H753XX, STM32H755XX, STM32H757XX, + * STM32H7B0XX, STM32H7B3XX, STM32H7S3x8, STM32H7S7X8 + */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* HASH register offsets ****************************************************/ + +#define STM32_HASH_CR_OFFSET 0x0000 /* Control Register */ +#define STM32_HASH_DIN_OFFSET 0x0004 /* Data Input Register */ +#define STM32_HASH_STR_OFFSET 0x0008 /* Start Register */ +#define STM32_HASH_HRA0_OFFSET 0x000C /* Alias Digest Reg 0 */ +#define STM32_HASH_HRA1_OFFSET 0x0010 /* Alias Digest Reg 1 */ +#define STM32_HASH_HRA2_OFFSET 0x0014 /* Alias Digest Reg 2 */ +#define STM32_HASH_HRA3_OFFSET 0x0018 /* Alias Digest Reg 3 */ +#define STM32_HASH_HRA4_OFFSET 0x001C /* Alias Digest Reg 4 */ + +#define STM32_HASH_IMR_OFFSET 0x0020 /* Interrupt Mask Register */ +#define STM32_HASH_SR_OFFSET 0x0024 /* Status Register */ + +#define STM32_HASH_CSR0_OFFSET 0x00f8 /* Context swap Register 0 */ +#define STM32_HASH_CSRx_OFFSET(x) (STM32_HASH_CSR0_OFFSET + 4 * (x)) + +#define STM32_HASH_HR0_OFFSET 0x0310 /* Digest Reg 0 */ +#define STM32_HASH_HR1_OFFSET 0x0314 /* Digest Reg 1 */ +#define STM32_HASH_HR2_OFFSET 0x0318 /* Digest Reg 2 */ +#define STM32_HASH_HR3_OFFSET 0x031c /* Digest Reg 3 */ +#define STM32_HASH_HR4_OFFSET 0x0320 /* Digest Reg 4 */ +#define STM32_HASH_HR5_OFFSET 0x0324 /* Supplemental Digest Reg 5 */ +#define STM32_HASH_HR6_OFFSET 0x0328 /* Supplemental Digest Reg 6 */ +#define STM32_HASH_HR7_OFFSET 0x032C /* Supplemental Digest Reg 7 */ + +/* HASH register addresses **************************************************/ + +#define STM32_HASH_CR (STM32_HASH_BASE + STM32_HASH_CR_OFFSET) +#define STM32_HASH_DIN (STM32_HASH_BASE + STM32_HASH_DIN_OFFSET) +#define STM32_HASH_STR (STM32_HASH_BASE + STM32_HASH_STR_OFFSET) +#define STM32_HASH_DMACR (STM32_HASH_BASE + STM32_HASH_DMACR_OFFSET) +#define STM32_HASH_HRA0 (STM32_HASH_BASE + STM32_HASH_HRA0_OFFSET) +#define STM32_HASH_HRA1 (STM32_HASH_BASE + STM32_HASH_HRA1_OFFSET) +#define STM32_HASH_HRA2 (STM32_HASH_BASE + STM32_HASH_HRA2_OFFSET) +#define STM32_HASH_HRA3 (STM32_HASH_BASE + STM32_HASH_HRA3_OFFSET) +#define STM32_HASH_HRA4 (STM32_HASH_BASE + STM32_HASH_HRA4_OFFSET) +#define STM32_HASH_IMR (STM32_HASH_BASE + STM32_HASH_IMR_OFFSET) +#define STM32_HASH_SR (STM32_HASH_BASE + STM32_HASH_SR_OFFSET) +#define STM32_HASH_CSR0 (STM32_HASH_BASE + STM32_HASH_CSR0_OFFSET) +#define STM32_HASH_HR0 (STM32_HASH_BASE + STM32_HASH_HR0_OFFSET) +#define STM32_HASH_HR1 (STM32_HASH_BASE + STM32_HASH_HR1_OFFSET) +#define STM32_HASH_HR2 (STM32_HASH_BASE + STM32_HASH_HR2_OFFSET) +#define STM32_HASH_HR3 (STM32_HASH_BASE + STM32_HASH_HR3_OFFSET) +#define STM32_HASH_HR4 (STM32_HASH_BASE + STM32_HASH_HR4_OFFSET) +#define STM32_HASH_HR5 (STM32_HASH_BASE + STM32_HASH_HR5_OFFSET) +#define STM32_HASH_HR6 (STM32_HASH_BASE + STM32_HASH_HR6_OFFSET) +#define STM32_HASH_HR7 (STM32_HASH_BASE + STM32_HASH_HR7_OFFSET) + +/* HASH register bit definitions ********************************************/ + +/* HASH CR register */ + +#define HASH_CR_LKEY_SHIFT 16 +#define HASH_CR_LKEY_MASK (1 << HASH_CR_LKEY_SHIFT) +#define HASH_CR_LKEY_LE_64 (0 << HASH_CR_LKEY_SHIFT) +#define HASH_CR_LKEY_GT_64 (1 << HASH_CR_LKEY_SHIFT) +#define HASH_CR_MDMAT_SHIFT 13 +#define HASH_CR_MDMAT_MASK (1 << HASH_CR_MDMAT_SHIFT) +#define HASH_CR_MDMAT_AUTO_SET (0 << HASH_CR_MDMAT_SHIFT) +#define HASH_CR_MDMAT_NOT_AUTO_SET (0 << HASH_CR_MDMAT_SHIFT) +#define HASH_CR_DINNE_SHIFT 12 +#define HASH_CR_DINNE_MASK (1 << HASH_CR_DINNE_SHIFT) +#define HASH_CR_DINNE_EMPTY (0 << HASH_CR_DINNE_SHIFT) +#define HASH_CR_DINNE_NOT_EMPTY (1 << HASH_CR_DINNE_SHIFT) +#define HASH_CR_NBW_SHIFT 8 +/* If 0 && DINNE == 0 then no word pushed; if DINNEset then one word pushed. + * If 1 then two words pushed (one in HASH_DIN and other in FIFO) + */ +#define HASH_CR_NBW_MASK (0xf << HASH_CR_NBW_SHIFT) + +#define HASH_CR_ALGO_MASK ((1 << 18) | (1 << 7)) +#define HASH_CR_ALGO_SHA1 ((0 << 18) | (0 << 7)) +#define HASH_CR_ALGO_MD5 ((0 << 18) | (1 << 7)) +#define HASH_CR_ALGO_SHA2_224 ((1 << 18) | (0 << 7)) +#define HASH_CR_ALGO_SHA2_256 ((1 << 18) | (1 << 7)) + +#define HASH_CR_MODE_SHIFT 6 +#define HASH_CR_MODE_MASK (1 << HASH_CR_MODE_SHIFT) +#define HASH_CR_MODE_HASH (0 << HASH_CR_MODE_SHIFT) +#define HASH_CR_MODE_HMAC (1 << HASH_CR_MODE_SHIFT) +#define HASH_CR_DATATYPE_SHIFT 4 +#define HASH_CR_DATATYPE_MASK (0x3 << HASH_CR_DATATYPE_SHiFT) +#define HASH_CR_DATATYPE_32 (0 << HASH_CR_DATATYPE_SHIFT) +#define HASH_CR_DATATYPE_16 (1 << HASH_CR_DATATYPE_SHIFT) +#define HASH_CR_DATATYPE_8 (2 << HASH_CR_DATATYPE_SHIFT) +#define HASH_CR_DATATYPE_1 (3 << HASH_CR_DATATYPE_SHIFT) +#define HASH_CR_DMAE_SHIFT 3 +#define HASH_CR_DMAE_MASK (1 << HASH_CR_DMAE_SHIFT) +#define HASH_CR_DMAE_DISABLE (0 << HASH_CR_DMAE_SHIFT) +#define HASH_CR_DMAE_ENABLE (1 << HASH_CR_DMAE_SHIFT) +#define HASH_CR_INIT_SHIFT 2 +#define HASH_CR_INIT_MASK (1 << HASH_CR_INIT_SHIFT) +#define HASH_CR_INIT HASH_CR_INIT_MASK + +/* HASH STR register */ + +#define HASH_STR_DCAL_SHIFT 8 +#define HASH_STR_DCAL (1 << HASH_STR_DCAL_SHIFT) +#define HASH_STR_DCAL_START HASH_STR_DCAL_MASK +#define HASH_STR_NBLW_SHIFT 0 +#define HASH_STR_NBLW_MASK (0x1F << HASH_STR_NBLW_SHIFT) +#define HASH_STR_NBLW(n) (((n) << HASH_STR_NBLW_SHIFT) \ + & HASH_STR_NBLW_MASK) +#define HASH_STR_NBLW_BYTES(n) ((((n) * 8) << HASH_STR_NBLW_SHIFT) \ + & HASH_STR_NBLW_MASK) + +/* HASH IMR register */ + +#define HASH_IMR_DCIE_SHIFT 1 +#define HASH_IMR_DCIE_MASK (1 << HASH_IMR_DCIE_SHIFT) +#define HASH_IMR_DCIE_DISABLE (0 << HASH_IMR_DCIE_SHIFT) +#define HASH_IMR_DCIE_ENABLE (1 << HASH_IMR_DCIE_SHIFT) +#define HASH_IMR_DINIE_SHIFT 1 +#define HASH_IMR_DINIE_MASK (1 << HASH_IMR_DINIE_SHIFT) +#define HASH_IMR_DINIE_DISABLE (0 << HASH_IMR_DINIE_SHIFT) +#define HASH_IMR_DINIE_ENABLE (1 << HASH_IMR_DINIE_SHIFT) + +/* HASH SR register */ + +#define HASH_SR_BUSY_SHIFT 3 +#define HASH_SR_BUSY_MASK (1 << HASH_SR_BUSY_SHIFT) +#define HASH_SR_BUSY HASH_SR_BUSY_MASK +#define HASH_SR_DMAS_SHIFT 2 +#define HASH_SR_DMAS_MASK (1 << HASH_SR_DMAS_SHIFT) +#define HASH_SR_DMAS HASH_SR_DMAS_MASK +#define HASH_SR_DCIS_SHIFT 1 +#define HASH_SR_DCIS_MASK (1 << HASH_SR_DCIS_SHIFT) +#define HASH_SR_DCIS HASH_SR_DCIS_MASK +#define HASH_SR_DINIS_SHIFT 0 +#define HASH_SR_DINIS_MASK (1 << HASH_SR_DINIS_SHIFT) +#define HASH_SR_DINIS HASH_SR_DINIS_MASK + +#endif /* __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32H7XXXX_HASH_H */ diff --git a/arch/arm/src/stm32h7/stm32_crypto.c b/arch/arm/src/stm32h7/stm32_crypto.c index a9cc1bd9f7fc7..c0c7bfb55d38e 100644 --- a/arch/arm/src/stm32h7/stm32_crypto.c +++ b/arch/arm/src/stm32h7/stm32_crypto.c @@ -37,6 +37,7 @@ #include "arm_internal.h" #include "hardware/stm32h7x3xx_rcc.h" #include "hardware/stm32h7xxxx_crc.h" +#include "hardware/stm32h7xxxx_hash.h" /* Following constants used in reverse32() to reverse * bit order of 32-bit value @@ -46,10 +47,19 @@ #define REV32_CONST3 0x0F0F0F0F #define REV32_CONST4 0x00FF00FF -#define STM32H7_CRC_RESET_TIMEOUT 1000 /* should be enough loops to reset */ +/* number polling iterations to wait for CRC to reset */ + +#define STM32H7_CRC_TIMEOUT 1000 /* should be enough... */ + +/* number polling iterations to wait for HASH to set CDIS/DINIS, + * or to clear BUSY + */ + +#define STM32H7_HASH_TIMEOUT 1000 /* should be enough... */ + #define CRC32_XOR_VALUE 0xFFFFFFFFUL -#undef CONFIG_STM32_CRYPTO_DEBUG +/* #define CONFIG_STM32_CRYPTO_DEBUG */ #ifdef CONFIG_STM32_CRYPTO_DEBUG #define stm32cryptoinfo(format, ...) \ @@ -78,6 +88,7 @@ ****************************************************************************/ static bool g_stm32_crc_initialized = false; +static bool g_stm32_hash_initialized = false; static uint32_t g_stm32_sesnum = 0; @@ -90,8 +101,17 @@ struct stm32_crypto_data { struct stm32_crc32 { - uint32_t init; /* init/interim CRC value */ + uint32_t init; /* init/interim CRC value */ } crc; + struct stm32_hash + { + bool hmac; /* true if hmac */ + uint8_t *key; /* hmac key */ + uint32_t klen; /* hmac key length */ + uint32_t rdata; /* unaligned hash data */ + uint32_t dsize; /* # byte sin digest */ + uint32_t rlen; /* # bytes accumulated in rdata */ + } hash; } u; struct stm32_crypto_data *hw_next; }; @@ -116,38 +136,115 @@ struct rn static struct rn stm32_crypto_regnames [] = { { - "RCC_AHB4RSTR", - STM32_RCC_AHB4RSTR, + "RCC_AHB4RSTR", STM32_RCC_AHB4RSTR, + }, + + { + "RCC_AHB4ENR", STM32_RCC_AHB4ENR, + }, + + { + "CRC_DR", STM32_CRC_DR, + }, + + { + "CRC_IDR", STM32_CRC_IDR, + }, + + { + "CRC_CR", STM32_CRC_CR, + }, + + { + "CRC_INIT", STM32_CRC_INIT, + }, + + { + "CRC_POL", STM32_CRC_POL, + }, + + { + "RCC_AHB2RSTR", STM32_RCC_AHB2RSTR, + }, + + { + "RCC_AHB2ENR", STM32_RCC_AHB2ENR, + }, + + { + "HASH_CR", STM32_HASH_CR, + }, + + { + "HASH_DIN", STM32_HASH_DIN, + }, + + { + "HASH_STR", STM32_HASH_STR, + }, + + { + "HASH_HRA0", STM32_HASH_HRA0, + }, + + { + "HASH_HRA1", STM32_HASH_HRA1, + }, + + { + "HASH_HRA2", STM32_HASH_HRA2, + }, + + { + "HASH_HRA3", STM32_HASH_HRA3, + }, + + { + "HASH_HRA4", STM32_HASH_HRA4, + }, + + { + "HASH_HR0", STM32_HASH_HR0, + }, + + { + "HASH_HR1", STM32_HASH_HR1, + }, + + { + "HASH_HR2", STM32_HASH_HR2, }, { - "RCC_AHB4ENR", - STM32_RCC_AHB4ENR, + "HASH_HR3", STM32_HASH_HR3, }, { - "CRC_DR", - STM32_CRC_DR, + "HASH_HR4", STM32_HASH_HR4, }, { - "CRC_IDR", - STM32_CRC_IDR, + "HASH_HR5", STM32_HASH_HR5, }, { - "CRC_CR", - STM32_CRC_CR, + "HASH_HR6", STM32_HASH_HR6, }, { - "CRC_INIT", - STM32_CRC_INIT, + "HASH_HR7", STM32_HASH_HR7, }, { - "CRC_POL", - STM32_CRC_POL, + "HASH_IMR", STM32_HASH_IMR, + }, + + { + "HASH_SR", STM32_HASH_SR, + }, + + { + "HASH_CSR0", STM32_HASH_CSR0, }, }; @@ -237,18 +334,42 @@ static void stm32_crypto_putreg32(const char *func, int line, * Name: stm32_wait_for_clr * * Description: - * wait for a bitmask to clear in HW register + * wait for all bits in bitmask to clear in HW register * ****************************************************************************/ static int stm32_wait_for_clr(uintptr_t regaddr, uint32_t bitmask, - uint32_t timeout) + uint32_t timeout) +{ + uint32_t regval; + while (timeout--) + { + regval = stm32crypto_getreg32(regaddr); + if ((regval & bitmask) == 0) + { + return 0; + } + } + + return -ETIMEDOUT; +} + +/**************************************************************************** + * Name: stm32_wait_for_set + * + * Description: + * wait for all bits in bitmask to set in HW register + * + ****************************************************************************/ + +static int stm32_wait_for_set(uintptr_t regaddr, uint32_t bitmask, + uint32_t timeout) { uint32_t regval; while (timeout--) { regval = stm32crypto_getreg32(regaddr); - if (regval & bitmask) + if ((regval & bitmask) == bitmask) { return 0; } @@ -317,7 +438,7 @@ static int crc32_init(struct stm32_crypto_data *sw) stm32crypto_putreg32(regval, STM32_CRC_CR); ret = stm32_wait_for_clr(STM32_CRC_CR, CRC_CR_RESET, - STM32H7_CRC_RESET_TIMEOUT); + STM32H7_CRC_TIMEOUT); return ret; } @@ -383,6 +504,250 @@ static int crc32_final(struct stm32_crypto_data *sw, caddr_t digest) return 0; } +static int hash_init(struct stm32_crypto_data *sw) +{ + irqstate_t flags; + uint32_t regval; + + stm32cryptoinfo(""); + + if (!g_stm32_hash_initialized) + { + g_stm32_hash_initialized = true; + + flags = enter_critical_section(); + + /* Clear/set AHB2RSTR to reset CRYP peripheral */ + + regval = stm32crypto_getreg32(STM32_RCC_AHB2RSTR); + regval |= RCC_AHB2RSTR_HASHRST; + stm32crypto_putreg32(regval, STM32_RCC_AHB2RSTR); + regval &= ~RCC_AHB2RSTR_HASHRST; + stm32crypto_putreg32(regval, STM32_RCC_AHB2RSTR); + + leave_critical_section(flags); + } + + /* Set the algorithm and digest size */ + + regval = 0; + switch (sw->hw_alg) + { + case CRYPTO_SHA1: + case CRYPTO_SHA1_HMAC: + regval = HASH_CR_ALGO_SHA1; + sw->u.hash.dsize = 20; + break; + case CRYPTO_MD5: + case CRYPTO_MD5_HMAC: + regval = HASH_CR_ALGO_MD5; + sw->u.hash.dsize = 16; + break; + case CRYPTO_SHA2_224: + case CRYPTO_SHA2_224_HMAC: + regval = HASH_CR_ALGO_SHA2_224; + sw->u.hash.dsize = 28; + break; + case CRYPTO_SHA2_256: + case CRYPTO_SHA2_256_HMAC: + regval = HASH_CR_ALGO_SHA2_256; + sw->u.hash.dsize = 32; + break; + + default: + return -EINVAL; + } + + /* If HMAC set mode, and key is large set HASH_CR_LKEY bit */ + + if (sw->u.hash.hmac) + { + regval |= HASH_CR_MODE_HMAC; + stm32cryptoinfo("klen %" PRIx32 "", sw->u.hash.klen); + if (sw->u.hash.klen > 64) + { + regval |= HASH_CR_LKEY_GT_64; + } + } + + regval |= HASH_CR_INIT; /* set init to configure HASH algorithm */ + regval |= HASH_CR_DATATYPE_8; /* 8-bit data... */ + stm32crypto_putreg32(regval, STM32_HASH_CR); + + sw->u.hash.rlen = 0; + sw->u.hash.rdata = 0; + + return 0; +} + +static int hash_update(struct stm32_crypto_data *sw, + uint8_t *buf, uint32_t len) +{ + const uint8_t *in_byte = buf; + const uint32_t *in_block; + int ret; + + stm32cryptoinfo("buf %" PRIxPTR " len %" PRIu32 "", + (uintptr_t)buf, len); + + if (len == 0) + { + return 0; + } + + /* If any remainder leftover from previous accumulation + * then accumulate them into hash.rdata to + * push into DIN + */ + + if (sw->u.hash.rlen) + { + while (sw->u.hash.rlen < sizeof(uint32_t)) + { + if (!len) + { + break; + } + + sw->u.hash.rdata |= (in_byte[0] << (8 * sw->u.hash.rlen)); + in_byte++; + sw->u.hash.rlen++; + len--; + } + + /* If hash_rlen still not sizeof(uint32_t) then input buffer + * doesn't hold enough bytes to write into DIN. + */ + + if (sw->u.hash.rlen < sizeof(uint32_t)) + { + return 0; + } + + stm32crypto_putreg32(sw->u.hash.rdata, STM32_HASH_DIN); + sw->u.hash.rlen = 0; + sw->u.hash.rdata = 0x0; + } + + in_block = (uint32_t *)in_byte; + + /* Loop pushing uint32_t of hash data into HASH_DIN */ + + while (len >= sizeof(uint32_t)) + { + ret = stm32_wait_for_clr(STM32_HASH_SR, HASH_SR_BUSY, + STM32H7_HASH_TIMEOUT); + if (ret < 0) + { + return ret; + } + + stm32crypto_putreg32(*in_block, STM32_HASH_DIN); + in_block++; + len -= sizeof(uint32_t); + } + + /* Accumulate any remaining bytes into hash.rdata */ + + if (len) + { + stm32cryptoinfo("len %" PRIu32 " hash.rlen: %" PRIu32 "", + len, sw->u.hash.rlen); + in_byte = (uint8_t *)in_block; + while (len) + { + sw->u.hash.rdata |= (in_byte[0] << (8 * sw->u.hash.rlen)); + sw->u.hash.rlen++; + in_byte++; + len--; + } + } + + return 0; +} + +static int hash_final(struct stm32_crypto_data *sw, caddr_t digest, + uint32_t wait_flag) +{ + uint32_t *out = (uint32_t *)digest; + uint32_t regval; + int ret; + + stm32cryptoinfo("digest %" PRIxPTR "", (uintptr_t)digest); + + /* If any data left in rdata, write it out */ + + if (sw->u.hash.rlen) + { + stm32crypto_putreg32(sw->u.hash.rdata, STM32_HASH_DIN); + } + + /* Start digest calculation. Set NBLW to number of + * bits of valid data in last write to HASH_DIN, and + * set DCAL to start the digest calculation. + */ + + regval = HASH_STR_NBLW_BYTES((uint32_t)sw->u.hash.rlen); + stm32crypto_putreg32(regval, STM32_HASH_STR); + + /* Set DCAL _after_ setting NBLW; have seen incorrect HMAC hash + * result if both done at same time. + */ + + regval |= HASH_STR_DCAL; + stm32crypto_putreg32(regval, STM32_HASH_STR); + + sw->u.hash.rlen = 0; + sw->u.hash.rdata = 0x0; + + /* Wait for the digest to compute + * (for HMAC wait for data to be ready) + */ + + ret = stm32_wait_for_set(STM32_HASH_SR, wait_flag, + STM32H7_HASH_TIMEOUT); + if (ret < 0) + { + return ret; + } + + /* Extract the resultant hash (if desired) */ + + if (digest) + { + regval = stm32crypto_getreg32(STM32_HASH_HRA0); + *out++ = __builtin_bswap32(regval); + regval = stm32crypto_getreg32(STM32_HASH_HRA1); + *out++ = __builtin_bswap32(regval); + regval = stm32crypto_getreg32(STM32_HASH_HRA2); + *out++ = __builtin_bswap32(regval); + regval = stm32crypto_getreg32(STM32_HASH_HRA3); + *out++ = __builtin_bswap32(regval); + + if (sw->u.hash.dsize >= 20) + { + regval = stm32crypto_getreg32(STM32_HASH_HRA4); + *out++ = __builtin_bswap32(regval); + } + + if (sw->u.hash.dsize >= 28) + { + regval = stm32crypto_getreg32(STM32_HASH_HR5); + *out++ = __builtin_bswap32(regval); + regval = stm32crypto_getreg32(STM32_HASH_HR6); + *out++ = __builtin_bswap32(regval); + } + + if (sw->u.hash.dsize == 32) + { + regval = stm32crypto_getreg32(STM32_HASH_HR7); + *out++ = __builtin_bswap32(regval); + } + } + + return 0; +} + /**************************************************************************** * Name: stm32_freesession * @@ -393,8 +758,9 @@ static int crc32_final(struct stm32_crypto_data *sw, caddr_t digest) static int stm32_freesession(uint64_t tid) { - FAR struct stm32_crypto_data *swd; + FAR struct stm32_crypto_data *sw; uint32_t sid = ((uint32_t) tid) & 0xffffffff; + int ret = 0; if (sid > g_stm32_sesnum || stm32_crypto_sessions == NULL || stm32_crypto_sessions[sid] == NULL) @@ -409,25 +775,41 @@ static int stm32_freesession(uint64_t tid) return 0; } - while ((swd = stm32_crypto_sessions[sid]) != NULL) + while ((sw = stm32_crypto_sessions[sid]) != NULL) { - stm32_crypto_sessions[sid] = swd->hw_next; + stm32_crypto_sessions[sid] = sw->hw_next; - switch (swd->hw_alg) + switch (sw->hw_alg) { + case CRYPTO_SHA1_HMAC: + case CRYPTO_MD5_HMAC: + case CRYPTO_SHA2_224_HMAC: + case CRYPTO_SHA2_256_HMAC: + if (sw->u.hash.key) + { + explicit_bzero(sw->u.hash.key, sw->u.hash.klen); + kmm_free(sw->u.hash.key); + } + break; + case CRYPTO_CRC32: + case CRYPTO_SHA1: + case CRYPTO_MD5: + case CRYPTO_SHA2_224: + case CRYPTO_SHA2_256: case CRYPTO_AES_CBC: case CRYPTO_AES_CTR: break; default: - return -EINVAL; + ret = -EINVAL; + break; } - kmm_free(swd); + kmm_free(sw); } - return 0; + return ret; } /**************************************************************************** @@ -441,8 +823,10 @@ static int stm32_freesession(uint64_t tid) static int stm32_newsession(uint32_t *sid, struct cryptoini *cri) { FAR struct stm32_crypto_data **swd; - int klen; + FAR struct stm32_crypto_data *sw; uint32_t i; + int klen; + int ret; stm32cryptoinfo(""); @@ -508,20 +892,75 @@ static int stm32_newsession(uint32_t *sid, struct cryptoini *cri) while (cri) { - *swd = kmm_zalloc(sizeof(struct stm32_crypto_data)); - if (*swd == NULL) + sw = kmm_zalloc(sizeof(struct stm32_crypto_data)); + *swd = sw; + if (sw == NULL) { stm32_freesession(i); return -ENOBUFS; } + sw->hw_alg = cri->cri_alg; switch (cri->cri_alg) { + case CRYPTO_MD5_HMAC: + case CRYPTO_SHA1_HMAC: + case CRYPTO_SHA2_224_HMAC: + case CRYPTO_SHA2_256_HMAC: + sw->u.hash.hmac = true; + sw->u.hash.klen = cri->cri_klen / 8; + sw->u.hash.key = kmm_malloc(sw->u.hash.klen); + if (sw->u.hash.key == NULL) + { + return -ENOBUFS; + } + + bcopy(cri->cri_key, sw->u.hash.key, sw->u.hash.klen); + + /* Initialize HW, push the key into DIN, wait for DINIS */ + + ret = hash_init(sw); + if (ret < 0) + { + return ret; + } + + stm32cryptoinfo("Push %" PRIu32 " bytes of outer hash into DIN", + sw->u.hash.klen); + ret = hash_update(sw, sw->u.hash.key, sw->u.hash.klen); + if (ret < 0) + { + return ret; + } + + stm32cryptoinfo("Wait for DINIS"); + ret = hash_final(sw, NULL, HASH_SR_DINIS); + if (ret < 0) + { + return ret; + } + + break; + + case CRYPTO_MD5: + case CRYPTO_SHA1: + case CRYPTO_SHA2_224: + case CRYPTO_SHA2_256: + sw->u.hash.hmac = false; + ret = hash_init(sw); + if (ret < 0) + { + return ret; + } + break; + case CRYPTO_CRC32: - crc32_init(*swd); + crc32_init(sw); break; + case CRYPTO_AES_CBC: break; + case CRYPTO_AES_CTR: klen = cri->cri_klen / 8 - 4; if ((klen != 16) && (klen != 24) && (klen != 32)) @@ -538,9 +977,9 @@ static int stm32_newsession(uint32_t *sid, struct cryptoini *cri) return -EINVAL; } - (*swd)->hw_alg = cri->cri_alg; + sw->hw_alg = cri->cri_alg; cri = cri->cri_next; - swd = &((*swd)->hw_next); + swd = &(sw->hw_next); } return 0; @@ -560,6 +999,7 @@ static int stm32_process(struct cryptop *crp) struct cryptodesc *crd; uint8_t iv[AESCTR_BLOCKSIZE]; uint32_t lid; + int ret; stm32cryptoinfo(""); @@ -567,11 +1007,13 @@ static int stm32_process(struct cryptop *crp) if (crp == NULL) { + stm32cryptoinfo(""); return -EINVAL; } - if (crp->crp_desc == NULL || crp->crp_buf == NULL) + if (crp->crp_desc == NULL) { + stm32cryptoinfo(""); crp->crp_etype = -EINVAL; goto done; } @@ -580,6 +1022,7 @@ static int stm32_process(struct cryptop *crp) if (lid >= g_stm32_sesnum || lid == 0 || stm32_crypto_sessions[lid] == NULL) { + stm32cryptoinfo(""); crp->crp_etype = -ENOENT; goto done; } @@ -605,11 +1048,64 @@ static int stm32_process(struct cryptop *crp) if (sw == NULL) { + stm32cryptoinfo(""); return -EINVAL; } switch (crd->crd_alg) { + case CRYPTO_MD5: + case CRYPTO_SHA1: + case CRYPTO_SHA2_224: + case CRYPTO_SHA2_256: + if (crd->crd_flags & CRD_F_UPDATE) + { + return hash_update(sw, crp->crp_buf, crd->crd_len); + } + else + { + return hash_final(sw, crp->crp_mac, HASH_SR_DCIS); + } + break; + case CRYPTO_MD5_HMAC: + case CRYPTO_SHA1_HMAC: + case CRYPTO_SHA2_224_HMAC: + case CRYPTO_SHA2_256_HMAC: + ret = hash_update(sw, crp->crp_buf, crd->crd_len); + if (ret < 0 || (crd->crd_flags & CRD_F_UPDATE)) + { + return ret; + } + + /* All HMAC data has been hashed, next step is + * 1) set DCAL and HBLW, wait for DINIS + */ + + ret = hash_final(sw, NULL, HASH_SR_DINIS); + if (ret < 0) + { + stm32cryptoinfo(""); + return ret; + } + + /* 2) Push outer hash (same as inner hash) into DIN */ + + stm32cryptoinfo("Push %" PRIu32 " bytes of inner hash", + sw->u.hash.klen); + + ret = hash_update(sw, sw->u.hash.key, sw->u.hash.klen); + if (ret < 0) + { + stm32cryptoinfo(""); + return ret; + } + + /* 3) normal finalization */ + + return hash_final(sw, crp->crp_mac, HASH_SR_DCIS); + + break; + case CRYPTO_CRC32: if (crd->crd_flags & CRD_F_UPDATE) { @@ -637,6 +1133,7 @@ static int stm32_process(struct cryptop *crp) crd->crd_klen / 8 - AESCTR_NONCESIZE, AES_MODE_CTR, crd->crd_flags & CRD_F_ENCRYPT); default: + stm32cryptoinfo("crc_alg %d", crd->crd_alg); return -EINVAL; } } @@ -664,6 +1161,15 @@ void hwcr_init(void) memset(algs, 0, sizeof(algs)); algs[CRYPTO_CRC32] = CRYPTO_ALG_FLAG_SUPPORTED; + algs[CRYPTO_MD5] = CRYPTO_ALG_FLAG_SUPPORTED; + algs[CRYPTO_SHA1] = CRYPTO_ALG_FLAG_SUPPORTED; + algs[CRYPTO_SHA2_224] = CRYPTO_ALG_FLAG_SUPPORTED; + algs[CRYPTO_SHA2_256] = CRYPTO_ALG_FLAG_SUPPORTED; + + algs[CRYPTO_MD5_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED; + algs[CRYPTO_SHA1_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED; + algs[CRYPTO_SHA2_224_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED; + algs[CRYPTO_SHA2_256_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_AES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_AES_CTR] = CRYPTO_ALG_FLAG_SUPPORTED; diff --git a/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c b/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c index c65bc2feeda73..d9e2ff31b6673 100644 --- a/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c +++ b/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c @@ -332,6 +332,12 @@ static inline void rcc_enableahb2(void) regval |= RCC_AHB2ENR_CRYPTEN; #endif +#ifdef CONFIG_STM32_HASH + /* Hash clock enable */ + + regval |= RCC_AHB2ENR_HASHEN; +#endif + putreg32(regval, STM32_RCC_AHB2ENR); /* Enable peripherals */ } diff --git a/boards/arm/stm32h7/nucleo-h753zi/configs/crypto/defconfig b/boards/arm/stm32h7/nucleo-h753zi/configs/crypto/defconfig index 8a3031bd43d28..b931a0cc571d9 100644 --- a/boards/arm/stm32h7/nucleo-h753zi/configs/crypto/defconfig +++ b/boards/arm/stm32h7/nucleo-h753zi/configs/crypto/defconfig @@ -10,7 +10,6 @@ # CONFIG_STANDARD_SERIAL is not set # CONFIG_TESTING_CRYPTO_3DES_CBC is not set # CONFIG_TESTING_CRYPTO_AES_XTS is not set -# CONFIG_TESTING_CRYPTO_HMAC is not set CONFIG_ALLOW_BSD_COMPONENTS=y CONFIG_ARCH="arm" CONFIG_ARCH_BOARD="nucleo-h753zi" @@ -50,10 +49,13 @@ CONFIG_START_MONTH=12 CONFIG_START_YEAR=2011 CONFIG_STM32_CRC=y CONFIG_STM32_CRYP=y +CONFIG_STM32_HASH=y CONFIG_STM32_USART3=y CONFIG_SYSTEM_NSH=y CONFIG_TASK_NAME_SIZE=0 CONFIG_TESTING_CRYPTO=y CONFIG_TESTING_CRYPTO_CRC32=y -CONFIG_TESTING_CRYPTO_STACKSIZE=4096 +CONFIG_TESTING_CRYPTO_HASH=y +CONFIG_TESTING_CRYPTO_HASH_DISABLE_SHA512=y +CONFIG_TESTING_CRYPTO_STACKSIZE=8192 CONFIG_USART3_SERIAL_CONSOLE=y