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