s390/crypto: Support for SHA3 via CPACF (MSA6)
authorJoerg Schmidbauer <jschmidb@de.ibm.com>
Wed, 14 Aug 2019 12:56:54 +0000 (14:56 +0200)
committerHeiko Carstens <heiko.carstens@de.ibm.com>
Fri, 13 Sep 2019 10:18:50 +0000 (12:18 +0200)
This patch introduces sha3 support for s390.

- Rework the s390-specific SHA1 and SHA2 related code to
  provide the basis for SHA3.
- Provide two new kernel modules sha3_256_s390 and
  sha3_512_s390 together with new kernel options.

Signed-off-by: Joerg Schmidbauer <jschmidb@de.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/crypto/Makefile
arch/s390/crypto/sha.h
arch/s390/crypto/sha3_256_s390.c [new file with mode: 0644]
arch/s390/crypto/sha3_512_s390.c [new file with mode: 0644]
arch/s390/crypto/sha_common.c
arch/s390/include/asm/cpacf.h
drivers/crypto/Kconfig

index e26d441..a08e3dc 100644 (file)
@@ -723,6 +723,8 @@ CONFIG_CRYPTO_PAES_S390=m
 CONFIG_CRYPTO_SHA1_S390=m
 CONFIG_CRYPTO_SHA256_S390=m
 CONFIG_CRYPTO_SHA512_S390=m
+CONFIG_CRYPTO_SHA3_256_S390=m
+CONFIG_CRYPTO_SHA3_512_S390=m
 CONFIG_CRYPTO_DES_S390=m
 CONFIG_CRYPTO_AES_S390=m
 CONFIG_CRYPTO_GHASH_S390=m
index e4bc400..3c3515d 100644 (file)
@@ -665,6 +665,8 @@ CONFIG_CRYPTO_PAES_S390=m
 CONFIG_CRYPTO_SHA1_S390=m
 CONFIG_CRYPTO_SHA256_S390=m
 CONFIG_CRYPTO_SHA512_S390=m
+CONFIG_CRYPTO_SHA3_256_S390=m
+CONFIG_CRYPTO_SHA3_512_S390=m
 CONFIG_CRYPTO_DES_S390=m
 CONFIG_CRYPTO_AES_S390=m
 CONFIG_CRYPTO_GHASH_S390=m
index a51010e..12889d4 100644 (file)
@@ -6,6 +6,8 @@
 obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o sha_common.o
 obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o sha_common.o
 obj-$(CONFIG_CRYPTO_SHA512_S390) += sha512_s390.o sha_common.o
+obj-$(CONFIG_CRYPTO_SHA3_256_S390) += sha3_256_s390.o sha_common.o
+obj-$(CONFIG_CRYPTO_SHA3_512_S390) += sha3_512_s390.o sha_common.o
 obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o
 obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
 obj-$(CONFIG_CRYPTO_PAES_S390) += paes_s390.o
index d6f8258..ada2f98 100644 (file)
 
 #include <linux/crypto.h>
 #include <crypto/sha.h>
+#include <crypto/sha3.h>
 
 /* must be big enough for the largest SHA variant */
-#define SHA_MAX_STATE_SIZE     (SHA512_DIGEST_SIZE / 4)
-#define SHA_MAX_BLOCK_SIZE      SHA512_BLOCK_SIZE
+#define SHA3_STATE_SIZE                        200
+#define CPACF_MAX_PARMBLOCK_SIZE       SHA3_STATE_SIZE
+#define SHA_MAX_BLOCK_SIZE             SHA3_224_BLOCK_SIZE
 
 struct s390_sha_ctx {
-       u64 count;              /* message length in bytes */
-       u32 state[SHA_MAX_STATE_SIZE];
-       u8 buf[2 * SHA_MAX_BLOCK_SIZE];
+       u64 count;              /* message length in bytes */
+       u32 state[CPACF_MAX_PARMBLOCK_SIZE / sizeof(u32)];
+       u8 buf[SHA_MAX_BLOCK_SIZE];
        int func;               /* KIMD function to use */
 };
 
diff --git a/arch/s390/crypto/sha3_256_s390.c b/arch/s390/crypto/sha3_256_s390.c
new file mode 100644 (file)
index 0000000..460cbbb
--- /dev/null
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Cryptographic API.
+ *
+ * s390 implementation of the SHA256 and SHA224 Secure Hash Algorithm.
+ *
+ * s390 Version:
+ *   Copyright IBM Corp. 2019
+ *   Author(s): Joerg Schmidbauer (jschmidb@de.ibm.com)
+ */
+#include <crypto/internal/hash.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/cpufeature.h>
+#include <crypto/sha.h>
+#include <crypto/sha3.h>
+#include <asm/cpacf.h>
+
+#include "sha.h"
+
+static int sha3_256_init(struct shash_desc *desc)
+{
+       struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+
+       memset(sctx->state, 0, sizeof(sctx->state));
+       sctx->count = 0;
+       sctx->func = CPACF_KIMD_SHA3_256;
+
+       return 0;
+}
+
+static int sha3_256_export(struct shash_desc *desc, void *out)
+{
+       struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+       struct sha3_state *octx = out;
+
+       octx->rsiz = sctx->count;
+       memcpy(octx->st, sctx->state, sizeof(octx->st));
+       memcpy(octx->buf, sctx->buf, sizeof(octx->buf));
+
+       return 0;
+}
+
+static int sha3_256_import(struct shash_desc *desc, const void *in)
+{
+       struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+       const struct sha3_state *ictx = in;
+
+       sctx->count = ictx->rsiz;
+       memcpy(sctx->state, ictx->st, sizeof(ictx->st));
+       memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+       sctx->func = CPACF_KIMD_SHA3_256;
+
+       return 0;
+}
+
+static int sha3_224_import(struct shash_desc *desc, const void *in)
+{
+       struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+       const struct sha3_state *ictx = in;
+
+       sctx->count = ictx->rsiz;
+       memcpy(sctx->state, ictx->st, sizeof(ictx->st));
+       memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+       sctx->func = CPACF_KIMD_SHA3_224;
+
+       return 0;
+}
+
+static struct shash_alg sha3_256_alg = {
+       .digestsize     =       SHA3_256_DIGEST_SIZE,      /* = 32 */
+       .init           =       sha3_256_init,
+       .update         =       s390_sha_update,
+       .final          =       s390_sha_final,
+       .export         =       sha3_256_export,
+       .import         =       sha3_256_import,
+       .descsize       =       sizeof(struct s390_sha_ctx),
+       .statesize      =       sizeof(struct sha3_state),
+       .base           =       {
+               .cra_name        =      "sha3-256",
+               .cra_driver_name =      "sha3-256-s390",
+               .cra_priority    =      300,
+               .cra_blocksize   =      SHA3_256_BLOCK_SIZE,
+               .cra_module      =      THIS_MODULE,
+       }
+};
+
+static int sha3_224_init(struct shash_desc *desc)
+{
+       struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+
+       memset(sctx->state, 0, sizeof(sctx->state));
+       sctx->count = 0;
+       sctx->func = CPACF_KIMD_SHA3_224;
+
+       return 0;
+}
+
+static struct shash_alg sha3_224_alg = {
+       .digestsize     =       SHA3_224_DIGEST_SIZE,
+       .init           =       sha3_224_init,
+       .update         =       s390_sha_update,
+       .final          =       s390_sha_final,
+       .export         =       sha3_256_export, /* same as for 256 */
+       .import         =       sha3_224_import, /* function code different! */
+       .descsize       =       sizeof(struct s390_sha_ctx),
+       .statesize      =       sizeof(struct sha3_state),
+       .base           =       {
+               .cra_name        =      "sha3-224",
+               .cra_driver_name =      "sha3-224-s390",
+               .cra_priority    =      300,
+               .cra_blocksize   =      SHA3_224_BLOCK_SIZE,
+               .cra_module      =      THIS_MODULE,
+       }
+};
+
+static int __init sha3_256_s390_init(void)
+{
+       int ret;
+
+       if (!cpacf_query_func(CPACF_KIMD, CPACF_KIMD_SHA3_256))
+               return -ENODEV;
+
+       ret = crypto_register_shash(&sha3_256_alg);
+       if (ret < 0)
+               goto out;
+
+       ret = crypto_register_shash(&sha3_224_alg);
+       if (ret < 0)
+               crypto_unregister_shash(&sha3_256_alg);
+out:
+       return ret;
+}
+
+static void __exit sha3_256_s390_fini(void)
+{
+       crypto_unregister_shash(&sha3_224_alg);
+       crypto_unregister_shash(&sha3_256_alg);
+}
+
+module_cpu_feature_match(MSA, sha3_256_s390_init);
+module_exit(sha3_256_s390_fini);
+
+MODULE_ALIAS_CRYPTO("sha3-256");
+MODULE_ALIAS_CRYPTO("sha3-224");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SHA3-256 and SHA3-224 Secure Hash Algorithm");
diff --git a/arch/s390/crypto/sha3_512_s390.c b/arch/s390/crypto/sha3_512_s390.c
new file mode 100644 (file)
index 0000000..72cf460
--- /dev/null
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Cryptographic API.
+ *
+ * s390 implementation of the SHA512 and SHA384 Secure Hash Algorithm.
+ *
+ * Copyright IBM Corp. 2019
+ * Author(s): Joerg Schmidbauer (jschmidb@de.ibm.com)
+ */
+#include <crypto/internal/hash.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/cpufeature.h>
+#include <crypto/sha.h>
+#include <crypto/sha3.h>
+#include <asm/cpacf.h>
+
+#include "sha.h"
+
+static int sha3_512_init(struct shash_desc *desc)
+{
+       struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+
+       memset(sctx->state, 0, sizeof(sctx->state));
+       sctx->count = 0;
+       sctx->func = CPACF_KIMD_SHA3_512;
+
+       return 0;
+}
+
+static int sha3_512_export(struct shash_desc *desc, void *out)
+{
+       struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+       struct sha3_state *octx = out;
+
+       octx->rsiz = sctx->count;
+       octx->rsizw = sctx->count >> 32;
+
+       memcpy(octx->st, sctx->state, sizeof(octx->st));
+       memcpy(octx->buf, sctx->buf, sizeof(octx->buf));
+
+       return 0;
+}
+
+static int sha3_512_import(struct shash_desc *desc, const void *in)
+{
+       struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+       const struct sha3_state *ictx = in;
+
+       if (unlikely(ictx->rsizw))
+               return -ERANGE;
+       sctx->count = ictx->rsiz;
+
+       memcpy(sctx->state, ictx->st, sizeof(ictx->st));
+       memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+       sctx->func = CPACF_KIMD_SHA3_512;
+
+       return 0;
+}
+
+static int sha3_384_import(struct shash_desc *desc, const void *in)
+{
+       struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+       const struct sha3_state *ictx = in;
+
+       if (unlikely(ictx->rsizw))
+               return -ERANGE;
+       sctx->count = ictx->rsiz;
+
+       memcpy(sctx->state, ictx->st, sizeof(ictx->st));
+       memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+       sctx->func = CPACF_KIMD_SHA3_384;
+
+       return 0;
+}
+
+static struct shash_alg sha3_512_alg = {
+       .digestsize     =       SHA3_512_DIGEST_SIZE,
+       .init           =       sha3_512_init,
+       .update         =       s390_sha_update,
+       .final          =       s390_sha_final,
+       .export         =       sha3_512_export,
+       .import         =       sha3_512_import,
+       .descsize       =       sizeof(struct s390_sha_ctx),
+       .statesize      =       sizeof(struct sha3_state),
+       .base           =       {
+               .cra_name        =      "sha3-512",
+               .cra_driver_name =      "sha3-512-s390",
+               .cra_priority    =      300,
+               .cra_blocksize   =      SHA3_512_BLOCK_SIZE,
+               .cra_module      =      THIS_MODULE,
+       }
+};
+
+MODULE_ALIAS_CRYPTO("sha3-512");
+
+static int sha3_384_init(struct shash_desc *desc)
+{
+       struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+
+       memset(sctx->state, 0, sizeof(sctx->state));
+       sctx->count = 0;
+       sctx->func = CPACF_KIMD_SHA3_384;
+
+       return 0;
+}
+
+static struct shash_alg sha3_384_alg = {
+       .digestsize     =       SHA3_384_DIGEST_SIZE,
+       .init           =       sha3_384_init,
+       .update         =       s390_sha_update,
+       .final          =       s390_sha_final,
+       .export         =       sha3_512_export, /* same as for 512 */
+       .import         =       sha3_384_import, /* function code different! */
+       .descsize       =       sizeof(struct s390_sha_ctx),
+       .statesize      =       sizeof(struct sha3_state),
+       .base           =       {
+               .cra_name        =      "sha3-384",
+               .cra_driver_name =      "sha3-384-s390",
+               .cra_priority    =      300,
+               .cra_blocksize   =      SHA3_384_BLOCK_SIZE,
+               .cra_ctxsize     =      sizeof(struct s390_sha_ctx),
+               .cra_module      =      THIS_MODULE,
+       }
+};
+
+MODULE_ALIAS_CRYPTO("sha3-384");
+
+static int __init init(void)
+{
+       int ret;
+
+       if (!cpacf_query_func(CPACF_KIMD, CPACF_KIMD_SHA3_512))
+               return -ENODEV;
+       ret = crypto_register_shash(&sha3_512_alg);
+       if (ret < 0)
+               goto out;
+       ret = crypto_register_shash(&sha3_384_alg);
+       if (ret < 0)
+               crypto_unregister_shash(&sha3_512_alg);
+out:
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       crypto_unregister_shash(&sha3_512_alg);
+       crypto_unregister_shash(&sha3_384_alg);
+}
+
+module_cpu_feature_match(MSA, init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SHA3-512 and SHA3-384 Secure Hash Algorithm");
index cf0718d..d39e0f0 100644 (file)
@@ -20,7 +20,7 @@ int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len)
        unsigned int index, n;
 
        /* how much is already in the buffer? */
-       index = ctx->count & (bsize - 1);
+       index = ctx->count % bsize;
        ctx->count += len;
 
        if ((index + len) < bsize)
@@ -37,7 +37,7 @@ int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len)
 
        /* process as many blocks as possible */
        if (len >= bsize) {
-               n = len & ~(bsize - 1);
+               n = (len / bsize) * bsize;
                cpacf_kimd(ctx->func, ctx->state, data, n);
                data += n;
                len -= n;
@@ -50,34 +50,63 @@ store:
 }
 EXPORT_SYMBOL_GPL(s390_sha_update);
 
+static int s390_crypto_shash_parmsize(int func)
+{
+       switch (func) {
+       case CPACF_KLMD_SHA_1:
+               return 20;
+       case CPACF_KLMD_SHA_256:
+               return 32;
+       case CPACF_KLMD_SHA_512:
+               return 64;
+       case CPACF_KLMD_SHA3_224:
+       case CPACF_KLMD_SHA3_256:
+       case CPACF_KLMD_SHA3_384:
+       case CPACF_KLMD_SHA3_512:
+               return 200;
+       default:
+               return -EINVAL;
+       }
+}
+
 int s390_sha_final(struct shash_desc *desc, u8 *out)
 {
        struct s390_sha_ctx *ctx = shash_desc_ctx(desc);
        unsigned int bsize = crypto_shash_blocksize(desc->tfm);
        u64 bits;
-       unsigned int index, end, plen;
-
-       /* SHA-512 uses 128 bit padding length */
-       plen = (bsize > SHA256_BLOCK_SIZE) ? 16 : 8;
+       unsigned int n, mbl_offset;
 
-       /* must perform manual padding */
-       index = ctx->count & (bsize - 1);
-       end = (index < bsize - plen) ? bsize : (2 * bsize);
-
-       /* start pad with 1 */
-       ctx->buf[index] = 0x80;
-       index++;
-
-       /* pad with zeros */
-       memset(ctx->buf + index, 0x00, end - index - 8);
-
-       /*
-        * Append message length. Well, SHA-512 wants a 128 bit length value,
-        * nevertheless we use u64, should be enough for now...
-        */
+       n = ctx->count % bsize;
        bits = ctx->count * 8;
-       memcpy(ctx->buf + end - 8, &bits, sizeof(bits));
-       cpacf_kimd(ctx->func, ctx->state, ctx->buf, end);
+       mbl_offset = s390_crypto_shash_parmsize(ctx->func) / sizeof(u32);
+       if (mbl_offset < 0)
+               return -EINVAL;
+
+       /* set total msg bit length (mbl) in CPACF parmblock */
+       switch (ctx->func) {
+       case CPACF_KLMD_SHA_1:
+       case CPACF_KLMD_SHA_256:
+               memcpy(ctx->state + mbl_offset, &bits, sizeof(bits));
+               break;
+       case CPACF_KLMD_SHA_512:
+               /*
+                * the SHA512 parmblock has a 128-bit mbl field, clear
+                * high-order u64 field, copy bits to low-order u64 field
+                */
+               memset(ctx->state + mbl_offset, 0x00, sizeof(bits));
+               mbl_offset += sizeof(u64) / sizeof(u32);
+               memcpy(ctx->state + mbl_offset, &bits, sizeof(bits));
+               break;
+       case CPACF_KLMD_SHA3_224:
+       case CPACF_KLMD_SHA3_256:
+       case CPACF_KLMD_SHA3_384:
+       case CPACF_KLMD_SHA3_512:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       cpacf_klmd(ctx->func, ctx->state, ctx->buf, n);
 
        /* copy digest to out */
        memcpy(out, ctx->state, crypto_shash_digestsize(desc->tfm));
index e3d53eb..a092f63 100644 (file)
 #define CPACF_KIMD_SHA_1       0x01
 #define CPACF_KIMD_SHA_256     0x02
 #define CPACF_KIMD_SHA_512     0x03
+#define CPACF_KIMD_SHA3_224    0x20
+#define CPACF_KIMD_SHA3_256    0x21
+#define CPACF_KIMD_SHA3_384    0x22
+#define CPACF_KIMD_SHA3_512    0x23
 #define CPACF_KIMD_GHASH       0x41
 
 /*
 #define CPACF_KLMD_SHA_1       0x01
 #define CPACF_KLMD_SHA_256     0x02
 #define CPACF_KLMD_SHA_512     0x03
+#define CPACF_KLMD_SHA3_224    0x20
+#define CPACF_KLMD_SHA3_256    0x21
+#define CPACF_KLMD_SHA3_384    0x22
+#define CPACF_KLMD_SHA3_512    0x23
 
 /*
  * function codes for the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
index 603413f..d7c85c7 100644 (file)
@@ -145,6 +145,26 @@ config CRYPTO_SHA512_S390
 
          It is available as of z10.
 
+config CRYPTO_SHA3_256_S390
+       tristate "SHA3_224 and SHA3_256 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA3_256 secure hash standard.
+
+         It is available as of z14.
+
+config CRYPTO_SHA3_512_S390
+       tristate "SHA3_384 and SHA3_512 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA3_512 secure hash standard.
+
+         It is available as of z14.
+
 config CRYPTO_DES_S390
        tristate "DES and Triple DES cipher algorithms"
        depends on S390