]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
lib: sm3: implement U-Boot parts
authorHeiko Schocher <hs@nabladev.com>
Tue, 18 Nov 2025 04:30:39 +0000 (05:30 +0100)
committerTom Rini <trini@konsulko.com>
Thu, 4 Dec 2025 15:38:58 +0000 (09:38 -0600)
add the U-Boot specific parts for the SM3 hash
implementation:

Signed-off-by: Heiko Schocher <hs@nabladev.com>
MAINTAINERS
boot/Kconfig
cmd/Kconfig
cmd/Makefile
cmd/sm3sum.c [new file with mode: 0644]
common/hash.c
include/u-boot/sm3.h
lib/sm3.c

index e1d79206e5009b18745cd517f6a13f6dce3b4073..dc62990a09094c588da6acaf0f6bd1ae9c42af12 100644 (file)
@@ -1689,6 +1689,7 @@ F:        test/lib/slre.c
 SM3
 M:     Heiko Schocher <hs@nabladev.com>
 S:     Maintained
+F:     cmd/sm3sum.c
 F:     include/u-boot/sm3.h
 F:     lib/sm3.c
 
index 85f4d4680699a8af5ba6f9bbec13697785d55f21..76cc628c9bd3faa88d99a1da417ed1db585353eb 100644 (file)
@@ -1042,6 +1042,7 @@ config MEASURED_BOOT
        select SHA256
        select SHA384
        select SHA512
+       select SM3
        help
          This option enables measurement of the boot process when booting
          without UEFI . Measurement involves creating cryptographic hashes
index 5b9c13d85e76a9bae917eb6c3611ae1dce551d9b..8e3efff2bee69e4be80fe8e87eb7815dd3ff8ca9 100644 (file)
@@ -264,6 +264,21 @@ config CMD_SBI
        help
          Display information about the SBI implementation.
 
+config CMD_SM3SUM
+       bool "sm3sum"
+       select SM3
+       select HASH
+       help
+         Compute SM3 checksum.
+         add SM3 hash functionality
+
+config SM3SUM_VERIFY
+       bool "sm3sum -v"
+       depends on CMD_SM3SUM
+       help
+         Add for the sm3sum command the -v option
+         to verify data against an SM3 checksum.
+
 config CMD_SMBIOS
        bool "smbios"
        depends on SMBIOS
index 254799077974142005fe9752ff7f1898509a609e..642042cfe0053c63e3fba58ba3eeb3505f3ba586 100644 (file)
@@ -177,6 +177,7 @@ obj-$(CONFIG_CMD_SETEXPR) += setexpr.o
 obj-$(CONFIG_CMD_SETEXPR_FMT) += printf.o
 obj-$(CONFIG_CMD_SPI) += spi.o
 obj-$(CONFIG_CMD_STRINGS) += strings.o
+obj-$(CONFIG_CMD_SM3SUM) += sm3sum.o
 obj-$(CONFIG_CMD_SMBIOS) += smbios.o
 obj-$(CONFIG_CMD_SMC) += smccc.o
 obj-$(CONFIG_CMD_SYSBOOT) += sysboot.o
diff --git a/cmd/sm3sum.c b/cmd/sm3sum.c
new file mode 100644 (file)
index 0000000..9044a32
--- /dev/null
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2025
+ * Heiko Schocher, Nabladev Software Engineering, hs@nabladev.com
+ *
+ * based on code from cmd/md5sum.c
+ */
+
+#include <command.h>
+#include <env.h>
+#include <hash.h>
+
+static int do_sm3sum(struct cmd_tbl *cmdtp, int flag, int argc,
+                    char *const argv[])
+{
+       int flags = HASH_FLAG_ENV;
+       int ac;
+       char *const *av;
+
+       if (argc < 3)
+               return CMD_RET_USAGE;
+
+       av = argv + 1;
+       ac = argc - 1;
+       if (IS_ENABLED(CONFIG_SM3SUM_VERIFY) && strcmp(*av, "-v") == 0) {
+               flags |= HASH_FLAG_VERIFY;
+               av++;
+               ac--;
+       }
+
+       return hash_command("sm3_256", flags, cmdtp, flag, ac, av);
+}
+
+#if IS_ENABLED(CONFIG_SM3SUM_VERIFY)
+U_BOOT_CMD(sm3sum, 5, 1, do_sm3sum,
+          "compute SM3 message digest",
+          "address count [[*]sum]\n"
+          "  - compute SM3 message digest [save to sum]\n"
+          "sm3sum -v address count [*]sum\n"
+          "  - verify sm3sum of memory area"
+);
+#else
+U_BOOT_CMD(sm3sum, 4, 1, do_sm3sum,
+          "compute SM3 message digest",
+          "address count [[*]sum]\n"
+          "  - compute SM3 message digest [save to sum]"
+);
+#endif /* IS_ENABLED(CONFIG_SM3SUM_VERIFY) */
index 0c45992d5c7a70bc5ca437465b96c769496278fd..71c4bef58263ffe2cb7d1cf0446e4791b7dca42a 100644 (file)
@@ -34,6 +34,7 @@
 #include <u-boot/sha256.h>
 #include <u-boot/sha512.h>
 #include <u-boot/md5.h>
+#include <u-boot/sm3.h>
 
 static int __maybe_unused hash_init_sha1(struct hash_algo *algo, void **ctxp)
 {
@@ -143,6 +144,34 @@ static int __maybe_unused hash_finish_sha512(struct hash_algo *algo, void *ctx,
        return 0;
 }
 
+static int __maybe_unused hash_init_sm3(struct hash_algo *algo, void **ctxp)
+{
+       struct sm3_context *ctx = malloc(sizeof(struct sm3_context));
+
+       sm3_init(ctx);
+       *ctxp = ctx;
+       return 0;
+}
+
+static int __maybe_unused hash_update_sm3(struct hash_algo *algo, void *ctx,
+                                         const void *buf, uint size,
+                                         int is_last)
+{
+       sm3_update((struct sm3_context *)ctx, buf, size);
+       return 0;
+}
+
+static int __maybe_unused hash_finish_sm3(struct hash_algo *algo, void *ctx,
+                                         void *dest_buf, int size)
+{
+       if (size < algo->digest_size)
+               return -1;
+
+       sm3_final((struct sm3_context *)ctx, dest_buf);
+       free(ctx);
+       return 0;
+}
+
 static int __maybe_unused hash_init_crc16_ccitt(struct hash_algo *algo,
                                                void **ctxp)
 {
@@ -298,6 +327,17 @@ static struct hash_algo hash_algo[] = {
 #endif
        },
 #endif
+#if CONFIG_IS_ENABLED(SM3)
+       {
+               .name           = "sm3_256",
+               .digest_size    = SM3_DIGEST_SIZE,
+               .chunk_size     = SM3_BLOCK_SIZE,
+               .hash_func_ws   = sm3_csum_wd,
+               .hash_init      = hash_init_sm3,
+               .hash_update    = hash_update_sm3,
+               .hash_finish    = hash_finish_sm3,
+       },
+#endif
 #if CONFIG_IS_ENABLED(CRC16)
        {
                .name           = "crc16-ccitt",
@@ -334,7 +374,7 @@ static struct hash_algo hash_algo[] = {
 #if CONFIG_IS_ENABLED(SHA256) || IS_ENABLED(CONFIG_CMD_SHA1SUM) || \
        CONFIG_IS_ENABLED(CRC32_VERIFY) || IS_ENABLED(CONFIG_CMD_HASH) || \
        CONFIG_IS_ENABLED(SHA384) || CONFIG_IS_ENABLED(SHA512) || \
-       IS_ENABLED(CONFIG_CMD_MD5SUM)
+       IS_ENABLED(CONFIG_CMD_MD5SUM) || CONFIG_IS_ENABLED(SM3)
 #define multi_hash()   1
 #else
 #define multi_hash()   0
index de16684ca0a755693d981eaa69bb1a65d9e025e5..b4ead96c77639ea79cd0ac99d605707d9c5dc0df 100644 (file)
@@ -24,4 +24,12 @@ struct sm3_context {
        uint8_t buffer[SM3_BLOCK_SIZE];
        int buflen;
 };
+
+void sm3_init(struct sm3_context *sctx);
+void sm3_update(struct sm3_context *sctx, const uint8_t *input, size_t ilen);
+void sm3_final(struct sm3_context *sctx, uint8_t output[SM3_DIGEST_SIZE]);
+void sm3_hash(const uint8_t *input, size_t ilen, uint8_t output[SM3_DIGEST_SIZE]);
+
+void sm3_csum_wd(const unsigned char *input, uint32_t len,
+                unsigned char *output, unsigned int chunk_sz);
 #endif
index bb994d187efd27da912f6f8cd794027d53838be0..2a4e825481d99acb49485d5b5e1f4a81ba9ed009 100644 (file)
--- a/lib/sm3.c
+++ b/lib/sm3.c
@@ -185,3 +185,128 @@ static inline void sm3_block(struct sm3_context *sctx,
                data += SM3_BLOCK_SIZE;
        }
 }
+
+void sm3_init(struct sm3_context *sctx)
+{
+       memset(sctx, 0, sizeof(*sctx));
+
+       /* Load initial values */
+       sctx->state[0] = SM3_IVA;
+       sctx->state[1] = SM3_IVB;
+       sctx->state[2] = SM3_IVC;
+       sctx->state[3] = SM3_IVD;
+       sctx->state[4] = SM3_IVE;
+       sctx->state[5] = SM3_IVF;
+       sctx->state[6] = SM3_IVG;
+       sctx->state[7] = SM3_IVH;
+       sctx->count = 0;
+}
+
+void sm3_update(struct sm3_context *sctx, const uint8_t *input, size_t ilen)
+{
+       unsigned int partial = sctx->count % SM3_BLOCK_SIZE;
+       u32 W[16];
+
+       sctx->count += ilen;
+
+       if ((partial + ilen) >= SM3_BLOCK_SIZE) {
+               int blocks;
+
+               if (partial) {
+                       int p = SM3_BLOCK_SIZE - partial;
+
+                       memcpy(sctx->buffer + partial, input, p);
+                       input += p;
+                       ilen -= p;
+
+                       sm3_block(sctx, sctx->buffer, 1, W);
+               }
+
+               blocks = ilen / SM3_BLOCK_SIZE;
+               ilen %= SM3_BLOCK_SIZE;
+
+               if (blocks) {
+                       sm3_block(sctx, input, blocks, W);
+                       input += blocks * SM3_BLOCK_SIZE;
+               }
+
+               memset(W, 0, sizeof(W));
+
+               partial = 0;
+       }
+       if (ilen)
+               memcpy(sctx->buffer + partial, input, ilen);
+}
+
+void sm3_final(struct sm3_context *sctx, uint8_t output[SM3_DIGEST_SIZE])
+{
+       const int bit_offset = SM3_BLOCK_SIZE - sizeof(u64);
+       __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
+       __be32 *digest = (__be32 *)&output[0];
+       unsigned int partial = sctx->count % SM3_BLOCK_SIZE;
+       u32 W[16];
+       int i;
+
+       sctx->buffer[partial++] = 0x80;
+       if (partial > bit_offset) {
+               memset(sctx->buffer + partial, 0, SM3_BLOCK_SIZE - partial);
+               partial = 0;
+
+               sm3_block(sctx, sctx->buffer, 1, W);
+       }
+
+       memset(sctx->buffer + partial, 0, bit_offset - partial);
+       *bits = cpu_to_be64(sctx->count << 3);
+       sm3_block(sctx, sctx->buffer, 1, W);
+
+       for (i = 0; i < 8; i++)
+               put_unaligned_be32(sctx->state[i], digest++);
+
+       /* Zeroize sensitive information. */
+       memset(W, 0, sizeof(W));
+       memset(sctx, 0, sizeof(*sctx));
+}
+
+/**
+ * sm3_hash - Calculate SM3 hash of input data
+ * @input: Input data
+ * @ilen: Input data length in bytes
+ * @output: Output buffer for hash (32 bytes)
+ */
+void sm3_hash(const uint8_t *input, size_t ilen, uint8_t output[SM3_DIGEST_SIZE])
+{
+       struct sm3_context sctx;
+
+       sm3_init(&sctx);
+       sm3_update(&sctx, input, ilen);
+       sm3_final(&sctx, output);
+}
+
+/**
+ * sm3_csum_wd - Calculate SM3 checksum on memory region using watchdog
+ * @addr: Starting address
+ * @len: Length in bytes
+ * @output: Output buffer for checksum (32 bytes)
+ * @flags: Flags for watchdog behavior
+ *
+ * This is the U-Boot API entry function for SM3 hash calculation
+ */
+void sm3_csum_wd(const unsigned char *input, uint32_t len,
+                unsigned char *output, unsigned int chunk_sz)
+{
+       struct sm3_context ctx;
+       uint32_t chunk;
+
+       sm3_init(&ctx);
+
+       /* Process data in chunks, kicking watchdog between chunks */
+       while (len > 0) {
+               chunk = (len > chunk_sz) ? chunk_sz : len;
+               sm3_update(&ctx, input, chunk);
+               input += chunk;
+               len -= chunk;
+
+               schedule();
+       }
+       sm3_final(&ctx, output);
+}