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