Skip to content

Commit 90860ae

Browse files
author
Eric Biggers
committed
lib/crypto: sha1: Add SHA-1 library functions
Add a library interface for SHA-1, following the SHA-2 one. As was the case with SHA-2, this will be useful for various in-kernel users. The crypto_shash interface will be reimplemented on top of it as well. Reviewed-by: Ard Biesheuvel <ardb@kernel.org> Link: https://lore.kernel.org/r/20250712232329.818226-4-ebiggers@kernel.org Signed-off-by: Eric Biggers <ebiggers@kernel.org>
1 parent 9503ca2 commit 90860ae

4 files changed

Lines changed: 184 additions & 7 deletions

File tree

include/crypto/sha1.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,64 @@ struct sha1_state {
3636
void sha1_init_raw(__u32 *buf);
3737
void sha1_transform(__u32 *digest, const char *data, __u32 *W);
3838

39+
/* State for the SHA-1 compression function */
40+
struct sha1_block_state {
41+
u32 h[SHA1_DIGEST_SIZE / 4];
42+
};
43+
44+
/**
45+
* struct sha1_ctx - Context for hashing a message with SHA-1
46+
* @state: the compression function state
47+
* @bytecount: number of bytes processed so far
48+
* @buf: partial block buffer; bytecount % SHA1_BLOCK_SIZE bytes are valid
49+
*/
50+
struct sha1_ctx {
51+
struct sha1_block_state state;
52+
u64 bytecount;
53+
u8 buf[SHA1_BLOCK_SIZE];
54+
};
55+
56+
/**
57+
* sha1_init() - Initialize a SHA-1 context for a new message
58+
* @ctx: the context to initialize
59+
*
60+
* If you don't need incremental computation, consider sha1() instead.
61+
*
62+
* Context: Any context.
63+
*/
64+
void sha1_init(struct sha1_ctx *ctx);
65+
66+
/**
67+
* sha1_update() - Update a SHA-1 context with message data
68+
* @ctx: the context to update; must have been initialized
69+
* @data: the message data
70+
* @len: the data length in bytes
71+
*
72+
* This can be called any number of times.
73+
*
74+
* Context: Any context.
75+
*/
76+
void sha1_update(struct sha1_ctx *ctx, const u8 *data, size_t len);
77+
78+
/**
79+
* sha1_final() - Finish computing a SHA-1 message digest
80+
* @ctx: the context to finalize; must have been initialized
81+
* @out: (output) the resulting SHA-1 message digest
82+
*
83+
* After finishing, this zeroizes @ctx. So the caller does not need to do it.
84+
*
85+
* Context: Any context.
86+
*/
87+
void sha1_final(struct sha1_ctx *ctx, u8 out[SHA1_DIGEST_SIZE]);
88+
89+
/**
90+
* sha1() - Compute SHA-1 message digest in one shot
91+
* @data: the message data
92+
* @len: the data length in bytes
93+
* @out: (output) the resulting SHA-1 message digest
94+
*
95+
* Context: Any context.
96+
*/
97+
void sha1(const u8 *data, size_t len, u8 out[SHA1_DIGEST_SIZE]);
98+
3999
#endif /* _CRYPTO_SHA1_H */

lib/crypto/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@ config CRYPTO_LIB_CHACHA20POLY1305
139139

140140
config CRYPTO_LIB_SHA1
141141
tristate
142+
help
143+
The SHA-1 library functions. Select this if your module uses any of
144+
the functions from <crypto/sha1.h>.
145+
146+
config CRYPTO_LIB_SHA1_ARCH
147+
bool
148+
depends on CRYPTO_LIB_SHA1 && !UML
142149

143150
config CRYPTO_LIB_SHA256
144151
tristate

lib/crypto/Makefile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,13 @@ libpoly1305-generic-y := poly1305-donna32.o
6565
libpoly1305-generic-$(CONFIG_ARCH_SUPPORTS_INT128) := poly1305-donna64.o
6666
libpoly1305-generic-y += poly1305-generic.o
6767

68-
obj-$(CONFIG_CRYPTO_LIB_SHA1) += libsha1.o
69-
libsha1-y := sha1.o
68+
################################################################################
69+
70+
obj-$(CONFIG_CRYPTO_LIB_SHA1) += libsha1.o
71+
libsha1-y := sha1.o
72+
ifeq ($(CONFIG_CRYPTO_LIB_SHA1_ARCH),y)
73+
CFLAGS_sha1.o += -I$(src)/$(SRCARCH)
74+
endif # CONFIG_CRYPTO_LIB_SHA1_ARCH
7075

7176
################################################################################
7277

lib/crypto/sha1.c

Lines changed: 110 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0
22
/*
3-
* SHA1 routine optimized to do word accesses rather than byte accesses,
4-
* and to avoid unnecessary copies into the context array.
5-
*
6-
* This was based on the git SHA1 implementation.
3+
* SHA-1 library functions
74
*/
85

96
#include <crypto/sha1.h>
@@ -14,6 +11,10 @@
1411
#include <linux/string.h>
1512
#include <linux/unaligned.h>
1613

14+
static const struct sha1_block_state sha1_iv = {
15+
.h = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 },
16+
};
17+
1718
/*
1819
* If you have 32 registers or more, the compiler can (and should)
1920
* try to change the array[] accesses into registers. However, on
@@ -137,5 +138,109 @@ void sha1_init_raw(__u32 *buf)
137138
}
138139
EXPORT_SYMBOL(sha1_init_raw);
139140

140-
MODULE_DESCRIPTION("SHA-1 Algorithm");
141+
static void __maybe_unused sha1_blocks_generic(struct sha1_block_state *state,
142+
const u8 *data, size_t nblocks)
143+
{
144+
u32 workspace[SHA1_WORKSPACE_WORDS];
145+
146+
do {
147+
sha1_transform(state->h, data, workspace);
148+
data += SHA1_BLOCK_SIZE;
149+
} while (--nblocks);
150+
151+
memzero_explicit(workspace, sizeof(workspace));
152+
}
153+
154+
#ifdef CONFIG_CRYPTO_LIB_SHA1_ARCH
155+
#include "sha1.h" /* $(SRCARCH)/sha1.h */
156+
#else
157+
#define sha1_blocks sha1_blocks_generic
158+
#endif
159+
160+
void sha1_init(struct sha1_ctx *ctx)
161+
{
162+
ctx->state = sha1_iv;
163+
ctx->bytecount = 0;
164+
}
165+
EXPORT_SYMBOL_GPL(sha1_init);
166+
167+
void sha1_update(struct sha1_ctx *ctx, const u8 *data, size_t len)
168+
{
169+
size_t partial = ctx->bytecount % SHA1_BLOCK_SIZE;
170+
171+
ctx->bytecount += len;
172+
173+
if (partial + len >= SHA1_BLOCK_SIZE) {
174+
size_t nblocks;
175+
176+
if (partial) {
177+
size_t l = SHA1_BLOCK_SIZE - partial;
178+
179+
memcpy(&ctx->buf[partial], data, l);
180+
data += l;
181+
len -= l;
182+
183+
sha1_blocks(&ctx->state, ctx->buf, 1);
184+
}
185+
186+
nblocks = len / SHA1_BLOCK_SIZE;
187+
len %= SHA1_BLOCK_SIZE;
188+
189+
if (nblocks) {
190+
sha1_blocks(&ctx->state, data, nblocks);
191+
data += nblocks * SHA1_BLOCK_SIZE;
192+
}
193+
partial = 0;
194+
}
195+
if (len)
196+
memcpy(&ctx->buf[partial], data, len);
197+
}
198+
EXPORT_SYMBOL_GPL(sha1_update);
199+
200+
void sha1_final(struct sha1_ctx *ctx, u8 out[SHA1_DIGEST_SIZE])
201+
{
202+
u64 bitcount = ctx->bytecount << 3;
203+
size_t partial = ctx->bytecount % SHA1_BLOCK_SIZE;
204+
205+
ctx->buf[partial++] = 0x80;
206+
if (partial > SHA1_BLOCK_SIZE - 8) {
207+
memset(&ctx->buf[partial], 0, SHA1_BLOCK_SIZE - partial);
208+
sha1_blocks(&ctx->state, ctx->buf, 1);
209+
partial = 0;
210+
}
211+
memset(&ctx->buf[partial], 0, SHA1_BLOCK_SIZE - 8 - partial);
212+
*(__be64 *)&ctx->buf[SHA1_BLOCK_SIZE - 8] = cpu_to_be64(bitcount);
213+
sha1_blocks(&ctx->state, ctx->buf, 1);
214+
215+
for (size_t i = 0; i < SHA1_DIGEST_SIZE; i += 4)
216+
put_unaligned_be32(ctx->state.h[i / 4], out + i);
217+
memzero_explicit(ctx, sizeof(*ctx));
218+
}
219+
EXPORT_SYMBOL_GPL(sha1_final);
220+
221+
void sha1(const u8 *data, size_t len, u8 out[SHA1_DIGEST_SIZE])
222+
{
223+
struct sha1_ctx ctx;
224+
225+
sha1_init(&ctx);
226+
sha1_update(&ctx, data, len);
227+
sha1_final(&ctx, out);
228+
}
229+
EXPORT_SYMBOL_GPL(sha1);
230+
231+
#ifdef sha1_mod_init_arch
232+
static int __init sha1_mod_init(void)
233+
{
234+
sha1_mod_init_arch();
235+
return 0;
236+
}
237+
subsys_initcall(sha1_mod_init);
238+
239+
static void __exit sha1_mod_exit(void)
240+
{
241+
}
242+
module_exit(sha1_mod_exit);
243+
#endif
244+
245+
MODULE_DESCRIPTION("SHA-1 library functions");
141246
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)