diff options
| author | Eric Biggers <ebiggers@kernel.org> | 2026-03-20 21:09:27 -0700 |
|---|---|---|
| committer | Eric Biggers <ebiggers@kernel.org> | 2026-03-23 17:50:59 -0700 |
| commit | 324bb3bb75ac21adbbc7e6ea5cdb0a735fb78a56 (patch) | |
| tree | 50fd9976634d569bdb0a42872e63338bcb4a864a /lib/crypto | |
| parent | 6dc7fce91041ec8d2f5e6fd589ee2962898d9f44 (diff) | |
lib/crypto: sm3: Add SM3 library API
Add a straightforward library API for SM3, mirroring the ones for the
other hash algorithms. It uses the existing generic implementation of
SM3's compression function in lib/crypto/sm3.c. Hooks are added for
architecture-optimized implementations, which later commits will wire up
to the existing optimized SM3 code for arm64, riscv, and x86.
Note that the rationale for this is *not* that SM3 should be used, or
that any kernel subsystem currently seems like a candidate for switching
from the sm3 crypto_shash to SM3 library. (SM3, in fact, shouldn't be
used. Likewise you shouldn't use MD5, SHA-1, RC4, etc...)
Rather, it's just that this will simplify how the kernel's existing SM3
code is integrated and make it much easier to maintain and test. SM3 is
one of the only hash algorithms with arch-optimized code that is still
integrated in the old way. By converting it to the new lib/crypto/ code
organization, we'll only have to keep track of one way of doing things.
The library will also get a KUnit test suite (as usual for lib/crypto/),
so it will become more easily and comprehensively tested as well.
Skip adding functions for HMAC-SM3 for now, though. There's not as much
point in adding those right now.
Note: similar to the other hash algorithms, the library API uses
'struct sm3_ctx', not 'struct sm3_state'. The existing 'struct
sm3_state' and the sm3_block_generic() function which uses it are
temporarily kept around until their users are updated by later commits.
Acked-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20260321040935.410034-5-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Diffstat (limited to 'lib/crypto')
| -rw-r--r-- | lib/crypto/Kconfig | 7 | ||||
| -rw-r--r-- | lib/crypto/sm3.c | 155 |
2 files changed, 143 insertions, 19 deletions
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig index 32fafe245f47..64c9a0bc4099 100644 --- a/lib/crypto/Kconfig +++ b/lib/crypto/Kconfig @@ -272,6 +272,13 @@ config CRYPTO_LIB_SHA3_ARCH config CRYPTO_LIB_SM3 tristate + help + The SM3 library functions. Select this if your module uses any of the + functions from <crypto/sm3.h>. + +config CRYPTO_LIB_SM3_ARCH + bool + depends on CRYPTO_LIB_SM3 && !UML source "lib/crypto/tests/Kconfig" diff --git a/lib/crypto/sm3.c b/lib/crypto/sm3.c index c6b9ad8a3ac6..20500cf4b8c0 100644 --- a/lib/crypto/sm3.c +++ b/lib/crypto/sm3.c @@ -15,6 +15,13 @@ #include <linux/string.h> #include <linux/unaligned.h> +static const struct sm3_block_state sm3_iv = { + .h = { + SM3_IVA, SM3_IVB, SM3_IVC, SM3_IVD, + SM3_IVE, SM3_IVF, SM3_IVG, SM3_IVH, + }, +}; + static const u32 ____cacheline_aligned K[64] = { 0x79cc4519, 0xf3988a32, 0xe7311465, 0xce6228cb, 0x9cc45197, 0x3988a32f, 0x7311465e, 0xe6228cbc, @@ -72,18 +79,19 @@ static const u32 ____cacheline_aligned K[64] = { ^ rol32(W[(i-13) & 0x0f], 7) \ ^ W[(i-6) & 0x0f]) -static void sm3_transform(struct sm3_state *sctx, u8 const *data, u32 W[16]) +static void sm3_transform(struct sm3_block_state *state, + const u8 data[SM3_BLOCK_SIZE], u32 W[16]) { u32 a, b, c, d, e, f, g, h, ss1, ss2; - a = sctx->state[0]; - b = sctx->state[1]; - c = sctx->state[2]; - d = sctx->state[3]; - e = sctx->state[4]; - f = sctx->state[5]; - g = sctx->state[6]; - h = sctx->state[7]; + a = state->h[0]; + b = state->h[1]; + c = state->h[2]; + d = state->h[3]; + e = state->h[4]; + f = state->h[5]; + g = state->h[6]; + h = state->h[7]; R1(a, b, c, d, e, f, g, h, K[0], I(0), I(4)); R1(d, a, b, c, h, e, f, g, K[1], I(1), I(5)); @@ -153,14 +161,14 @@ static void sm3_transform(struct sm3_state *sctx, u8 const *data, u32 W[16]) R2(c, d, a, b, g, h, e, f, K[62], W1(62), W2(66)); R2(b, c, d, a, f, g, h, e, K[63], W1(63), W2(67)); - sctx->state[0] ^= a; - sctx->state[1] ^= b; - sctx->state[2] ^= c; - sctx->state[3] ^= d; - sctx->state[4] ^= e; - sctx->state[5] ^= f; - sctx->state[6] ^= g; - sctx->state[7] ^= h; + state->h[0] ^= a; + state->h[1] ^= b; + state->h[2] ^= c; + state->h[3] ^= d; + state->h[4] ^= e; + state->h[5] ^= f; + state->h[6] ^= g; + state->h[7] ^= h; } #undef R #undef R1 @@ -174,7 +182,7 @@ void sm3_block_generic(struct sm3_state *sctx, u8 const *data, int blocks) u32 W[16]; do { - sm3_transform(sctx, data, W); + sm3_transform((struct sm3_block_state *)sctx->state, data, W); data += SM3_BLOCK_SIZE; } while (--blocks); @@ -182,5 +190,114 @@ void sm3_block_generic(struct sm3_state *sctx, u8 const *data, int blocks) } EXPORT_SYMBOL_GPL(sm3_block_generic); -MODULE_DESCRIPTION("Generic SM3 library"); +static void __maybe_unused sm3_blocks_generic(struct sm3_block_state *state, + const u8 *data, size_t nblocks) +{ + u32 W[16]; + + do { + sm3_transform(state, data, W); + data += SM3_BLOCK_SIZE; + } while (--nblocks); + + memzero_explicit(W, sizeof(W)); +} + +#ifdef CONFIG_CRYPTO_LIB_SM3_ARCH +#include "sm3.h" /* $(SRCARCH)/sm3.h */ +#else +#define sm3_blocks sm3_blocks_generic +#endif + +void sm3_init(struct sm3_ctx *ctx) +{ + ctx->state = sm3_iv; + ctx->bytecount = 0; +} +EXPORT_SYMBOL_GPL(sm3_init); + +void sm3_update(struct sm3_ctx *ctx, const u8 *data, size_t len) +{ + size_t partial = ctx->bytecount % SM3_BLOCK_SIZE; + + ctx->bytecount += len; + + if (partial + len >= SM3_BLOCK_SIZE) { + size_t nblocks; + + if (partial) { + size_t l = SM3_BLOCK_SIZE - partial; + + memcpy(&ctx->buf[partial], data, l); + data += l; + len -= l; + + sm3_blocks(&ctx->state, ctx->buf, 1); + } + + nblocks = len / SM3_BLOCK_SIZE; + len %= SM3_BLOCK_SIZE; + + if (nblocks) { + sm3_blocks(&ctx->state, data, nblocks); + data += nblocks * SM3_BLOCK_SIZE; + } + partial = 0; + } + if (len) + memcpy(&ctx->buf[partial], data, len); +} +EXPORT_SYMBOL_GPL(sm3_update); + +static void __sm3_final(struct sm3_ctx *ctx, u8 out[SM3_DIGEST_SIZE]) +{ + u64 bitcount = ctx->bytecount << 3; + size_t partial = ctx->bytecount % SM3_BLOCK_SIZE; + + ctx->buf[partial++] = 0x80; + if (partial > SM3_BLOCK_SIZE - 8) { + memset(&ctx->buf[partial], 0, SM3_BLOCK_SIZE - partial); + sm3_blocks(&ctx->state, ctx->buf, 1); + partial = 0; + } + memset(&ctx->buf[partial], 0, SM3_BLOCK_SIZE - 8 - partial); + *(__be64 *)&ctx->buf[SM3_BLOCK_SIZE - 8] = cpu_to_be64(bitcount); + sm3_blocks(&ctx->state, ctx->buf, 1); + + for (size_t i = 0; i < SM3_DIGEST_SIZE; i += 4) + put_unaligned_be32(ctx->state.h[i / 4], out + i); +} + +void sm3_final(struct sm3_ctx *ctx, u8 out[SM3_DIGEST_SIZE]) +{ + __sm3_final(ctx, out); + memzero_explicit(ctx, sizeof(*ctx)); +} +EXPORT_SYMBOL_GPL(sm3_final); + +void sm3(const u8 *data, size_t len, u8 out[SM3_DIGEST_SIZE]) +{ + struct sm3_ctx ctx; + + sm3_init(&ctx); + sm3_update(&ctx, data, len); + sm3_final(&ctx, out); +} +EXPORT_SYMBOL_GPL(sm3); + +#ifdef sm3_mod_init_arch +static int __init sm3_mod_init(void) +{ + sm3_mod_init_arch(); + return 0; +} +subsys_initcall(sm3_mod_init); + +static void __exit sm3_mod_exit(void) +{ +} +module_exit(sm3_mod_exit); +#endif + +MODULE_DESCRIPTION("SM3 library functions"); MODULE_LICENSE("GPL v2"); |
