summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/crypto/sm3.h70
-rw-r--r--lib/crypto/Kconfig7
-rw-r--r--lib/crypto/sm3.c155
3 files changed, 203 insertions, 29 deletions
diff --git a/include/crypto/sm3.h b/include/crypto/sm3.h
index 918d318795ef..702c5326b4be 100644
--- a/include/crypto/sm3.h
+++ b/include/crypto/sm3.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Common values for SM3 algorithm
+ * SM3 hash algorithm
*
* Copyright (C) 2017 ARM Limited or its affiliates.
* Copyright (C) 2017 Gilad Ben-Yossef <gilad@benyossef.com>
@@ -31,16 +31,66 @@ struct sm3_state {
u8 buffer[SM3_BLOCK_SIZE];
};
-/*
- * Stand-alone implementation of the SM3 algorithm. It is designed to
- * have as little dependencies as possible so it can be used in the
- * kexec_file purgatory. In other cases you should generally use the
- * hash APIs from include/crypto/hash.h. Especially when hashing large
- * amounts of data as those APIs may be hw-accelerated.
+void sm3_block_generic(struct sm3_state *sctx, u8 const *data, int blocks);
+
+/* State for the SM3 compression function */
+struct sm3_block_state {
+ u32 h[SM3_DIGEST_SIZE / 4];
+};
+
+/**
+ * struct sm3_ctx - Context for hashing a message with SM3
+ * @state: the compression function state
+ * @bytecount: number of bytes processed so far
+ * @buf: partial block buffer; bytecount % SM3_BLOCK_SIZE bytes are valid
+ */
+struct sm3_ctx {
+ struct sm3_block_state state;
+ u64 bytecount;
+ u8 buf[SM3_BLOCK_SIZE] __aligned(__alignof__(__be64));
+};
+
+/**
+ * sm3_init() - Initialize an SM3 context for a new message
+ * @ctx: the context to initialize
*
- * For details see lib/crypto/sm3.c
+ * If you don't need incremental computation, consider sm3() instead.
+ *
+ * Context: Any context.
*/
+void sm3_init(struct sm3_ctx *ctx);
-void sm3_block_generic(struct sm3_state *sctx, u8 const *data, int blocks);
+/**
+ * sm3_update() - Update an SM3 context with message data
+ * @ctx: the context to update; must have been initialized
+ * @data: the message data
+ * @len: the data length in bytes
+ *
+ * This can be called any number of times.
+ *
+ * Context: Any context.
+ */
+void sm3_update(struct sm3_ctx *ctx, const u8 *data, size_t len);
+
+/**
+ * sm3_final() - Finish computing an SM3 message digest
+ * @ctx: the context to finalize; must have been initialized
+ * @out: (output) the resulting SM3 message digest
+ *
+ * After finishing, this zeroizes @ctx. So the caller does not need to do it.
+ *
+ * Context: Any context.
+ */
+void sm3_final(struct sm3_ctx *ctx, u8 out[at_least SM3_DIGEST_SIZE]);
+
+/**
+ * sm3() - Compute SM3 message digest in one shot
+ * @data: the message data
+ * @len: the data length in bytes
+ * @out: (output) the resulting SM3 message digest
+ *
+ * Context: Any context.
+ */
+void sm3(const u8 *data, size_t len, u8 out[at_least SM3_DIGEST_SIZE]);
-#endif
+#endif /* _CRYPTO_SM3_H */
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");