diff --git a/components/esp_hal_security/esp32/include/hal/sha_ll.h b/components/esp_hal_security/esp32/include/hal/sha_ll.h index 18b4e775e43..42b2402d67f 100644 --- a/components/esp_hal_security/esp32/include/hal/sha_ll.h +++ b/components/esp_hal_security/esp32/include/hal/sha_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -195,6 +195,18 @@ static inline void sha_ll_read_digest(esp_sha_type sha_type, void *digest_state, } } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * This chip has no SM3 hardware. + * + * @return false + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return false; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_security/esp32c2/include/hal/sha_ll.h b/components/esp_hal_security/esp32c2/include/hal/sha_ll.h index a353e70d197..3dc6780df34 100644 --- a/components/esp_hal_security/esp32c2/include/hal/sha_ll.h +++ b/components/esp_hal_security/esp32c2/include/hal/sha_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -180,6 +180,18 @@ static inline void sha_ll_write_digest(esp_sha_type sha_type, void *digest_state } } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * This chip has no SM3 hardware. + * + * @return false + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return false; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_security/esp32c3/include/hal/sha_ll.h b/components/esp_hal_security/esp32c3/include/hal/sha_ll.h index 6970f1ccbea..700f8ab7600 100644 --- a/components/esp_hal_security/esp32c3/include/hal/sha_ll.h +++ b/components/esp_hal_security/esp32c3/include/hal/sha_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -184,6 +184,18 @@ static inline void sha_ll_write_digest(esp_sha_type sha_type, void *digest_state } } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * This chip has no SM3 hardware. + * + * @return false + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return false; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_security/esp32c5/include/hal/sha_ll.h b/components/esp_hal_security/esp32c5/include/hal/sha_ll.h index 28c66a0bcc1..62f550a150a 100644 --- a/components/esp_hal_security/esp32c5/include/hal/sha_ll.h +++ b/components/esp_hal_security/esp32c5/include/hal/sha_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -191,6 +191,18 @@ static inline void sha_ll_t_len_set(uint8_t t_len) REG_WRITE(SHA_T_LENGTH_REG, t_len); } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * This chip has no eFuse that disables SM3, so the mode is always available. + * + * @return true + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return true; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_security/esp32c6/include/hal/sha_ll.h b/components/esp_hal_security/esp32c6/include/hal/sha_ll.h index 1c727408d45..9ed487d4733 100644 --- a/components/esp_hal_security/esp32c6/include/hal/sha_ll.h +++ b/components/esp_hal_security/esp32c6/include/hal/sha_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -170,6 +170,18 @@ static inline void sha_ll_write_digest(esp_sha_type sha_type, void *digest_state } } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * This chip has no SM3 hardware. + * + * @return false + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return false; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_security/esp32c61/include/hal/sha_ll.h b/components/esp_hal_security/esp32c61/include/hal/sha_ll.h index c1e90c4e0ef..dc699b40edf 100644 --- a/components/esp_hal_security/esp32c61/include/hal/sha_ll.h +++ b/components/esp_hal_security/esp32c61/include/hal/sha_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -169,6 +169,18 @@ static inline void sha_ll_write_digest(esp_sha_type sha_type, void *digest_state } } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * This chip has no SM3 hardware. + * + * @return false + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return false; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_security/esp32h2/include/hal/sha_ll.h b/components/esp_hal_security/esp32h2/include/hal/sha_ll.h index 32ece1b085b..6df20e0d052 100644 --- a/components/esp_hal_security/esp32h2/include/hal/sha_ll.h +++ b/components/esp_hal_security/esp32h2/include/hal/sha_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -171,6 +171,18 @@ static inline void sha_ll_write_digest(esp_sha_type sha_type, void *digest_state } } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * This chip has no SM3 hardware. + * + * @return false + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return false; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_security/esp32h21/include/hal/sha_ll.h b/components/esp_hal_security/esp32h21/include/hal/sha_ll.h index 2b6dc3d6aa4..bfb4df5f5d5 100644 --- a/components/esp_hal_security/esp32h21/include/hal/sha_ll.h +++ b/components/esp_hal_security/esp32h21/include/hal/sha_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -171,6 +171,18 @@ static inline void sha_ll_write_digest(esp_sha_type sha_type, void *digest_state } } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * This chip has no SM3 hardware. + * + * @return false + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return false; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_security/esp32p4/include/hal/sha_ll.h b/components/esp_hal_security/esp32p4/include/hal/sha_ll.h index 49ec3f72870..bb61650b794 100644 --- a/components/esp_hal_security/esp32p4/include/hal/sha_ll.h +++ b/components/esp_hal_security/esp32p4/include/hal/sha_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -206,6 +206,18 @@ static inline void sha_ll_t_len_set(uint8_t t_len) REG_WRITE(SHA_T_LENGTH_REG, t_len); } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * This chip has no SM3 hardware. + * + * @return false + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return false; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_security/esp32s2/include/hal/sha_ll.h b/components/esp_hal_security/esp32s2/include/hal/sha_ll.h index 1f13e1d01bc..3bc6574b8f2 100644 --- a/components/esp_hal_security/esp32s2/include/hal/sha_ll.h +++ b/components/esp_hal_security/esp32s2/include/hal/sha_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -223,6 +223,18 @@ static inline void sha_ll_t_len_set(uint8_t t_len) REG_WRITE(SHA_T_LENGTH_REG, t_len); } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * This chip has no SM3 hardware. + * + * @return false + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return false; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_security/esp32s3/include/hal/sha_ll.h b/components/esp_hal_security/esp32s3/include/hal/sha_ll.h index 357ff5980eb..2072db67274 100644 --- a/components/esp_hal_security/esp32s3/include/hal/sha_ll.h +++ b/components/esp_hal_security/esp32s3/include/hal/sha_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -201,6 +201,18 @@ static inline void sha_ll_t_len_set(uint8_t t_len) REG_WRITE(SHA_T_LENGTH_REG, t_len); } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * This chip has no SM3 hardware. + * + * @return false + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return false; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_security/esp32s31/include/hal/sha_ll.h b/components/esp_hal_security/esp32s31/include/hal/sha_ll.h index ca6151d9e5f..97e329c7b13 100644 --- a/components/esp_hal_security/esp32s31/include/hal/sha_ll.h +++ b/components/esp_hal_security/esp32s31/include/hal/sha_ll.h @@ -9,6 +9,7 @@ #include "hal/sha_types.h" #include "soc/hp_sys_clkrst_struct.h" #include "soc/hwcrypto_reg.h" +#include "soc/efuse_struct.h" /* ESP32-S31 SHA register header uses SHA_2_SM_3_H_MEM/M_MEM naming * instead of SHA_H_MEM/M_MEM. Define compatibility macros. */ @@ -211,6 +212,20 @@ static inline void sha_ll_t_len_set(uint8_t t_len) REG_WRITE(SHA_T_LENGTH_REG, t_len); } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * The DIS_SM_CRYPT eFuse disables SM2 and SM3 permanently. The function reads + * the eFuse shadow register directly, so it reports the real chip state also + * when CONFIG_EFUSE_VIRTUAL is enabled. + * + * @return true if SM3 is available, false if the eFuse disables it + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return !EFUSE.rd_repeat_data1.dis_sm_crypt; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_security/include/hal/sha_hal.h b/components/esp_hal_security/include/hal/sha_hal.h index c6c11d6cebe..a1d7be76f5e 100644 --- a/components/esp_hal_security/include/hal/sha_hal.h +++ b/components/esp_hal_security/include/hal/sha_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -73,6 +73,14 @@ void sha_hal_write_digest(esp_sha_type sha_type, void *digest_state); void sha_hal_hash_dma(size_t num_blocks, bool first_block); #endif +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * @return true if SM3 is available. false if the chip has no SM3 hardware + * or if an eFuse disables it. + */ +bool sha_hal_is_sm3_supported(void); + #if SOC_SHA_SUPPORT_SHA512_T /** * @brief Calculates and sets the initial digiest for SHA512_t diff --git a/components/esp_hal_security/sha_hal.c b/components/esp_hal_security/sha_hal.c index d7da7f4fe6a..95e8c087c2a 100644 --- a/components/esp_hal_security/sha_hal.c +++ b/components/esp_hal_security/sha_hal.c @@ -44,6 +44,9 @@ inline static size_t state_length(esp_sha_type type) return SHA1_STATE_LEN_WORDS; case SHA2_224: case SHA2_256: +#if SOC_SHA_SUPPORT_SM3 + case SM3: +#endif return SHA256_STATE_LEN_WORDS; #if SOC_SHA_SUPPORT_SHA384 case SHA2_384: @@ -136,6 +139,11 @@ void sha_hal_write_digest(esp_sha_type sha_type, void *digest_state) } #endif //SOC_SHA_SUPPORT_RESUME +bool sha_hal_is_sm3_supported(void) +{ + return sha_ll_is_sm3_supported(); +} + #if SOC_SHA_SUPPORT_SHA512_T /* Calculates and sets the initial digiest for SHA512_t */ diff --git a/components/esp_hal_security/test_apps/crypto/main/sha/test_sha.c b/components/esp_hal_security/test_apps/crypto/main/sha/test_sha.c index 8c5acb98804..4d7e3151652 100644 --- a/components/esp_hal_security/test_apps/crypto/main/sha/test_sha.c +++ b/components/esp_hal_security/test_apps/crypto/main/sha/test_sha.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 */ @@ -18,6 +18,11 @@ #include "sha_block.h" #include "sha_dma.h" +#if SOC_SHA_SUPPORT_SM3 +#include "esp_sm3.h" +#include "hal/sha_hal.h" +#endif + #if SOC_SHA_SUPPORTED #if SOC_SHA_SUPPORT_SHA1 @@ -257,6 +262,133 @@ TEST(sha, test_sha256_dma) #endif /* SOC_SHA_SUPPORT_DMA*/ #endif /* SOC_SHA_SUPPORT_SHA256 */ +#if SOC_SHA_SUPPORT_SM3 + +/* Reference digests for SM3 test inputs (cross-checked with OpenSSL dgst -sm3): + * [0] "abc" (GM/T 0004-2012 spec vector) + * [1] "abcd" x 16 (one full 64-byte block) + * [2] 0xEE x 1030 (multi-block, non-aligned tail) + */ +static const uint8_t sm3_expected[3][32] = { + { + 0x66, 0xc7, 0xf0, 0xf4, 0x62, 0xee, 0xed, 0xd9, + 0xd1, 0xf2, 0xd4, 0x6b, 0xdc, 0x10, 0xe4, 0xe2, + 0x41, 0x67, 0xc4, 0x87, 0x5c, 0xf2, 0xf7, 0xa2, + 0x29, 0x7d, 0xa0, 0x2b, 0x8f, 0x4b, 0xa8, 0xe0, + }, + { + 0xde, 0xbe, 0x9f, 0xf9, 0x22, 0x75, 0xb8, 0xa1, + 0x38, 0x60, 0x48, 0x89, 0xc1, 0x8e, 0x5a, 0x4d, + 0x6f, 0xdb, 0x70, 0xe5, 0x38, 0x7e, 0x57, 0x65, + 0x29, 0x3d, 0xcb, 0xa3, 0x9c, 0x0c, 0x57, 0x32, + }, + { + 0xfb, 0x7d, 0xd6, 0x4a, 0xd5, 0x0d, 0x5a, 0x16, + 0x2e, 0x92, 0x90, 0xa0, 0xd8, 0x3f, 0xa6, 0x01, + 0x86, 0x9b, 0x79, 0xf2, 0xda, 0xff, 0xbe, 0x16, + 0xac, 0x6b, 0x6c, 0x06, 0x52, 0x21, 0x56, 0x0a, + }, +}; + +/* Skip the esp_sm3 API tests when the chip forbids the SM crypto functions. */ +static void sm3_api_skip_if_disabled(void) +{ + if (!sha_hal_is_sm3_supported()) { + TEST_IGNORE_MESSAGE("SM crypto disabled by eFuse (DIS_SM_CRYPT)"); + } +} + +TEST(sha, test_sm3_api_one_shot) +{ + uint8_t digest[ESP_SM3_DIGEST_LEN]; + + sm3_api_skip_if_disabled(); + + TEST_ASSERT_EQUAL(ESP_OK, esp_sm3("abc", 3, digest, sizeof(digest))); + TEST_ASSERT_EQUAL_HEX8_ARRAY(sm3_expected[0], digest, sizeof(digest)); + + uint8_t one_block_input[ESP_SM3_BLOCK_LEN]; + for (size_t i = 0; i < sizeof(one_block_input); i += 4) { + memcpy(&one_block_input[i], "abcd", 4); + } + TEST_ASSERT_EQUAL(ESP_OK, esp_sm3(one_block_input, sizeof(one_block_input), digest, sizeof(digest))); + TEST_ASSERT_EQUAL_HEX8_ARRAY(sm3_expected[1], digest, sizeof(digest)); + + uint8_t *buffer = heap_caps_calloc(BUFFER_SZ, sizeof(uint8_t), MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(buffer); + memset(buffer, 0xEE, BUFFER_SZ); + TEST_ASSERT_EQUAL(ESP_OK, esp_sm3(buffer, BUFFER_SZ, digest, sizeof(digest))); + TEST_ASSERT_EQUAL_HEX8_ARRAY(sm3_expected[2], digest, sizeof(digest)); + heap_caps_free(buffer); +} + +/* Feed the message in uneven pieces. Every piece that does not end on a block + boundary forces the driver to save and restore the digest state. */ +TEST(sha, test_sm3_api_streaming) +{ + static const size_t chunk_sizes[] = { 1, 62, 1, 64, 3, 200, 128, 129 }; + uint8_t digest[ESP_SM3_DIGEST_LEN]; + esp_sm3_ctx_handle_t ctx; + + sm3_api_skip_if_disabled(); + + uint8_t *buffer = heap_caps_calloc(BUFFER_SZ, sizeof(uint8_t), MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(buffer); + memset(buffer, 0xEE, BUFFER_SZ); + + TEST_ASSERT_EQUAL(ESP_OK, esp_sm3_create(&ctx)); + + size_t offset = 0; + size_t index = 0; + while (offset < BUFFER_SZ) { + size_t chunk = chunk_sizes[index % (sizeof(chunk_sizes) / sizeof(chunk_sizes[0]))]; + if (chunk > BUFFER_SZ - offset) { + chunk = BUFFER_SZ - offset; + } + TEST_ASSERT_EQUAL(ESP_OK, esp_sm3_update(ctx, buffer + offset, chunk)); + offset += chunk; + index++; + } + + TEST_ASSERT_EQUAL(ESP_OK, esp_sm3_finish(ctx, digest, sizeof(digest))); + esp_sm3_delete(ctx); + heap_caps_free(buffer); + + TEST_ASSERT_EQUAL_HEX8_ARRAY(sm3_expected[2], digest, sizeof(digest)); +} + +TEST(sha, test_sm3_api_bad_args) +{ + uint8_t digest[ESP_SM3_DIGEST_LEN]; + + sm3_api_skip_if_disabled(); + + /* A short output buffer must be rejected before any byte reaches it. */ + memset(digest, 0xA5, sizeof(digest)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_SIZE, + esp_sm3("abc", 3, digest, ESP_SM3_DIGEST_LEN - 1)); + for (size_t i = 0; i < sizeof(digest); i++) { + TEST_ASSERT_EQUAL_HEX8(0xA5, digest[i]); + } + + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_sm3("abc", 3, NULL, sizeof(digest))); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_sm3(NULL, 3, digest, sizeof(digest))); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_sm3_create(NULL)); + + /* An empty message is valid input. The digest comes from the padding + block alone, so it proves that the pad-only path works. */ + static const uint8_t sm3_expected_empty[ESP_SM3_DIGEST_LEN] = { + 0x1a, 0xb2, 0x1d, 0x83, 0x55, 0xcf, 0xa1, 0x7f, + 0x8e, 0x61, 0x19, 0x48, 0x31, 0xe8, 0x1a, 0x8f, + 0x22, 0xbe, 0xc8, 0xc7, 0x28, 0xfe, 0xfb, 0x74, + 0x7e, 0xd0, 0x35, 0xeb, 0x50, 0x82, 0xaa, 0x2b, + }; + TEST_ASSERT_EQUAL(ESP_OK, esp_sm3(NULL, 0, digest, sizeof(digest))); + TEST_ASSERT_EQUAL_HEX8_ARRAY(sm3_expected_empty, digest, sizeof(digest)); +} + +#endif /* SOC_SHA_SUPPORT_SM3 */ + #if SOC_SHA_SUPPORT_SHA384 TEST(sha, test_sha384_block) @@ -329,6 +461,12 @@ TEST_GROUP_RUNNER(sha) #endif /* SOC_SHA_SUPPORT_DMA*/ #endif /* SOC_SHA_SUPPORT_SHA256 */ +#if SOC_SHA_SUPPORT_SM3 + RUN_TEST_CASE(sha, test_sm3_api_one_shot); + RUN_TEST_CASE(sha, test_sm3_api_streaming); + RUN_TEST_CASE(sha, test_sm3_api_bad_args); +#endif /* SOC_SHA_SUPPORT_SM3 */ + #if SOC_SHA_SUPPORT_SHA384 RUN_TEST_CASE(sha, test_sha384_block); #if SOC_SHA_SUPPORT_DMA diff --git a/components/esp_rom/esp32c5/include/esp32c5/rom/sha.h b/components/esp_rom/esp32c5/include/esp32c5/rom/sha.h index be03f8ab107..b2e90a67aee 100644 --- a/components/esp_rom/esp32c5/include/esp32c5/rom/sha.h +++ b/components/esp_rom/esp32c5/include/esp32c5/rom/sha.h @@ -23,6 +23,7 @@ typedef enum { SHA2_512224, SHA2_512256, SHA2_512T, + SM3 = 14, SHA_TYPE_MAX } SHA_TYPE; diff --git a/components/esp_rom/esp32h4/include/esp32h4/rom/sha.h b/components/esp_rom/esp32h4/include/esp32h4/rom/sha.h index 0d4a84c105a..995fdc99690 100644 --- a/components/esp_rom/esp32h4/include/esp32h4/rom/sha.h +++ b/components/esp_rom/esp32h4/include/esp32h4/rom/sha.h @@ -23,6 +23,7 @@ typedef enum { SHA2_512224, SHA2_512256, SHA2_512T, + SM3 = 14, SHA_TYPE_MAX } SHA_TYPE; diff --git a/components/esp_rom/esp32s31/include/esp32s31/rom/sha.h b/components/esp_rom/esp32s31/include/esp32s31/rom/sha.h index 0d4a84c105a..995fdc99690 100644 --- a/components/esp_rom/esp32s31/include/esp32s31/rom/sha.h +++ b/components/esp_rom/esp32s31/include/esp32s31/rom/sha.h @@ -23,6 +23,7 @@ typedef enum { SHA2_512224, SHA2_512256, SHA2_512T, + SM3 = 14, SHA_TYPE_MAX } SHA_TYPE; diff --git a/components/esp_security/CMakeLists.txt b/components/esp_security/CMakeLists.txt index 9d55a5336ac..6bf0e97a3a2 100644 --- a/components/esp_security/CMakeLists.txt +++ b/components/esp_security/CMakeLists.txt @@ -23,6 +23,10 @@ if(NOT non_os_build) list(APPEND srcs "src/esp_ds.c") endif() + if(CONFIG_SOC_SHA_SUPPORT_SM3) + list(APPEND srcs "src/esp_sm3.c") + endif() + if(CONFIG_SOC_KEY_MANAGER_SUPPORTED) list(APPEND srcs "src/esp_key_mgr.c") endif() diff --git a/components/esp_security/include/esp_sm3.h b/components/esp_security/include/esp_sm3.h new file mode 100644 index 00000000000..dbdf9f74eaf --- /dev/null +++ b/components/esp_security/include/esp_sm3.h @@ -0,0 +1,121 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include + +#include "esp_err.h" +#include "soc/soc_caps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_SHA_SUPPORT_SM3 + +/** Length of an SM3 digest in bytes. */ +#define ESP_SM3_DIGEST_LEN 32 + +/** Size of an SM3 message block in bytes. */ +#define ESP_SM3_BLOCK_LEN 64 + +/** + * @brief Handle of one SM3 operation. + * + * esp_sm3_create() allocates the context. esp_sm3_delete() releases it. Do not + * read or write the context. + */ +typedef struct esp_sm3_ctx_s *esp_sm3_ctx_handle_t; + +/** + * @brief Start a new SM3 operation. + * + * The function allocates the context. Call esp_sm3_delete() to release it. + * + * @param[out] ctx Receives the handle of the new context. The function writes + * NULL if it returns ESP_ERR_NO_MEM or ESP_ERR_NOT_SUPPORTED. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if ctx is NULL + * - ESP_ERR_NO_MEM if the allocation fails + * - ESP_ERR_NOT_SUPPORTED if an eFuse disables the SM crypto functions + */ +esp_err_t esp_sm3_create(esp_sm3_ctx_handle_t *ctx); + +/** + * @brief Add message bytes to an SM3 operation. + * + * Call this function as many times as necessary. The function acquires the SHA + * peripheral only when the new bytes complete at least one 64-byte block. It + * releases the peripheral before it returns. + * + * @param ctx Context from esp_sm3_create(). + * @param input Message bytes. Can be NULL if ilen is 0. + * @param ilen Number of message bytes. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if ctx is NULL, or if input is NULL and ilen is not 0 + * - ESP_ERR_NOT_SUPPORTED if an eFuse disables the SM crypto functions + */ +esp_err_t esp_sm3_update(esp_sm3_ctx_handle_t ctx, const void *input, size_t ilen); + +/** + * @brief Complete an SM3 operation and read the digest. + * + * The function always acquires the SHA peripheral, because the padding + * completes the last message block. It releases the peripheral before it + * returns. + * + * @param ctx Context from esp_sm3_create(). + * @param output Buffer for the digest. + * @param olen Size of output in bytes. Must be ESP_SM3_DIGEST_LEN or more. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if ctx or output is NULL + * - ESP_ERR_INVALID_SIZE if olen is too small + * - ESP_ERR_NOT_SUPPORTED if an eFuse disables the SM crypto functions + */ +esp_err_t esp_sm3_finish(esp_sm3_ctx_handle_t ctx, uint8_t *output, size_t olen); + +/** + * @brief Erase and release an SM3 context. + * + * The function erases the message bytes and the digest state. Then it frees + * the context. Call this function after esp_sm3_finish(), and also to abandon + * an operation. The handle is not valid after the call. If you do not call + * this function, the context stays allocated. + * + * @param ctx Context from esp_sm3_create(). The function accepts NULL. + */ +void esp_sm3_delete(esp_sm3_ctx_handle_t ctx); + +/** + * @brief Compute the SM3 digest of one buffer. + * + * @param input Message bytes. Can be NULL if ilen is 0. + * @param ilen Number of message bytes. + * @param output Buffer for the digest. + * @param olen Size of output in bytes. Must be ESP_SM3_DIGEST_LEN or more. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if output is NULL, or if input is NULL and ilen is not 0 + * - ESP_ERR_INVALID_SIZE if olen is too small + * - ESP_ERR_NOT_SUPPORTED if an eFuse disables the SM crypto functions + */ +esp_err_t esp_sm3(const void *input, size_t ilen, uint8_t *output, size_t olen); + +#endif /* SOC_SHA_SUPPORT_SM3 */ + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_security/src/esp_sm3.c b/components/esp_security/src/esp_sm3.c new file mode 100644 index 00000000000..a70b5825643 --- /dev/null +++ b/components/esp_security/src/esp_sm3.c @@ -0,0 +1,251 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + * + * SM3 (GM/T 0004-2012) implementation on the ESP SHA peripheral. + * + * SM3 uses the same message schedule as the SHA-256 family: a 64-byte block, + * a 256-bit state, and the same padding. Only the compression function + * differs, and the SHA peripheral provides it as mode SM3. + */ + +#include + +#include "esp_err.h" +#include "esp_macros.h" +#include "hal/sha_types.h" +#include "esp_sm3.h" +#include "soc/soc_caps.h" +#include "hal/sha_hal.h" +#include "esp_crypto_periph_clk.h" +#include "esp_crypto_lock.h" +#include "esp_heap_caps.h" + +#if SOC_SHA_SUPPORT_SM3 + +/** + * @brief SM3 operation context. + * + * esp_sm3_create() allocates the context for the streaming API, and + * esp_sm3_delete() releases it. esp_sm3() keeps one on its own stack. The caller + * never sees the members. + */ +struct esp_sm3_ctx_s { + unsigned char buffer[ESP_SM3_BLOCK_LEN]; /*!< Message bytes that do not fill a block yet */ + uint64_t total; /*!< Number of message bytes processed */ + uint32_t state[ESP_SM3_DIGEST_LEN / 4]; /*!< Intermediate digest state */ + bool state_valid; /*!< True when state holds an intermediate digest */ +}; + +static const unsigned char sm3_padding[ESP_SM3_BLOCK_LEN] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void esp_sm3_zeroize(void *buf, size_t len) +{ + volatile uint8_t *p = (volatile uint8_t *)buf; + for (size_t i = 0; i < len; i++) { + *p++ = 0; + } +} + +static inline void sm3_put_be32(uint32_t value, unsigned char *out) +{ + out[0] = (unsigned char)(value >> 24); + out[1] = (unsigned char)(value >> 16); + out[2] = (unsigned char)(value >> 8); + out[3] = (unsigned char)(value); +} + +/* Hash the pending block, then every whole block of input. The caller must hold + the SHA peripheral and must have selected mode SM3. */ +static void sm3_hash_blocks(esp_sm3_ctx_handle_t ctx, const unsigned char *input, + size_t len, bool has_pending_block, bool first_block) +{ + if (has_pending_block) { + sha_hal_hash_block(SM3, ctx->buffer, ESP_SM3_BLOCK_LEN / 4, first_block); + first_block = false; + } + + for (size_t done = 0; done < len; done += ESP_SM3_BLOCK_LEN) { + sha_hal_hash_block(SM3, input + done, ESP_SM3_BLOCK_LEN / 4, first_block); + first_block = false; + } +} + +/* Run len bytes of input, plus any pending block, through the peripheral. */ +static esp_err_t sm3_process(esp_sm3_ctx_handle_t ctx, const unsigned char *input, + size_t len, bool has_pending_block) +{ + /* Repeat the check here. An application can burn DIS_SM_CRYPT after + esp_sm3_create(). From that point the peripheral must stay unreachable. */ + if (!sha_hal_is_sm3_supported()) { + return ESP_ERR_NOT_SUPPORTED; + } + + /* The hardware keeps no state between calls. Give it back the digest that + the previous call read out, or start the mode on an empty context. */ + bool first_block = !ctx->state_valid; + + esp_crypto_sha_aes_lock_acquire(); + esp_crypto_sha_enable_periph_clk(true); + sha_hal_wait_idle(); + sha_hal_set_mode(SM3); + if (!first_block) { + sha_hal_write_digest(SM3, ctx->state); + } + + sm3_hash_blocks(ctx, input, len, has_pending_block, first_block); + + sha_hal_read_digest(SM3, ctx->state); + ctx->state_valid = true; + + esp_crypto_sha_enable_periph_clk(false); + esp_crypto_sha_aes_lock_release(); + + return ESP_OK; +} + +esp_err_t esp_sm3_create(esp_sm3_ctx_handle_t *ctx) +{ + if (ctx == NULL) { + return ESP_ERR_INVALID_ARG; + } + *ctx = NULL; + + /* An eFuse can disable SM2 and SM3 permanently. On such a part the SHA + peripheral gives no valid digest in mode SM3. */ + if (!sha_hal_is_sm3_supported()) { + return ESP_ERR_NOT_SUPPORTED; + } + + struct esp_sm3_ctx_s *sm3_ctx = heap_caps_calloc(1, sizeof(*sm3_ctx), MALLOC_CAP_INTERNAL); + if (sm3_ctx == NULL) { + return ESP_ERR_NO_MEM; + } + *ctx = sm3_ctx; + + return ESP_OK; +} + +esp_err_t esp_sm3_update(esp_sm3_ctx_handle_t ctx, const void *input, size_t ilen) +{ + if (ctx == NULL || (input == NULL && ilen != 0)) { + return ESP_ERR_INVALID_ARG; + } + + if (ilen == 0) { + return ESP_OK; + } + + const unsigned char *in = (const unsigned char *)input; + size_t left = (size_t)(ctx->total & (ESP_SM3_BLOCK_LEN - 1)); + size_t fill = ESP_SM3_BLOCK_LEN - left; + bool has_pending_block = false; + + ctx->total += ilen; + + /* Complete the block that the previous call left pending. */ + if (left && ilen >= fill) { + memcpy(ctx->buffer + left, in, fill); + in += fill; + ilen -= fill; + left = 0; + has_pending_block = true; + } + + size_t len = ESP_ALIGN_DOWN(ilen, ESP_SM3_BLOCK_LEN); + + if (len || has_pending_block) { + esp_err_t ret = sm3_process(ctx, in, len, has_pending_block); + if (ret != ESP_OK) { + return ret; + } + } + + if (ilen > len) { + memcpy(ctx->buffer + left, in + len, ilen - len); + } + + return ESP_OK; +} + +esp_err_t esp_sm3_finish(esp_sm3_ctx_handle_t ctx, uint8_t *output, size_t olen) +{ + if (ctx == NULL || output == NULL) { + return ESP_ERR_INVALID_ARG; + } + + /* Check the buffer before any byte reaches it. */ + if (olen < ESP_SM3_DIGEST_LEN) { + return ESP_ERR_INVALID_SIZE; + } + + /* Read the counter before the update advances it. */ + uint64_t bits = ctx->total << 3; + size_t last = (size_t)(ctx->total & (ESP_SM3_BLOCK_LEN - 1)); + size_t padn = (last < 56) ? (56 - last) : (120 - last); + + /* Stage the padding and the length field together. One update then closes + the message with a single hold of the peripheral. */ + unsigned char tail[ESP_SM3_BLOCK_LEN + 8]; + + memcpy(tail, sm3_padding, padn); + sm3_put_be32((uint32_t)(bits >> 32), tail + padn); + sm3_put_be32((uint32_t)bits, tail + padn + 4); + + esp_err_t ret = esp_sm3_update(ctx, tail, padn + 8); + if (ret != ESP_OK) { + return ret; + } + + memcpy(output, ctx->state, ESP_SM3_DIGEST_LEN); + + return ESP_OK; +} + +void esp_sm3_delete(esp_sm3_ctx_handle_t ctx) +{ + if (ctx != NULL) { + esp_sm3_zeroize(ctx, sizeof(*ctx)); + } + free(ctx); +} + +esp_err_t esp_sm3(const void *input, size_t ilen, uint8_t *output, size_t olen) +{ + if (output == NULL || (input == NULL && ilen != 0)) { + return ESP_ERR_INVALID_ARG; + } + + if (olen < ESP_SM3_DIGEST_LEN) { + return ESP_ERR_INVALID_SIZE; + } + + /* An eFuse can disable SM2 and SM3 permanently. On such a part the SHA + peripheral gives no valid digest in mode SM3. */ + if (!sha_hal_is_sm3_supported()) { + return ESP_ERR_NOT_SUPPORTED; + } + + /* The context is private to this call, so keep it on the stack. The + one-shot path then needs no allocation. */ + struct esp_sm3_ctx_s ctx; + + memset(&ctx, 0, sizeof(ctx)); + + esp_err_t ret = esp_sm3_update(&ctx, input, ilen); + if (ret == ESP_OK) { + ret = esp_sm3_finish(&ctx, output, olen); + } + + esp_sm3_zeroize(&ctx, sizeof(ctx)); + + return ret; +} + +#endif /* SOC_SHA_SUPPORT_SM3 */ diff --git a/components/hal/esp32h4/include/hal/sha_ll.h b/components/hal/esp32h4/include/hal/sha_ll.h index 53fd27b8eeb..e263e2a5151 100644 --- a/components/hal/esp32h4/include/hal/sha_ll.h +++ b/components/hal/esp32h4/include/hal/sha_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -189,6 +189,18 @@ static inline void sha_ll_t_len_set(uint8_t t_len) REG_WRITE(SHA_T_LENGTH_REG, t_len); } +/** + * @brief Check whether the SHA peripheral can run the SM3 mode. + * + * This chip has no eFuse that disables SM3, so the mode is always available. + * + * @return true + */ +static inline bool sha_ll_is_sm3_supported(void) +{ + return true; +} + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 69a3494449a..2741a627a3c 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -911,6 +911,10 @@ config SOC_SHA_SUPPORT_SHA512_T bool default y +config SOC_SHA_SUPPORT_SM3 + bool + default y + config SOC_ECC_CONSTANT_TIME_POINT_MUL bool default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 2ae9bdc0d73..4f28358f4b2 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -375,6 +375,7 @@ #define SOC_SHA_SUPPORT_SHA512_224 (1) #define SOC_SHA_SUPPORT_SHA512_256 (1) #define SOC_SHA_SUPPORT_SHA512_T (1) +#define SOC_SHA_SUPPORT_SM3 (1) /*--------------------------- ECC CAPS ---------------------------------------*/ #define SOC_ECC_CONSTANT_TIME_POINT_MUL 1 diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 345d9929cf2..d3699d96549 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -815,6 +815,10 @@ config SOC_SHA_SUPPORT_SHA512_T bool default y +config SOC_SHA_SUPPORT_SM3 + bool + default y + config SOC_ECC_CONSTANT_TIME_POINT_MUL bool default y diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 8013422edda..aa81befb9d4 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -352,6 +352,7 @@ #define SOC_SHA_SUPPORT_SHA384 (1) #define SOC_SHA_SUPPORT_SHA512 (1) #define SOC_SHA_SUPPORT_SHA512_T (1) +#define SOC_SHA_SUPPORT_SM3 (1) /*--------------------------- ECC CAPS ---------------------------------------*/ #define SOC_ECC_CONSTANT_TIME_POINT_MUL 1 diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 1bea7895fde..4afb95caa0a 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -1091,6 +1091,10 @@ config SOC_SHA_SUPPORT_SHA512_T bool default y +config SOC_SHA_SUPPORT_SM3 + bool + default y + config SOC_MPI_MEM_BLOCKS_NUM int default 4 diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index b3ccb18e14f..59ec24311f0 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -401,6 +401,7 @@ #define SOC_SHA_SUPPORT_SHA512_224 (1) #define SOC_SHA_SUPPORT_SHA512_256 (1) #define SOC_SHA_SUPPORT_SHA512_T (1) +#define SOC_SHA_SUPPORT_SM3 (1) /*--------------------------- MPI CAPS ---------------------------------------*/ #define SOC_MPI_MEM_BLOCKS_NUM (4) diff --git a/docs/conf_common.py b/docs/conf_common.py index 3d4e209b3d6..676fb0aa3a2 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -404,6 +404,7 @@ conditional_include_dict = { 'SOC_DIG_SIGN_SUPPORTED': ['api-reference/peripherals/ds.rst'], 'SOC_ECDSA_SUPPORTED': ['api-reference/peripherals/ecdsa.rst'], 'SOC_HMAC_SUPPORTED': ['api-reference/peripherals/hmac.rst'], + 'SOC_SHA_SUPPORT_SM3': ['api-reference/peripherals/sm3.rst'], 'SOC_GDMA_SUPPORT_CRC': ['api-reference/peripherals/async_crc.rst'], 'SOC_ASYNC_MEMCPY_SUPPORTED': ['api-reference/peripherals/async_memcpy.rst'], 'SOC_DMA2D_SUPPORTED': ['api-reference/peripherals/async_color_convert.rst'], diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 6664e6a81ae..e92f3482276 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -271,6 +271,7 @@ INPUT = \ $(PROJECT_PATH)/components/esp_ringbuf/include/freertos/ringbuf.h \ $(PROJECT_PATH)/components/esp_rom/include/esp_rom_sys.h \ $(PROJECT_PATH)/components/esp_security/include/esp_ds.h \ + $(PROJECT_PATH)/components/esp_security/include/esp_sm3.h \ $(PROJECT_PATH)/components/esp_system/include/esp_debug_helpers.h \ $(PROJECT_PATH)/components/esp_system/include/esp_expression_with_stack.h \ $(PROJECT_PATH)/components/esp_system/include/esp_freertos_hooks.h \ diff --git a/docs/en/api-reference/peripherals/index.rst b/docs/en/api-reference/peripherals/index.rst index 7e4c551a434..3934c850953 100644 --- a/docs/en/api-reference/peripherals/index.rst +++ b/docs/en/api-reference/peripherals/index.rst @@ -42,6 +42,7 @@ Peripherals API :SOC_GPSPI_SUPPORTED: sdspi_host :SOC_SDIO_SLAVE_SUPPORTED: sdio_slave :SOC_SDM_SUPPORTED: sdm + :SOC_SHA_SUPPORT_SM3: sm3 :SOC_SPI_FLASH_SUPPORTED: spi_flash/index :SOC_GPSPI_SUPPORTED: spi_master :SOC_GPSPI_SUPPORTED: spi_slave diff --git a/docs/en/api-reference/peripherals/sm3.rst b/docs/en/api-reference/peripherals/sm3.rst new file mode 100644 index 00000000000..02ac8395efd --- /dev/null +++ b/docs/en/api-reference/peripherals/sm3.rst @@ -0,0 +1,77 @@ +SM3 Hash Accelerator +==================== + +:link_to_translation:`zh_CN:[中文]` + +SM3 (GM/T 0004-2012) is a cryptographic hash function of the Chinese ShangMi (SM) standards. It reads the message in 64-byte blocks and produces a 256-bit digest, comparable to SHA-256. On {IDF_TARGET_NAME}, the SHA accelerator computes SM3 in hardware. + +The ``esp_sm3`` API is the only interface to the SM3 hardware. SM3 is not available through the Mbed TLS or PSA Crypto APIs. + +.. only:: esp32s31 + + An eFuse (``DIS_SM_CRYPT``) can disable all the SM crypto functions permanently. On a chip with this eFuse set, :cpp:func:`esp_sm3_create` and :cpp:func:`esp_sm3` return :c:macro:`ESP_ERR_NOT_SUPPORTED`. Always check the return value. + +One-Shot Digest +--------------- + +Use :cpp:func:`esp_sm3` when the whole message is in one buffer: + +.. code-block:: c + + #include "esp_sm3.h" + + uint8_t digest[ESP_SM3_DIGEST_LEN]; + + esp_err_t err = esp_sm3(message, message_len, digest, sizeof(digest)); + if (err != ESP_OK) { + // No digest was written. Handle the error. + } + +Streaming Digest +---------------- + +Use the context functions when the message arrives in parts: + +.. code-block:: c + + #include "esp_sm3.h" + + uint8_t digest[ESP_SM3_DIGEST_LEN]; + esp_sm3_ctx_handle_t ctx = NULL; + + esp_err_t err = esp_sm3_create(&ctx); + if (err != ESP_OK) { + return err; + } + + err = esp_sm3_update(ctx, part1, part1_len); + if (err == ESP_OK) { + err = esp_sm3_update(ctx, part2, part2_len); + } + if (err == ESP_OK) { + err = esp_sm3_finish(ctx, digest, sizeof(digest)); + } + + esp_sm3_delete(ctx); + +:cpp:func:`esp_sm3_create` allocates the context and writes the handle to ``ctx``. If the function returns :c:macro:`ESP_ERR_NO_MEM` or :c:macro:`ESP_ERR_NOT_SUPPORTED`, it writes NULL to ``ctx``. The context is opaque. The application must not read or write it. + +:cpp:func:`esp_sm3_delete` erases the message bytes and the digest state. Then it frees the context. The handle is not valid after the call. If the application does not call this function, the context stays allocated. + +Call :cpp:func:`esp_sm3_delete` after :cpp:func:`esp_sm3_finish`. Call it also to abandon an operation. + +Concurrency +----------- + +:cpp:func:`esp_sm3_update` and :cpp:func:`esp_sm3_finish` acquire the SHA peripheral. They hold it only while the hardware processes a message block, and they release it before they return. :cpp:func:`esp_sm3_create` and :cpp:func:`esp_sm3_delete` never touch the peripheral. + +:cpp:func:`esp_sm3_update` acquires the peripheral only when the new bytes complete at least one 64-byte block. A call with fewer bytes copies them into the context and returns. :cpp:func:`esp_sm3_finish` always acquires the peripheral, because the padding completes the last block. + +An operation can therefore stay open for a long time at no cost to other users of the peripheral. Operations with different contexts can run in parallel from different tasks. + +Do not use one context from two tasks at the same time. + +API Reference +------------- + +.. include-build-file:: inc/esp_sm3.inc diff --git a/docs/zh_CN/api-reference/peripherals/index.rst b/docs/zh_CN/api-reference/peripherals/index.rst index 344b23e76a4..b116c0047ee 100644 --- a/docs/zh_CN/api-reference/peripherals/index.rst +++ b/docs/zh_CN/api-reference/peripherals/index.rst @@ -42,6 +42,7 @@ :SOC_GPSPI_SUPPORTED: sdspi_host :SOC_SDIO_SLAVE_SUPPORTED: sdio_slave :SOC_SDM_SUPPORTED: sdm + :SOC_SHA_SUPPORT_SM3: sm3 :SOC_SPI_FLASH_SUPPORTED: spi_flash/index :SOC_GPSPI_SUPPORTED: spi_master :SOC_GPSPI_SUPPORTED: spi_slave diff --git a/docs/zh_CN/api-reference/peripherals/sm3.rst b/docs/zh_CN/api-reference/peripherals/sm3.rst new file mode 100644 index 00000000000..78f980b8ac6 --- /dev/null +++ b/docs/zh_CN/api-reference/peripherals/sm3.rst @@ -0,0 +1,77 @@ +SM3 杂凑加速器 +============== + +:link_to_translation:`en:[English]` + +SM3(GM/T 0004-2012)是中国商用密码(SM)标准中的密码杂凑算法。它以 64 字节为分组读取消息,输出 256 位摘要,与 SHA-256 相当。在 {IDF_TARGET_NAME} 上,SHA 加速器以硬件方式计算 SM3。 + +``esp_sm3`` API 是访问 SM3 硬件的唯一接口。Mbed TLS 和 PSA Crypto API 均不提供 SM3。 + +.. only:: esp32s31 + + eFuse ``DIS_SM_CRYPT`` 可永久禁用全部 SM 密码功能。在烧写了该 eFuse 的芯片上,:cpp:func:`esp_sm3_create` 和 :cpp:func:`esp_sm3` 返回 :c:macro:`ESP_ERR_NOT_SUPPORTED`。请始终检查返回值。 + +一次性摘要 +---------- + +当整条消息位于同一个缓冲区时,使用 :cpp:func:`esp_sm3`: + +.. code-block:: c + + #include "esp_sm3.h" + + uint8_t digest[ESP_SM3_DIGEST_LEN]; + + esp_err_t err = esp_sm3(message, message_len, digest, sizeof(digest)); + if (err != ESP_OK) { + // 未写入摘要,请处理该错误。 + } + +流式摘要 +-------- + +当消息分多次到达时,使用上下文函数: + +.. code-block:: c + + #include "esp_sm3.h" + + uint8_t digest[ESP_SM3_DIGEST_LEN]; + esp_sm3_ctx_handle_t ctx = NULL; + + esp_err_t err = esp_sm3_create(&ctx); + if (err != ESP_OK) { + return err; + } + + err = esp_sm3_update(ctx, part1, part1_len); + if (err == ESP_OK) { + err = esp_sm3_update(ctx, part2, part2_len); + } + if (err == ESP_OK) { + err = esp_sm3_finish(ctx, digest, sizeof(digest)); + } + + esp_sm3_delete(ctx); + +:cpp:func:`esp_sm3_create` 会分配上下文,并把句柄写入 ``ctx``。如果该函数返回 :c:macro:`ESP_ERR_NO_MEM` 或 :c:macro:`ESP_ERR_NOT_SUPPORTED`,则向 ``ctx`` 写入 NULL。上下文是不透明的,应用程序不得读写其内容。 + +:cpp:func:`esp_sm3_delete` 会清除上下文中的消息字节和摘要状态,然后释放该上下文。调用之后句柄失效。如果应用程序不调用该函数,该上下文会一直占用内存。 + +请在调用 :cpp:func:`esp_sm3_finish` 之后调用 :cpp:func:`esp_sm3_delete`。中止操作时同样需要调用。 + +并发 +---- + +:cpp:func:`esp_sm3_update` 和 :cpp:func:`esp_sm3_finish` 会占用 SHA 外设。它们仅在硬件处理消息分组期间持有该外设,并在返回前释放。:cpp:func:`esp_sm3_create` 和 :cpp:func:`esp_sm3_delete` 不会访问该外设。 + +只有当新增字节凑满至少一个 64 字节分组时,:cpp:func:`esp_sm3_update` 才会占用该外设。字节不足时,该函数只把它们复制到上下文中并返回。:cpp:func:`esp_sm3_finish` 总会占用该外设,因为填充会凑满最后一个分组。 + +因此,一个操作可以长时间保持打开状态,而不会给该外设的其他使用者带来开销。使用不同上下文的操作可以在不同任务中并行执行。 + +不要在两个任务中同时使用同一个上下文。 + +API 参考 +-------- + +.. include-build-file:: inc/esp_sm3.inc