Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
004a403c LH |
2 | /* |
3 | * Asynchronous Cryptographic Hash operations. | |
4 | * | |
4d707a47 EB |
5 | * This is the implementation of the ahash (asynchronous hash) API. It differs |
6 | * from shash (synchronous hash) in that ahash supports asynchronous operations, | |
7 | * and it hashes data from scatterlists instead of virtually addressed buffers. | |
8 | * | |
9 | * The ahash API provides access to both ahash and shash algorithms. The shash | |
10 | * API only provides access to shash algorithms. | |
004a403c LH |
11 | * |
12 | * Copyright (c) 2008 Loc Ho <lho@amcc.com> | |
004a403c LH |
13 | */ |
14 | ||
20036252 | 15 | #include <crypto/scatterwalk.h> |
42808e5d | 16 | #include <linux/cryptouser.h> |
004a403c LH |
17 | #include <linux/err.h> |
18 | #include <linux/kernel.h> | |
19 | #include <linux/module.h> | |
20 | #include <linux/sched.h> | |
21 | #include <linux/slab.h> | |
22 | #include <linux/seq_file.h> | |
42808e5d | 23 | #include <linux/string.h> |
6238cbae | 24 | #include <net/netlink.h> |
004a403c | 25 | |
42808e5d | 26 | #include "hash.h" |
004a403c | 27 | |
b64d143b HX |
28 | #define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000e |
29 | ||
6d1b41fc EB |
30 | static const struct crypto_type crypto_ahash_type; |
31 | ||
ecf889b7 EB |
32 | static int shash_async_setkey(struct crypto_ahash *tfm, const u8 *key, |
33 | unsigned int keylen) | |
34 | { | |
35 | struct crypto_shash **ctx = crypto_ahash_ctx(tfm); | |
36 | ||
37 | return crypto_shash_setkey(*ctx, key, keylen); | |
38 | } | |
39 | ||
40 | static int shash_async_init(struct ahash_request *req) | |
41 | { | |
42 | struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); | |
43 | struct shash_desc *desc = ahash_request_ctx(req); | |
44 | ||
45 | desc->tfm = *ctx; | |
46 | ||
47 | return crypto_shash_init(desc); | |
48 | } | |
49 | ||
50 | int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc) | |
51 | { | |
52 | struct crypto_hash_walk walk; | |
53 | int nbytes; | |
54 | ||
55 | for (nbytes = crypto_hash_walk_first(req, &walk); nbytes > 0; | |
56 | nbytes = crypto_hash_walk_done(&walk, nbytes)) | |
57 | nbytes = crypto_shash_update(desc, walk.data, nbytes); | |
58 | ||
59 | return nbytes; | |
60 | } | |
61 | EXPORT_SYMBOL_GPL(shash_ahash_update); | |
62 | ||
63 | static int shash_async_update(struct ahash_request *req) | |
64 | { | |
65 | return shash_ahash_update(req, ahash_request_ctx(req)); | |
66 | } | |
67 | ||
68 | static int shash_async_final(struct ahash_request *req) | |
69 | { | |
70 | return crypto_shash_final(ahash_request_ctx(req), req->result); | |
71 | } | |
72 | ||
73 | int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc) | |
74 | { | |
75 | struct crypto_hash_walk walk; | |
76 | int nbytes; | |
77 | ||
78 | nbytes = crypto_hash_walk_first(req, &walk); | |
79 | if (!nbytes) | |
80 | return crypto_shash_final(desc, req->result); | |
81 | ||
82 | do { | |
83 | nbytes = crypto_hash_walk_last(&walk) ? | |
84 | crypto_shash_finup(desc, walk.data, nbytes, | |
85 | req->result) : | |
86 | crypto_shash_update(desc, walk.data, nbytes); | |
87 | nbytes = crypto_hash_walk_done(&walk, nbytes); | |
88 | } while (nbytes > 0); | |
89 | ||
90 | return nbytes; | |
91 | } | |
92 | EXPORT_SYMBOL_GPL(shash_ahash_finup); | |
93 | ||
94 | static int shash_async_finup(struct ahash_request *req) | |
95 | { | |
96 | struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); | |
97 | struct shash_desc *desc = ahash_request_ctx(req); | |
98 | ||
99 | desc->tfm = *ctx; | |
100 | ||
101 | return shash_ahash_finup(req, desc); | |
102 | } | |
103 | ||
104 | int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) | |
105 | { | |
106 | unsigned int nbytes = req->nbytes; | |
107 | struct scatterlist *sg; | |
108 | unsigned int offset; | |
109 | int err; | |
110 | ||
111 | if (nbytes && | |
112 | (sg = req->src, offset = sg->offset, | |
113 | nbytes <= min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset))) { | |
114 | void *data; | |
115 | ||
116 | data = kmap_local_page(sg_page(sg)); | |
117 | err = crypto_shash_digest(desc, data + offset, nbytes, | |
118 | req->result); | |
119 | kunmap_local(data); | |
120 | } else | |
121 | err = crypto_shash_init(desc) ?: | |
122 | shash_ahash_finup(req, desc); | |
123 | ||
124 | return err; | |
125 | } | |
126 | EXPORT_SYMBOL_GPL(shash_ahash_digest); | |
127 | ||
128 | static int shash_async_digest(struct ahash_request *req) | |
129 | { | |
130 | struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); | |
131 | struct shash_desc *desc = ahash_request_ctx(req); | |
132 | ||
133 | desc->tfm = *ctx; | |
134 | ||
135 | return shash_ahash_digest(req, desc); | |
136 | } | |
137 | ||
138 | static int shash_async_export(struct ahash_request *req, void *out) | |
139 | { | |
140 | return crypto_shash_export(ahash_request_ctx(req), out); | |
141 | } | |
142 | ||
143 | static int shash_async_import(struct ahash_request *req, const void *in) | |
144 | { | |
145 | struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); | |
146 | struct shash_desc *desc = ahash_request_ctx(req); | |
147 | ||
148 | desc->tfm = *ctx; | |
149 | ||
150 | return crypto_shash_import(desc, in); | |
151 | } | |
152 | ||
153 | static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm) | |
154 | { | |
155 | struct crypto_shash **ctx = crypto_tfm_ctx(tfm); | |
156 | ||
157 | crypto_free_shash(*ctx); | |
158 | } | |
159 | ||
160 | static int crypto_init_shash_ops_async(struct crypto_tfm *tfm) | |
161 | { | |
162 | struct crypto_alg *calg = tfm->__crt_alg; | |
163 | struct shash_alg *alg = __crypto_shash_alg(calg); | |
164 | struct crypto_ahash *crt = __crypto_ahash_cast(tfm); | |
165 | struct crypto_shash **ctx = crypto_tfm_ctx(tfm); | |
166 | struct crypto_shash *shash; | |
167 | ||
168 | if (!crypto_mod_get(calg)) | |
169 | return -EAGAIN; | |
170 | ||
171 | shash = crypto_create_tfm(calg, &crypto_shash_type); | |
172 | if (IS_ERR(shash)) { | |
173 | crypto_mod_put(calg); | |
174 | return PTR_ERR(shash); | |
175 | } | |
176 | ||
177 | *ctx = shash; | |
178 | tfm->exit = crypto_exit_shash_ops_async; | |
179 | ||
180 | crt->init = shash_async_init; | |
181 | crt->update = shash_async_update; | |
182 | crt->final = shash_async_final; | |
183 | crt->finup = shash_async_finup; | |
184 | crt->digest = shash_async_digest; | |
185 | if (crypto_shash_alg_has_setkey(alg)) | |
186 | crt->setkey = shash_async_setkey; | |
187 | ||
188 | crypto_ahash_set_flags(crt, crypto_shash_get_flags(shash) & | |
189 | CRYPTO_TFM_NEED_KEY); | |
190 | ||
191 | crt->export = shash_async_export; | |
192 | crt->import = shash_async_import; | |
193 | ||
194 | crt->reqsize = sizeof(struct shash_desc) + crypto_shash_descsize(shash); | |
195 | ||
196 | return 0; | |
197 | } | |
198 | ||
199 | static struct crypto_ahash * | |
200 | crypto_clone_shash_ops_async(struct crypto_ahash *nhash, | |
201 | struct crypto_ahash *hash) | |
202 | { | |
203 | struct crypto_shash **nctx = crypto_ahash_ctx(nhash); | |
204 | struct crypto_shash **ctx = crypto_ahash_ctx(hash); | |
205 | struct crypto_shash *shash; | |
206 | ||
207 | shash = crypto_clone_shash(*ctx); | |
208 | if (IS_ERR(shash)) { | |
209 | crypto_free_ahash(nhash); | |
210 | return ERR_CAST(shash); | |
211 | } | |
212 | ||
213 | *nctx = shash; | |
214 | ||
215 | return nhash; | |
216 | } | |
217 | ||
20036252 HX |
218 | static int hash_walk_next(struct crypto_hash_walk *walk) |
219 | { | |
20036252 HX |
220 | unsigned int offset = walk->offset; |
221 | unsigned int nbytes = min(walk->entrylen, | |
222 | ((unsigned int)(PAGE_SIZE)) - offset); | |
223 | ||
aa969515 | 224 | walk->data = kmap_local_page(walk->pg); |
20036252 | 225 | walk->data += offset; |
20036252 HX |
226 | walk->entrylen -= nbytes; |
227 | return nbytes; | |
228 | } | |
229 | ||
230 | static int hash_walk_new_entry(struct crypto_hash_walk *walk) | |
231 | { | |
232 | struct scatterlist *sg; | |
233 | ||
234 | sg = walk->sg; | |
20036252 | 235 | walk->offset = sg->offset; |
13f4bb78 HX |
236 | walk->pg = sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT); |
237 | walk->offset = offset_in_page(walk->offset); | |
20036252 HX |
238 | walk->entrylen = sg->length; |
239 | ||
240 | if (walk->entrylen > walk->total) | |
241 | walk->entrylen = walk->total; | |
242 | walk->total -= walk->entrylen; | |
243 | ||
244 | return hash_walk_next(walk); | |
245 | } | |
246 | ||
247 | int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) | |
248 | { | |
20036252 HX |
249 | walk->data -= walk->offset; |
250 | ||
aa969515 | 251 | kunmap_local(walk->data); |
8afa25aa | 252 | crypto_yield(walk->flags); |
20036252 HX |
253 | |
254 | if (err) | |
255 | return err; | |
256 | ||
77568e53 | 257 | if (walk->entrylen) { |
d315a0e0 HX |
258 | walk->offset = 0; |
259 | walk->pg++; | |
20036252 | 260 | return hash_walk_next(walk); |
d315a0e0 | 261 | } |
20036252 HX |
262 | |
263 | if (!walk->total) | |
264 | return 0; | |
265 | ||
5be4d4c9 | 266 | walk->sg = sg_next(walk->sg); |
20036252 HX |
267 | |
268 | return hash_walk_new_entry(walk); | |
269 | } | |
270 | EXPORT_SYMBOL_GPL(crypto_hash_walk_done); | |
271 | ||
272 | int crypto_hash_walk_first(struct ahash_request *req, | |
273 | struct crypto_hash_walk *walk) | |
274 | { | |
275 | walk->total = req->nbytes; | |
276 | ||
6d9529c5 TC |
277 | if (!walk->total) { |
278 | walk->entrylen = 0; | |
20036252 | 279 | return 0; |
6d9529c5 | 280 | } |
20036252 | 281 | |
20036252 | 282 | walk->sg = req->src; |
8afa25aa | 283 | walk->flags = req->base.flags; |
20036252 HX |
284 | |
285 | return hash_walk_new_entry(walk); | |
286 | } | |
287 | EXPORT_SYMBOL_GPL(crypto_hash_walk_first); | |
288 | ||
ba7d7433 EB |
289 | static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, |
290 | unsigned int keylen) | |
291 | { | |
292 | return -ENOSYS; | |
293 | } | |
294 | ||
295 | static void ahash_set_needkey(struct crypto_ahash *tfm) | |
296 | { | |
297 | const struct hash_alg_common *alg = crypto_hash_alg_common(tfm); | |
298 | ||
299 | if (tfm->setkey != ahash_nosetkey && | |
300 | !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY)) | |
301 | crypto_ahash_set_flags(tfm, CRYPTO_TFM_NEED_KEY); | |
302 | } | |
303 | ||
66f6ce5e | 304 | int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, |
004a403c LH |
305 | unsigned int keylen) |
306 | { | |
c626910f | 307 | int err = tfm->setkey(tfm, key, keylen); |
9fa68f62 | 308 | |
ba7d7433 EB |
309 | if (unlikely(err)) { |
310 | ahash_set_needkey(tfm); | |
9fa68f62 | 311 | return err; |
ba7d7433 | 312 | } |
004a403c | 313 | |
9fa68f62 EB |
314 | crypto_ahash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); |
315 | return 0; | |
004a403c | 316 | } |
66f6ce5e | 317 | EXPORT_SYMBOL_GPL(crypto_ahash_setkey); |
004a403c | 318 | |
d9588045 HX |
319 | static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt, |
320 | bool has_state) | |
66f6ce5e HX |
321 | { |
322 | struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | |
66f6ce5e | 323 | unsigned int ds = crypto_ahash_digestsize(tfm); |
d9588045 HX |
324 | struct ahash_request *subreq; |
325 | unsigned int subreq_size; | |
326 | unsigned int reqsize; | |
327 | u8 *result; | |
328 | gfp_t gfp; | |
329 | u32 flags; | |
66f6ce5e | 330 | |
d9588045 HX |
331 | subreq_size = sizeof(*subreq); |
332 | reqsize = crypto_ahash_reqsize(tfm); | |
333 | reqsize = ALIGN(reqsize, crypto_tfm_ctx_alignment()); | |
334 | subreq_size += reqsize; | |
335 | subreq_size += ds; | |
d9588045 HX |
336 | |
337 | flags = ahash_request_flags(req); | |
338 | gfp = (flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; | |
339 | subreq = kmalloc(subreq_size, gfp); | |
340 | if (!subreq) | |
66f6ce5e HX |
341 | return -ENOMEM; |
342 | ||
d9588045 HX |
343 | ahash_request_set_tfm(subreq, tfm); |
344 | ahash_request_set_callback(subreq, flags, cplt, req); | |
345 | ||
346 | result = (u8 *)(subreq + 1) + reqsize; | |
d9588045 HX |
347 | |
348 | ahash_request_set_crypt(subreq, req->src, result, req->nbytes); | |
349 | ||
350 | if (has_state) { | |
351 | void *state; | |
352 | ||
353 | state = kmalloc(crypto_ahash_statesize(tfm), gfp); | |
354 | if (!state) { | |
355 | kfree(subreq); | |
356 | return -ENOMEM; | |
357 | } | |
358 | ||
359 | crypto_ahash_export(req, state); | |
360 | crypto_ahash_import(subreq, state); | |
361 | kfree_sensitive(state); | |
362 | } | |
363 | ||
364 | req->priv = subreq; | |
66f6ce5e | 365 | |
1ffc9fbd MV |
366 | return 0; |
367 | } | |
368 | ||
ef0579b6 | 369 | static void ahash_restore_req(struct ahash_request *req, int err) |
1ffc9fbd | 370 | { |
d9588045 | 371 | struct ahash_request *subreq = req->priv; |
1ffc9fbd | 372 | |
ef0579b6 | 373 | if (!err) |
d9588045 | 374 | memcpy(req->result, subreq->result, |
ef0579b6 HX |
375 | crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); |
376 | ||
1ffc9fbd MV |
377 | req->priv = NULL; |
378 | ||
d9588045 | 379 | kfree_sensitive(subreq); |
1ffc9fbd MV |
380 | } |
381 | ||
66f6ce5e HX |
382 | int crypto_ahash_final(struct ahash_request *req) |
383 | { | |
f7d76e05 | 384 | struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); |
42808e5d | 385 | struct hash_alg_common *alg = crypto_hash_alg_common(tfm); |
cac5818c | 386 | |
42808e5d HX |
387 | if (IS_ENABLED(CONFIG_CRYPTO_STATS)) |
388 | atomic64_inc(&hash_get_stat(alg)->hash_cnt); | |
389 | ||
c626910f | 390 | return crypto_hash_errstat(alg, tfm->final(req)); |
66f6ce5e HX |
391 | } |
392 | EXPORT_SYMBOL_GPL(crypto_ahash_final); | |
393 | ||
394 | int crypto_ahash_finup(struct ahash_request *req) | |
395 | { | |
f7d76e05 | 396 | struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); |
42808e5d | 397 | struct hash_alg_common *alg = crypto_hash_alg_common(tfm); |
cac5818c | 398 | |
42808e5d HX |
399 | if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { |
400 | struct crypto_istat_hash *istat = hash_get_stat(alg); | |
401 | ||
402 | atomic64_inc(&istat->hash_cnt); | |
403 | atomic64_add(req->nbytes, &istat->hash_tlen); | |
404 | } | |
405 | ||
c626910f | 406 | return crypto_hash_errstat(alg, tfm->finup(req)); |
66f6ce5e HX |
407 | } |
408 | EXPORT_SYMBOL_GPL(crypto_ahash_finup); | |
409 | ||
410 | int crypto_ahash_digest(struct ahash_request *req) | |
411 | { | |
9fa68f62 | 412 | struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); |
42808e5d | 413 | struct hash_alg_common *alg = crypto_hash_alg_common(tfm); |
c626910f | 414 | int err; |
42808e5d HX |
415 | |
416 | if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { | |
417 | struct crypto_istat_hash *istat = hash_get_stat(alg); | |
418 | ||
419 | atomic64_inc(&istat->hash_cnt); | |
420 | atomic64_add(req->nbytes, &istat->hash_tlen); | |
421 | } | |
9fa68f62 EB |
422 | |
423 | if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) | |
c626910f EB |
424 | err = -ENOKEY; |
425 | else | |
426 | err = tfm->digest(req); | |
42808e5d | 427 | |
c626910f | 428 | return crypto_hash_errstat(alg, err); |
66f6ce5e HX |
429 | } |
430 | EXPORT_SYMBOL_GPL(crypto_ahash_digest); | |
431 | ||
255e48eb | 432 | static void ahash_def_finup_done2(void *data, int err) |
66f6ce5e | 433 | { |
255e48eb | 434 | struct ahash_request *areq = data; |
66f6ce5e HX |
435 | |
436 | if (err == -EINPROGRESS) | |
437 | return; | |
438 | ||
ef0579b6 | 439 | ahash_restore_req(areq, err); |
66f6ce5e | 440 | |
d9588045 | 441 | ahash_request_complete(areq, err); |
66f6ce5e HX |
442 | } |
443 | ||
444 | static int ahash_def_finup_finish1(struct ahash_request *req, int err) | |
445 | { | |
d9588045 HX |
446 | struct ahash_request *subreq = req->priv; |
447 | ||
66f6ce5e HX |
448 | if (err) |
449 | goto out; | |
450 | ||
d9588045 | 451 | subreq->base.complete = ahash_def_finup_done2; |
ef0579b6 | 452 | |
d9588045 | 453 | err = crypto_ahash_reqtfm(req)->final(subreq); |
4e5b0ad5 | 454 | if (err == -EINPROGRESS || err == -EBUSY) |
ef0579b6 | 455 | return err; |
66f6ce5e HX |
456 | |
457 | out: | |
ef0579b6 | 458 | ahash_restore_req(req, err); |
66f6ce5e HX |
459 | return err; |
460 | } | |
461 | ||
255e48eb | 462 | static void ahash_def_finup_done1(void *data, int err) |
66f6ce5e | 463 | { |
255e48eb | 464 | struct ahash_request *areq = data; |
d9588045 | 465 | struct ahash_request *subreq; |
66f6ce5e | 466 | |
d9588045 HX |
467 | if (err == -EINPROGRESS) |
468 | goto out; | |
ef0579b6 | 469 | |
d9588045 HX |
470 | subreq = areq->priv; |
471 | subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG; | |
ef0579b6 | 472 | |
66f6ce5e | 473 | err = ahash_def_finup_finish1(areq, err); |
d9588045 | 474 | if (err == -EINPROGRESS || err == -EBUSY) |
ef0579b6 | 475 | return; |
66f6ce5e | 476 | |
d9588045 HX |
477 | out: |
478 | ahash_request_complete(areq, err); | |
66f6ce5e HX |
479 | } |
480 | ||
481 | static int ahash_def_finup(struct ahash_request *req) | |
482 | { | |
483 | struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | |
d4a7a0fb | 484 | int err; |
66f6ce5e | 485 | |
d9588045 | 486 | err = ahash_save_req(req, ahash_def_finup_done1, true); |
d4a7a0fb MV |
487 | if (err) |
488 | return err; | |
66f6ce5e | 489 | |
d9588045 | 490 | err = tfm->update(req->priv); |
4e5b0ad5 | 491 | if (err == -EINPROGRESS || err == -EBUSY) |
ef0579b6 HX |
492 | return err; |
493 | ||
d4a7a0fb | 494 | return ahash_def_finup_finish1(req, err); |
66f6ce5e HX |
495 | } |
496 | ||
e73d340d HX |
497 | static void crypto_ahash_exit_tfm(struct crypto_tfm *tfm) |
498 | { | |
499 | struct crypto_ahash *hash = __crypto_ahash_cast(tfm); | |
500 | struct ahash_alg *alg = crypto_ahash_alg(hash); | |
501 | ||
502 | alg->exit_tfm(hash); | |
503 | } | |
504 | ||
88056ec3 HX |
505 | static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) |
506 | { | |
507 | struct crypto_ahash *hash = __crypto_ahash_cast(tfm); | |
508 | struct ahash_alg *alg = crypto_ahash_alg(hash); | |
88056ec3 | 509 | |
66f6ce5e | 510 | hash->setkey = ahash_nosetkey; |
66f6ce5e | 511 | |
c7535fb2 HX |
512 | crypto_ahash_set_statesize(hash, alg->halg.statesize); |
513 | ||
88056ec3 HX |
514 | if (tfm->__crt_alg->cra_type != &crypto_ahash_type) |
515 | return crypto_init_shash_ops_async(tfm); | |
516 | ||
88056ec3 HX |
517 | hash->init = alg->init; |
518 | hash->update = alg->update; | |
66f6ce5e HX |
519 | hash->final = alg->final; |
520 | hash->finup = alg->finup ?: ahash_def_finup; | |
88056ec3 | 521 | hash->digest = alg->digest; |
6f221f7e KK |
522 | hash->export = alg->export; |
523 | hash->import = alg->import; | |
66f6ce5e | 524 | |
a5596d63 | 525 | if (alg->setkey) { |
66f6ce5e | 526 | hash->setkey = alg->setkey; |
ba7d7433 | 527 | ahash_set_needkey(hash); |
a5596d63 | 528 | } |
88056ec3 | 529 | |
e73d340d HX |
530 | if (alg->exit_tfm) |
531 | tfm->exit = crypto_ahash_exit_tfm; | |
532 | ||
533 | return alg->init_tfm ? alg->init_tfm(hash) : 0; | |
88056ec3 HX |
534 | } |
535 | ||
536 | static unsigned int crypto_ahash_extsize(struct crypto_alg *alg) | |
537 | { | |
2495cf25 HX |
538 | if (alg->cra_type != &crypto_ahash_type) |
539 | return sizeof(struct crypto_shash *); | |
88056ec3 | 540 | |
2495cf25 | 541 | return crypto_alg_extsize(alg); |
88056ec3 HX |
542 | } |
543 | ||
48fb3e57 EB |
544 | static void crypto_ahash_free_instance(struct crypto_instance *inst) |
545 | { | |
546 | struct ahash_instance *ahash = ahash_instance(inst); | |
547 | ||
48fb3e57 EB |
548 | ahash->free(ahash); |
549 | } | |
550 | ||
c0f9e01d HX |
551 | static int __maybe_unused crypto_ahash_report( |
552 | struct sk_buff *skb, struct crypto_alg *alg) | |
6238cbae SK |
553 | { |
554 | struct crypto_report_hash rhash; | |
555 | ||
37db69e0 EB |
556 | memset(&rhash, 0, sizeof(rhash)); |
557 | ||
558 | strscpy(rhash.type, "ahash", sizeof(rhash.type)); | |
6238cbae SK |
559 | |
560 | rhash.blocksize = alg->cra_blocksize; | |
561 | rhash.digestsize = __crypto_hash_alg_common(alg)->digestsize; | |
562 | ||
37db69e0 | 563 | return nla_put(skb, CRYPTOCFGA_REPORT_HASH, sizeof(rhash), &rhash); |
6238cbae SK |
564 | } |
565 | ||
004a403c | 566 | static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) |
d8c34b94 | 567 | __maybe_unused; |
004a403c LH |
568 | static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) |
569 | { | |
570 | seq_printf(m, "type : ahash\n"); | |
571 | seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? | |
572 | "yes" : "no"); | |
573 | seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); | |
88056ec3 HX |
574 | seq_printf(m, "digestsize : %u\n", |
575 | __crypto_hash_alg_common(alg)->digestsize); | |
004a403c LH |
576 | } |
577 | ||
42808e5d HX |
578 | static int __maybe_unused crypto_ahash_report_stat( |
579 | struct sk_buff *skb, struct crypto_alg *alg) | |
580 | { | |
581 | return crypto_hash_report_stat(skb, alg, "ahash"); | |
582 | } | |
583 | ||
6d1b41fc | 584 | static const struct crypto_type crypto_ahash_type = { |
88056ec3 HX |
585 | .extsize = crypto_ahash_extsize, |
586 | .init_tfm = crypto_ahash_init_tfm, | |
48fb3e57 | 587 | .free = crypto_ahash_free_instance, |
004a403c LH |
588 | #ifdef CONFIG_PROC_FS |
589 | .show = crypto_ahash_show, | |
590 | #endif | |
b8969a1b | 591 | #if IS_ENABLED(CONFIG_CRYPTO_USER) |
6238cbae | 592 | .report = crypto_ahash_report, |
c0f9e01d | 593 | #endif |
42808e5d HX |
594 | #ifdef CONFIG_CRYPTO_STATS |
595 | .report_stat = crypto_ahash_report_stat, | |
596 | #endif | |
88056ec3 HX |
597 | .maskclear = ~CRYPTO_ALG_TYPE_MASK, |
598 | .maskset = CRYPTO_ALG_TYPE_AHASH_MASK, | |
599 | .type = CRYPTO_ALG_TYPE_AHASH, | |
600 | .tfmsize = offsetof(struct crypto_ahash, base), | |
004a403c | 601 | }; |
004a403c | 602 | |
84a9c938 EB |
603 | int crypto_grab_ahash(struct crypto_ahash_spawn *spawn, |
604 | struct crypto_instance *inst, | |
605 | const char *name, u32 type, u32 mask) | |
606 | { | |
607 | spawn->base.frontend = &crypto_ahash_type; | |
608 | return crypto_grab_spawn(&spawn->base, inst, name, type, mask); | |
609 | } | |
610 | EXPORT_SYMBOL_GPL(crypto_grab_ahash); | |
611 | ||
88056ec3 HX |
612 | struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type, |
613 | u32 mask) | |
614 | { | |
615 | return crypto_alloc_tfm(alg_name, &crypto_ahash_type, type, mask); | |
616 | } | |
617 | EXPORT_SYMBOL_GPL(crypto_alloc_ahash); | |
618 | ||
8d18e34c HX |
619 | int crypto_has_ahash(const char *alg_name, u32 type, u32 mask) |
620 | { | |
621 | return crypto_type_has_alg(alg_name, &crypto_ahash_type, type, mask); | |
622 | } | |
623 | EXPORT_SYMBOL_GPL(crypto_has_ahash); | |
624 | ||
ed3630b8 HX |
625 | struct crypto_ahash *crypto_clone_ahash(struct crypto_ahash *hash) |
626 | { | |
627 | struct hash_alg_common *halg = crypto_hash_alg_common(hash); | |
628 | struct crypto_tfm *tfm = crypto_ahash_tfm(hash); | |
629 | struct crypto_ahash *nhash; | |
630 | struct ahash_alg *alg; | |
631 | int err; | |
632 | ||
633 | if (!crypto_hash_alg_has_setkey(halg)) { | |
634 | tfm = crypto_tfm_get(tfm); | |
635 | if (IS_ERR(tfm)) | |
636 | return ERR_CAST(tfm); | |
637 | ||
638 | return hash; | |
639 | } | |
640 | ||
641 | nhash = crypto_clone_tfm(&crypto_ahash_type, tfm); | |
642 | ||
643 | if (IS_ERR(nhash)) | |
644 | return nhash; | |
645 | ||
646 | nhash->init = hash->init; | |
647 | nhash->update = hash->update; | |
648 | nhash->final = hash->final; | |
649 | nhash->finup = hash->finup; | |
650 | nhash->digest = hash->digest; | |
651 | nhash->export = hash->export; | |
652 | nhash->import = hash->import; | |
653 | nhash->setkey = hash->setkey; | |
654 | nhash->reqsize = hash->reqsize; | |
c7535fb2 | 655 | nhash->statesize = hash->statesize; |
ed3630b8 HX |
656 | |
657 | if (tfm->__crt_alg->cra_type != &crypto_ahash_type) | |
658 | return crypto_clone_shash_ops_async(nhash, hash); | |
659 | ||
660 | err = -ENOSYS; | |
661 | alg = crypto_ahash_alg(hash); | |
662 | if (!alg->clone_tfm) | |
663 | goto out_free_nhash; | |
664 | ||
665 | err = alg->clone_tfm(nhash, hash); | |
666 | if (err) | |
667 | goto out_free_nhash; | |
668 | ||
669 | return nhash; | |
670 | ||
671 | out_free_nhash: | |
672 | crypto_free_ahash(nhash); | |
673 | return ERR_PTR(err); | |
674 | } | |
675 | EXPORT_SYMBOL_GPL(crypto_clone_ahash); | |
676 | ||
01c2dece HX |
677 | static int ahash_prepare_alg(struct ahash_alg *alg) |
678 | { | |
679 | struct crypto_alg *base = &alg->halg.base; | |
42808e5d | 680 | int err; |
01c2dece | 681 | |
42808e5d | 682 | if (alg->halg.statesize == 0) |
01c2dece HX |
683 | return -EINVAL; |
684 | ||
42808e5d HX |
685 | err = hash_prepare_alg(&alg->halg); |
686 | if (err) | |
687 | return err; | |
688 | ||
01c2dece | 689 | base->cra_type = &crypto_ahash_type; |
01c2dece HX |
690 | base->cra_flags |= CRYPTO_ALG_TYPE_AHASH; |
691 | ||
692 | return 0; | |
693 | } | |
694 | ||
695 | int crypto_register_ahash(struct ahash_alg *alg) | |
696 | { | |
697 | struct crypto_alg *base = &alg->halg.base; | |
698 | int err; | |
699 | ||
700 | err = ahash_prepare_alg(alg); | |
701 | if (err) | |
702 | return err; | |
703 | ||
704 | return crypto_register_alg(base); | |
705 | } | |
706 | EXPORT_SYMBOL_GPL(crypto_register_ahash); | |
707 | ||
c6d633a9 | 708 | void crypto_unregister_ahash(struct ahash_alg *alg) |
01c2dece | 709 | { |
c6d633a9 | 710 | crypto_unregister_alg(&alg->halg.base); |
01c2dece HX |
711 | } |
712 | EXPORT_SYMBOL_GPL(crypto_unregister_ahash); | |
713 | ||
6f7473c5 RV |
714 | int crypto_register_ahashes(struct ahash_alg *algs, int count) |
715 | { | |
716 | int i, ret; | |
717 | ||
718 | for (i = 0; i < count; i++) { | |
719 | ret = crypto_register_ahash(&algs[i]); | |
720 | if (ret) | |
721 | goto err; | |
722 | } | |
723 | ||
724 | return 0; | |
725 | ||
726 | err: | |
727 | for (--i; i >= 0; --i) | |
728 | crypto_unregister_ahash(&algs[i]); | |
729 | ||
730 | return ret; | |
731 | } | |
732 | EXPORT_SYMBOL_GPL(crypto_register_ahashes); | |
733 | ||
734 | void crypto_unregister_ahashes(struct ahash_alg *algs, int count) | |
735 | { | |
736 | int i; | |
737 | ||
738 | for (i = count - 1; i >= 0; --i) | |
739 | crypto_unregister_ahash(&algs[i]); | |
740 | } | |
741 | EXPORT_SYMBOL_GPL(crypto_unregister_ahashes); | |
742 | ||
01c2dece HX |
743 | int ahash_register_instance(struct crypto_template *tmpl, |
744 | struct ahash_instance *inst) | |
745 | { | |
746 | int err; | |
747 | ||
d4fdc2df EB |
748 | if (WARN_ON(!inst->free)) |
749 | return -EINVAL; | |
750 | ||
01c2dece HX |
751 | err = ahash_prepare_alg(&inst->alg); |
752 | if (err) | |
753 | return err; | |
754 | ||
755 | return crypto_register_instance(tmpl, ahash_crypto_instance(inst)); | |
756 | } | |
757 | EXPORT_SYMBOL_GPL(ahash_register_instance); | |
758 | ||
cd6ed77a EB |
759 | bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg) |
760 | { | |
761 | struct crypto_alg *alg = &halg->base; | |
762 | ||
763 | if (alg->cra_type != &crypto_ahash_type) | |
764 | return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg)); | |
765 | ||
766 | return __crypto_ahash_alg(alg)->setkey != NULL; | |
767 | } | |
768 | EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey); | |
769 | ||
004a403c LH |
770 | MODULE_LICENSE("GPL"); |
771 | MODULE_DESCRIPTION("Asynchronous cryptographic hash type"); |