1 /* 2 * Cryptographic API. 3 * 4 * CRC32C chksum 5 * 6 * This module file is a wrapper to invoke the lib/crc32c routines. 7 * 8 * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au> 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the Free 12 * Software Foundation; either version 2 of the License, or (at your option) 13 * any later version. 14 * 15 */ 16 17 #include <crypto/internal/hash.h> 18 #include <linux/init.h> 19 #include <linux/module.h> 20 #include <linux/string.h> 21 #include <linux/crc32c.h> 22 #include <linux/kernel.h> 23 24 #define CHKSUM_BLOCK_SIZE 1 25 #define CHKSUM_DIGEST_SIZE 4 26 27 struct chksum_ctx { 28 u32 crc; 29 u32 key; 30 }; 31 32 /* 33 * Steps through buffer one byte at at time, calculates reflected 34 * crc using table. 35 */ 36 37 static void chksum_init(struct crypto_tfm *tfm) 38 { 39 struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); 40 41 mctx->crc = mctx->key; 42 } 43 44 /* 45 * Setting the seed allows arbitrary accumulators and flexible XOR policy 46 * If your algorithm starts with ~0, then XOR with ~0 before you set 47 * the seed. 48 */ 49 static int chksum_setkey(struct crypto_tfm *tfm, const u8 *key, 50 unsigned int keylen) 51 { 52 struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); 53 54 if (keylen != sizeof(mctx->crc)) { 55 tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 56 return -EINVAL; 57 } 58 mctx->key = le32_to_cpu(*(__le32 *)key); 59 return 0; 60 } 61 62 static void chksum_update(struct crypto_tfm *tfm, const u8 *data, 63 unsigned int length) 64 { 65 struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); 66 67 mctx->crc = crc32c(mctx->crc, data, length); 68 } 69 70 static void chksum_final(struct crypto_tfm *tfm, u8 *out) 71 { 72 struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); 73 74 *(__le32 *)out = ~cpu_to_le32(mctx->crc); 75 } 76 77 static int crc32c_cra_init_old(struct crypto_tfm *tfm) 78 { 79 struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); 80 81 mctx->key = ~0; 82 return 0; 83 } 84 85 static struct crypto_alg old_alg = { 86 .cra_name = "crc32c", 87 .cra_flags = CRYPTO_ALG_TYPE_DIGEST, 88 .cra_blocksize = CHKSUM_BLOCK_SIZE, 89 .cra_ctxsize = sizeof(struct chksum_ctx), 90 .cra_module = THIS_MODULE, 91 .cra_list = LIST_HEAD_INIT(old_alg.cra_list), 92 .cra_init = crc32c_cra_init_old, 93 .cra_u = { 94 .digest = { 95 .dia_digestsize= CHKSUM_DIGEST_SIZE, 96 .dia_setkey = chksum_setkey, 97 .dia_init = chksum_init, 98 .dia_update = chksum_update, 99 .dia_final = chksum_final 100 } 101 } 102 }; 103 104 /* 105 * Setting the seed allows arbitrary accumulators and flexible XOR policy 106 * If your algorithm starts with ~0, then XOR with ~0 before you set 107 * the seed. 108 */ 109 static int crc32c_setkey(struct crypto_ahash *hash, const u8 *key, 110 unsigned int keylen) 111 { 112 u32 *mctx = crypto_ahash_ctx(hash); 113 114 if (keylen != sizeof(u32)) { 115 crypto_ahash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN); 116 return -EINVAL; 117 } 118 *mctx = le32_to_cpup((__le32 *)key); 119 return 0; 120 } 121 122 static int crc32c_init(struct ahash_request *req) 123 { 124 u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); 125 u32 *crcp = ahash_request_ctx(req); 126 127 *crcp = *mctx; 128 return 0; 129 } 130 131 static int crc32c_update(struct ahash_request *req) 132 { 133 struct crypto_hash_walk walk; 134 u32 *crcp = ahash_request_ctx(req); 135 u32 crc = *crcp; 136 int nbytes; 137 138 for (nbytes = crypto_hash_walk_first(req, &walk); nbytes; 139 nbytes = crypto_hash_walk_done(&walk, 0)) 140 crc = crc32c(crc, walk.data, nbytes); 141 142 *crcp = crc; 143 return 0; 144 } 145 146 static int crc32c_final(struct ahash_request *req) 147 { 148 u32 *crcp = ahash_request_ctx(req); 149 150 *(__le32 *)req->result = ~cpu_to_le32p(crcp); 151 return 0; 152 } 153 154 static int crc32c_digest(struct ahash_request *req) 155 { 156 struct crypto_hash_walk walk; 157 u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); 158 u32 crc = *mctx; 159 int nbytes; 160 161 for (nbytes = crypto_hash_walk_first(req, &walk); nbytes; 162 nbytes = crypto_hash_walk_done(&walk, 0)) 163 crc = crc32c(crc, walk.data, nbytes); 164 165 *(__le32 *)req->result = ~cpu_to_le32(crc); 166 return 0; 167 } 168 169 static int crc32c_cra_init(struct crypto_tfm *tfm) 170 { 171 u32 *key = crypto_tfm_ctx(tfm); 172 173 *key = ~0; 174 175 tfm->crt_ahash.reqsize = sizeof(u32); 176 177 return 0; 178 } 179 180 static struct crypto_alg alg = { 181 .cra_name = "crc32c", 182 .cra_driver_name = "crc32c-generic", 183 .cra_priority = 100, 184 .cra_flags = CRYPTO_ALG_TYPE_AHASH, 185 .cra_blocksize = CHKSUM_BLOCK_SIZE, 186 .cra_alignmask = 3, 187 .cra_ctxsize = sizeof(u32), 188 .cra_module = THIS_MODULE, 189 .cra_list = LIST_HEAD_INIT(alg.cra_list), 190 .cra_init = crc32c_cra_init, 191 .cra_type = &crypto_ahash_type, 192 .cra_u = { 193 .ahash = { 194 .digestsize = CHKSUM_DIGEST_SIZE, 195 .setkey = crc32c_setkey, 196 .init = crc32c_init, 197 .update = crc32c_update, 198 .final = crc32c_final, 199 .digest = crc32c_digest, 200 } 201 } 202 }; 203 204 static int __init crc32c_mod_init(void) 205 { 206 int err; 207 208 err = crypto_register_alg(&old_alg); 209 if (err) 210 return err; 211 212 err = crypto_register_alg(&alg); 213 if (err) 214 crypto_unregister_alg(&old_alg); 215 216 return err; 217 } 218 219 static void __exit crc32c_mod_fini(void) 220 { 221 crypto_unregister_alg(&alg); 222 crypto_unregister_alg(&old_alg); 223 } 224 225 module_init(crc32c_mod_init); 226 module_exit(crc32c_mod_fini); 227 228 MODULE_AUTHOR("Clay Haapala <chaapala@cisco.com>"); 229 MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c"); 230 MODULE_LICENSE("GPL"); 231