diff options
Diffstat (limited to 'crypto/cryptd.c')
-rw-r--r-- | crypto/cryptd.c | 253 |
1 files changed, 248 insertions, 5 deletions
diff --git a/crypto/cryptd.c b/crypto/cryptd.c index b150de562057..d29e06b350ff 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c | |||
@@ -11,6 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <crypto/algapi.h> | 13 | #include <crypto/algapi.h> |
14 | #include <crypto/internal/hash.h> | ||
14 | #include <linux/err.h> | 15 | #include <linux/err.h> |
15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
16 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
@@ -45,6 +46,13 @@ struct cryptd_blkcipher_request_ctx { | |||
45 | crypto_completion_t complete; | 46 | crypto_completion_t complete; |
46 | }; | 47 | }; |
47 | 48 | ||
49 | struct cryptd_hash_ctx { | ||
50 | struct crypto_hash *child; | ||
51 | }; | ||
52 | |||
53 | struct cryptd_hash_request_ctx { | ||
54 | crypto_completion_t complete; | ||
55 | }; | ||
48 | 56 | ||
49 | static inline struct cryptd_state *cryptd_get_state(struct crypto_tfm *tfm) | 57 | static inline struct cryptd_state *cryptd_get_state(struct crypto_tfm *tfm) |
50 | { | 58 | { |
@@ -82,10 +90,8 @@ static void cryptd_blkcipher_crypt(struct ablkcipher_request *req, | |||
82 | 90 | ||
83 | rctx = ablkcipher_request_ctx(req); | 91 | rctx = ablkcipher_request_ctx(req); |
84 | 92 | ||
85 | if (unlikely(err == -EINPROGRESS)) { | 93 | if (unlikely(err == -EINPROGRESS)) |
86 | rctx->complete(&req->base, err); | 94 | goto out; |
87 | return; | ||
88 | } | ||
89 | 95 | ||
90 | desc.tfm = child; | 96 | desc.tfm = child; |
91 | desc.info = req->info; | 97 | desc.info = req->info; |
@@ -95,8 +101,9 @@ static void cryptd_blkcipher_crypt(struct ablkcipher_request *req, | |||
95 | 101 | ||
96 | req->base.complete = rctx->complete; | 102 | req->base.complete = rctx->complete; |
97 | 103 | ||
104 | out: | ||
98 | local_bh_disable(); | 105 | local_bh_disable(); |
99 | req->base.complete(&req->base, err); | 106 | rctx->complete(&req->base, err); |
100 | local_bh_enable(); | 107 | local_bh_enable(); |
101 | } | 108 | } |
102 | 109 | ||
@@ -261,6 +268,240 @@ out_put_alg: | |||
261 | return inst; | 268 | return inst; |
262 | } | 269 | } |
263 | 270 | ||
271 | static int cryptd_hash_init_tfm(struct crypto_tfm *tfm) | ||
272 | { | ||
273 | struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); | ||
274 | struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst); | ||
275 | struct crypto_spawn *spawn = &ictx->spawn; | ||
276 | struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm); | ||
277 | struct crypto_hash *cipher; | ||
278 | |||
279 | cipher = crypto_spawn_hash(spawn); | ||
280 | if (IS_ERR(cipher)) | ||
281 | return PTR_ERR(cipher); | ||
282 | |||
283 | ctx->child = cipher; | ||
284 | tfm->crt_ahash.reqsize = | ||
285 | sizeof(struct cryptd_hash_request_ctx); | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static void cryptd_hash_exit_tfm(struct crypto_tfm *tfm) | ||
290 | { | ||
291 | struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm); | ||
292 | struct cryptd_state *state = cryptd_get_state(tfm); | ||
293 | int active; | ||
294 | |||
295 | mutex_lock(&state->mutex); | ||
296 | active = ahash_tfm_in_queue(&state->queue, | ||
297 | __crypto_ahash_cast(tfm)); | ||
298 | mutex_unlock(&state->mutex); | ||
299 | |||
300 | BUG_ON(active); | ||
301 | |||
302 | crypto_free_hash(ctx->child); | ||
303 | } | ||
304 | |||
305 | static int cryptd_hash_setkey(struct crypto_ahash *parent, | ||
306 | const u8 *key, unsigned int keylen) | ||
307 | { | ||
308 | struct cryptd_hash_ctx *ctx = crypto_ahash_ctx(parent); | ||
309 | struct crypto_hash *child = ctx->child; | ||
310 | int err; | ||
311 | |||
312 | crypto_hash_clear_flags(child, CRYPTO_TFM_REQ_MASK); | ||
313 | crypto_hash_set_flags(child, crypto_ahash_get_flags(parent) & | ||
314 | CRYPTO_TFM_REQ_MASK); | ||
315 | err = crypto_hash_setkey(child, key, keylen); | ||
316 | crypto_ahash_set_flags(parent, crypto_hash_get_flags(child) & | ||
317 | CRYPTO_TFM_RES_MASK); | ||
318 | return err; | ||
319 | } | ||
320 | |||
321 | static int cryptd_hash_enqueue(struct ahash_request *req, | ||
322 | crypto_completion_t complete) | ||
323 | { | ||
324 | struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req); | ||
325 | struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | ||
326 | struct cryptd_state *state = | ||
327 | cryptd_get_state(crypto_ahash_tfm(tfm)); | ||
328 | int err; | ||
329 | |||
330 | rctx->complete = req->base.complete; | ||
331 | req->base.complete = complete; | ||
332 | |||
333 | spin_lock_bh(&state->lock); | ||
334 | err = ahash_enqueue_request(&state->queue, req); | ||
335 | spin_unlock_bh(&state->lock); | ||
336 | |||
337 | wake_up_process(state->task); | ||
338 | return err; | ||
339 | } | ||
340 | |||
341 | static void cryptd_hash_init(struct crypto_async_request *req_async, int err) | ||
342 | { | ||
343 | struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); | ||
344 | struct crypto_hash *child = ctx->child; | ||
345 | struct ahash_request *req = ahash_request_cast(req_async); | ||
346 | struct cryptd_hash_request_ctx *rctx; | ||
347 | struct hash_desc desc; | ||
348 | |||
349 | rctx = ahash_request_ctx(req); | ||
350 | |||
351 | if (unlikely(err == -EINPROGRESS)) | ||
352 | goto out; | ||
353 | |||
354 | desc.tfm = child; | ||
355 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
356 | |||
357 | err = crypto_hash_crt(child)->init(&desc); | ||
358 | |||
359 | req->base.complete = rctx->complete; | ||
360 | |||
361 | out: | ||
362 | local_bh_disable(); | ||
363 | rctx->complete(&req->base, err); | ||
364 | local_bh_enable(); | ||
365 | } | ||
366 | |||
367 | static int cryptd_hash_init_enqueue(struct ahash_request *req) | ||
368 | { | ||
369 | return cryptd_hash_enqueue(req, cryptd_hash_init); | ||
370 | } | ||
371 | |||
372 | static void cryptd_hash_update(struct crypto_async_request *req_async, int err) | ||
373 | { | ||
374 | struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); | ||
375 | struct crypto_hash *child = ctx->child; | ||
376 | struct ahash_request *req = ahash_request_cast(req_async); | ||
377 | struct cryptd_hash_request_ctx *rctx; | ||
378 | struct hash_desc desc; | ||
379 | |||
380 | rctx = ahash_request_ctx(req); | ||
381 | |||
382 | if (unlikely(err == -EINPROGRESS)) | ||
383 | goto out; | ||
384 | |||
385 | desc.tfm = child; | ||
386 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
387 | |||
388 | err = crypto_hash_crt(child)->update(&desc, | ||
389 | req->src, | ||
390 | req->nbytes); | ||
391 | |||
392 | req->base.complete = rctx->complete; | ||
393 | |||
394 | out: | ||
395 | local_bh_disable(); | ||
396 | rctx->complete(&req->base, err); | ||
397 | local_bh_enable(); | ||
398 | } | ||
399 | |||
400 | static int cryptd_hash_update_enqueue(struct ahash_request *req) | ||
401 | { | ||
402 | return cryptd_hash_enqueue(req, cryptd_hash_update); | ||
403 | } | ||
404 | |||
405 | static void cryptd_hash_final(struct crypto_async_request *req_async, int err) | ||
406 | { | ||
407 | struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); | ||
408 | struct crypto_hash *child = ctx->child; | ||
409 | struct ahash_request *req = ahash_request_cast(req_async); | ||
410 | struct cryptd_hash_request_ctx *rctx; | ||
411 | struct hash_desc desc; | ||
412 | |||
413 | rctx = ahash_request_ctx(req); | ||
414 | |||
415 | if (unlikely(err == -EINPROGRESS)) | ||
416 | goto out; | ||
417 | |||
418 | desc.tfm = child; | ||
419 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
420 | |||
421 | err = crypto_hash_crt(child)->final(&desc, req->result); | ||
422 | |||
423 | req->base.complete = rctx->complete; | ||
424 | |||
425 | out: | ||
426 | local_bh_disable(); | ||
427 | rctx->complete(&req->base, err); | ||
428 | local_bh_enable(); | ||
429 | } | ||
430 | |||
431 | static int cryptd_hash_final_enqueue(struct ahash_request *req) | ||
432 | { | ||
433 | return cryptd_hash_enqueue(req, cryptd_hash_final); | ||
434 | } | ||
435 | |||
436 | static void cryptd_hash_digest(struct crypto_async_request *req_async, int err) | ||
437 | { | ||
438 | struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); | ||
439 | struct crypto_hash *child = ctx->child; | ||
440 | struct ahash_request *req = ahash_request_cast(req_async); | ||
441 | struct cryptd_hash_request_ctx *rctx; | ||
442 | struct hash_desc desc; | ||
443 | |||
444 | rctx = ahash_request_ctx(req); | ||
445 | |||
446 | if (unlikely(err == -EINPROGRESS)) | ||
447 | goto out; | ||
448 | |||
449 | desc.tfm = child; | ||
450 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
451 | |||
452 | err = crypto_hash_crt(child)->digest(&desc, | ||
453 | req->src, | ||
454 | req->nbytes, | ||
455 | req->result); | ||
456 | |||
457 | req->base.complete = rctx->complete; | ||
458 | |||
459 | out: | ||
460 | local_bh_disable(); | ||
461 | rctx->complete(&req->base, err); | ||
462 | local_bh_enable(); | ||
463 | } | ||
464 | |||
465 | static int cryptd_hash_digest_enqueue(struct ahash_request *req) | ||
466 | { | ||
467 | return cryptd_hash_enqueue(req, cryptd_hash_digest); | ||
468 | } | ||
469 | |||
470 | static struct crypto_instance *cryptd_alloc_hash( | ||
471 | struct rtattr **tb, struct cryptd_state *state) | ||
472 | { | ||
473 | struct crypto_instance *inst; | ||
474 | struct crypto_alg *alg; | ||
475 | |||
476 | alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH, | ||
477 | CRYPTO_ALG_TYPE_HASH_MASK); | ||
478 | if (IS_ERR(alg)) | ||
479 | return ERR_PTR(PTR_ERR(alg)); | ||
480 | |||
481 | inst = cryptd_alloc_instance(alg, state); | ||
482 | if (IS_ERR(inst)) | ||
483 | goto out_put_alg; | ||
484 | |||
485 | inst->alg.cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC; | ||
486 | inst->alg.cra_type = &crypto_ahash_type; | ||
487 | |||
488 | inst->alg.cra_ahash.digestsize = alg->cra_hash.digestsize; | ||
489 | inst->alg.cra_ctxsize = sizeof(struct cryptd_hash_ctx); | ||
490 | |||
491 | inst->alg.cra_init = cryptd_hash_init_tfm; | ||
492 | inst->alg.cra_exit = cryptd_hash_exit_tfm; | ||
493 | |||
494 | inst->alg.cra_ahash.init = cryptd_hash_init_enqueue; | ||
495 | inst->alg.cra_ahash.update = cryptd_hash_update_enqueue; | ||
496 | inst->alg.cra_ahash.final = cryptd_hash_final_enqueue; | ||
497 | inst->alg.cra_ahash.setkey = cryptd_hash_setkey; | ||
498 | inst->alg.cra_ahash.digest = cryptd_hash_digest_enqueue; | ||
499 | |||
500 | out_put_alg: | ||
501 | crypto_mod_put(alg); | ||
502 | return inst; | ||
503 | } | ||
504 | |||
264 | static struct cryptd_state state; | 505 | static struct cryptd_state state; |
265 | 506 | ||
266 | static struct crypto_instance *cryptd_alloc(struct rtattr **tb) | 507 | static struct crypto_instance *cryptd_alloc(struct rtattr **tb) |
@@ -274,6 +515,8 @@ static struct crypto_instance *cryptd_alloc(struct rtattr **tb) | |||
274 | switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) { | 515 | switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) { |
275 | case CRYPTO_ALG_TYPE_BLKCIPHER: | 516 | case CRYPTO_ALG_TYPE_BLKCIPHER: |
276 | return cryptd_alloc_blkcipher(tb, &state); | 517 | return cryptd_alloc_blkcipher(tb, &state); |
518 | case CRYPTO_ALG_TYPE_DIGEST: | ||
519 | return cryptd_alloc_hash(tb, &state); | ||
277 | } | 520 | } |
278 | 521 | ||
279 | return ERR_PTR(-EINVAL); | 522 | return ERR_PTR(-EINVAL); |