-/*
+/*
* Cryptographic API.
*
* CRC32C chksum
*
- * This module file is a wrapper to invoke the lib/crc32c routines.
+ *@Article{castagnoli-crc,
+ * author = { Guy Castagnoli and Stefan Braeuer and Martin Herrman},
+ * title = {{Optimization of Cyclic Redundancy-Check Codes with 24
+ * and 32 Parity Bits}},
+ * journal = IEEE Transactions on Communication,
+ * year = {1993},
+ * volume = {41},
+ * number = {6},
+ * pages = {},
+ * month = {June},
+ *}
+ * Used by the iSCSI driver, possibly others, and derived from the
+ * the iscsi-crc.c module of the linux-iscsi driver at
+ * http://linux-iscsi.sourceforge.net.
+ *
+ * Following the example of lib/crc32, this function is intended to be
+ * flexible and useful for all users. Modules that currently have their
+ * own crc32c, but hopefully may be able to use this one are:
+ * net/sctp (please add all your doco to here if you change to
+ * use this one!)
+ * <endoflist>
+ *
+ * Copyright (c) 2004 Cisco Systems, Inc.
+ * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
+ * Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
+
+#include <crypto/internal/hash.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
-#include <linux/crypto.h>
-#include <linux/crc32c.h>
-#include <linux/types.h>
-#include <asm/byteorder.h>
+#include <linux/kernel.h>
+#include <linux/crc32.h>
-#define CHKSUM_BLOCK_SIZE 32
+#define CHKSUM_BLOCK_SIZE 1
#define CHKSUM_DIGEST_SIZE 4
struct chksum_ctx {
+ u32 key;
+};
+
+struct chksum_desc_ctx {
u32 crc;
};
/*
- * Steps through buffer one byte at at time, calculates reflected
+ * Steps through buffer one byte at at time, calculates reflected
* crc using table.
*/
-static void chksum_init(struct crypto_tfm *tfm)
+static int chksum_init(struct shash_desc *desc)
{
- struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
+ struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ ctx->crc = mctx->key;
- mctx->crc = ~(u32)0; /* common usage */
+ return 0;
}
/*
* If your algorithm starts with ~0, then XOR with ~0 before you set
* the seed.
*/
-static int chksum_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen, u32 *flags)
+static int chksum_setkey(struct crypto_shash *tfm, const u8 *key,
+ unsigned int keylen)
{
- struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
+ struct chksum_ctx *mctx = crypto_shash_ctx(tfm);
- if (keylen != sizeof(mctx->crc)) {
- if (flags)
- *flags = CRYPTO_TFM_RES_BAD_KEY_LEN;
+ if (keylen != sizeof(mctx->key)) {
+ crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
return -EINVAL;
}
- mctx->crc = __cpu_to_le32(*(u32 *)key);
+ mctx->key = le32_to_cpu(*(__le32 *)key);
return 0;
}
-static void chksum_update(struct crypto_tfm *tfm, const u8 *data,
- unsigned int length)
+static int chksum_update(struct shash_desc *desc, const u8 *data,
+ unsigned int length)
{
- struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
- u32 mcrc;
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ ctx->crc = __crc32c_le(ctx->crc, data, length);
+ return 0;
+}
+
+static int chksum_final(struct shash_desc *desc, u8 *out)
+{
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
- mcrc = crc32c(mctx->crc, data, (size_t)length);
+ *(__le32 *)out = ~cpu_to_le32p(&ctx->crc);
+ return 0;
+}
- mctx->crc = mcrc;
+static int __chksum_finup(u32 *crcp, const u8 *data, unsigned int len, u8 *out)
+{
+ *(__le32 *)out = ~cpu_to_le32(__crc32c_le(*crcp, data, len));
+ return 0;
}
-static void chksum_final(struct crypto_tfm *tfm, u8 *out)
+static int chksum_finup(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ return __chksum_finup(&ctx->crc, data, len, out);
+}
+
+static int chksum_digest(struct shash_desc *desc, const u8 *data,
+ unsigned int length, u8 *out)
+{
+ struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
+
+ return __chksum_finup(&mctx->key, data, length, out);
+}
+
+static int crc32c_cra_init(struct crypto_tfm *tfm)
{
struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
- u32 mcrc = (mctx->crc ^ ~(u32)0);
-
- *(u32 *)out = __le32_to_cpu(mcrc);
+
+ mctx->key = ~0;
+ return 0;
}
-static struct crypto_alg alg = {
- .cra_name = "crc32c",
- .cra_flags = CRYPTO_ALG_TYPE_DIGEST,
- .cra_blocksize = CHKSUM_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct chksum_ctx),
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(alg.cra_list),
- .cra_u = {
- .digest = {
- .dia_digestsize= CHKSUM_DIGEST_SIZE,
- .dia_setkey = chksum_setkey,
- .dia_init = chksum_init,
- .dia_update = chksum_update,
- .dia_final = chksum_final
- }
+static struct shash_alg alg = {
+ .digestsize = CHKSUM_DIGEST_SIZE,
+ .setkey = chksum_setkey,
+ .init = chksum_init,
+ .update = chksum_update,
+ .final = chksum_final,
+ .finup = chksum_finup,
+ .digest = chksum_digest,
+ .descsize = sizeof(struct chksum_desc_ctx),
+ .base = {
+ .cra_name = "crc32c",
+ .cra_driver_name = "crc32c-generic",
+ .cra_priority = 100,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_alignmask = 3,
+ .cra_ctxsize = sizeof(struct chksum_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_init = crc32c_cra_init,
}
};
-static int __init init(void)
+static int __init crc32c_mod_init(void)
{
- return crypto_register_alg(&alg);
+ return crypto_register_shash(&alg);
}
-static void __exit fini(void)
+static void __exit crc32c_mod_fini(void)
{
- crypto_unregister_alg(&alg);
+ crypto_unregister_shash(&alg);
}
-module_init(init);
-module_exit(fini);
+module_init(crc32c_mod_init);
+module_exit(crc32c_mod_fini);
MODULE_AUTHOR("Clay Haapala <chaapala@cisco.com>");
MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c");