2010-02-16 15:31:19 +03:00
/*
2005-04-17 02:20:36 +04:00
* Cryptographic API .
*
* CRC32C chksum
*
2008-11-07 10:11:47 +03:00
* @ 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.
2005-04-17 02:20:36 +04:00
*
2008-11-07 10:11:47 +03:00
* 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 .
2008-07-08 16:54:28 +04:00
* Copyright ( c ) 2008 Herbert Xu < herbert @ gondor . apana . org . au >
*
2005-04-17 02:20:36 +04:00
* 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
2010-02-16 15:31:19 +03:00
* Software Foundation ; either version 2 of the License , or ( at your option )
2005-04-17 02:20:36 +04:00
* any later version .
*
*/
2008-07-08 16:54:28 +04:00
2018-05-20 08:07:38 +03:00
# include <asm/unaligned.h>
2008-07-08 16:54:28 +04:00
# include <crypto/internal/hash.h>
2005-04-17 02:20:36 +04:00
# include <linux/init.h>
# include <linux/module.h>
# include <linux/string.h>
2006-08-06 17:03:08 +04:00
# include <linux/kernel.h>
2012-03-24 02:02:25 +04:00
# include <linux/crc32.h>
2005-04-17 02:20:36 +04:00
2008-07-08 16:54:28 +04:00
# define CHKSUM_BLOCK_SIZE 1
2005-04-17 02:20:36 +04:00
# define CHKSUM_DIGEST_SIZE 4
struct chksum_ctx {
2006-08-06 17:03:08 +04:00
u32 key ;
2005-04-17 02:20:36 +04:00
} ;
2008-09-09 11:23:07 +04:00
struct chksum_desc_ctx {
u32 crc ;
} ;
2005-04-17 02:20:36 +04:00
/*
2010-02-16 15:31:19 +03:00
* Steps through buffer one byte at at time , calculates reflected
2005-04-17 02:20:36 +04:00
* crc using table .
*/
2008-09-09 11:23:07 +04:00
static int chksum_init ( struct shash_desc * desc )
2005-04-17 02:20:36 +04:00
{
2008-09-09 11:23:07 +04:00
struct chksum_ctx * mctx = crypto_shash_ctx ( desc - > tfm ) ;
struct chksum_desc_ctx * ctx = shash_desc_ctx ( desc ) ;
ctx - > crc = mctx - > key ;
2005-04-17 02:20:36 +04:00
2008-09-09 11:23:07 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/*
* 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 .
*/
2008-09-09 11:23:07 +04:00
static int chksum_setkey ( struct crypto_shash * tfm , const u8 * key ,
2006-08-13 08:16:39 +04:00
unsigned int keylen )
2005-04-17 02:20:36 +04:00
{
2008-09-09 11:23:07 +04:00
struct chksum_ctx * mctx = crypto_shash_ctx ( tfm ) ;
2005-04-17 02:20:36 +04:00
2008-09-09 11:23:07 +04:00
if ( keylen ! = sizeof ( mctx - > key ) ) {
crypto_shash_set_flags ( tfm , CRYPTO_TFM_RES_BAD_KEY_LEN ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2018-05-20 08:07:38 +03:00
mctx - > key = get_unaligned_le32 ( key ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-09-09 11:23:07 +04:00
static int chksum_update ( struct shash_desc * desc , const u8 * data ,
unsigned int length )
2005-04-17 02:20:36 +04:00
{
2008-09-09 11:23:07 +04:00
struct chksum_desc_ctx * ctx = shash_desc_ctx ( desc ) ;
2005-04-17 02:20:36 +04:00
2012-03-24 02:02:25 +04:00
ctx - > crc = __crc32c_le ( ctx - > crc , data , length ) ;
2006-08-06 17:03:08 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-09-09 11:23:07 +04:00
static int chksum_final ( struct shash_desc * desc , u8 * out )
2008-07-08 16:54:28 +04:00
{
2008-09-09 11:23:07 +04:00
struct chksum_desc_ctx * ctx = shash_desc_ctx ( desc ) ;
2008-07-08 16:54:28 +04:00
2018-05-20 08:07:38 +03:00
put_unaligned_le32 ( ~ ctx - > crc , out ) ;
2008-07-08 16:54:28 +04:00
return 0 ;
}
2008-09-09 11:23:07 +04:00
static int __chksum_finup ( u32 * crcp , const u8 * data , unsigned int len , u8 * out )
2008-07-08 16:54:28 +04:00
{
2018-05-20 08:07:38 +03:00
put_unaligned_le32 ( ~ __crc32c_le ( * crcp , data , len ) , out ) ;
2008-07-08 16:54:28 +04:00
return 0 ;
}
2008-09-09 11:23:07 +04:00
static int chksum_finup ( struct shash_desc * desc , const u8 * data ,
unsigned int len , u8 * out )
2008-07-08 16:54:28 +04:00
{
2008-09-09 11:23:07 +04:00
struct chksum_desc_ctx * ctx = shash_desc_ctx ( desc ) ;
2008-07-08 16:54:28 +04:00
2008-09-09 11:23:07 +04:00
return __chksum_finup ( & ctx - > crc , data , len , out ) ;
2008-07-08 16:54:28 +04:00
}
2008-09-09 11:23:07 +04:00
static int chksum_digest ( struct shash_desc * desc , const u8 * data ,
unsigned int length , u8 * out )
2008-07-08 16:54:28 +04:00
{
2008-09-09 11:23:07 +04:00
struct chksum_ctx * mctx = crypto_shash_ctx ( desc - > tfm ) ;
2008-07-08 16:54:28 +04:00
2008-09-09 11:23:07 +04:00
return __chksum_finup ( & mctx - > key , data , length , out ) ;
2008-07-08 16:54:28 +04:00
}
static int crc32c_cra_init ( struct crypto_tfm * tfm )
{
2008-09-09 11:23:07 +04:00
struct chksum_ctx * mctx = crypto_tfm_ctx ( tfm ) ;
2008-07-08 16:54:28 +04:00
2008-09-09 11:23:07 +04:00
mctx - > key = ~ 0 ;
2008-07-08 16:54:28 +04:00
return 0 ;
}
2008-09-09 11:23:07 +04:00
static struct shash_alg alg = {
. digestsize = CHKSUM_DIGEST_SIZE ,
. setkey = chksum_setkey ,
2011-06-08 17:23:40 +04:00
. init = chksum_init ,
. update = chksum_update ,
. final = chksum_final ,
. finup = chksum_finup ,
. digest = chksum_digest ,
2008-09-09 11:23:07 +04:00
. descsize = sizeof ( struct chksum_desc_ctx ) ,
. base = {
. cra_name = " crc32c " ,
. cra_driver_name = " crc32c-generic " ,
. cra_priority = 100 ,
2018-01-03 22:16:26 +03:00
. cra_flags = CRYPTO_ALG_OPTIONAL_KEY ,
2008-09-09 11:23:07 +04:00
. cra_blocksize = CHKSUM_BLOCK_SIZE ,
. cra_ctxsize = sizeof ( struct chksum_ctx ) ,
. cra_module = THIS_MODULE ,
. cra_init = crc32c_cra_init ,
2008-07-08 16:54:28 +04:00
}
} ;
2008-04-05 17:00:57 +04:00
static int __init crc32c_mod_init ( void )
2005-04-17 02:20:36 +04:00
{
2008-09-09 11:23:07 +04:00
return crypto_register_shash ( & alg ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-05 17:00:57 +04:00
static void __exit crc32c_mod_fini ( void )
2005-04-17 02:20:36 +04:00
{
2008-09-09 11:23:07 +04:00
crypto_unregister_shash ( & alg ) ;
2005-04-17 02:20:36 +04:00
}
2019-04-12 07:57:42 +03:00
subsys_initcall ( crc32c_mod_init ) ;
2008-04-05 17:00:57 +04:00
module_exit ( crc32c_mod_fini ) ;
2005-04-17 02:20:36 +04:00
MODULE_AUTHOR ( " Clay Haapala <chaapala@cisco.com> " ) ;
MODULE_DESCRIPTION ( " CRC32c (Castagnoli) calculations wrapper for lib/crc32c " ) ;
MODULE_LICENSE ( " GPL " ) ;
2014-11-21 04:05:53 +03:00
MODULE_ALIAS_CRYPTO ( " crc32c " ) ;
2015-01-11 20:17:42 +03:00
MODULE_ALIAS_CRYPTO ( " crc32c-generic " ) ;