162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Cryptographic API.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * powerpc implementation of the SHA1 Secure Hash Algorithm.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Derived from cryptoapi implementation, adapted for in-place
862306a36Sopenharmony_ci * scatterlist interface.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Derived from "crypto/sha1.c"
1162306a36Sopenharmony_ci * Copyright (c) Alan Smithee.
1262306a36Sopenharmony_ci * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
1362306a36Sopenharmony_ci * Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci#include <crypto/internal/hash.h>
1662306a36Sopenharmony_ci#include <linux/init.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/mm.h>
1962306a36Sopenharmony_ci#include <linux/types.h>
2062306a36Sopenharmony_ci#include <crypto/sha1.h>
2162306a36Sopenharmony_ci#include <crypto/sha1_base.h>
2262306a36Sopenharmony_ci#include <asm/byteorder.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_civoid powerpc_sha_transform(u32 *state, const u8 *src);
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic int powerpc_sha1_update(struct shash_desc *desc, const u8 *data,
2762306a36Sopenharmony_ci			       unsigned int len)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	struct sha1_state *sctx = shash_desc_ctx(desc);
3062306a36Sopenharmony_ci	unsigned int partial, done;
3162306a36Sopenharmony_ci	const u8 *src;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	partial = sctx->count & 0x3f;
3462306a36Sopenharmony_ci	sctx->count += len;
3562306a36Sopenharmony_ci	done = 0;
3662306a36Sopenharmony_ci	src = data;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if ((partial + len) > 63) {
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci		if (partial) {
4162306a36Sopenharmony_ci			done = -partial;
4262306a36Sopenharmony_ci			memcpy(sctx->buffer + partial, data, done + 64);
4362306a36Sopenharmony_ci			src = sctx->buffer;
4462306a36Sopenharmony_ci		}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci		do {
4762306a36Sopenharmony_ci			powerpc_sha_transform(sctx->state, src);
4862306a36Sopenharmony_ci			done += 64;
4962306a36Sopenharmony_ci			src = data + done;
5062306a36Sopenharmony_ci		} while (done + 63 < len);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci		partial = 0;
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci	memcpy(sctx->buffer + partial, src, len - done);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	return 0;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/* Add padding and return the message digest. */
6162306a36Sopenharmony_cistatic int powerpc_sha1_final(struct shash_desc *desc, u8 *out)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	struct sha1_state *sctx = shash_desc_ctx(desc);
6462306a36Sopenharmony_ci	__be32 *dst = (__be32 *)out;
6562306a36Sopenharmony_ci	u32 i, index, padlen;
6662306a36Sopenharmony_ci	__be64 bits;
6762306a36Sopenharmony_ci	static const u8 padding[64] = { 0x80, };
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	bits = cpu_to_be64(sctx->count << 3);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/* Pad out to 56 mod 64 */
7262306a36Sopenharmony_ci	index = sctx->count & 0x3f;
7362306a36Sopenharmony_ci	padlen = (index < 56) ? (56 - index) : ((64+56) - index);
7462306a36Sopenharmony_ci	powerpc_sha1_update(desc, padding, padlen);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/* Append length */
7762306a36Sopenharmony_ci	powerpc_sha1_update(desc, (const u8 *)&bits, sizeof(bits));
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/* Store state in digest */
8062306a36Sopenharmony_ci	for (i = 0; i < 5; i++)
8162306a36Sopenharmony_ci		dst[i] = cpu_to_be32(sctx->state[i]);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/* Wipe context */
8462306a36Sopenharmony_ci	memset(sctx, 0, sizeof *sctx);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return 0;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic int powerpc_sha1_export(struct shash_desc *desc, void *out)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct sha1_state *sctx = shash_desc_ctx(desc);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	memcpy(out, sctx, sizeof(*sctx));
9462306a36Sopenharmony_ci	return 0;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic int powerpc_sha1_import(struct shash_desc *desc, const void *in)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct sha1_state *sctx = shash_desc_ctx(desc);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	memcpy(sctx, in, sizeof(*sctx));
10262306a36Sopenharmony_ci	return 0;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic struct shash_alg alg = {
10662306a36Sopenharmony_ci	.digestsize	=	SHA1_DIGEST_SIZE,
10762306a36Sopenharmony_ci	.init		=	sha1_base_init,
10862306a36Sopenharmony_ci	.update		=	powerpc_sha1_update,
10962306a36Sopenharmony_ci	.final		=	powerpc_sha1_final,
11062306a36Sopenharmony_ci	.export		=	powerpc_sha1_export,
11162306a36Sopenharmony_ci	.import		=	powerpc_sha1_import,
11262306a36Sopenharmony_ci	.descsize	=	sizeof(struct sha1_state),
11362306a36Sopenharmony_ci	.statesize	=	sizeof(struct sha1_state),
11462306a36Sopenharmony_ci	.base		=	{
11562306a36Sopenharmony_ci		.cra_name	=	"sha1",
11662306a36Sopenharmony_ci		.cra_driver_name=	"sha1-powerpc",
11762306a36Sopenharmony_ci		.cra_blocksize	=	SHA1_BLOCK_SIZE,
11862306a36Sopenharmony_ci		.cra_module	=	THIS_MODULE,
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int __init sha1_powerpc_mod_init(void)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	return crypto_register_shash(&alg);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic void __exit sha1_powerpc_mod_fini(void)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	crypto_unregister_shash(&alg);
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cimodule_init(sha1_powerpc_mod_init);
13362306a36Sopenharmony_cimodule_exit(sha1_powerpc_mod_fini);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
13662306a36Sopenharmony_ciMODULE_DESCRIPTION("SHA1 Secure Hash Algorithm");
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("sha1");
13962306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("sha1-powerpc");
140