Skip to content

Commit 324bb3b

Browse files
author
Eric Biggers
committed
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>
1 parent 6dc7fce commit 324bb3b

3 files changed

Lines changed: 203 additions & 29 deletions

File tree

include/crypto/sm3.h

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* SPDX-License-Identifier: GPL-2.0-only */
22
/*
3-
* Common values for SM3 algorithm
3+
* SM3 hash algorithm
44
*
55
* Copyright (C) 2017 ARM Limited or its affiliates.
66
* Copyright (C) 2017 Gilad Ben-Yossef <gilad@benyossef.com>
@@ -31,16 +31,66 @@ struct sm3_state {
3131
u8 buffer[SM3_BLOCK_SIZE];
3232
};
3333

34-
/*
35-
* Stand-alone implementation of the SM3 algorithm. It is designed to
36-
* have as little dependencies as possible so it can be used in the
37-
* kexec_file purgatory. In other cases you should generally use the
38-
* hash APIs from include/crypto/hash.h. Especially when hashing large
39-
* amounts of data as those APIs may be hw-accelerated.
34+
void sm3_block_generic(struct sm3_state *sctx, u8 const *data, int blocks);
35+
36+
/* State for the SM3 compression function */
37+
struct sm3_block_state {
38+
u32 h[SM3_DIGEST_SIZE / 4];
39+
};
40+
41+
/**
42+
* struct sm3_ctx - Context for hashing a message with SM3
43+
* @state: the compression function state
44+
* @bytecount: number of bytes processed so far
45+
* @buf: partial block buffer; bytecount % SM3_BLOCK_SIZE bytes are valid
46+
*/
47+
struct sm3_ctx {
48+
struct sm3_block_state state;
49+
u64 bytecount;
50+
u8 buf[SM3_BLOCK_SIZE] __aligned(__alignof__(__be64));
51+
};
52+
53+
/**
54+
* sm3_init() - Initialize an SM3 context for a new message
55+
* @ctx: the context to initialize
4056
*
41-
* For details see lib/crypto/sm3.c
57+
* If you don't need incremental computation, consider sm3() instead.
58+
*
59+
* Context: Any context.
4260
*/
61+
void sm3_init(struct sm3_ctx *ctx);
4362

44-
void sm3_block_generic(struct sm3_state *sctx, u8 const *data, int blocks);
63+
/**
64+
* sm3_update() - Update an SM3 context with message data
65+
* @ctx: the context to update; must have been initialized
66+
* @data: the message data
67+
* @len: the data length in bytes
68+
*
69+
* This can be called any number of times.
70+
*
71+
* Context: Any context.
72+
*/
73+
void sm3_update(struct sm3_ctx *ctx, const u8 *data, size_t len);
74+
75+
/**
76+
* sm3_final() - Finish computing an SM3 message digest
77+
* @ctx: the context to finalize; must have been initialized
78+
* @out: (output) the resulting SM3 message digest
79+
*
80+
* After finishing, this zeroizes @ctx. So the caller does not need to do it.
81+
*
82+
* Context: Any context.
83+
*/
84+
void sm3_final(struct sm3_ctx *ctx, u8 out[at_least SM3_DIGEST_SIZE]);
85+
86+
/**
87+
* sm3() - Compute SM3 message digest in one shot
88+
* @data: the message data
89+
* @len: the data length in bytes
90+
* @out: (output) the resulting SM3 message digest
91+
*
92+
* Context: Any context.
93+
*/
94+
void sm3(const u8 *data, size_t len, u8 out[at_least SM3_DIGEST_SIZE]);
4595

46-
#endif
96+
#endif /* _CRYPTO_SM3_H */

lib/crypto/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,13 @@ config CRYPTO_LIB_SHA3_ARCH
272272

273273
config CRYPTO_LIB_SM3
274274
tristate
275+
help
276+
The SM3 library functions. Select this if your module uses any of the
277+
functions from <crypto/sm3.h>.
278+
279+
config CRYPTO_LIB_SM3_ARCH
280+
bool
281+
depends on CRYPTO_LIB_SM3 && !UML
275282

276283
source "lib/crypto/tests/Kconfig"
277284

lib/crypto/sm3.c

Lines changed: 136 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515
#include <linux/string.h>
1616
#include <linux/unaligned.h>
1717

18+
static const struct sm3_block_state sm3_iv = {
19+
.h = {
20+
SM3_IVA, SM3_IVB, SM3_IVC, SM3_IVD,
21+
SM3_IVE, SM3_IVF, SM3_IVG, SM3_IVH,
22+
},
23+
};
24+
1825
static const u32 ____cacheline_aligned K[64] = {
1926
0x79cc4519, 0xf3988a32, 0xe7311465, 0xce6228cb,
2027
0x9cc45197, 0x3988a32f, 0x7311465e, 0xe6228cbc,
@@ -72,18 +79,19 @@ static const u32 ____cacheline_aligned K[64] = {
7279
^ rol32(W[(i-13) & 0x0f], 7) \
7380
^ W[(i-6) & 0x0f])
7481

75-
static void sm3_transform(struct sm3_state *sctx, u8 const *data, u32 W[16])
82+
static void sm3_transform(struct sm3_block_state *state,
83+
const u8 data[SM3_BLOCK_SIZE], u32 W[16])
7684
{
7785
u32 a, b, c, d, e, f, g, h, ss1, ss2;
7886

79-
a = sctx->state[0];
80-
b = sctx->state[1];
81-
c = sctx->state[2];
82-
d = sctx->state[3];
83-
e = sctx->state[4];
84-
f = sctx->state[5];
85-
g = sctx->state[6];
86-
h = sctx->state[7];
87+
a = state->h[0];
88+
b = state->h[1];
89+
c = state->h[2];
90+
d = state->h[3];
91+
e = state->h[4];
92+
f = state->h[5];
93+
g = state->h[6];
94+
h = state->h[7];
8795

8896
R1(a, b, c, d, e, f, g, h, K[0], I(0), I(4));
8997
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])
153161
R2(c, d, a, b, g, h, e, f, K[62], W1(62), W2(66));
154162
R2(b, c, d, a, f, g, h, e, K[63], W1(63), W2(67));
155163

156-
sctx->state[0] ^= a;
157-
sctx->state[1] ^= b;
158-
sctx->state[2] ^= c;
159-
sctx->state[3] ^= d;
160-
sctx->state[4] ^= e;
161-
sctx->state[5] ^= f;
162-
sctx->state[6] ^= g;
163-
sctx->state[7] ^= h;
164+
state->h[0] ^= a;
165+
state->h[1] ^= b;
166+
state->h[2] ^= c;
167+
state->h[3] ^= d;
168+
state->h[4] ^= e;
169+
state->h[5] ^= f;
170+
state->h[6] ^= g;
171+
state->h[7] ^= h;
164172
}
165173
#undef R
166174
#undef R1
@@ -174,13 +182,122 @@ void sm3_block_generic(struct sm3_state *sctx, u8 const *data, int blocks)
174182
u32 W[16];
175183

176184
do {
177-
sm3_transform(sctx, data, W);
185+
sm3_transform((struct sm3_block_state *)sctx->state, data, W);
178186
data += SM3_BLOCK_SIZE;
179187
} while (--blocks);
180188

181189
memzero_explicit(W, sizeof(W));
182190
}
183191
EXPORT_SYMBOL_GPL(sm3_block_generic);
184192

185-
MODULE_DESCRIPTION("Generic SM3 library");
193+
static void __maybe_unused sm3_blocks_generic(struct sm3_block_state *state,
194+
const u8 *data, size_t nblocks)
195+
{
196+
u32 W[16];
197+
198+
do {
199+
sm3_transform(state, data, W);
200+
data += SM3_BLOCK_SIZE;
201+
} while (--nblocks);
202+
203+
memzero_explicit(W, sizeof(W));
204+
}
205+
206+
#ifdef CONFIG_CRYPTO_LIB_SM3_ARCH
207+
#include "sm3.h" /* $(SRCARCH)/sm3.h */
208+
#else
209+
#define sm3_blocks sm3_blocks_generic
210+
#endif
211+
212+
void sm3_init(struct sm3_ctx *ctx)
213+
{
214+
ctx->state = sm3_iv;
215+
ctx->bytecount = 0;
216+
}
217+
EXPORT_SYMBOL_GPL(sm3_init);
218+
219+
void sm3_update(struct sm3_ctx *ctx, const u8 *data, size_t len)
220+
{
221+
size_t partial = ctx->bytecount % SM3_BLOCK_SIZE;
222+
223+
ctx->bytecount += len;
224+
225+
if (partial + len >= SM3_BLOCK_SIZE) {
226+
size_t nblocks;
227+
228+
if (partial) {
229+
size_t l = SM3_BLOCK_SIZE - partial;
230+
231+
memcpy(&ctx->buf[partial], data, l);
232+
data += l;
233+
len -= l;
234+
235+
sm3_blocks(&ctx->state, ctx->buf, 1);
236+
}
237+
238+
nblocks = len / SM3_BLOCK_SIZE;
239+
len %= SM3_BLOCK_SIZE;
240+
241+
if (nblocks) {
242+
sm3_blocks(&ctx->state, data, nblocks);
243+
data += nblocks * SM3_BLOCK_SIZE;
244+
}
245+
partial = 0;
246+
}
247+
if (len)
248+
memcpy(&ctx->buf[partial], data, len);
249+
}
250+
EXPORT_SYMBOL_GPL(sm3_update);
251+
252+
static void __sm3_final(struct sm3_ctx *ctx, u8 out[SM3_DIGEST_SIZE])
253+
{
254+
u64 bitcount = ctx->bytecount << 3;
255+
size_t partial = ctx->bytecount % SM3_BLOCK_SIZE;
256+
257+
ctx->buf[partial++] = 0x80;
258+
if (partial > SM3_BLOCK_SIZE - 8) {
259+
memset(&ctx->buf[partial], 0, SM3_BLOCK_SIZE - partial);
260+
sm3_blocks(&ctx->state, ctx->buf, 1);
261+
partial = 0;
262+
}
263+
memset(&ctx->buf[partial], 0, SM3_BLOCK_SIZE - 8 - partial);
264+
*(__be64 *)&ctx->buf[SM3_BLOCK_SIZE - 8] = cpu_to_be64(bitcount);
265+
sm3_blocks(&ctx->state, ctx->buf, 1);
266+
267+
for (size_t i = 0; i < SM3_DIGEST_SIZE; i += 4)
268+
put_unaligned_be32(ctx->state.h[i / 4], out + i);
269+
}
270+
271+
void sm3_final(struct sm3_ctx *ctx, u8 out[SM3_DIGEST_SIZE])
272+
{
273+
__sm3_final(ctx, out);
274+
memzero_explicit(ctx, sizeof(*ctx));
275+
}
276+
EXPORT_SYMBOL_GPL(sm3_final);
277+
278+
void sm3(const u8 *data, size_t len, u8 out[SM3_DIGEST_SIZE])
279+
{
280+
struct sm3_ctx ctx;
281+
282+
sm3_init(&ctx);
283+
sm3_update(&ctx, data, len);
284+
sm3_final(&ctx, out);
285+
}
286+
EXPORT_SYMBOL_GPL(sm3);
287+
288+
#ifdef sm3_mod_init_arch
289+
static int __init sm3_mod_init(void)
290+
{
291+
sm3_mod_init_arch();
292+
return 0;
293+
}
294+
subsys_initcall(sm3_mod_init);
295+
296+
static void __exit sm3_mod_exit(void)
297+
{
298+
}
299+
module_exit(sm3_mod_exit);
300+
#endif
301+
302+
MODULE_DESCRIPTION("SM3 library functions");
186303
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)