SM3
M: Heiko Schocher <hs@nabladev.com>
S: Maintained
+F: cmd/sm3sum.c
F: include/u-boot/sm3.h
F: lib/sm3.c
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
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
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
--- /dev/null
+// 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) */
#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)
{
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)
{
#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",
#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
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
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);
+}