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 *}
18*743b9150SRandy 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 /*
53*743b9150SRandy 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