Whamcloud - gitweb
LU-2053 crypto: Fix cfs_crypto_hash memleak
[fs/lustre-release.git] / libcfs / libcfs / linux / linux-crypto-crc32.c
1 /* GPL HEADER START
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 only,
7  * as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License version 2 for more details (a copy is included
13  * in the LICENSE file that accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License
16  * version 2 along with this program; If not, see http://www.gnu.org/licenses
17  *
18  * Please  visit http://www.xyratex.com/contact if you need additional
19  * information or have any questions.
20  *
21  * GPL HEADER END
22  */
23
24 /*
25  * Copyright 2012 Xyratex Technology Limited
26  */
27
28 /*
29  * This is crypto api shash wrappers to crc32_le.
30  */
31
32 #include <linux/module.h>
33 #include <linux/crc32.h>
34 #ifdef HAVE_STRUCT_SHASH_ALG
35 #include <crypto/internal/hash.h>
36 #else
37 #include <linux/crypto.h>
38 #endif
39
40 #define CHKSUM_BLOCK_SIZE       1
41 #define CHKSUM_DIGEST_SIZE      4
42
43 static u32 __crc32_le(u32 crc, unsigned char const *p, size_t len)
44 {
45         return crc32_le(crc, p, len);
46 }
47
48 /** No default init with ~0 */
49 static int crc32_cra_init(struct crypto_tfm *tfm)
50 {
51         u32 *key = crypto_tfm_ctx(tfm);
52
53         *key = 0;
54
55         return 0;
56 }
57
58
59 #ifdef HAVE_STRUCT_SHASH_ALG
60 /*
61  * Setting the seed allows arbitrary accumulators and flexible XOR policy
62  * If your algorithm starts with ~0, then XOR with ~0 before you set
63  * the seed.
64  */
65 static int crc32_setkey(struct crypto_shash *hash, const u8 *key,
66                         unsigned int keylen)
67 {
68         u32 *mctx = crypto_shash_ctx(hash);
69
70         if (keylen != sizeof(u32)) {
71                 crypto_shash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
72                 return -EINVAL;
73         }
74         *mctx = le32_to_cpup((__le32 *)key);
75         return 0;
76 }
77
78 static int crc32_init(struct shash_desc *desc)
79 {
80         u32 *mctx = crypto_shash_ctx(desc->tfm);
81         u32 *crcp = shash_desc_ctx(desc);
82
83         *crcp = *mctx;
84
85         return 0;
86 }
87
88 static int crc32_update(struct shash_desc *desc, const u8 *data,
89                         unsigned int len)
90 {
91         u32 *crcp = shash_desc_ctx(desc);
92
93         *crcp = __crc32_le(*crcp, data, len);
94         return 0;
95 }
96 /* No final XOR 0xFFFFFFFF, like crc32_le */
97 static int __crc32_finup(u32 *crcp, const u8 *data, unsigned int len,
98                          u8 *out)
99 {
100         *(__le32 *)out = cpu_to_le32(__crc32_le(*crcp, data, len));
101         return 0;
102 }
103
104 static int crc32_finup(struct shash_desc *desc, const u8 *data,
105                        unsigned int len, u8 *out)
106 {
107         return __crc32_finup(shash_desc_ctx(desc), data, len, out);
108 }
109
110 static int crc32_final(struct shash_desc *desc, u8 *out)
111 {
112         u32 *crcp = shash_desc_ctx(desc);
113
114         *(__le32 *)out = cpu_to_le32p(crcp);
115         return 0;
116 }
117
118 static int crc32_digest(struct shash_desc *desc, const u8 *data,
119                         unsigned int len, u8 *out)
120 {
121         return __crc32_finup(crypto_shash_ctx(desc->tfm), data, len,
122                              out);
123 }
124 static struct shash_alg alg = {
125         .setkey         = crc32_setkey,
126         .init           = crc32_init,
127         .update         = crc32_update,
128         .final          = crc32_final,
129         .finup          = crc32_finup,
130         .digest         = crc32_digest,
131         .descsize       = sizeof(u32),
132         .digestsize     = CHKSUM_DIGEST_SIZE,
133         .base           = {
134                 .cra_name               = "crc32",
135                 .cra_driver_name        = "crc32-table",
136                 .cra_priority           = 100,
137                 .cra_blocksize          = CHKSUM_BLOCK_SIZE,
138                 .cra_ctxsize            = sizeof(u32),
139                 .cra_module             = THIS_MODULE,
140                 .cra_init               = crc32_cra_init,
141         }
142 };
143 #else   /* HAVE_STRUCT_SHASH_ALG */
144 #ifdef HAVE_DIGEST_SETKEY_FLAGS
145 static int crc32_digest_setkey(struct crypto_tfm *tfm, const u8 *key,
146                                unsigned int keylen, unsigned int *flags)
147 #else
148 static int crc32_digest_setkey(struct crypto_tfm *tfm, const u8 *key,
149                                unsigned int keylen)
150 #endif
151 {
152         u32 *mctx = crypto_tfm_ctx(tfm);
153
154         if (keylen != sizeof(u32)) {
155                 tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
156                 return -EINVAL;
157         }
158         *mctx = le32_to_cpup((__le32 *)key);
159         return 0;
160 }
161
162 static void crc32_digest_init(struct crypto_tfm *tfm)
163 {
164         u32 *mctx = crypto_tfm_ctx(tfm);
165
166         *mctx = 0;
167
168 }
169 static void crc32_digest_update(struct crypto_tfm *tfm, const u8 *data,
170                                 unsigned int len)
171 {
172         u32 *crcp = crypto_tfm_ctx(tfm);
173
174         *crcp = __crc32_le(*crcp, data, len);
175 }
176
177 static void crc32_digest_final(struct crypto_tfm *tfm, u8 *out)
178 {
179         u32 *crcp = crypto_tfm_ctx(tfm);
180
181         *(__le32 *)out = cpu_to_le32p(crcp);
182 }
183
184 static struct crypto_alg alg = {
185         .cra_name               = "crc32",
186         .cra_flags              = CRYPTO_ALG_TYPE_DIGEST,
187         .cra_driver_name        = "crc32-table",
188         .cra_priority           = 100,
189         .cra_blocksize          = CHKSUM_BLOCK_SIZE,
190         .cra_ctxsize            = sizeof(u32),
191         .cra_module             = THIS_MODULE,
192         .cra_init               = crc32_cra_init,
193         .cra_list               = LIST_HEAD_INIT(alg.cra_list),
194         .cra_u                  = {
195                 .digest         = {
196                         .dia_digestsize = CHKSUM_DIGEST_SIZE,
197                         .dia_setkey     = crc32_digest_setkey,
198                         .dia_init       = crc32_digest_init,
199                         .dia_update     = crc32_digest_update,
200                         .dia_final      = crc32_digest_final
201                 }
202         }
203 };
204 #endif  /* HAVE_STRUCT_SHASH_ALG */
205
206 int cfs_crypto_crc32_register(void)
207 {
208 #ifdef HAVE_STRUCT_SHASH_ALG
209         return crypto_register_shash(&alg);
210 #else
211         return crypto_register_alg(&alg);
212 #endif
213 }
214 EXPORT_SYMBOL(cfs_crypto_crc32_register);
215
216 void cfs_crypto_crc32_unregister(void)
217 {
218 #ifdef HAVE_STRUCT_SHASH_ALG
219         crypto_unregister_shash(&alg);
220 #else
221         crypto_unregister_alg(&alg);
222 #endif
223 }
224 EXPORT_SYMBOL(cfs_crypto_crc32_unregister);