xref: /linux/crypto/crc32c_generic.c (revision 7ebdfaa52d15b947503f76474477f92854796d96)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Cryptographic API.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * CRC32C chksum
51da177e4SLinus Torvalds  *
669c35efcSHerbert Xu  *@Article{castagnoli-crc,
769c35efcSHerbert Xu  * author =       { Guy Castagnoli and Stefan Braeuer and Martin Herrman},
869c35efcSHerbert Xu  * title =        {{Optimization of Cyclic Redundancy-Check Codes with 24
969c35efcSHerbert Xu  *                 and 32 Parity Bits}},
1069c35efcSHerbert Xu  * journal =      IEEE Transactions on Communication,
1169c35efcSHerbert Xu  * year =         {1993},
1269c35efcSHerbert Xu  * volume =       {41},
1369c35efcSHerbert Xu  * number =       {6},
1469c35efcSHerbert Xu  * pages =        {},
1569c35efcSHerbert Xu  * month =        {June},
1669c35efcSHerbert Xu  *}
1769c35efcSHerbert Xu  * Used by the iSCSI driver, possibly others, and derived from the
1869c35efcSHerbert Xu  * the iscsi-crc.c module of the linux-iscsi driver at
1969c35efcSHerbert Xu  * http://linux-iscsi.sourceforge.net.
201da177e4SLinus Torvalds  *
2169c35efcSHerbert Xu  * Following the example of lib/crc32, this function is intended to be
2269c35efcSHerbert Xu  * flexible and useful for all users.  Modules that currently have their
2369c35efcSHerbert Xu  * own crc32c, but hopefully may be able to use this one are:
2469c35efcSHerbert Xu  *  net/sctp (please add all your doco to here if you change to
2569c35efcSHerbert Xu  *            use this one!)
2669c35efcSHerbert Xu  *  <endoflist>
2769c35efcSHerbert Xu  *
2869c35efcSHerbert Xu  * Copyright (c) 2004 Cisco Systems, Inc.
295773a3e6SHerbert Xu  * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
305773a3e6SHerbert Xu  *
311da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify it
321da177e4SLinus Torvalds  * under the terms of the GNU General Public License as published by the Free
331da177e4SLinus Torvalds  * Software Foundation; either version 2 of the License, or (at your option)
341da177e4SLinus Torvalds  * any later version.
351da177e4SLinus Torvalds  *
361da177e4SLinus Torvalds  */
375773a3e6SHerbert Xu 
385773a3e6SHerbert Xu #include <crypto/internal/hash.h>
391da177e4SLinus Torvalds #include <linux/init.h>
401da177e4SLinus Torvalds #include <linux/module.h>
411da177e4SLinus Torvalds #include <linux/string.h>
4225cdbcd9SHerbert Xu #include <linux/kernel.h>
436a0962b2SDarrick J. Wong #include <linux/crc32.h>
441da177e4SLinus Torvalds 
455773a3e6SHerbert Xu #define CHKSUM_BLOCK_SIZE	1
461da177e4SLinus Torvalds #define CHKSUM_DIGEST_SIZE	4
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds struct chksum_ctx {
4925cdbcd9SHerbert Xu 	u32 key;
501da177e4SLinus Torvalds };
511da177e4SLinus Torvalds 
52faccc4bbSHerbert Xu struct chksum_desc_ctx {
53faccc4bbSHerbert Xu 	u32 crc;
54faccc4bbSHerbert Xu };
55faccc4bbSHerbert Xu 
561da177e4SLinus Torvalds /*
571da177e4SLinus Torvalds  * Steps through buffer one byte at at time, calculates reflected
581da177e4SLinus Torvalds  * crc using table.
591da177e4SLinus Torvalds  */
601da177e4SLinus Torvalds 
61faccc4bbSHerbert Xu static int chksum_init(struct shash_desc *desc)
621da177e4SLinus Torvalds {
63faccc4bbSHerbert Xu 	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
64faccc4bbSHerbert Xu 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
651da177e4SLinus Torvalds 
66faccc4bbSHerbert Xu 	ctx->crc = mctx->key;
67faccc4bbSHerbert Xu 
68faccc4bbSHerbert Xu 	return 0;
691da177e4SLinus Torvalds }
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds /*
721da177e4SLinus Torvalds  * Setting the seed allows arbitrary accumulators and flexible XOR policy
731da177e4SLinus Torvalds  * If your algorithm starts with ~0, then XOR with ~0 before you set
741da177e4SLinus Torvalds  * the seed.
751da177e4SLinus Torvalds  */
76faccc4bbSHerbert Xu static int chksum_setkey(struct crypto_shash *tfm, const u8 *key,
77560c06aeSHerbert Xu 			 unsigned int keylen)
781da177e4SLinus Torvalds {
79faccc4bbSHerbert Xu 	struct chksum_ctx *mctx = crypto_shash_ctx(tfm);
801da177e4SLinus Torvalds 
81faccc4bbSHerbert Xu 	if (keylen != sizeof(mctx->key)) {
82faccc4bbSHerbert Xu 		crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
831da177e4SLinus Torvalds 		return -EINVAL;
841da177e4SLinus Torvalds 	}
8525cdbcd9SHerbert Xu 	mctx->key = le32_to_cpu(*(__le32 *)key);
861da177e4SLinus Torvalds 	return 0;
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
89faccc4bbSHerbert Xu static int chksum_update(struct shash_desc *desc, const u8 *data,
906c2bb98bSHerbert Xu 			 unsigned int length)
911da177e4SLinus Torvalds {
92faccc4bbSHerbert Xu 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
931da177e4SLinus Torvalds 
946a0962b2SDarrick J. Wong 	ctx->crc = __crc32c_le(ctx->crc, data, length);
95faccc4bbSHerbert Xu 	return 0;
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds 
98faccc4bbSHerbert Xu static int chksum_final(struct shash_desc *desc, u8 *out)
991da177e4SLinus Torvalds {
100faccc4bbSHerbert Xu 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
1011da177e4SLinus Torvalds 
102faccc4bbSHerbert Xu 	*(__le32 *)out = ~cpu_to_le32p(&ctx->crc);
103faccc4bbSHerbert Xu 	return 0;
10425cdbcd9SHerbert Xu }
10525cdbcd9SHerbert Xu 
106faccc4bbSHerbert Xu static int __chksum_finup(u32 *crcp, const u8 *data, unsigned int len, u8 *out)
107faccc4bbSHerbert Xu {
1086a0962b2SDarrick J. Wong 	*(__le32 *)out = ~cpu_to_le32(__crc32c_le(*crcp, data, len));
109faccc4bbSHerbert Xu 	return 0;
110faccc4bbSHerbert Xu }
111faccc4bbSHerbert Xu 
112faccc4bbSHerbert Xu static int chksum_finup(struct shash_desc *desc, const u8 *data,
113faccc4bbSHerbert Xu 			unsigned int len, u8 *out)
114faccc4bbSHerbert Xu {
115faccc4bbSHerbert Xu 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
116faccc4bbSHerbert Xu 
117faccc4bbSHerbert Xu 	return __chksum_finup(&ctx->crc, data, len, out);
118faccc4bbSHerbert Xu }
119faccc4bbSHerbert Xu 
120faccc4bbSHerbert Xu static int chksum_digest(struct shash_desc *desc, const u8 *data,
121faccc4bbSHerbert Xu 			 unsigned int length, u8 *out)
122faccc4bbSHerbert Xu {
123faccc4bbSHerbert Xu 	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
124faccc4bbSHerbert Xu 
125faccc4bbSHerbert Xu 	return __chksum_finup(&mctx->key, data, length, out);
126faccc4bbSHerbert Xu }
127faccc4bbSHerbert Xu 
128faccc4bbSHerbert Xu static int crc32c_cra_init(struct crypto_tfm *tfm)
12925cdbcd9SHerbert Xu {
13025cdbcd9SHerbert Xu 	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
13125cdbcd9SHerbert Xu 
13225cdbcd9SHerbert Xu 	mctx->key = ~0;
13325cdbcd9SHerbert Xu 	return 0;
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds 
136faccc4bbSHerbert Xu static struct shash_alg alg = {
137faccc4bbSHerbert Xu 	.digestsize		=	CHKSUM_DIGEST_SIZE,
138faccc4bbSHerbert Xu 	.setkey			=	chksum_setkey,
139faccc4bbSHerbert Xu 	.init		=	chksum_init,
140faccc4bbSHerbert Xu 	.update		=	chksum_update,
141faccc4bbSHerbert Xu 	.final		=	chksum_final,
142faccc4bbSHerbert Xu 	.finup		=	chksum_finup,
143faccc4bbSHerbert Xu 	.digest		=	chksum_digest,
144faccc4bbSHerbert Xu 	.descsize		=	sizeof(struct chksum_desc_ctx),
145faccc4bbSHerbert Xu 	.base			=	{
1465773a3e6SHerbert Xu 		.cra_name		=	"crc32c",
1475773a3e6SHerbert Xu 		.cra_driver_name	=	"crc32c-generic",
1485773a3e6SHerbert Xu 		.cra_priority		=	100,
1495773a3e6SHerbert Xu 		.cra_blocksize		=	CHKSUM_BLOCK_SIZE,
1505773a3e6SHerbert Xu 		.cra_alignmask		=	3,
151faccc4bbSHerbert Xu 		.cra_ctxsize		=	sizeof(struct chksum_ctx),
1525773a3e6SHerbert Xu 		.cra_module		=	THIS_MODULE,
1535773a3e6SHerbert Xu 		.cra_init		=	crc32c_cra_init,
1545773a3e6SHerbert Xu 	}
1555773a3e6SHerbert Xu };
1565773a3e6SHerbert Xu 
1573af5b90bSKamalesh Babulal static int __init crc32c_mod_init(void)
1581da177e4SLinus Torvalds {
159faccc4bbSHerbert Xu 	return crypto_register_shash(&alg);
1601da177e4SLinus Torvalds }
1611da177e4SLinus Torvalds 
1623af5b90bSKamalesh Babulal static void __exit crc32c_mod_fini(void)
1631da177e4SLinus Torvalds {
164faccc4bbSHerbert Xu 	crypto_unregister_shash(&alg);
1651da177e4SLinus Torvalds }
1661da177e4SLinus Torvalds 
1673af5b90bSKamalesh Babulal module_init(crc32c_mod_init);
1683af5b90bSKamalesh Babulal module_exit(crc32c_mod_fini);
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds MODULE_AUTHOR("Clay Haapala <chaapala@cisco.com>");
1711da177e4SLinus Torvalds MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c");
1721da177e4SLinus Torvalds MODULE_LICENSE("GPL");
173*5d26a105SKees Cook MODULE_ALIAS_CRYPTO("crc32c");
17406e5a1f2STim Chen MODULE_SOFTDEP("pre: crc32c");
175