From: Hans-Joachim Picht <hpicht@redhat.com> Date: Wed, 9 Jan 2008 17:24:22 +0100 Subject: [s390] crypto: new CP assist functions Message-id: 20080109162422.GD27770@redhat.com O-Subject: [RHEL5 U2 PATCH 4/4 ] In-Kernel crypto exploitation of new CP Assist functions (AES 192 / 256 and SHA 384 / 512) Bugzilla: 318961 Description ============ Support for hardware accelerated in-kernel crypto, used to improve performance for encryption (e.g. crypto file systems) and to provide better protection against key breakage. Bugzilla ========= BZ 318961 https://bugzilla.redhat.com/show_bug.cgi?id=318961 Upstream status of the patch: ============================= The code will be submitted upstream soon. Test status: ============ Kernel with patch was built and successfully tested Please ACK. With best regards, Hans -- arch/s390/crypto/Makefile | 1 arch/s390/crypto/crypt_s390.h | 2 arch/s390/crypto/sha512_s390.c | 202 +++++++++++++++++++++++++++++++++++++++++ crypto/Kconfig | 13 ++ 4 files changed, 218 insertions(+) diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile index fcf8237..9ed8ee0 100644 --- a/arch/s390/crypto/Makefile +++ b/arch/s390/crypto/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o +obj-$(CONFIG_CRYPTO_SHA512_S390) += sha512_s390.o obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o obj-$(CONFIG_S390_PRNG) += prng.o diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h index 6edc0f6..9298094 100644 --- a/arch/s390/crypto/crypt_s390.h +++ b/arch/s390/crypto/crypt_s390.h @@ -75,6 +75,7 @@ enum crypt_s390_kimd_func { KIMD_QUERY = CRYPT_S390_KIMD | 0, KIMD_SHA_1 = CRYPT_S390_KIMD | 1, KIMD_SHA_256 = CRYPT_S390_KIMD | 2, + KIMD_SHA_512 = CRYPT_S390_KIMD | 3, }; /* function codes for KLMD (COMPUTE LAST MESSAGE DIGEST) @@ -84,6 +85,7 @@ enum crypt_s390_klmd_func { KLMD_QUERY = CRYPT_S390_KLMD | 0, KLMD_SHA_1 = CRYPT_S390_KLMD | 1, KLMD_SHA_256 = CRYPT_S390_KLMD | 2, + KLMD_SHA_512 = CRYPT_S390_KLMD | 3, }; /* function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) diff --git a/arch/s390/crypto/sha512_s390.c b/arch/s390/crypto/sha512_s390.c new file mode 100644 index 0000000..d587b4c --- /dev/null +++ b/arch/s390/crypto/sha512_s390.c @@ -0,0 +1,202 @@ +/* + * Cryptographic API. + * + * s390 implementation of the SHA512 Secure Hash Algorithm. + * + * Copyright IBM Corp. 2007 + * Author(s): Jan Glauber (jang@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/crypto.h> + +#include "crypt_s390.h" + +#define SHA384_DIGEST_SIZE 48 +#define SHA384_BLOCK_SIZE 128 + +#define SHA512_DIGEST_SIZE 64 +#define SHA512_BLOCK_SIZE 128 + +struct s390_sha512_ctx { + u64 count; + u64 state[8]; + u8 buf[2 * SHA512_BLOCK_SIZE]; +}; + +static void sha512_init(struct crypto_tfm *tfm) +{ + struct s390_sha512_ctx *sctx = crypto_tfm_ctx(tfm); + + sctx->state[0] = 0x6a09e667f3bcc908ULL; + sctx->state[1] = 0xbb67ae8584caa73bULL; + sctx->state[2] = 0x3c6ef372fe94f82bULL; + sctx->state[3] = 0xa54ff53a5f1d36f1ULL; + sctx->state[4] = 0x510e527fade682d1ULL; + sctx->state[5] = 0x9b05688c2b3e6c1fULL; + sctx->state[6] = 0x1f83d9abfb41bd6bULL; + sctx->state[7] = 0x5be0cd19137e2179ULL; + sctx->count = 0; + memset(sctx->buf, 0, sizeof(sctx->buf)); +} + +static void sha384_init(struct crypto_tfm *tfm) +{ + struct s390_sha512_ctx *sctx = crypto_tfm_ctx(tfm); + + sctx->state[0] = 0xcbbb9d5dc1059ed8ULL; + sctx->state[1] = 0x629a292a367cd507ULL; + sctx->state[2] = 0x9159015a3070dd17ULL; + sctx->state[3] = 0x152fecd8f70e5939ULL; + sctx->state[4] = 0x67332667ffc00b31ULL; + sctx->state[5] = 0x8eb44a8768581511ULL; + sctx->state[6] = 0xdb0c2e0d64f98fa7ULL; + sctx->state[7] = 0x47b5481dbefa4fa4ULL; + sctx->count = 0; + memset(sctx->buf, 0, sizeof(sctx->buf)); +} + +static void sha512_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) +{ + struct s390_sha512_ctx *sctx = crypto_tfm_ctx(tfm); + unsigned int bsize = SHA512_BLOCK_SIZE; + unsigned int index; + int ret; + + /* how much is already in the buffer? */ + index = sctx->count & (bsize - 1); + sctx->count += len; + + if ((index + len) < bsize) + goto store; + + /* process one stored block */ + if (index) { + memcpy(sctx->buf + index, data, bsize - index); + ret = crypt_s390_kimd(KIMD_SHA_512, sctx->state, sctx->buf, bsize); + BUG_ON(ret != bsize); + data += bsize - index; + len -= bsize - index; + } + + /* process as many blocks as possible */ + if (len >= bsize) { + ret = crypt_s390_kimd(KIMD_SHA_512, sctx->state, data, len & ~(bsize - 1)); + BUG_ON(ret != (len & ~(bsize - 1))); + data += ret; + len -= ret; + } +store: + /* anything left? */ + if (len) + memcpy(sctx->buf + index , data, len); +} + +static void sha512_final(struct crypto_tfm *tfm, u8 *out) +{ + struct s390_sha512_ctx *sctx = crypto_tfm_ctx(tfm); + unsigned int bsize = SHA512_BLOCK_SIZE; + u64 bits; + unsigned int index, end; + int ret; + + /* must perform manual padding */ + index = sctx->count & (bsize - 1); + end = (index < bsize - 16) ? bsize : (2 * bsize); + + sctx->buf[index] = 0x80; /* start pad with 1 */ + index++; + + /* pad with zeros */ + memset(sctx->buf + index, 0x00, end - index - 8); + + /* + * Append message length. Well, SHA-512 wants a 128 bit lenght value, + * nevertheless I use u64, 64 bit message length should be enough for now. + */ + bits = sctx->count * 8; + memcpy(sctx->buf + end - 8, &bits, sizeof(bits)); + + ret = crypt_s390_kimd(KIMD_SHA_512, sctx->state, sctx->buf, end); + BUG_ON(ret != end); + + memcpy(out, sctx->state, SHA512_DIGEST_SIZE); /* copy digest to out */ + memset(sctx, 0, sizeof *sctx); /* wipe context */ +} + +static void sha384_final(struct crypto_tfm *tfm, u8 *out) +{ + struct s390_sha512_ctx *sctx = crypto_tfm_ctx(tfm); + u8 hash[SHA512_DIGEST_SIZE]; + + sha512_final(tfm, hash); + + memcpy(out, hash, SHA384_DIGEST_SIZE); /* copy digest to out */ + memset(sctx, 0, sizeof *sctx); /* wipe context */ +} + +static struct crypto_alg sha512_alg = { + .cra_name = "sha512", + .cra_driver_name = "sha512-s390", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = SHA512_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s390_sha512_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(sha512_alg.cra_list), + .cra_u = { .digest = { + .dia_digestsize = SHA512_DIGEST_SIZE, + .dia_init = sha512_init, + .dia_update = sha512_update, + .dia_final = sha512_final } } +}; + +static struct crypto_alg sha384_alg = { + .cra_name = "sha384", + .cra_driver_name = "sha384-s390", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = SHA384_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s390_sha512_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(sha384_alg.cra_list), + .cra_u = { .digest = { + .dia_digestsize = SHA384_DIGEST_SIZE, + .dia_init = sha384_init, + .dia_update = sha512_update, + .dia_final = sha384_final } } +}; + +static int __init init(void) +{ + int ret; + + if (!crypt_s390_func_available(KIMD_SHA_512)) + return -EOPNOTSUPP; + ret = crypto_register_alg(&sha512_alg); + if (ret < 0) + goto out; + ret = crypto_register_alg(&sha384_alg); + if (ret < 0) + crypto_unregister_alg(&sha512_alg); +out: + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&sha512_alg); + crypto_unregister_alg(&sha384_alg); +} + +module_init(init); +module_exit(fini); + +MODULE_ALIAS("sha512"); +MODULE_ALIAS("sha384"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA512 and SHA-384 Secure Hash Algorithm"); diff --git a/crypto/Kconfig b/crypto/Kconfig index 9169915..82107d2 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -144,6 +144,19 @@ config CRYPTO_SHA512 This code also includes SHA-384, a 384 bit hash with 192 bits of security against collision attacks. +config CRYPTO_SHA512_S390 + tristate "SHA384 and SHA512 digest algorithms (s390)" + depends on CRYPTO && S390 + help + SHA512 secure hash standard (DFIPS 180-2). + + This is the s390 hardware accelerated implementation of SHA + implementing a 512 bit hash with 256 bits of + security against collision attacks. + + This code also includes SHA-384, a 384 bit hash with 192 bits + of security against collision attacks. + config CRYPTO_WP512 tristate "Whirlpool digest algorithms" depends on CRYPTO