Commit 8f8fd38b authored by Clay Haapala's avatar Clay Haapala Committed by David S. Miller

[CRYPTO]: Provide crc32c as a type of digest.

parent 7cf5ff20
...@@ -183,6 +183,16 @@ config CRYPTO_MICHAEL_MIC ...@@ -183,6 +183,16 @@ config CRYPTO_MICHAEL_MIC
should not be used for other purposes because of the weakness should not be used for other purposes because of the weakness
of the algorithm. of the algorithm.
config CRYPTO_CRC32C
tristate "CRC32c CRC algorithm"
depends on CRYPTO
select LIBCRC32C
help
Castagnoli, et al Cyclic Redundancy-Check Algorithm. Used
by iSCSI for header and data digests and by others.
See Castagnoli93. This implementation uses lib/libcrc32c.
Module will be crc32c.
config CRYPTO_TEST config CRYPTO_TEST
tristate "Testing module" tristate "Testing module"
depends on CRYPTO depends on CRYPTO
......
...@@ -24,5 +24,6 @@ obj-$(CONFIG_CRYPTO_CAST6) += cast6.o ...@@ -24,5 +24,6 @@ obj-$(CONFIG_CRYPTO_CAST6) += cast6.o
obj-$(CONFIG_CRYPTO_ARC4) += arc4.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o
obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
/*
* Cryptographic API.
*
* CRC32C chksum
*
* This module file is a wrapper to invoke the lib/crc32c routines.
*
* 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)
* any later version.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/crypto.h>
#include <linux/crc32c.h>
#include <asm/byteorder.h>
#define CHKSUM_BLOCK_SIZE 32
#define CHKSUM_DIGEST_SIZE 4
struct chksum_ctx {
u32 crc;
};
/*
* Steps through buffer one byte at at time, calculates reflected
* crc using table.
*/
static void chksum_init(void *ctx)
{
struct chksum_ctx *mctx = ctx;
mctx->crc = ~(u32)0; /* common usage */
}
/*
* Setting the seed allows arbitrary accumulators and flexible XOR policy
* If your algorithm starts with ~0, then XOR with ~0 before you set
* the seed.
*/
static int chksum_setkey(void *ctx, const u8 *key, unsigned int keylen,
u32 *flags)
{
struct chksum_ctx *mctx = ctx;
if (keylen != sizeof(mctx->crc)) {
if (flags)
*flags = CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
}
mctx->crc = __cpu_to_le32(*(u32 *)key);
return 0;
}
static void chksum_update(void *ctx, const u8 *data, size_t length)
{
struct chksum_ctx *mctx = ctx;
u32 mcrc;
mcrc = crc32c(mctx->crc, data, length);
mctx->crc = mcrc;
}
static void chksum_final(void *ctx, u8 *out)
{
struct chksum_ctx *mctx = ctx;
u32 mcrc = (mctx->crc ^ ~(u32)0);
*(u32 *)out = __le32_to_cpu(mcrc);
}
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 int __init init(void)
{
return crypto_register_alg(&alg);
}
static void __exit fini(void)
{
crypto_unregister_alg(&alg);
}
module_init(init);
module_exit(fini);
MODULE_AUTHOR("Clay Haapala <chaapala@cisco.com>");
MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c");
MODULE_LICENSE("GPL");
...@@ -61,7 +61,7 @@ static char *tvmem; ...@@ -61,7 +61,7 @@ static char *tvmem;
static char *check[] = { static char *check[] = {
"des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
"twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6",
"arc4", "michael_mic", "deflate", NULL "arc4", "michael_mic", "deflate", "crc32c", NULL
}; };
static void static void
...@@ -495,6 +495,107 @@ test_deflate(void) ...@@ -495,6 +495,107 @@ test_deflate(void)
crypto_free_tfm(tfm); crypto_free_tfm(tfm);
} }
static void
test_crc32c(void)
{
#define NUMVEC 6
#define VECSIZE 40
int i, j, pass;
u32 crc;
u8 b, test_vec[NUMVEC][VECSIZE];
static u32 vec_results[NUMVEC] = {
0x0e2c157f, 0xe980ebf6, 0xde74bded,
0xd579c862, 0xba979ad0, 0x2b29d913
};
static u32 tot_vec_results = 0x24c5d375;
struct scatterlist sg[NUMVEC];
struct crypto_tfm *tfm;
char *fmtdata = "testing crc32c initialized to %08x: %s\n";
#define SEEDTESTVAL 0xedcba987
u32 seed;
printk("\ntesting crc32c\n");
tfm = crypto_alloc_tfm("crc32c", 0);
if (tfm == NULL) {
printk("failed to load transform for crc32c\n");
return;
}
crypto_digest_init(tfm);
crypto_digest_final(tfm, (u8*)&crc);
printk(fmtdata, crc, (crc == 0) ? "pass" : "ERROR");
/*
* stuff test_vec with known values, simple incrementing
* byte values.
*/
b = 0;
for (i = 0; i < NUMVEC; i++) {
for (j = 0; j < VECSIZE; j++)
test_vec[i][j] = ++b;
sg[i].page = virt_to_page(test_vec[i]);
sg[i].offset = offset_in_page(test_vec[i]);
sg[i].length = VECSIZE;
}
seed = SEEDTESTVAL;
(void)crypto_digest_setkey(tfm, (const u8*)&seed, sizeof(u32));
crypto_digest_final(tfm, (u8*)&crc);
printk("testing crc32c setkey returns %08x : %s\n", crc, (crc == (SEEDTESTVAL ^ ~(u32)0)) ?
"pass" : "ERROR");
printk("testing crc32c using update/final:\n");
pass = 1; /* assume all is well */
for (i = 0; i < NUMVEC; i++) {
seed = ~(u32)0;
(void)crypto_digest_setkey(tfm, (const u8*)&seed, sizeof(u32));
crypto_digest_update(tfm, &sg[i], 1);
crypto_digest_final(tfm, (u8*)&crc);
if (crc == vec_results[i]) {
printk(" %08x:OK", crc);
} else {
printk(" %08x:BAD, wanted %08x\n", crc, vec_results[i]);
pass = 0;
}
}
printk("\ntesting crc32c using incremental accumulator:\n");
crc = 0;
for (i = 0; i < NUMVEC; i++) {
seed = (crc ^ ~(u32)0);
(void)crypto_digest_setkey(tfm, (const u8*)&seed, sizeof(u32));
crypto_digest_update(tfm, &sg[i], 1);
crypto_digest_final(tfm, (u8*)&crc);
}
if (crc == tot_vec_results) {
printk(" %08x:OK", crc);
} else {
printk(" %08x:BAD, wanted %08x\n", crc, tot_vec_results);
pass = 0;
}
printk("\ntesting crc32c using digest:\n");
seed = ~(u32)0;
(void)crypto_digest_setkey(tfm, (const u8*)&seed, sizeof(u32));
crypto_digest_digest(tfm, sg, NUMVEC, (u8*)&crc);
if (crc == tot_vec_results) {
printk(" %08x:OK", crc);
} else {
printk(" %08x:BAD, wanted %08x\n", crc, tot_vec_results);
pass = 0;
}
printk("\n%s\n", pass ? "pass" : "ERROR");
crypto_free_tfm(tfm);
printk("crc32c test complete\n");
}
static void static void
test_available(void) test_available(void)
{ {
...@@ -567,6 +668,7 @@ do_test(void) ...@@ -567,6 +668,7 @@ do_test(void)
test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS); test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS); test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
test_deflate(); test_deflate();
test_crc32c();
#ifdef CONFIG_CRYPTO_HMAC #ifdef CONFIG_CRYPTO_HMAC
test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
test_hmac("sha1", hmac_sha1_tv_template, HMAC_SHA1_TEST_VECTORS); test_hmac("sha1", hmac_sha1_tv_template, HMAC_SHA1_TEST_VECTORS);
...@@ -657,6 +759,10 @@ do_test(void) ...@@ -657,6 +759,10 @@ do_test(void)
test_hash("michael_mic", michael_mic_tv_template, MICHAEL_MIC_TEST_VECTORS); test_hash("michael_mic", michael_mic_tv_template, MICHAEL_MIC_TEST_VECTORS);
break; break;
case 18:
test_crc32c();
break;
#ifdef CONFIG_CRYPTO_HMAC #ifdef CONFIG_CRYPTO_HMAC
case 100: case 100:
test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment