Merge branch 'linus' into cpus4096
[pandora-kernel.git] / crypto / crc32c.c
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");