1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#include <crypto/hash.h>
32#include <linux/scatterlist.h>
33#include <linux/libcfs/libcfs.h>
34#include <linux/libcfs/libcfs_crypto.h>
35#include "linux-crypto.h"
36
37
38
39
40static int cfs_crypto_hash_speeds[CFS_HASH_ALG_MAX];
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61static int cfs_crypto_hash_alloc(enum cfs_crypto_hash_alg hash_alg,
62 const struct cfs_crypto_hash_type **type,
63 struct ahash_request **req,
64 unsigned char *key,
65 unsigned int key_len)
66{
67 struct crypto_ahash *tfm;
68 int err = 0;
69
70 *type = cfs_crypto_hash_type(hash_alg);
71
72 if (!*type) {
73 CWARN("Unsupported hash algorithm id = %d, max id is %d\n",
74 hash_alg, CFS_HASH_ALG_MAX);
75 return -EINVAL;
76 }
77 tfm = crypto_alloc_ahash((*type)->cht_name, 0, CRYPTO_ALG_ASYNC);
78
79 if (IS_ERR(tfm)) {
80 CDEBUG(D_INFO, "Failed to alloc crypto hash %s\n",
81 (*type)->cht_name);
82 return PTR_ERR(tfm);
83 }
84
85 *req = ahash_request_alloc(tfm, GFP_KERNEL);
86 if (!*req) {
87 CDEBUG(D_INFO, "Failed to alloc ahash_request for %s\n",
88 (*type)->cht_name);
89 crypto_free_ahash(tfm);
90 return -ENOMEM;
91 }
92
93 ahash_request_set_callback(*req, 0, NULL, NULL);
94
95 if (key)
96 err = crypto_ahash_setkey(tfm, key, key_len);
97 else if ((*type)->cht_key)
98 err = crypto_ahash_setkey(tfm,
99 (unsigned char *)&((*type)->cht_key),
100 (*type)->cht_size);
101
102 if (err) {
103 ahash_request_free(*req);
104 crypto_free_ahash(tfm);
105 return err;
106 }
107
108 CDEBUG(D_INFO, "Using crypto hash: %s (%s) speed %d MB/s\n",
109 crypto_ahash_alg_name(tfm), crypto_ahash_driver_name(tfm),
110 cfs_crypto_hash_speeds[hash_alg]);
111
112 err = crypto_ahash_init(*req);
113 if (err) {
114 ahash_request_free(*req);
115 crypto_free_ahash(tfm);
116 }
117 return err;
118}
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146int cfs_crypto_hash_digest(enum cfs_crypto_hash_alg hash_alg,
147 const void *buf, unsigned int buf_len,
148 unsigned char *key, unsigned int key_len,
149 unsigned char *hash, unsigned int *hash_len)
150{
151 struct scatterlist sl;
152 struct ahash_request *req;
153 int err;
154 const struct cfs_crypto_hash_type *type;
155
156 if (!buf || !buf_len || !hash_len)
157 return -EINVAL;
158
159 err = cfs_crypto_hash_alloc(hash_alg, &type, &req, key, key_len);
160 if (err)
161 return err;
162
163 if (!hash || *hash_len < type->cht_size) {
164 *hash_len = type->cht_size;
165 crypto_free_ahash(crypto_ahash_reqtfm(req));
166 ahash_request_free(req);
167 return -ENOSPC;
168 }
169 sg_init_one(&sl, buf, buf_len);
170
171 ahash_request_set_crypt(req, &sl, hash, sl.length);
172 err = crypto_ahash_digest(req);
173 crypto_free_ahash(crypto_ahash_reqtfm(req));
174 ahash_request_free(req);
175
176 return err;
177}
178EXPORT_SYMBOL(cfs_crypto_hash_digest);
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197struct ahash_request *
198cfs_crypto_hash_init(enum cfs_crypto_hash_alg hash_alg,
199 unsigned char *key, unsigned int key_len)
200{
201 struct ahash_request *req;
202 int err;
203 const struct cfs_crypto_hash_type *type;
204
205 err = cfs_crypto_hash_alloc(hash_alg, &type, &req, key, key_len);
206
207 if (err)
208 return ERR_PTR(err);
209 return req;
210}
211EXPORT_SYMBOL(cfs_crypto_hash_init);
212
213
214
215
216
217
218
219
220
221
222
223
224int cfs_crypto_hash_update_page(struct ahash_request *req,
225 struct page *page, unsigned int offset,
226 unsigned int len)
227{
228 struct scatterlist sl;
229
230 sg_init_table(&sl, 1);
231 sg_set_page(&sl, page, len, offset & ~PAGE_MASK);
232
233 ahash_request_set_crypt(req, &sl, NULL, sl.length);
234 return crypto_ahash_update(req);
235}
236EXPORT_SYMBOL(cfs_crypto_hash_update_page);
237
238
239
240
241
242
243
244
245
246
247
248int cfs_crypto_hash_update(struct ahash_request *req,
249 const void *buf, unsigned int buf_len)
250{
251 struct scatterlist sl;
252
253 sg_init_one(&sl, buf, buf_len);
254
255 ahash_request_set_crypt(req, &sl, NULL, sl.length);
256 return crypto_ahash_update(req);
257}
258EXPORT_SYMBOL(cfs_crypto_hash_update);
259
260
261
262
263
264
265
266
267
268
269
270
271
272int cfs_crypto_hash_final(struct ahash_request *req,
273 unsigned char *hash, unsigned int *hash_len)
274{
275 int err;
276 int size = crypto_ahash_digestsize(crypto_ahash_reqtfm(req));
277
278 if (!hash || !hash_len) {
279 err = 0;
280 goto free_ahash;
281 }
282 if (*hash_len < size) {
283 err = -EOVERFLOW;
284 goto free_ahash;
285 }
286
287 ahash_request_set_crypt(req, NULL, hash, 0);
288 err = crypto_ahash_final(req);
289 if (!err)
290 *hash_len = size;
291free_ahash:
292 crypto_free_ahash(crypto_ahash_reqtfm(req));
293 ahash_request_free(req);
294 return err;
295}
296EXPORT_SYMBOL(cfs_crypto_hash_final);
297
298
299
300
301
302
303
304
305
306
307
308
309static void cfs_crypto_performance_test(enum cfs_crypto_hash_alg hash_alg)
310{
311 int buf_len = max(PAGE_SIZE, 1048576UL);
312 void *buf;
313 unsigned long start, end;
314 int bcount, err = 0;
315 struct page *page;
316 unsigned char hash[CFS_CRYPTO_HASH_DIGESTSIZE_MAX];
317 unsigned int hash_len = sizeof(hash);
318
319 page = alloc_page(GFP_KERNEL);
320 if (!page) {
321 err = -ENOMEM;
322 goto out_err;
323 }
324
325 buf = kmap(page);
326 memset(buf, 0xAD, PAGE_SIZE);
327 kunmap(page);
328
329 for (start = jiffies, end = start + msecs_to_jiffies(MSEC_PER_SEC),
330 bcount = 0; time_before(jiffies, end); bcount++) {
331 struct ahash_request *hdesc;
332 int i;
333
334 hdesc = cfs_crypto_hash_init(hash_alg, NULL, 0);
335 if (IS_ERR(hdesc)) {
336 err = PTR_ERR(hdesc);
337 break;
338 }
339
340 for (i = 0; i < buf_len / PAGE_SIZE; i++) {
341 err = cfs_crypto_hash_update_page(hdesc, page, 0,
342 PAGE_SIZE);
343 if (err)
344 break;
345 }
346
347 err = cfs_crypto_hash_final(hdesc, hash, &hash_len);
348 if (err)
349 break;
350 }
351 end = jiffies;
352 __free_page(page);
353out_err:
354 if (err) {
355 cfs_crypto_hash_speeds[hash_alg] = err;
356 CDEBUG(D_INFO, "Crypto hash algorithm %s test error: rc = %d\n",
357 cfs_crypto_hash_name(hash_alg), err);
358 } else {
359 unsigned long tmp;
360
361 tmp = ((bcount * buf_len / jiffies_to_msecs(end - start)) *
362 1000) / (1024 * 1024);
363 cfs_crypto_hash_speeds[hash_alg] = (int)tmp;
364 CDEBUG(D_CONFIG, "Crypto hash algorithm %s speed = %d MB/s\n",
365 cfs_crypto_hash_name(hash_alg),
366 cfs_crypto_hash_speeds[hash_alg]);
367 }
368}
369
370
371
372
373
374
375
376
377
378
379
380
381
382int cfs_crypto_hash_speed(enum cfs_crypto_hash_alg hash_alg)
383{
384 if (hash_alg < CFS_HASH_ALG_MAX)
385 return cfs_crypto_hash_speeds[hash_alg];
386 return -ENOENT;
387}
388EXPORT_SYMBOL(cfs_crypto_hash_speed);
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408static int cfs_crypto_test_hashes(void)
409{
410 enum cfs_crypto_hash_alg hash_alg;
411
412 for (hash_alg = 0; hash_alg < CFS_HASH_ALG_MAX; hash_alg++)
413 cfs_crypto_performance_test(hash_alg);
414
415 return 0;
416}
417
418static int adler32;
419
420
421
422
423
424
425int cfs_crypto_register(void)
426{
427 request_module("crc32c");
428
429 adler32 = cfs_crypto_adler32_register();
430
431
432 cfs_crypto_test_hashes();
433 return 0;
434}
435
436
437
438
439void cfs_crypto_unregister(void)
440{
441 if (!adler32)
442 cfs_crypto_adler32_unregister();
443}
444