xref: /openbmc/linux/crypto/crc32c_generic.c (revision 743b9150)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
206e5a1f2STim Chen /*
306e5a1f2STim Chen  * Cryptographic API.
406e5a1f2STim Chen  *
506e5a1f2STim Chen  * CRC32C chksum
606e5a1f2STim Chen  *
706e5a1f2STim Chen  *@Article{castagnoli-crc,
806e5a1f2STim Chen  * author =       { Guy Castagnoli and Stefan Braeuer and Martin Herrman},
906e5a1f2STim Chen  * title =        {{Optimization of Cyclic Redundancy-Check Codes with 24
1006e5a1f2STim Chen  *                 and 32 Parity Bits}},
1106e5a1f2STim Chen  * journal =      IEEE Transactions on Communication,
1206e5a1f2STim Chen  * year =         {1993},
1306e5a1f2STim Chen  * volume =       {41},
1406e5a1f2STim Chen  * number =       {6},
1506e5a1f2STim Chen  * pages =        {},
1606e5a1f2STim Chen  * month =        {June},
1706e5a1f2STim Chen  *}
18743b9150SRandy Dunlap  * Used by the iSCSI driver, possibly others, and derived from
1906e5a1f2STim Chen  * the iscsi-crc.c module of the linux-iscsi driver at
2006e5a1f2STim Chen  * http://linux-iscsi.sourceforge.net.
2106e5a1f2STim Chen  *
2206e5a1f2STim Chen  * Following the example of lib/crc32, this function is intended to be
2306e5a1f2STim Chen  * flexible and useful for all users.  Modules that currently have their
2406e5a1f2STim Chen  * own crc32c, but hopefully may be able to use this one are:
2506e5a1f2STim Chen  *  net/sctp (please add all your doco to here if you change to
2606e5a1f2STim Chen  *            use this one!)
2706e5a1f2STim Chen  *  <endoflist>
2806e5a1f2STim Chen  *
2906e5a1f2STim Chen  * Copyright (c) 2004 Cisco Systems, Inc.
3006e5a1f2STim Chen  * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
3106e5a1f2STim Chen  */
3206e5a1f2STim Chen 
337bcfb136SEric Biggers #include <asm/unaligned.h>
3406e5a1f2STim Chen #include <crypto/internal/hash.h>
3506e5a1f2STim Chen #include <linux/init.h>
3606e5a1f2STim Chen #include <linux/module.h>
3706e5a1f2STim Chen #include <linux/string.h>
3806e5a1f2STim Chen #include <linux/kernel.h>
3906e5a1f2STim Chen #include <linux/crc32.h>
4006e5a1f2STim Chen 
4106e5a1f2STim Chen #define CHKSUM_BLOCK_SIZE	1
4206e5a1f2STim Chen #define CHKSUM_DIGEST_SIZE	4
4306e5a1f2STim Chen 
4406e5a1f2STim Chen struct chksum_ctx {
4506e5a1f2STim Chen 	u32 key;
4606e5a1f2STim Chen };
4706e5a1f2STim Chen 
4806e5a1f2STim Chen struct chksum_desc_ctx {
4906e5a1f2STim Chen 	u32 crc;
5006e5a1f2STim Chen };
5106e5a1f2STim Chen 
5206e5a1f2STim Chen /*
53743b9150SRandy Dunlap  * Steps through buffer one byte at a time, calculates reflected
5406e5a1f2STim Chen  * crc using table.
5506e5a1f2STim Chen  */
5606e5a1f2STim Chen 
chksum_init(struct shash_desc * desc)5706e5a1f2STim Chen static int chksum_init(struct shash_desc *desc)
5806e5a1f2STim Chen {
5906e5a1f2STim Chen 	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
6006e5a1f2STim Chen 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
6106e5a1f2STim Chen 
6206e5a1f2STim Chen 	ctx->crc = mctx->key;
6306e5a1f2STim Chen 
6406e5a1f2STim Chen 	return 0;
6506e5a1f2STim Chen }
6606e5a1f2STim Chen 
6706e5a1f2STim Chen /*
6806e5a1f2STim Chen  * Setting the seed allows arbitrary accumulators and flexible XOR policy
6906e5a1f2STim Chen  * If your algorithm starts with ~0, then XOR with ~0 before you set
7006e5a1f2STim Chen  * the seed.
7106e5a1f2STim Chen  */
chksum_setkey(struct crypto_shash * tfm,const u8 * key,unsigned int keylen)7206e5a1f2STim Chen static int chksum_setkey(struct crypto_shash *tfm, const u8 *key,
7306e5a1f2STim Chen 			 unsigned int keylen)
7406e5a1f2STim Chen {
7506e5a1f2STim Chen 	struct chksum_ctx *mctx = crypto_shash_ctx(tfm);
7606e5a1f2STim Chen 
77674f368aSEric Biggers 	if (keylen != sizeof(mctx->key))
7806e5a1f2STim Chen 		return -EINVAL;
797bcfb136SEric Biggers 	mctx->key = get_unaligned_le32(key);
8006e5a1f2STim Chen 	return 0;
8106e5a1f2STim Chen }
8206e5a1f2STim Chen 
chksum_update(struct shash_desc * desc,const u8 * data,unsigned int length)8306e5a1f2STim Chen static int chksum_update(struct shash_desc *desc, const u8 *data,
8406e5a1f2STim Chen 			 unsigned int length)
8506e5a1f2STim Chen {
8606e5a1f2STim Chen 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
8706e5a1f2STim Chen 
8806e5a1f2STim Chen 	ctx->crc = __crc32c_le(ctx->crc, data, length);
8906e5a1f2STim Chen 	return 0;
9006e5a1f2STim Chen }
9106e5a1f2STim Chen 
chksum_final(struct shash_desc * desc,u8 * out)9206e5a1f2STim Chen static int chksum_final(struct shash_desc *desc, u8 *out)
9306e5a1f2STim Chen {
9406e5a1f2STim Chen 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
9506e5a1f2STim Chen 
967bcfb136SEric Biggers 	put_unaligned_le32(~ctx->crc, out);
9706e5a1f2STim Chen 	return 0;
9806e5a1f2STim Chen }
9906e5a1f2STim Chen 
__chksum_finup(u32 * crcp,const u8 * data,unsigned int len,u8 * out)10006e5a1f2STim Chen static int __chksum_finup(u32 *crcp, const u8 *data, unsigned int len, u8 *out)
10106e5a1f2STim Chen {
1027bcfb136SEric Biggers 	put_unaligned_le32(~__crc32c_le(*crcp, data, len), out);
10306e5a1f2STim Chen 	return 0;
10406e5a1f2STim Chen }
10506e5a1f2STim Chen 
chksum_finup(struct shash_desc * desc,const u8 * data,unsigned int len,u8 * out)10606e5a1f2STim Chen static int chksum_finup(struct shash_desc *desc, const u8 *data,
10706e5a1f2STim Chen 			unsigned int len, u8 *out)
10806e5a1f2STim Chen {
10906e5a1f2STim Chen 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
11006e5a1f2STim Chen 
11106e5a1f2STim Chen 	return __chksum_finup(&ctx->crc, data, len, out);
11206e5a1f2STim Chen }
11306e5a1f2STim Chen 
chksum_digest(struct shash_desc * desc,const u8 * data,unsigned int length,u8 * out)11406e5a1f2STim Chen static int chksum_digest(struct shash_desc *desc, const u8 *data,
11506e5a1f2STim Chen 			 unsigned int length, u8 *out)
11606e5a1f2STim Chen {
11706e5a1f2STim Chen 	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
11806e5a1f2STim Chen 
11906e5a1f2STim Chen 	return __chksum_finup(&mctx->key, data, length, out);
12006e5a1f2STim Chen }
12106e5a1f2STim Chen 
crc32c_cra_init(struct crypto_tfm * tfm)12206e5a1f2STim Chen static int crc32c_cra_init(struct crypto_tfm *tfm)
12306e5a1f2STim Chen {
12406e5a1f2STim Chen 	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
12506e5a1f2STim Chen 
12606e5a1f2STim Chen 	mctx->key = ~0;
12706e5a1f2STim Chen 	return 0;
12806e5a1f2STim Chen }
12906e5a1f2STim Chen 
13006e5a1f2STim Chen static struct shash_alg alg = {
13106e5a1f2STim Chen 	.digestsize		=	CHKSUM_DIGEST_SIZE,
13206e5a1f2STim Chen 	.setkey			=	chksum_setkey,
13306e5a1f2STim Chen 	.init		=	chksum_init,
13406e5a1f2STim Chen 	.update		=	chksum_update,
13506e5a1f2STim Chen 	.final		=	chksum_final,
13606e5a1f2STim Chen 	.finup		=	chksum_finup,
13706e5a1f2STim Chen 	.digest		=	chksum_digest,
13806e5a1f2STim Chen 	.descsize		=	sizeof(struct chksum_desc_ctx),
13906e5a1f2STim Chen 	.base			=	{
14006e5a1f2STim Chen 		.cra_name		=	"crc32c",
14106e5a1f2STim Chen 		.cra_driver_name	=	"crc32c-generic",
14206e5a1f2STim Chen 		.cra_priority		=	100,
143a208fa8fSEric Biggers 		.cra_flags		=	CRYPTO_ALG_OPTIONAL_KEY,
14406e5a1f2STim Chen 		.cra_blocksize		=	CHKSUM_BLOCK_SIZE,
14506e5a1f2STim Chen 		.cra_ctxsize		=	sizeof(struct chksum_ctx),
14606e5a1f2STim Chen 		.cra_module		=	THIS_MODULE,
14706e5a1f2STim Chen 		.cra_init		=	crc32c_cra_init,
14806e5a1f2STim Chen 	}
14906e5a1f2STim Chen };
15006e5a1f2STim Chen 
crc32c_mod_init(void)15106e5a1f2STim Chen static int __init crc32c_mod_init(void)
15206e5a1f2STim Chen {
15306e5a1f2STim Chen 	return crypto_register_shash(&alg);
15406e5a1f2STim Chen }
15506e5a1f2STim Chen 
crc32c_mod_fini(void)15606e5a1f2STim Chen static void __exit crc32c_mod_fini(void)
15706e5a1f2STim Chen {
15806e5a1f2STim Chen 	crypto_unregister_shash(&alg);
15906e5a1f2STim Chen }
16006e5a1f2STim Chen 
161c4741b23SEric Biggers subsys_initcall(crc32c_mod_init);
16206e5a1f2STim Chen module_exit(crc32c_mod_fini);
16306e5a1f2STim Chen 
16406e5a1f2STim Chen MODULE_AUTHOR("Clay Haapala <chaapala@cisco.com>");
16506e5a1f2STim Chen MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c");
16606e5a1f2STim Chen MODULE_LICENSE("GPL");
1675d26a105SKees Cook MODULE_ALIAS_CRYPTO("crc32c");
1683e14dcf7SMathias Krause MODULE_ALIAS_CRYPTO("crc32c-generic");
169