OSDN Git Service

crypto: morus - Add common SIMD glue code for MORUS
authorOndrej Mosnacek <omosnacek@gmail.com>
Fri, 11 May 2018 12:19:11 +0000 (14:19 +0200)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 18 May 2018 16:15:18 +0000 (00:15 +0800)
This patch adds a common glue code for optimized implementations of
MORUS AEAD algorithms.

Signed-off-by: Ondrej Mosnacek <omosnacek@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/Kconfig
crypto/Makefile
crypto/morus1280_glue.c [new file with mode: 0644]
crypto/morus640_glue.c [new file with mode: 0644]
include/crypto/morus1280_glue.h [new file with mode: 0644]
include/crypto/morus640_glue.h [new file with mode: 0644]

index 7c53547..4761667 100644 (file)
@@ -340,12 +340,28 @@ config CRYPTO_MORUS640
        help
          Support for the MORUS-640 dedicated AEAD algorithm.
 
+config CRYPTO_MORUS640_GLUE
+       tristate "MORUS-640 AEAD algorithm (glue for SIMD optimizations)"
+       select CRYPTO_AEAD
+       select CRYPTO_CRYPTD
+       help
+         Common glue for SIMD optimizations of the MORUS-640 dedicated AEAD
+         algorithm.
+
 config CRYPTO_MORUS1280
        tristate "MORUS-1280 AEAD algorithm"
        select CRYPTO_AEAD
        help
          Support for the MORUS-1280 dedicated AEAD algorithm.
 
+config CRYPTO_MORUS1280_GLUE
+       tristate "MORUS-1280 AEAD algorithm (glue for SIMD optimizations)"
+       select CRYPTO_AEAD
+       select CRYPTO_CRYPTD
+       help
+         Common glue for SIMD optimizations of the MORUS-1280 dedicated AEAD
+         algorithm.
+
 config CRYPTO_SEQIV
        tristate "Sequence Number IV Generator"
        select CRYPTO_AEAD
index 6d1d40e..68a7c54 100644 (file)
@@ -91,6 +91,8 @@ obj-$(CONFIG_CRYPTO_AEGIS128L) += aegis128l.o
 obj-$(CONFIG_CRYPTO_AEGIS256) += aegis256.o
 obj-$(CONFIG_CRYPTO_MORUS640) += morus640.o
 obj-$(CONFIG_CRYPTO_MORUS1280) += morus1280.o
+obj-$(CONFIG_CRYPTO_MORUS640_GLUE) += morus640_glue.o
+obj-$(CONFIG_CRYPTO_MORUS1280_GLUE) += morus1280_glue.o
 obj-$(CONFIG_CRYPTO_PCRYPT) += pcrypt.o
 obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o
 obj-$(CONFIG_CRYPTO_MCRYPTD) += mcryptd.o
diff --git a/crypto/morus1280_glue.c b/crypto/morus1280_glue.c
new file mode 100644 (file)
index 0000000..ce1e5c3
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * The MORUS-1280 Authenticated-Encryption Algorithm
+ *   Common glue skeleton
+ *
+ * Copyright (c) 2016-2018 Ondrej Mosnacek <omosnacek@gmail.com>
+ * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved.
+ *
+ * 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 <crypto/cryptd.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/morus1280_glue.h>
+#include <crypto/scatterwalk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <asm/fpu/api.h>
+
+struct morus1280_state {
+       struct morus1280_block s[MORUS_STATE_BLOCKS];
+};
+
+struct morus1280_ops {
+       int (*skcipher_walk_init)(struct skcipher_walk *walk,
+                                 struct aead_request *req, bool atomic);
+
+       void (*crypt_blocks)(void *state, const void *src, void *dst,
+                            unsigned int length);
+       void (*crypt_tail)(void *state, const void *src, void *dst,
+                          unsigned int length);
+};
+
+static void crypto_morus1280_glue_process_ad(
+               struct morus1280_state *state,
+               const struct morus1280_glue_ops *ops,
+               struct scatterlist *sg_src, unsigned int assoclen)
+{
+       struct scatter_walk walk;
+       struct morus1280_block buf;
+       unsigned int pos = 0;
+
+       scatterwalk_start(&walk, sg_src);
+       while (assoclen != 0) {
+               unsigned int size = scatterwalk_clamp(&walk, assoclen);
+               unsigned int left = size;
+               void *mapped = scatterwalk_map(&walk);
+               const u8 *src = (const u8 *)mapped;
+
+               if (pos + size >= MORUS1280_BLOCK_SIZE) {
+                       if (pos > 0) {
+                               unsigned int fill = MORUS1280_BLOCK_SIZE - pos;
+                               memcpy(buf.bytes + pos, src, fill);
+                               ops->ad(state, buf.bytes, MORUS1280_BLOCK_SIZE);
+                               pos = 0;
+                               left -= fill;
+                               src += fill;
+                       }
+
+                       ops->ad(state, src, left);
+                       src += left & ~(MORUS1280_BLOCK_SIZE - 1);
+                       left &= MORUS1280_BLOCK_SIZE - 1;
+               }
+
+               memcpy(buf.bytes + pos, src, left);
+
+               pos += left;
+               assoclen -= size;
+               scatterwalk_unmap(mapped);
+               scatterwalk_advance(&walk, size);
+               scatterwalk_done(&walk, 0, assoclen);
+       }
+
+       if (pos > 0) {
+               memset(buf.bytes + pos, 0, MORUS1280_BLOCK_SIZE - pos);
+               ops->ad(state, buf.bytes, MORUS1280_BLOCK_SIZE);
+       }
+}
+
+static void crypto_morus1280_glue_process_crypt(struct morus1280_state *state,
+                                               struct morus1280_ops ops,
+                                               struct aead_request *req)
+{
+       struct skcipher_walk walk;
+       u8 *cursor_src, *cursor_dst;
+       unsigned int chunksize, base;
+
+       ops.skcipher_walk_init(&walk, req, false);
+
+       while (walk.nbytes) {
+               cursor_src = walk.src.virt.addr;
+               cursor_dst = walk.dst.virt.addr;
+               chunksize = walk.nbytes;
+
+               ops.crypt_blocks(state, cursor_src, cursor_dst, chunksize);
+
+               base = chunksize & ~(MORUS1280_BLOCK_SIZE - 1);
+               cursor_src += base;
+               cursor_dst += base;
+               chunksize &= MORUS1280_BLOCK_SIZE - 1;
+
+               if (chunksize > 0)
+                       ops.crypt_tail(state, cursor_src, cursor_dst,
+                                      chunksize);
+
+               skcipher_walk_done(&walk, 0);
+       }
+}
+
+int crypto_morus1280_glue_setkey(struct crypto_aead *aead, const u8 *key,
+                                unsigned int keylen)
+{
+       struct morus1280_ctx *ctx = crypto_aead_ctx(aead);
+
+       if (keylen == MORUS1280_BLOCK_SIZE) {
+               memcpy(ctx->key.bytes, key, MORUS1280_BLOCK_SIZE);
+       } else if (keylen == MORUS1280_BLOCK_SIZE / 2) {
+               memcpy(ctx->key.bytes, key, keylen);
+               memcpy(ctx->key.bytes + keylen, key, keylen);
+       } else {
+               crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_morus1280_glue_setkey);
+
+int crypto_morus1280_glue_setauthsize(struct crypto_aead *tfm,
+                                     unsigned int authsize)
+{
+       return (authsize <= MORUS_MAX_AUTH_SIZE) ? 0 : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(crypto_morus1280_glue_setauthsize);
+
+static void crypto_morus1280_glue_crypt(struct aead_request *req,
+                                       struct morus1280_ops ops,
+                                       unsigned int cryptlen,
+                                       struct morus1280_block *tag_xor)
+{
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       struct morus1280_ctx *ctx = crypto_aead_ctx(tfm);
+       struct morus1280_state state;
+
+       kernel_fpu_begin();
+
+       ctx->ops->init(&state, &ctx->key, req->iv);
+       crypto_morus1280_glue_process_ad(&state, ctx->ops, req->src, req->assoclen);
+       crypto_morus1280_glue_process_crypt(&state, ops, req);
+       ctx->ops->final(&state, tag_xor, req->assoclen, cryptlen);
+
+       kernel_fpu_end();
+}
+
+int crypto_morus1280_glue_encrypt(struct aead_request *req)
+{
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       struct morus1280_ctx *ctx = crypto_aead_ctx(tfm);
+       struct morus1280_ops OPS = {
+               .skcipher_walk_init = skcipher_walk_aead_encrypt,
+               .crypt_blocks = ctx->ops->enc,
+               .crypt_tail = ctx->ops->enc_tail,
+       };
+
+       struct morus1280_block tag = {};
+       unsigned int authsize = crypto_aead_authsize(tfm);
+       unsigned int cryptlen = req->cryptlen;
+
+       crypto_morus1280_glue_crypt(req, OPS, cryptlen, &tag);
+
+       scatterwalk_map_and_copy(tag.bytes, req->dst,
+                                req->assoclen + cryptlen, authsize, 1);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_morus1280_glue_encrypt);
+
+int crypto_morus1280_glue_decrypt(struct aead_request *req)
+{
+       static const u8 zeros[MORUS1280_BLOCK_SIZE] = {};
+
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       struct morus1280_ctx *ctx = crypto_aead_ctx(tfm);
+       struct morus1280_ops OPS = {
+               .skcipher_walk_init = skcipher_walk_aead_decrypt,
+               .crypt_blocks = ctx->ops->dec,
+               .crypt_tail = ctx->ops->dec_tail,
+       };
+
+       struct morus1280_block tag;
+       unsigned int authsize = crypto_aead_authsize(tfm);
+       unsigned int cryptlen = req->cryptlen - authsize;
+
+       scatterwalk_map_and_copy(tag.bytes, req->src,
+                                req->assoclen + cryptlen, authsize, 0);
+
+       crypto_morus1280_glue_crypt(req, OPS, cryptlen, &tag);
+
+       return crypto_memneq(tag.bytes, zeros, authsize) ? -EBADMSG : 0;
+}
+EXPORT_SYMBOL_GPL(crypto_morus1280_glue_decrypt);
+
+void crypto_morus1280_glue_init_ops(struct crypto_aead *aead,
+                                   const struct morus1280_glue_ops *ops)
+{
+       struct morus1280_ctx *ctx = crypto_aead_ctx(aead);
+       ctx->ops = ops;
+}
+EXPORT_SYMBOL_GPL(crypto_morus1280_glue_init_ops);
+
+int cryptd_morus1280_glue_setkey(struct crypto_aead *aead, const u8 *key,
+                                unsigned int keylen)
+{
+       struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+       struct cryptd_aead *cryptd_tfm = *ctx;
+
+       return crypto_aead_setkey(&cryptd_tfm->base, key, keylen);
+}
+EXPORT_SYMBOL_GPL(cryptd_morus1280_glue_setkey);
+
+int cryptd_morus1280_glue_setauthsize(struct crypto_aead *aead,
+                                     unsigned int authsize)
+{
+       struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+       struct cryptd_aead *cryptd_tfm = *ctx;
+
+       return crypto_aead_setauthsize(&cryptd_tfm->base, authsize);
+}
+EXPORT_SYMBOL_GPL(cryptd_morus1280_glue_setauthsize);
+
+int cryptd_morus1280_glue_encrypt(struct aead_request *req)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+       struct cryptd_aead *cryptd_tfm = *ctx;
+
+       aead = &cryptd_tfm->base;
+       if (irq_fpu_usable() && (!in_atomic() ||
+                                !cryptd_aead_queued(cryptd_tfm)))
+               aead = cryptd_aead_child(cryptd_tfm);
+
+       aead_request_set_tfm(req, aead);
+
+       return crypto_aead_encrypt(req);
+}
+EXPORT_SYMBOL_GPL(cryptd_morus1280_glue_encrypt);
+
+int cryptd_morus1280_glue_decrypt(struct aead_request *req)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+       struct cryptd_aead *cryptd_tfm = *ctx;
+
+       aead = &cryptd_tfm->base;
+       if (irq_fpu_usable() && (!in_atomic() ||
+                                !cryptd_aead_queued(cryptd_tfm)))
+               aead = cryptd_aead_child(cryptd_tfm);
+
+       aead_request_set_tfm(req, aead);
+
+       return crypto_aead_decrypt(req);
+}
+EXPORT_SYMBOL_GPL(cryptd_morus1280_glue_decrypt);
+
+int cryptd_morus1280_glue_init_tfm(struct crypto_aead *aead)
+{
+       struct cryptd_aead *cryptd_tfm;
+       struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+       const char *name = crypto_aead_alg(aead)->base.cra_driver_name;
+       char internal_name[CRYPTO_MAX_ALG_NAME];
+
+       if (snprintf(internal_name, CRYPTO_MAX_ALG_NAME, "__%s", name)
+                       >= CRYPTO_MAX_ALG_NAME)
+               return -ENAMETOOLONG;
+
+       cryptd_tfm = cryptd_alloc_aead(internal_name, CRYPTO_ALG_INTERNAL,
+                                      CRYPTO_ALG_INTERNAL);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+
+       *ctx = cryptd_tfm;
+       crypto_aead_set_reqsize(aead, crypto_aead_reqsize(&cryptd_tfm->base));
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cryptd_morus1280_glue_init_tfm);
+
+void cryptd_morus1280_glue_exit_tfm(struct crypto_aead *aead)
+{
+       struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+
+       cryptd_free_aead(*ctx);
+}
+EXPORT_SYMBOL_GPL(cryptd_morus1280_glue_exit_tfm);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>");
+MODULE_DESCRIPTION("MORUS-1280 AEAD mode -- glue for optimizations");
diff --git a/crypto/morus640_glue.c b/crypto/morus640_glue.c
new file mode 100644 (file)
index 0000000..c7e788c
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * The MORUS-640 Authenticated-Encryption Algorithm
+ *   Common glue skeleton
+ *
+ * Copyright (c) 2016-2018 Ondrej Mosnacek <omosnacek@gmail.com>
+ * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved.
+ *
+ * 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 <crypto/cryptd.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/morus640_glue.h>
+#include <crypto/scatterwalk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <asm/fpu/api.h>
+
+struct morus640_state {
+       struct morus640_block s[MORUS_STATE_BLOCKS];
+};
+
+struct morus640_ops {
+       int (*skcipher_walk_init)(struct skcipher_walk *walk,
+                                 struct aead_request *req, bool atomic);
+
+       void (*crypt_blocks)(void *state, const void *src, void *dst,
+                            unsigned int length);
+       void (*crypt_tail)(void *state, const void *src, void *dst,
+                          unsigned int length);
+};
+
+static void crypto_morus640_glue_process_ad(
+               struct morus640_state *state,
+               const struct morus640_glue_ops *ops,
+               struct scatterlist *sg_src, unsigned int assoclen)
+{
+       struct scatter_walk walk;
+       struct morus640_block buf;
+       unsigned int pos = 0;
+
+       scatterwalk_start(&walk, sg_src);
+       while (assoclen != 0) {
+               unsigned int size = scatterwalk_clamp(&walk, assoclen);
+               unsigned int left = size;
+               void *mapped = scatterwalk_map(&walk);
+               const u8 *src = (const u8 *)mapped;
+
+               if (pos + size >= MORUS640_BLOCK_SIZE) {
+                       if (pos > 0) {
+                               unsigned int fill = MORUS640_BLOCK_SIZE - pos;
+                               memcpy(buf.bytes + pos, src, fill);
+                               ops->ad(state, buf.bytes, MORUS640_BLOCK_SIZE);
+                               pos = 0;
+                               left -= fill;
+                               src += fill;
+                       }
+
+                       ops->ad(state, src, left);
+                       src += left & ~(MORUS640_BLOCK_SIZE - 1);
+                       left &= MORUS640_BLOCK_SIZE - 1;
+               }
+
+               memcpy(buf.bytes + pos, src, left);
+
+               pos += left;
+               assoclen -= size;
+               scatterwalk_unmap(mapped);
+               scatterwalk_advance(&walk, size);
+               scatterwalk_done(&walk, 0, assoclen);
+       }
+
+       if (pos > 0) {
+               memset(buf.bytes + pos, 0, MORUS640_BLOCK_SIZE - pos);
+               ops->ad(state, buf.bytes, MORUS640_BLOCK_SIZE);
+       }
+}
+
+static void crypto_morus640_glue_process_crypt(struct morus640_state *state,
+                                              struct morus640_ops ops,
+                                              struct aead_request *req)
+{
+       struct skcipher_walk walk;
+       u8 *cursor_src, *cursor_dst;
+       unsigned int chunksize, base;
+
+       ops.skcipher_walk_init(&walk, req, false);
+
+       while (walk.nbytes) {
+               cursor_src = walk.src.virt.addr;
+               cursor_dst = walk.dst.virt.addr;
+               chunksize = walk.nbytes;
+
+               ops.crypt_blocks(state, cursor_src, cursor_dst, chunksize);
+
+               base = chunksize & ~(MORUS640_BLOCK_SIZE - 1);
+               cursor_src += base;
+               cursor_dst += base;
+               chunksize &= MORUS640_BLOCK_SIZE - 1;
+
+               if (chunksize > 0)
+                       ops.crypt_tail(state, cursor_src, cursor_dst,
+                                      chunksize);
+
+               skcipher_walk_done(&walk, 0);
+       }
+}
+
+int crypto_morus640_glue_setkey(struct crypto_aead *aead, const u8 *key,
+                               unsigned int keylen)
+{
+       struct morus640_ctx *ctx = crypto_aead_ctx(aead);
+
+       if (keylen != MORUS640_BLOCK_SIZE) {
+               crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
+               return -EINVAL;
+       }
+
+       memcpy(ctx->key.bytes, key, MORUS640_BLOCK_SIZE);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_morus640_glue_setkey);
+
+int crypto_morus640_glue_setauthsize(struct crypto_aead *tfm,
+                                    unsigned int authsize)
+{
+       return (authsize <= MORUS_MAX_AUTH_SIZE) ? 0 : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(crypto_morus640_glue_setauthsize);
+
+static void crypto_morus640_glue_crypt(struct aead_request *req,
+                                      struct morus640_ops ops,
+                                      unsigned int cryptlen,
+                                      struct morus640_block *tag_xor)
+{
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       struct morus640_ctx *ctx = crypto_aead_ctx(tfm);
+       struct morus640_state state;
+
+       kernel_fpu_begin();
+
+       ctx->ops->init(&state, &ctx->key, req->iv);
+       crypto_morus640_glue_process_ad(&state, ctx->ops, req->src, req->assoclen);
+       crypto_morus640_glue_process_crypt(&state, ops, req);
+       ctx->ops->final(&state, tag_xor, req->assoclen, cryptlen);
+
+       kernel_fpu_end();
+}
+
+int crypto_morus640_glue_encrypt(struct aead_request *req)
+{
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       struct morus640_ctx *ctx = crypto_aead_ctx(tfm);
+       struct morus640_ops OPS = {
+               .skcipher_walk_init = skcipher_walk_aead_encrypt,
+               .crypt_blocks = ctx->ops->enc,
+               .crypt_tail = ctx->ops->enc_tail,
+       };
+
+       struct morus640_block tag = {};
+       unsigned int authsize = crypto_aead_authsize(tfm);
+       unsigned int cryptlen = req->cryptlen;
+
+       crypto_morus640_glue_crypt(req, OPS, cryptlen, &tag);
+
+       scatterwalk_map_and_copy(tag.bytes, req->dst,
+                                req->assoclen + cryptlen, authsize, 1);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_morus640_glue_encrypt);
+
+int crypto_morus640_glue_decrypt(struct aead_request *req)
+{
+       static const u8 zeros[MORUS640_BLOCK_SIZE] = {};
+
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       struct morus640_ctx *ctx = crypto_aead_ctx(tfm);
+       struct morus640_ops OPS = {
+               .skcipher_walk_init = skcipher_walk_aead_decrypt,
+               .crypt_blocks = ctx->ops->dec,
+               .crypt_tail = ctx->ops->dec_tail,
+       };
+
+       struct morus640_block tag;
+       unsigned int authsize = crypto_aead_authsize(tfm);
+       unsigned int cryptlen = req->cryptlen - authsize;
+
+       scatterwalk_map_and_copy(tag.bytes, req->src,
+                                req->assoclen + cryptlen, authsize, 0);
+
+       crypto_morus640_glue_crypt(req, OPS, cryptlen, &tag);
+
+       return crypto_memneq(tag.bytes, zeros, authsize) ? -EBADMSG : 0;
+}
+EXPORT_SYMBOL_GPL(crypto_morus640_glue_decrypt);
+
+void crypto_morus640_glue_init_ops(struct crypto_aead *aead,
+                                  const struct morus640_glue_ops *ops)
+{
+       struct morus640_ctx *ctx = crypto_aead_ctx(aead);
+       ctx->ops = ops;
+}
+EXPORT_SYMBOL_GPL(crypto_morus640_glue_init_ops);
+
+int cryptd_morus640_glue_setkey(struct crypto_aead *aead, const u8 *key,
+                               unsigned int keylen)
+{
+       struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+       struct cryptd_aead *cryptd_tfm = *ctx;
+
+       return crypto_aead_setkey(&cryptd_tfm->base, key, keylen);
+}
+EXPORT_SYMBOL_GPL(cryptd_morus640_glue_setkey);
+
+int cryptd_morus640_glue_setauthsize(struct crypto_aead *aead,
+                                    unsigned int authsize)
+{
+       struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+       struct cryptd_aead *cryptd_tfm = *ctx;
+
+       return crypto_aead_setauthsize(&cryptd_tfm->base, authsize);
+}
+EXPORT_SYMBOL_GPL(cryptd_morus640_glue_setauthsize);
+
+int cryptd_morus640_glue_encrypt(struct aead_request *req)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+       struct cryptd_aead *cryptd_tfm = *ctx;
+
+       aead = &cryptd_tfm->base;
+       if (irq_fpu_usable() && (!in_atomic() ||
+                                !cryptd_aead_queued(cryptd_tfm)))
+               aead = cryptd_aead_child(cryptd_tfm);
+
+       aead_request_set_tfm(req, aead);
+
+       return crypto_aead_encrypt(req);
+}
+EXPORT_SYMBOL_GPL(cryptd_morus640_glue_encrypt);
+
+int cryptd_morus640_glue_decrypt(struct aead_request *req)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+       struct cryptd_aead *cryptd_tfm = *ctx;
+
+       aead = &cryptd_tfm->base;
+       if (irq_fpu_usable() && (!in_atomic() ||
+                                !cryptd_aead_queued(cryptd_tfm)))
+               aead = cryptd_aead_child(cryptd_tfm);
+
+       aead_request_set_tfm(req, aead);
+
+       return crypto_aead_decrypt(req);
+}
+EXPORT_SYMBOL_GPL(cryptd_morus640_glue_decrypt);
+
+int cryptd_morus640_glue_init_tfm(struct crypto_aead *aead)
+{
+       struct cryptd_aead *cryptd_tfm;
+       struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+       const char *name = crypto_aead_alg(aead)->base.cra_driver_name;
+       char internal_name[CRYPTO_MAX_ALG_NAME];
+
+       if (snprintf(internal_name, CRYPTO_MAX_ALG_NAME, "__%s", name)
+                       >= CRYPTO_MAX_ALG_NAME)
+               return -ENAMETOOLONG;
+
+       cryptd_tfm = cryptd_alloc_aead(internal_name, CRYPTO_ALG_INTERNAL,
+                                      CRYPTO_ALG_INTERNAL);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+
+       *ctx = cryptd_tfm;
+       crypto_aead_set_reqsize(aead, crypto_aead_reqsize(&cryptd_tfm->base));
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cryptd_morus640_glue_init_tfm);
+
+void cryptd_morus640_glue_exit_tfm(struct crypto_aead *aead)
+{
+       struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+
+       cryptd_free_aead(*ctx);
+}
+EXPORT_SYMBOL_GPL(cryptd_morus640_glue_exit_tfm);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>");
+MODULE_DESCRIPTION("MORUS-640 AEAD mode -- glue for optimizations");
diff --git a/include/crypto/morus1280_glue.h b/include/crypto/morus1280_glue.h
new file mode 100644 (file)
index 0000000..b26dd70
--- /dev/null
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * The MORUS-1280 Authenticated-Encryption Algorithm
+ *   Common glue skeleton -- header file
+ *
+ * Copyright (c) 2016-2018 Ondrej Mosnacek <omosnacek@gmail.com>
+ * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _CRYPTO_MORUS1280_GLUE_H
+#define _CRYPTO_MORUS1280_GLUE_H
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <crypto/algapi.h>
+#include <crypto/aead.h>
+#include <crypto/morus_common.h>
+
+#define MORUS1280_WORD_SIZE 8
+#define MORUS1280_BLOCK_SIZE (MORUS_BLOCK_WORDS * MORUS1280_WORD_SIZE)
+
+struct morus1280_block {
+       u8 bytes[MORUS1280_BLOCK_SIZE];
+};
+
+struct morus1280_glue_ops {
+       void (*init)(void *state, const void *key, const void *iv);
+       void (*ad)(void *state, const void *data, unsigned int length);
+       void (*enc)(void *state, const void *src, void *dst, unsigned int length);
+       void (*dec)(void *state, const void *src, void *dst, unsigned int length);
+       void (*enc_tail)(void *state, const void *src, void *dst, unsigned int length);
+       void (*dec_tail)(void *state, const void *src, void *dst, unsigned int length);
+       void (*final)(void *state, void *tag_xor, u64 assoclen, u64 cryptlen);
+};
+
+struct morus1280_ctx {
+       const struct morus1280_glue_ops *ops;
+       struct morus1280_block key;
+};
+
+void crypto_morus1280_glue_init_ops(struct crypto_aead *aead,
+                                   const struct morus1280_glue_ops *ops);
+int crypto_morus1280_glue_setkey(struct crypto_aead *aead, const u8 *key,
+                                unsigned int keylen);
+int crypto_morus1280_glue_setauthsize(struct crypto_aead *tfm,
+                                     unsigned int authsize);
+int crypto_morus1280_glue_encrypt(struct aead_request *req);
+int crypto_morus1280_glue_decrypt(struct aead_request *req);
+
+int cryptd_morus1280_glue_setkey(struct crypto_aead *aead, const u8 *key,
+                                unsigned int keylen);
+int cryptd_morus1280_glue_setauthsize(struct crypto_aead *aead,
+                                     unsigned int authsize);
+int cryptd_morus1280_glue_encrypt(struct aead_request *req);
+int cryptd_morus1280_glue_decrypt(struct aead_request *req);
+int cryptd_morus1280_glue_init_tfm(struct crypto_aead *aead);
+void cryptd_morus1280_glue_exit_tfm(struct crypto_aead *aead);
+
+#define MORUS1280_DECLARE_ALGS(id, driver_name, priority) \
+       static const struct morus1280_glue_ops crypto_morus1280_##id##_ops = {\
+               .init = crypto_morus1280_##id##_init, \
+               .ad = crypto_morus1280_##id##_ad, \
+               .enc = crypto_morus1280_##id##_enc, \
+               .enc_tail = crypto_morus1280_##id##_enc_tail, \
+               .dec = crypto_morus1280_##id##_dec, \
+               .dec_tail = crypto_morus1280_##id##_dec_tail, \
+               .final = crypto_morus1280_##id##_final, \
+       }; \
+       \
+       static int crypto_morus1280_##id##_init_tfm(struct crypto_aead *tfm) \
+       { \
+               crypto_morus1280_glue_init_ops(tfm, &crypto_morus1280_##id##_ops); \
+               return 0; \
+       } \
+       \
+       static void crypto_morus1280_##id##_exit_tfm(struct crypto_aead *tfm) \
+       { \
+       } \
+       \
+       struct aead_alg crypto_morus1280_##id##_algs[] = {\
+               { \
+                       .setkey = crypto_morus1280_glue_setkey, \
+                       .setauthsize = crypto_morus1280_glue_setauthsize, \
+                       .encrypt = crypto_morus1280_glue_encrypt, \
+                       .decrypt = crypto_morus1280_glue_decrypt, \
+                       .init = crypto_morus1280_##id##_init_tfm, \
+                       .exit = crypto_morus1280_##id##_exit_tfm, \
+                       \
+                       .ivsize = MORUS_NONCE_SIZE, \
+                       .maxauthsize = MORUS_MAX_AUTH_SIZE, \
+                       .chunksize = MORUS1280_BLOCK_SIZE, \
+                       \
+                       .base = { \
+                               .cra_flags = CRYPTO_ALG_INTERNAL, \
+                               .cra_blocksize = 1, \
+                               .cra_ctxsize = sizeof(struct morus1280_ctx), \
+                               .cra_alignmask = 0, \
+                               \
+                               .cra_name = "__morus1280", \
+                               .cra_driver_name = "__"driver_name, \
+                               \
+                               .cra_module = THIS_MODULE, \
+                       } \
+               }, { \
+                       .setkey = cryptd_morus1280_glue_setkey, \
+                       .setauthsize = cryptd_morus1280_glue_setauthsize, \
+                       .encrypt = cryptd_morus1280_glue_encrypt, \
+                       .decrypt = cryptd_morus1280_glue_decrypt, \
+                       .init = cryptd_morus1280_glue_init_tfm, \
+                       .exit = cryptd_morus1280_glue_exit_tfm, \
+                       \
+                       .ivsize = MORUS_NONCE_SIZE, \
+                       .maxauthsize = MORUS_MAX_AUTH_SIZE, \
+                       .chunksize = MORUS1280_BLOCK_SIZE, \
+                       \
+                       .base = { \
+                               .cra_flags = CRYPTO_ALG_ASYNC, \
+                               .cra_blocksize = 1, \
+                               .cra_ctxsize = sizeof(struct crypto_aead *), \
+                               .cra_alignmask = 0, \
+                               \
+                               .cra_priority = priority, \
+                               \
+                               .cra_name = "morus1280", \
+                               .cra_driver_name = driver_name, \
+                               \
+                               .cra_module = THIS_MODULE, \
+                       } \
+               } \
+       }
+
+#endif /* _CRYPTO_MORUS1280_GLUE_H */
diff --git a/include/crypto/morus640_glue.h b/include/crypto/morus640_glue.h
new file mode 100644 (file)
index 0000000..90c8db0
--- /dev/null
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * The MORUS-640 Authenticated-Encryption Algorithm
+ *   Common glue skeleton -- header file
+ *
+ * Copyright (c) 2016-2018 Ondrej Mosnacek <omosnacek@gmail.com>
+ * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _CRYPTO_MORUS640_GLUE_H
+#define _CRYPTO_MORUS640_GLUE_H
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <crypto/algapi.h>
+#include <crypto/aead.h>
+#include <crypto/morus_common.h>
+
+#define MORUS640_WORD_SIZE 4
+#define MORUS640_BLOCK_SIZE (MORUS_BLOCK_WORDS * MORUS640_WORD_SIZE)
+
+struct morus640_block {
+       u8 bytes[MORUS640_BLOCK_SIZE];
+};
+
+struct morus640_glue_ops {
+       void (*init)(void *state, const void *key, const void *iv);
+       void (*ad)(void *state, const void *data, unsigned int length);
+       void (*enc)(void *state, const void *src, void *dst, unsigned int length);
+       void (*dec)(void *state, const void *src, void *dst, unsigned int length);
+       void (*enc_tail)(void *state, const void *src, void *dst, unsigned int length);
+       void (*dec_tail)(void *state, const void *src, void *dst, unsigned int length);
+       void (*final)(void *state, void *tag_xor, u64 assoclen, u64 cryptlen);
+};
+
+struct morus640_ctx {
+       const struct morus640_glue_ops *ops;
+       struct morus640_block key;
+};
+
+void crypto_morus640_glue_init_ops(struct crypto_aead *aead,
+                                  const struct morus640_glue_ops *ops);
+int crypto_morus640_glue_setkey(struct crypto_aead *aead, const u8 *key,
+                               unsigned int keylen);
+int crypto_morus640_glue_setauthsize(struct crypto_aead *tfm,
+                                    unsigned int authsize);
+int crypto_morus640_glue_encrypt(struct aead_request *req);
+int crypto_morus640_glue_decrypt(struct aead_request *req);
+
+int cryptd_morus640_glue_setkey(struct crypto_aead *aead, const u8 *key,
+                               unsigned int keylen);
+int cryptd_morus640_glue_setauthsize(struct crypto_aead *aead,
+                                    unsigned int authsize);
+int cryptd_morus640_glue_encrypt(struct aead_request *req);
+int cryptd_morus640_glue_decrypt(struct aead_request *req);
+int cryptd_morus640_glue_init_tfm(struct crypto_aead *aead);
+void cryptd_morus640_glue_exit_tfm(struct crypto_aead *aead);
+
+#define MORUS640_DECLARE_ALGS(id, driver_name, priority) \
+       static const struct morus640_glue_ops crypto_morus640_##id##_ops = {\
+               .init = crypto_morus640_##id##_init, \
+               .ad = crypto_morus640_##id##_ad, \
+               .enc = crypto_morus640_##id##_enc, \
+               .enc_tail = crypto_morus640_##id##_enc_tail, \
+               .dec = crypto_morus640_##id##_dec, \
+               .dec_tail = crypto_morus640_##id##_dec_tail, \
+               .final = crypto_morus640_##id##_final, \
+       }; \
+       \
+       static int crypto_morus640_##id##_init_tfm(struct crypto_aead *tfm) \
+       { \
+               crypto_morus640_glue_init_ops(tfm, &crypto_morus640_##id##_ops); \
+               return 0; \
+       } \
+       \
+       static void crypto_morus640_##id##_exit_tfm(struct crypto_aead *tfm) \
+       { \
+       } \
+       \
+       struct aead_alg crypto_morus640_##id##_algs[] = {\
+               { \
+                       .setkey = crypto_morus640_glue_setkey, \
+                       .setauthsize = crypto_morus640_glue_setauthsize, \
+                       .encrypt = crypto_morus640_glue_encrypt, \
+                       .decrypt = crypto_morus640_glue_decrypt, \
+                       .init = crypto_morus640_##id##_init_tfm, \
+                       .exit = crypto_morus640_##id##_exit_tfm, \
+                       \
+                       .ivsize = MORUS_NONCE_SIZE, \
+                       .maxauthsize = MORUS_MAX_AUTH_SIZE, \
+                       .chunksize = MORUS640_BLOCK_SIZE, \
+                       \
+                       .base = { \
+                               .cra_flags = CRYPTO_ALG_INTERNAL, \
+                               .cra_blocksize = 1, \
+                               .cra_ctxsize = sizeof(struct morus640_ctx), \
+                               .cra_alignmask = 0, \
+                               \
+                               .cra_name = "__morus640", \
+                               .cra_driver_name = "__"driver_name, \
+                               \
+                               .cra_module = THIS_MODULE, \
+                       } \
+               }, { \
+                       .setkey = cryptd_morus640_glue_setkey, \
+                       .setauthsize = cryptd_morus640_glue_setauthsize, \
+                       .encrypt = cryptd_morus640_glue_encrypt, \
+                       .decrypt = cryptd_morus640_glue_decrypt, \
+                       .init = cryptd_morus640_glue_init_tfm, \
+                       .exit = cryptd_morus640_glue_exit_tfm, \
+                       \
+                       .ivsize = MORUS_NONCE_SIZE, \
+                       .maxauthsize = MORUS_MAX_AUTH_SIZE, \
+                       .chunksize = MORUS640_BLOCK_SIZE, \
+                       \
+                       .base = { \
+                               .cra_flags = CRYPTO_ALG_ASYNC, \
+                               .cra_blocksize = 1, \
+                               .cra_ctxsize = sizeof(struct crypto_aead *), \
+                               .cra_alignmask = 0, \
+                               \
+                               .cra_priority = priority, \
+                               \
+                               .cra_name = "morus640", \
+                               .cra_driver_name = driver_name, \
+                               \
+                               .cra_module = THIS_MODULE, \
+                       } \
+               } \
+       }
+
+#endif /* _CRYPTO_MORUS640_GLUE_H */