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>
This commit is contained in:
@@ -36,4 +36,64 @@ struct sha1_state {
|
||||
void sha1_init_raw(__u32 *buf);
|
||||
void sha1_transform(__u32 *digest, const char *data, __u32 *W);
|
||||
|
||||
/* State for the SHA-1 compression function */
|
||||
struct sha1_block_state {
|
||||
u32 h[SHA1_DIGEST_SIZE / 4];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sha1_ctx - Context for hashing a message with SHA-1
|
||||
* @state: the compression function state
|
||||
* @bytecount: number of bytes processed so far
|
||||
* @buf: partial block buffer; bytecount % SHA1_BLOCK_SIZE bytes are valid
|
||||
*/
|
||||
struct sha1_ctx {
|
||||
struct sha1_block_state state;
|
||||
u64 bytecount;
|
||||
u8 buf[SHA1_BLOCK_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* sha1_init() - Initialize a SHA-1 context for a new message
|
||||
* @ctx: the context to initialize
|
||||
*
|
||||
* If you don't need incremental computation, consider sha1() instead.
|
||||
*
|
||||
* Context: Any context.
|
||||
*/
|
||||
void sha1_init(struct sha1_ctx *ctx);
|
||||
|
||||
/**
|
||||
* sha1_update() - Update a SHA-1 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 sha1_update(struct sha1_ctx *ctx, const u8 *data, size_t len);
|
||||
|
||||
/**
|
||||
* sha1_final() - Finish computing a SHA-1 message digest
|
||||
* @ctx: the context to finalize; must have been initialized
|
||||
* @out: (output) the resulting SHA-1 message digest
|
||||
*
|
||||
* After finishing, this zeroizes @ctx. So the caller does not need to do it.
|
||||
*
|
||||
* Context: Any context.
|
||||
*/
|
||||
void sha1_final(struct sha1_ctx *ctx, u8 out[SHA1_DIGEST_SIZE]);
|
||||
|
||||
/**
|
||||
* sha1() - Compute SHA-1 message digest in one shot
|
||||
* @data: the message data
|
||||
* @len: the data length in bytes
|
||||
* @out: (output) the resulting SHA-1 message digest
|
||||
*
|
||||
* Context: Any context.
|
||||
*/
|
||||
void sha1(const u8 *data, size_t len, u8 out[SHA1_DIGEST_SIZE]);
|
||||
|
||||
#endif /* _CRYPTO_SHA1_H */
|
||||
|
||||
@@ -139,6 +139,13 @@ config CRYPTO_LIB_CHACHA20POLY1305
|
||||
|
||||
config CRYPTO_LIB_SHA1
|
||||
tristate
|
||||
help
|
||||
The SHA-1 library functions. Select this if your module uses any of
|
||||
the functions from <crypto/sha1.h>.
|
||||
|
||||
config CRYPTO_LIB_SHA1_ARCH
|
||||
bool
|
||||
depends on CRYPTO_LIB_SHA1 && !UML
|
||||
|
||||
config CRYPTO_LIB_SHA256
|
||||
tristate
|
||||
|
||||
+7
-2
@@ -65,8 +65,13 @@ libpoly1305-generic-y := poly1305-donna32.o
|
||||
libpoly1305-generic-$(CONFIG_ARCH_SUPPORTS_INT128) := poly1305-donna64.o
|
||||
libpoly1305-generic-y += poly1305-generic.o
|
||||
|
||||
obj-$(CONFIG_CRYPTO_LIB_SHA1) += libsha1.o
|
||||
libsha1-y := sha1.o
|
||||
################################################################################
|
||||
|
||||
obj-$(CONFIG_CRYPTO_LIB_SHA1) += libsha1.o
|
||||
libsha1-y := sha1.o
|
||||
ifeq ($(CONFIG_CRYPTO_LIB_SHA1_ARCH),y)
|
||||
CFLAGS_sha1.o += -I$(src)/$(SRCARCH)
|
||||
endif # CONFIG_CRYPTO_LIB_SHA1_ARCH
|
||||
|
||||
################################################################################
|
||||
|
||||
|
||||
+110
-5
@@ -1,9 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* SHA1 routine optimized to do word accesses rather than byte accesses,
|
||||
* and to avoid unnecessary copies into the context array.
|
||||
*
|
||||
* This was based on the git SHA1 implementation.
|
||||
* SHA-1 library functions
|
||||
*/
|
||||
|
||||
#include <crypto/sha1.h>
|
||||
@@ -14,6 +11,10 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
static const struct sha1_block_state sha1_iv = {
|
||||
.h = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 },
|
||||
};
|
||||
|
||||
/*
|
||||
* If you have 32 registers or more, the compiler can (and should)
|
||||
* try to change the array[] accesses into registers. However, on
|
||||
@@ -137,5 +138,109 @@ void sha1_init_raw(__u32 *buf)
|
||||
}
|
||||
EXPORT_SYMBOL(sha1_init_raw);
|
||||
|
||||
MODULE_DESCRIPTION("SHA-1 Algorithm");
|
||||
static void __maybe_unused sha1_blocks_generic(struct sha1_block_state *state,
|
||||
const u8 *data, size_t nblocks)
|
||||
{
|
||||
u32 workspace[SHA1_WORKSPACE_WORDS];
|
||||
|
||||
do {
|
||||
sha1_transform(state->h, data, workspace);
|
||||
data += SHA1_BLOCK_SIZE;
|
||||
} while (--nblocks);
|
||||
|
||||
memzero_explicit(workspace, sizeof(workspace));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CRYPTO_LIB_SHA1_ARCH
|
||||
#include "sha1.h" /* $(SRCARCH)/sha1.h */
|
||||
#else
|
||||
#define sha1_blocks sha1_blocks_generic
|
||||
#endif
|
||||
|
||||
void sha1_init(struct sha1_ctx *ctx)
|
||||
{
|
||||
ctx->state = sha1_iv;
|
||||
ctx->bytecount = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sha1_init);
|
||||
|
||||
void sha1_update(struct sha1_ctx *ctx, const u8 *data, size_t len)
|
||||
{
|
||||
size_t partial = ctx->bytecount % SHA1_BLOCK_SIZE;
|
||||
|
||||
ctx->bytecount += len;
|
||||
|
||||
if (partial + len >= SHA1_BLOCK_SIZE) {
|
||||
size_t nblocks;
|
||||
|
||||
if (partial) {
|
||||
size_t l = SHA1_BLOCK_SIZE - partial;
|
||||
|
||||
memcpy(&ctx->buf[partial], data, l);
|
||||
data += l;
|
||||
len -= l;
|
||||
|
||||
sha1_blocks(&ctx->state, ctx->buf, 1);
|
||||
}
|
||||
|
||||
nblocks = len / SHA1_BLOCK_SIZE;
|
||||
len %= SHA1_BLOCK_SIZE;
|
||||
|
||||
if (nblocks) {
|
||||
sha1_blocks(&ctx->state, data, nblocks);
|
||||
data += nblocks * SHA1_BLOCK_SIZE;
|
||||
}
|
||||
partial = 0;
|
||||
}
|
||||
if (len)
|
||||
memcpy(&ctx->buf[partial], data, len);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sha1_update);
|
||||
|
||||
void sha1_final(struct sha1_ctx *ctx, u8 out[SHA1_DIGEST_SIZE])
|
||||
{
|
||||
u64 bitcount = ctx->bytecount << 3;
|
||||
size_t partial = ctx->bytecount % SHA1_BLOCK_SIZE;
|
||||
|
||||
ctx->buf[partial++] = 0x80;
|
||||
if (partial > SHA1_BLOCK_SIZE - 8) {
|
||||
memset(&ctx->buf[partial], 0, SHA1_BLOCK_SIZE - partial);
|
||||
sha1_blocks(&ctx->state, ctx->buf, 1);
|
||||
partial = 0;
|
||||
}
|
||||
memset(&ctx->buf[partial], 0, SHA1_BLOCK_SIZE - 8 - partial);
|
||||
*(__be64 *)&ctx->buf[SHA1_BLOCK_SIZE - 8] = cpu_to_be64(bitcount);
|
||||
sha1_blocks(&ctx->state, ctx->buf, 1);
|
||||
|
||||
for (size_t i = 0; i < SHA1_DIGEST_SIZE; i += 4)
|
||||
put_unaligned_be32(ctx->state.h[i / 4], out + i);
|
||||
memzero_explicit(ctx, sizeof(*ctx));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sha1_final);
|
||||
|
||||
void sha1(const u8 *data, size_t len, u8 out[SHA1_DIGEST_SIZE])
|
||||
{
|
||||
struct sha1_ctx ctx;
|
||||
|
||||
sha1_init(&ctx);
|
||||
sha1_update(&ctx, data, len);
|
||||
sha1_final(&ctx, out);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sha1);
|
||||
|
||||
#ifdef sha1_mod_init_arch
|
||||
static int __init sha1_mod_init(void)
|
||||
{
|
||||
sha1_mod_init_arch();
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(sha1_mod_init);
|
||||
|
||||
static void __exit sha1_mod_exit(void)
|
||||
{
|
||||
}
|
||||
module_exit(sha1_mod_exit);
|
||||
#endif
|
||||
|
||||
MODULE_DESCRIPTION("SHA-1 library functions");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
Reference in New Issue
Block a user