xref: /openbmc/linux/arch/arm64/crypto/sha3-ce-glue.c (revision e52b7023cdad005756cd91d7c54fa90ef6b43d32)
115d5910eSArd Biesheuvel /* SPDX-License-Identifier: GPL-2.0 */
215d5910eSArd Biesheuvel /*
315d5910eSArd Biesheuvel  * sha3-ce-glue.c - core SHA-3 transform using v8.2 Crypto Extensions
415d5910eSArd Biesheuvel  *
515d5910eSArd Biesheuvel  * Copyright (C) 2018 Linaro Ltd <ard.biesheuvel@linaro.org>
615d5910eSArd Biesheuvel  *
715d5910eSArd Biesheuvel  * This program is free software; you can redistribute it and/or modify
815d5910eSArd Biesheuvel  * it under the terms of the GNU General Public License version 2 as
915d5910eSArd Biesheuvel  * published by the Free Software Foundation.
1015d5910eSArd Biesheuvel  */
1115d5910eSArd Biesheuvel 
1215d5910eSArd Biesheuvel #include <asm/hwcap.h>
1315d5910eSArd Biesheuvel #include <asm/neon.h>
1415d5910eSArd Biesheuvel #include <asm/simd.h>
1515d5910eSArd Biesheuvel #include <asm/unaligned.h>
1615d5910eSArd Biesheuvel #include <crypto/internal/hash.h>
17*e52b7023SEric Biggers #include <crypto/internal/simd.h>
1815d5910eSArd Biesheuvel #include <crypto/sha3.h>
1915d5910eSArd Biesheuvel #include <linux/cpufeature.h>
2015d5910eSArd Biesheuvel #include <linux/crypto.h>
2115d5910eSArd Biesheuvel #include <linux/module.h>
2215d5910eSArd Biesheuvel 
2315d5910eSArd Biesheuvel MODULE_DESCRIPTION("SHA3 secure hash using ARMv8 Crypto Extensions");
2415d5910eSArd Biesheuvel MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
2515d5910eSArd Biesheuvel MODULE_LICENSE("GPL v2");
2615d5910eSArd Biesheuvel 
2715d5910eSArd Biesheuvel asmlinkage void sha3_ce_transform(u64 *st, const u8 *data, int blocks,
2815d5910eSArd Biesheuvel 				  int md_len);
2915d5910eSArd Biesheuvel 
3015d5910eSArd Biesheuvel static int sha3_update(struct shash_desc *desc, const u8 *data,
3115d5910eSArd Biesheuvel 		       unsigned int len)
3215d5910eSArd Biesheuvel {
3315d5910eSArd Biesheuvel 	struct sha3_state *sctx = shash_desc_ctx(desc);
3415d5910eSArd Biesheuvel 	unsigned int digest_size = crypto_shash_digestsize(desc->tfm);
3515d5910eSArd Biesheuvel 
36*e52b7023SEric Biggers 	if (!crypto_simd_usable())
3715d5910eSArd Biesheuvel 		return crypto_sha3_update(desc, data, len);
3815d5910eSArd Biesheuvel 
3915d5910eSArd Biesheuvel 	if ((sctx->partial + len) >= sctx->rsiz) {
4015d5910eSArd Biesheuvel 		int blocks;
4115d5910eSArd Biesheuvel 
4215d5910eSArd Biesheuvel 		if (sctx->partial) {
4315d5910eSArd Biesheuvel 			int p = sctx->rsiz - sctx->partial;
4415d5910eSArd Biesheuvel 
4515d5910eSArd Biesheuvel 			memcpy(sctx->buf + sctx->partial, data, p);
4615d5910eSArd Biesheuvel 			kernel_neon_begin();
4715d5910eSArd Biesheuvel 			sha3_ce_transform(sctx->st, sctx->buf, 1, digest_size);
4815d5910eSArd Biesheuvel 			kernel_neon_end();
4915d5910eSArd Biesheuvel 
5015d5910eSArd Biesheuvel 			data += p;
5115d5910eSArd Biesheuvel 			len -= p;
5215d5910eSArd Biesheuvel 			sctx->partial = 0;
5315d5910eSArd Biesheuvel 		}
5415d5910eSArd Biesheuvel 
5515d5910eSArd Biesheuvel 		blocks = len / sctx->rsiz;
5615d5910eSArd Biesheuvel 		len %= sctx->rsiz;
5715d5910eSArd Biesheuvel 
5815d5910eSArd Biesheuvel 		if (blocks) {
5915d5910eSArd Biesheuvel 			kernel_neon_begin();
6015d5910eSArd Biesheuvel 			sha3_ce_transform(sctx->st, data, blocks, digest_size);
6115d5910eSArd Biesheuvel 			kernel_neon_end();
6215d5910eSArd Biesheuvel 			data += blocks * sctx->rsiz;
6315d5910eSArd Biesheuvel 		}
6415d5910eSArd Biesheuvel 	}
6515d5910eSArd Biesheuvel 
6615d5910eSArd Biesheuvel 	if (len) {
6715d5910eSArd Biesheuvel 		memcpy(sctx->buf + sctx->partial, data, len);
6815d5910eSArd Biesheuvel 		sctx->partial += len;
6915d5910eSArd Biesheuvel 	}
7015d5910eSArd Biesheuvel 	return 0;
7115d5910eSArd Biesheuvel }
7215d5910eSArd Biesheuvel 
7315d5910eSArd Biesheuvel static int sha3_final(struct shash_desc *desc, u8 *out)
7415d5910eSArd Biesheuvel {
7515d5910eSArd Biesheuvel 	struct sha3_state *sctx = shash_desc_ctx(desc);
7615d5910eSArd Biesheuvel 	unsigned int digest_size = crypto_shash_digestsize(desc->tfm);
7715d5910eSArd Biesheuvel 	__le64 *digest = (__le64 *)out;
7815d5910eSArd Biesheuvel 	int i;
7915d5910eSArd Biesheuvel 
80*e52b7023SEric Biggers 	if (!crypto_simd_usable())
8115d5910eSArd Biesheuvel 		return crypto_sha3_final(desc, out);
8215d5910eSArd Biesheuvel 
8315d5910eSArd Biesheuvel 	sctx->buf[sctx->partial++] = 0x06;
8415d5910eSArd Biesheuvel 	memset(sctx->buf + sctx->partial, 0, sctx->rsiz - sctx->partial);
8515d5910eSArd Biesheuvel 	sctx->buf[sctx->rsiz - 1] |= 0x80;
8615d5910eSArd Biesheuvel 
8715d5910eSArd Biesheuvel 	kernel_neon_begin();
8815d5910eSArd Biesheuvel 	sha3_ce_transform(sctx->st, sctx->buf, 1, digest_size);
8915d5910eSArd Biesheuvel 	kernel_neon_end();
9015d5910eSArd Biesheuvel 
9115d5910eSArd Biesheuvel 	for (i = 0; i < digest_size / 8; i++)
9215d5910eSArd Biesheuvel 		put_unaligned_le64(sctx->st[i], digest++);
9315d5910eSArd Biesheuvel 
9415d5910eSArd Biesheuvel 	if (digest_size & 4)
9515d5910eSArd Biesheuvel 		put_unaligned_le32(sctx->st[i], (__le32 *)digest);
9615d5910eSArd Biesheuvel 
9715d5910eSArd Biesheuvel 	*sctx = (struct sha3_state){};
9815d5910eSArd Biesheuvel 	return 0;
9915d5910eSArd Biesheuvel }
10015d5910eSArd Biesheuvel 
10115d5910eSArd Biesheuvel static struct shash_alg algs[] = { {
10215d5910eSArd Biesheuvel 	.digestsize		= SHA3_224_DIGEST_SIZE,
10315d5910eSArd Biesheuvel 	.init			= crypto_sha3_init,
10415d5910eSArd Biesheuvel 	.update			= sha3_update,
10515d5910eSArd Biesheuvel 	.final			= sha3_final,
10615d5910eSArd Biesheuvel 	.descsize		= sizeof(struct sha3_state),
10715d5910eSArd Biesheuvel 	.base.cra_name		= "sha3-224",
10815d5910eSArd Biesheuvel 	.base.cra_driver_name	= "sha3-224-ce",
10915d5910eSArd Biesheuvel 	.base.cra_blocksize	= SHA3_224_BLOCK_SIZE,
11015d5910eSArd Biesheuvel 	.base.cra_module	= THIS_MODULE,
11115d5910eSArd Biesheuvel 	.base.cra_priority	= 200,
11215d5910eSArd Biesheuvel }, {
11315d5910eSArd Biesheuvel 	.digestsize		= SHA3_256_DIGEST_SIZE,
11415d5910eSArd Biesheuvel 	.init			= crypto_sha3_init,
11515d5910eSArd Biesheuvel 	.update			= sha3_update,
11615d5910eSArd Biesheuvel 	.final			= sha3_final,
11715d5910eSArd Biesheuvel 	.descsize		= sizeof(struct sha3_state),
11815d5910eSArd Biesheuvel 	.base.cra_name		= "sha3-256",
11915d5910eSArd Biesheuvel 	.base.cra_driver_name	= "sha3-256-ce",
12015d5910eSArd Biesheuvel 	.base.cra_blocksize	= SHA3_256_BLOCK_SIZE,
12115d5910eSArd Biesheuvel 	.base.cra_module	= THIS_MODULE,
12215d5910eSArd Biesheuvel 	.base.cra_priority	= 200,
12315d5910eSArd Biesheuvel }, {
12415d5910eSArd Biesheuvel 	.digestsize		= SHA3_384_DIGEST_SIZE,
12515d5910eSArd Biesheuvel 	.init			= crypto_sha3_init,
12615d5910eSArd Biesheuvel 	.update			= sha3_update,
12715d5910eSArd Biesheuvel 	.final			= sha3_final,
12815d5910eSArd Biesheuvel 	.descsize		= sizeof(struct sha3_state),
12915d5910eSArd Biesheuvel 	.base.cra_name		= "sha3-384",
13015d5910eSArd Biesheuvel 	.base.cra_driver_name	= "sha3-384-ce",
13115d5910eSArd Biesheuvel 	.base.cra_blocksize	= SHA3_384_BLOCK_SIZE,
13215d5910eSArd Biesheuvel 	.base.cra_module	= THIS_MODULE,
13315d5910eSArd Biesheuvel 	.base.cra_priority	= 200,
13415d5910eSArd Biesheuvel }, {
13515d5910eSArd Biesheuvel 	.digestsize		= SHA3_512_DIGEST_SIZE,
13615d5910eSArd Biesheuvel 	.init			= crypto_sha3_init,
13715d5910eSArd Biesheuvel 	.update			= sha3_update,
13815d5910eSArd Biesheuvel 	.final			= sha3_final,
13915d5910eSArd Biesheuvel 	.descsize		= sizeof(struct sha3_state),
14015d5910eSArd Biesheuvel 	.base.cra_name		= "sha3-512",
14115d5910eSArd Biesheuvel 	.base.cra_driver_name	= "sha3-512-ce",
14215d5910eSArd Biesheuvel 	.base.cra_blocksize	= SHA3_512_BLOCK_SIZE,
14315d5910eSArd Biesheuvel 	.base.cra_module	= THIS_MODULE,
14415d5910eSArd Biesheuvel 	.base.cra_priority	= 200,
14515d5910eSArd Biesheuvel } };
14615d5910eSArd Biesheuvel 
14715d5910eSArd Biesheuvel static int __init sha3_neon_mod_init(void)
14815d5910eSArd Biesheuvel {
14915d5910eSArd Biesheuvel 	return crypto_register_shashes(algs, ARRAY_SIZE(algs));
15015d5910eSArd Biesheuvel }
15115d5910eSArd Biesheuvel 
15215d5910eSArd Biesheuvel static void __exit sha3_neon_mod_fini(void)
15315d5910eSArd Biesheuvel {
15415d5910eSArd Biesheuvel 	crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
15515d5910eSArd Biesheuvel }
15615d5910eSArd Biesheuvel 
15715d5910eSArd Biesheuvel module_cpu_feature_match(SHA3, sha3_neon_mod_init);
15815d5910eSArd Biesheuvel module_exit(sha3_neon_mod_fini);
159