diff options
author | Gerald Schaefer <gerald.schaefer@de.ibm.com> | 2011-05-04 01:09:44 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2011-05-04 01:09:44 -0400 |
commit | 0200f3ecc19660bebeabbcbaf212957fcf1dbf8f (patch) | |
tree | 584b5b936a58f3d9db09fca73ed10bdf20f942f5 /arch/s390/crypto/des_s390.c | |
parent | 9996e3421cae20a17c99881b2ac0f7562f760e04 (diff) |
crypto: s390 - add System z hardware support for CTR mode
This patch adds System z hardware acceleration support for AES, DES
and 3DES in CTR mode. The hardware support is available starting with
System z196.
Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'arch/s390/crypto/des_s390.c')
-rw-r--r-- | arch/s390/crypto/des_s390.c | 169 |
1 files changed, 168 insertions, 1 deletions
diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index c36a01d70e04..a52bfd124d86 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * s390 implementation of the DES Cipher Algorithm. | 4 | * s390 implementation of the DES Cipher Algorithm. |
5 | * | 5 | * |
6 | * Copyright IBM Corp. 2003,2007 | 6 | * Copyright IBM Corp. 2003,2011 |
7 | * Author(s): Thomas Spatzier | 7 | * Author(s): Thomas Spatzier |
8 | * Jan Glauber (jan.glauber@de.ibm.com) | 8 | * Jan Glauber (jan.glauber@de.ibm.com) |
9 | * | 9 | * |
@@ -24,6 +24,8 @@ | |||
24 | 24 | ||
25 | #define DES3_KEY_SIZE (3 * DES_KEY_SIZE) | 25 | #define DES3_KEY_SIZE (3 * DES_KEY_SIZE) |
26 | 26 | ||
27 | static u8 *ctrblk; | ||
28 | |||
27 | struct s390_des_ctx { | 29 | struct s390_des_ctx { |
28 | u8 iv[DES_BLOCK_SIZE]; | 30 | u8 iv[DES_BLOCK_SIZE]; |
29 | u8 key[DES3_KEY_SIZE]; | 31 | u8 key[DES3_KEY_SIZE]; |
@@ -370,6 +372,143 @@ static struct crypto_alg cbc_des3_alg = { | |||
370 | } | 372 | } |
371 | }; | 373 | }; |
372 | 374 | ||
375 | static int ctr_desall_crypt(struct blkcipher_desc *desc, long func, | ||
376 | struct s390_des_ctx *ctx, struct blkcipher_walk *walk) | ||
377 | { | ||
378 | int ret = blkcipher_walk_virt_block(desc, walk, DES_BLOCK_SIZE); | ||
379 | unsigned int i, n, nbytes; | ||
380 | u8 buf[DES_BLOCK_SIZE]; | ||
381 | u8 *out, *in; | ||
382 | |||
383 | memcpy(ctrblk, walk->iv, DES_BLOCK_SIZE); | ||
384 | while ((nbytes = walk->nbytes) >= DES_BLOCK_SIZE) { | ||
385 | out = walk->dst.virt.addr; | ||
386 | in = walk->src.virt.addr; | ||
387 | while (nbytes >= DES_BLOCK_SIZE) { | ||
388 | /* align to block size, max. PAGE_SIZE */ | ||
389 | n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : | ||
390 | nbytes & ~(DES_BLOCK_SIZE - 1); | ||
391 | for (i = DES_BLOCK_SIZE; i < n; i += DES_BLOCK_SIZE) { | ||
392 | memcpy(ctrblk + i, ctrblk + i - DES_BLOCK_SIZE, | ||
393 | DES_BLOCK_SIZE); | ||
394 | crypto_inc(ctrblk + i, DES_BLOCK_SIZE); | ||
395 | } | ||
396 | ret = crypt_s390_kmctr(func, ctx->key, out, in, n, ctrblk); | ||
397 | BUG_ON((ret < 0) || (ret != n)); | ||
398 | if (n > DES_BLOCK_SIZE) | ||
399 | memcpy(ctrblk, ctrblk + n - DES_BLOCK_SIZE, | ||
400 | DES_BLOCK_SIZE); | ||
401 | crypto_inc(ctrblk, DES_BLOCK_SIZE); | ||
402 | out += n; | ||
403 | in += n; | ||
404 | nbytes -= n; | ||
405 | } | ||
406 | ret = blkcipher_walk_done(desc, walk, nbytes); | ||
407 | } | ||
408 | |||
409 | /* final block may be < DES_BLOCK_SIZE, copy only nbytes */ | ||
410 | if (nbytes) { | ||
411 | out = walk->dst.virt.addr; | ||
412 | in = walk->src.virt.addr; | ||
413 | ret = crypt_s390_kmctr(func, ctx->key, buf, in, | ||
414 | DES_BLOCK_SIZE, ctrblk); | ||
415 | BUG_ON(ret < 0 || ret != DES_BLOCK_SIZE); | ||
416 | memcpy(out, buf, nbytes); | ||
417 | crypto_inc(ctrblk, DES_BLOCK_SIZE); | ||
418 | ret = blkcipher_walk_done(desc, walk, 0); | ||
419 | } | ||
420 | memcpy(walk->iv, ctrblk, DES_BLOCK_SIZE); | ||
421 | return ret; | ||
422 | } | ||
423 | |||
424 | static int ctr_des_encrypt(struct blkcipher_desc *desc, | ||
425 | struct scatterlist *dst, struct scatterlist *src, | ||
426 | unsigned int nbytes) | ||
427 | { | ||
428 | struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); | ||
429 | struct blkcipher_walk walk; | ||
430 | |||
431 | blkcipher_walk_init(&walk, dst, src, nbytes); | ||
432 | return ctr_desall_crypt(desc, KMCTR_DEA_ENCRYPT, ctx, &walk); | ||
433 | } | ||
434 | |||
435 | static int ctr_des_decrypt(struct blkcipher_desc *desc, | ||
436 | struct scatterlist *dst, struct scatterlist *src, | ||
437 | unsigned int nbytes) | ||
438 | { | ||
439 | struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); | ||
440 | struct blkcipher_walk walk; | ||
441 | |||
442 | blkcipher_walk_init(&walk, dst, src, nbytes); | ||
443 | return ctr_desall_crypt(desc, KMCTR_DEA_DECRYPT, ctx, &walk); | ||
444 | } | ||
445 | |||
446 | static struct crypto_alg ctr_des_alg = { | ||
447 | .cra_name = "ctr(des)", | ||
448 | .cra_driver_name = "ctr-des-s390", | ||
449 | .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, | ||
450 | .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, | ||
451 | .cra_blocksize = 1, | ||
452 | .cra_ctxsize = sizeof(struct s390_des_ctx), | ||
453 | .cra_type = &crypto_blkcipher_type, | ||
454 | .cra_module = THIS_MODULE, | ||
455 | .cra_list = LIST_HEAD_INIT(ctr_des_alg.cra_list), | ||
456 | .cra_u = { | ||
457 | .blkcipher = { | ||
458 | .min_keysize = DES_KEY_SIZE, | ||
459 | .max_keysize = DES_KEY_SIZE, | ||
460 | .ivsize = DES_BLOCK_SIZE, | ||
461 | .setkey = des_setkey, | ||
462 | .encrypt = ctr_des_encrypt, | ||
463 | .decrypt = ctr_des_decrypt, | ||
464 | } | ||
465 | } | ||
466 | }; | ||
467 | |||
468 | static int ctr_des3_encrypt(struct blkcipher_desc *desc, | ||
469 | struct scatterlist *dst, struct scatterlist *src, | ||
470 | unsigned int nbytes) | ||
471 | { | ||
472 | struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); | ||
473 | struct blkcipher_walk walk; | ||
474 | |||
475 | blkcipher_walk_init(&walk, dst, src, nbytes); | ||
476 | return ctr_desall_crypt(desc, KMCTR_TDEA_192_ENCRYPT, ctx, &walk); | ||
477 | } | ||
478 | |||
479 | static int ctr_des3_decrypt(struct blkcipher_desc *desc, | ||
480 | struct scatterlist *dst, struct scatterlist *src, | ||
481 | unsigned int nbytes) | ||
482 | { | ||
483 | struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); | ||
484 | struct blkcipher_walk walk; | ||
485 | |||
486 | blkcipher_walk_init(&walk, dst, src, nbytes); | ||
487 | return ctr_desall_crypt(desc, KMCTR_TDEA_192_DECRYPT, ctx, &walk); | ||
488 | } | ||
489 | |||
490 | static struct crypto_alg ctr_des3_alg = { | ||
491 | .cra_name = "ctr(des3_ede)", | ||
492 | .cra_driver_name = "ctr-des3_ede-s390", | ||
493 | .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, | ||
494 | .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, | ||
495 | .cra_blocksize = 1, | ||
496 | .cra_ctxsize = sizeof(struct s390_des_ctx), | ||
497 | .cra_type = &crypto_blkcipher_type, | ||
498 | .cra_module = THIS_MODULE, | ||
499 | .cra_list = LIST_HEAD_INIT(ctr_des3_alg.cra_list), | ||
500 | .cra_u = { | ||
501 | .blkcipher = { | ||
502 | .min_keysize = DES3_KEY_SIZE, | ||
503 | .max_keysize = DES3_KEY_SIZE, | ||
504 | .ivsize = DES_BLOCK_SIZE, | ||
505 | .setkey = des3_setkey, | ||
506 | .encrypt = ctr_des3_encrypt, | ||
507 | .decrypt = ctr_des3_decrypt, | ||
508 | } | ||
509 | } | ||
510 | }; | ||
511 | |||
373 | static int __init des_s390_init(void) | 512 | static int __init des_s390_init(void) |
374 | { | 513 | { |
375 | int ret; | 514 | int ret; |
@@ -396,9 +535,32 @@ static int __init des_s390_init(void) | |||
396 | ret = crypto_register_alg(&cbc_des3_alg); | 535 | ret = crypto_register_alg(&cbc_des3_alg); |
397 | if (ret) | 536 | if (ret) |
398 | goto cbc_des3_err; | 537 | goto cbc_des3_err; |
538 | |||
539 | if (crypt_s390_func_available(KMCTR_DEA_ENCRYPT, | ||
540 | CRYPT_S390_MSA | CRYPT_S390_MSA4) && | ||
541 | crypt_s390_func_available(KMCTR_TDEA_192_ENCRYPT, | ||
542 | CRYPT_S390_MSA | CRYPT_S390_MSA4)) { | ||
543 | ret = crypto_register_alg(&ctr_des_alg); | ||
544 | if (ret) | ||
545 | goto ctr_des_err; | ||
546 | ret = crypto_register_alg(&ctr_des3_alg); | ||
547 | if (ret) | ||
548 | goto ctr_des3_err; | ||
549 | ctrblk = (u8 *) __get_free_page(GFP_KERNEL); | ||
550 | if (!ctrblk) { | ||
551 | ret = -ENOMEM; | ||
552 | goto ctr_mem_err; | ||
553 | } | ||
554 | } | ||
399 | out: | 555 | out: |
400 | return ret; | 556 | return ret; |
401 | 557 | ||
558 | ctr_mem_err: | ||
559 | crypto_unregister_alg(&ctr_des3_alg); | ||
560 | ctr_des3_err: | ||
561 | crypto_unregister_alg(&ctr_des_alg); | ||
562 | ctr_des_err: | ||
563 | crypto_unregister_alg(&cbc_des3_alg); | ||
402 | cbc_des3_err: | 564 | cbc_des3_err: |
403 | crypto_unregister_alg(&ecb_des3_alg); | 565 | crypto_unregister_alg(&ecb_des3_alg); |
404 | ecb_des3_err: | 566 | ecb_des3_err: |
@@ -415,6 +577,11 @@ des_err: | |||
415 | 577 | ||
416 | static void __exit des_s390_exit(void) | 578 | static void __exit des_s390_exit(void) |
417 | { | 579 | { |
580 | if (ctrblk) { | ||
581 | crypto_unregister_alg(&ctr_des_alg); | ||
582 | crypto_unregister_alg(&ctr_des3_alg); | ||
583 | free_page((unsigned long) ctrblk); | ||
584 | } | ||
418 | crypto_unregister_alg(&cbc_des3_alg); | 585 | crypto_unregister_alg(&cbc_des3_alg); |
419 | crypto_unregister_alg(&ecb_des3_alg); | 586 | crypto_unregister_alg(&ecb_des3_alg); |
420 | crypto_unregister_alg(&des3_alg); | 587 | crypto_unregister_alg(&des3_alg); |