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