diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-12-07 07:31:10 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2008-01-10 16:16:47 -0500 |
commit | d00aa19b507b39ee9a680d0d2ac2ae483686453a (patch) | |
tree | 87c4ad0b7aeee3524beec9f6b96fff0a84ec5dd8 | |
parent | 9ffde35a8edd3486cd7c80af931c15cec99a1a0d (diff) |
[CRYPTO] gcm: Allow block cipher parameter
This patch adds the gcm_base template which takes a block cipher
parameter instead of cipher. This allows the user to specify a
specific CTR implementation.
This also fixes a leak of the cipher algorithm that was previously
looked up but never freed.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | crypto/gcm.c | 113 |
1 files changed, 89 insertions, 24 deletions
diff --git a/crypto/gcm.c b/crypto/gcm.c index f6bee6f209a6..e87e5de8e7b3 100644 --- a/crypto/gcm.c +++ b/crypto/gcm.c | |||
@@ -413,30 +413,23 @@ static void crypto_gcm_exit_tfm(struct crypto_tfm *tfm) | |||
413 | crypto_free_ablkcipher(ctx->ctr); | 413 | crypto_free_ablkcipher(ctx->ctr); |
414 | } | 414 | } |
415 | 415 | ||
416 | static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb) | 416 | static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb, |
417 | const char *full_name, | ||
418 | const char *ctr_name) | ||
417 | { | 419 | { |
420 | struct crypto_attr_type *algt; | ||
418 | struct crypto_instance *inst; | 421 | struct crypto_instance *inst; |
419 | struct crypto_alg *ctr; | 422 | struct crypto_alg *ctr; |
420 | struct crypto_alg *cipher; | ||
421 | struct gcm_instance_ctx *ctx; | 423 | struct gcm_instance_ctx *ctx; |
422 | int err; | 424 | int err; |
423 | char ctr_name[CRYPTO_MAX_ALG_NAME]; | ||
424 | 425 | ||
425 | err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD); | 426 | algt = crypto_get_attr_type(tb); |
426 | if (err) | 427 | err = PTR_ERR(algt); |
428 | if (IS_ERR(algt)) | ||
427 | return ERR_PTR(err); | 429 | return ERR_PTR(err); |
428 | 430 | ||
429 | cipher = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER, | 431 | if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) |
430 | CRYPTO_ALG_TYPE_MASK); | 432 | return ERR_PTR(-EINVAL); |
431 | |||
432 | inst = ERR_PTR(PTR_ERR(cipher)); | ||
433 | if (IS_ERR(cipher)) | ||
434 | return inst; | ||
435 | |||
436 | inst = ERR_PTR(ENAMETOOLONG); | ||
437 | if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", | ||
438 | cipher->cra_name) >= CRYPTO_MAX_ALG_NAME) | ||
439 | return inst; | ||
440 | 433 | ||
441 | ctr = crypto_alg_mod_lookup(ctr_name, CRYPTO_ALG_TYPE_BLKCIPHER, | 434 | ctr = crypto_alg_mod_lookup(ctr_name, CRYPTO_ALG_TYPE_BLKCIPHER, |
442 | CRYPTO_ALG_TYPE_MASK); | 435 | CRYPTO_ALG_TYPE_MASK); |
@@ -444,7 +437,14 @@ static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb) | |||
444 | if (IS_ERR(ctr)) | 437 | if (IS_ERR(ctr)) |
445 | return ERR_PTR(PTR_ERR(ctr)); | 438 | return ERR_PTR(PTR_ERR(ctr)); |
446 | 439 | ||
447 | if (cipher->cra_blocksize != 16) | 440 | /* We only support 16-byte blocks. */ |
441 | if ((ctr->cra_type == &crypto_blkcipher_type ? | ||
442 | ctr->cra_blkcipher.ivsize : ctr->cra_ablkcipher.ivsize) != 16) | ||
443 | goto out_put_ctr; | ||
444 | |||
445 | /* Not a stream cipher? */ | ||
446 | err = -EINVAL; | ||
447 | if (ctr->cra_blocksize != 1) | ||
448 | goto out_put_ctr; | 448 | goto out_put_ctr; |
449 | 449 | ||
450 | inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); | 450 | inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); |
@@ -453,21 +453,21 @@ static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb) | |||
453 | goto out_put_ctr; | 453 | goto out_put_ctr; |
454 | 454 | ||
455 | err = -ENAMETOOLONG; | 455 | err = -ENAMETOOLONG; |
456 | if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, | 456 | if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, |
457 | "gcm(%s)", cipher->cra_name) >= CRYPTO_MAX_ALG_NAME || | 457 | "gcm_base(%s)", ctr->cra_driver_name) >= |
458 | snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, | 458 | CRYPTO_MAX_ALG_NAME) |
459 | "gcm(%s)", cipher->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) | ||
460 | goto err_free_inst; | 459 | goto err_free_inst; |
461 | 460 | ||
462 | |||
463 | ctx = crypto_instance_ctx(inst); | 461 | ctx = crypto_instance_ctx(inst); |
464 | err = crypto_init_spawn(&ctx->ctr, ctr, inst, CRYPTO_ALG_TYPE_MASK); | 462 | err = crypto_init_spawn(&ctx->ctr, ctr, inst, CRYPTO_ALG_TYPE_MASK); |
465 | if (err) | 463 | if (err) |
466 | goto err_free_inst; | 464 | goto err_free_inst; |
467 | 465 | ||
466 | memcpy(inst->alg.cra_name, full_name, CRYPTO_MAX_ALG_NAME); | ||
467 | |||
468 | inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC; | 468 | inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC; |
469 | inst->alg.cra_priority = ctr->cra_priority; | 469 | inst->alg.cra_priority = ctr->cra_priority; |
470 | inst->alg.cra_blocksize = 16; | 470 | inst->alg.cra_blocksize = 1; |
471 | inst->alg.cra_alignmask = ctr->cra_alignmask | (__alignof__(u64) - 1); | 471 | inst->alg.cra_alignmask = ctr->cra_alignmask | (__alignof__(u64) - 1); |
472 | inst->alg.cra_type = &crypto_aead_type; | 472 | inst->alg.cra_type = &crypto_aead_type; |
473 | inst->alg.cra_aead.ivsize = 16; | 473 | inst->alg.cra_aead.ivsize = 16; |
@@ -489,6 +489,29 @@ out_put_ctr: | |||
489 | goto out; | 489 | goto out; |
490 | } | 490 | } |
491 | 491 | ||
492 | static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb) | ||
493 | { | ||
494 | int err; | ||
495 | const char *cipher_name; | ||
496 | char ctr_name[CRYPTO_MAX_ALG_NAME]; | ||
497 | char full_name[CRYPTO_MAX_ALG_NAME]; | ||
498 | |||
499 | cipher_name = crypto_attr_alg_name(tb[1]); | ||
500 | err = PTR_ERR(cipher_name); | ||
501 | if (IS_ERR(cipher_name)) | ||
502 | return ERR_PTR(err); | ||
503 | |||
504 | if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >= | ||
505 | CRYPTO_MAX_ALG_NAME) | ||
506 | return ERR_PTR(-ENAMETOOLONG); | ||
507 | |||
508 | if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >= | ||
509 | CRYPTO_MAX_ALG_NAME) | ||
510 | return ERR_PTR(-ENAMETOOLONG); | ||
511 | |||
512 | return crypto_gcm_alloc_common(tb, full_name, ctr_name); | ||
513 | } | ||
514 | |||
492 | static void crypto_gcm_free(struct crypto_instance *inst) | 515 | static void crypto_gcm_free(struct crypto_instance *inst) |
493 | { | 516 | { |
494 | struct gcm_instance_ctx *ctx = crypto_instance_ctx(inst); | 517 | struct gcm_instance_ctx *ctx = crypto_instance_ctx(inst); |
@@ -504,14 +527,55 @@ static struct crypto_template crypto_gcm_tmpl = { | |||
504 | .module = THIS_MODULE, | 527 | .module = THIS_MODULE, |
505 | }; | 528 | }; |
506 | 529 | ||
530 | static struct crypto_instance *crypto_gcm_base_alloc(struct rtattr **tb) | ||
531 | { | ||
532 | int err; | ||
533 | const char *ctr_name; | ||
534 | char full_name[CRYPTO_MAX_ALG_NAME]; | ||
535 | |||
536 | ctr_name = crypto_attr_alg_name(tb[1]); | ||
537 | err = PTR_ERR(ctr_name); | ||
538 | if (IS_ERR(ctr_name)) | ||
539 | return ERR_PTR(err); | ||
540 | |||
541 | if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s)", | ||
542 | ctr_name) >= CRYPTO_MAX_ALG_NAME) | ||
543 | return ERR_PTR(-ENAMETOOLONG); | ||
544 | |||
545 | return crypto_gcm_alloc_common(tb, full_name, ctr_name); | ||
546 | } | ||
547 | |||
548 | static struct crypto_template crypto_gcm_base_tmpl = { | ||
549 | .name = "gcm_base", | ||
550 | .alloc = crypto_gcm_base_alloc, | ||
551 | .free = crypto_gcm_free, | ||
552 | .module = THIS_MODULE, | ||
553 | }; | ||
554 | |||
507 | static int __init crypto_gcm_module_init(void) | 555 | static int __init crypto_gcm_module_init(void) |
508 | { | 556 | { |
509 | return crypto_register_template(&crypto_gcm_tmpl); | 557 | int err; |
558 | |||
559 | err = crypto_register_template(&crypto_gcm_base_tmpl); | ||
560 | if (err) | ||
561 | goto out; | ||
562 | |||
563 | err = crypto_register_template(&crypto_gcm_tmpl); | ||
564 | if (err) | ||
565 | goto out_undo_base; | ||
566 | |||
567 | out: | ||
568 | return err; | ||
569 | |||
570 | out_undo_base: | ||
571 | crypto_unregister_template(&crypto_gcm_base_tmpl); | ||
572 | goto out; | ||
510 | } | 573 | } |
511 | 574 | ||
512 | static void __exit crypto_gcm_module_exit(void) | 575 | static void __exit crypto_gcm_module_exit(void) |
513 | { | 576 | { |
514 | crypto_unregister_template(&crypto_gcm_tmpl); | 577 | crypto_unregister_template(&crypto_gcm_tmpl); |
578 | crypto_unregister_template(&crypto_gcm_base_tmpl); | ||
515 | } | 579 | } |
516 | 580 | ||
517 | module_init(crypto_gcm_module_init); | 581 | module_init(crypto_gcm_module_init); |
@@ -520,3 +584,4 @@ module_exit(crypto_gcm_module_exit); | |||
520 | MODULE_LICENSE("GPL"); | 584 | MODULE_LICENSE("GPL"); |
521 | MODULE_DESCRIPTION("Galois/Counter Mode"); | 585 | MODULE_DESCRIPTION("Galois/Counter Mode"); |
522 | MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>"); | 586 | MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>"); |
587 | MODULE_ALIAS("gcm_base"); | ||