* Re: [v2 PATCH 6/16] crypto: cryptd - Add support for skcipher
From: Eric Biggers @ 2016-11-14 1:45 UTC (permalink / raw)
To: Herbert Xu; +Cc: Linux Crypto Mailing List
In-Reply-To: <E1c5tE9-00029x-Rk@gondolin.me.apana.org.au>
On Sun, Nov 13, 2016 at 07:45:37PM +0800, Herbert Xu wrote:
> +static void cryptd_skcipher_encrypt(struct crypto_async_request *base,
> + int err)
> +{
> + struct skcipher_request *req = skcipher_request_cast(base);
> + struct cryptd_skcipher_request_ctx *rctx = skcipher_request_ctx(req);
> + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
> + struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
> + struct crypto_skcipher *child = ctx->child;
> + SKCIPHER_REQUEST_ON_STACK(subreq, child);
> +
> + if (unlikely(err == -EINPROGRESS))
> + goto out;
> +
> + skcipher_request_set_tfm(subreq, child);
> + skcipher_request_set_callback(subreq, CRYPTO_TFM_REQ_MAY_SLEEP,
> + NULL, NULL);
> + skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen,
> + req->iv);
> +
> + err = crypto_skcipher_encrypt(subreq);
> + skcipher_request_zero(subreq);
> +
> + req->base.complete = rctx->complete;
> +
> +out:
> + cryptd_skcipher_complete(req, err);
> +}
> +
> +static void cryptd_skcipher_decrypt(struct crypto_async_request *base,
> + int err)
> +{
> + struct skcipher_request *req = skcipher_request_cast(base);
> + struct cryptd_skcipher_request_ctx *rctx = skcipher_request_ctx(req);
> + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
> + struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
> + struct crypto_skcipher *child = ctx->child;
> + SKCIPHER_REQUEST_ON_STACK(subreq, child);
> +
> + if (unlikely(err == -EINPROGRESS))
> + goto out;
> +
> + skcipher_request_set_tfm(subreq, child);
> + skcipher_request_set_callback(subreq, CRYPTO_TFM_REQ_MAY_SLEEP,
> + NULL, NULL);
> + skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen,
> + req->iv);
> +
> + err = crypto_skcipher_decrypt(subreq);
> + skcipher_request_zero(subreq);
> +
> + req->base.complete = rctx->complete;
> +
> +out:
> + cryptd_skcipher_complete(req, err);
> +}
cryptd_skcipher_encrypt() and cryptd_skcipher_decrypt() are identical except for
whether crypto_skcipher_encrypt() or crypto_skcipher_decrypt() is used. I
suggest having them wrap a function cryptd_skcipher_crypt() that takes in a
function pointer to crypto_skcipher_encrypt or crypto_skcipher_decrypt.
Alternatively a bool would be okay too.
Eric
^ permalink raw reply
* Re: [v2 PATCH 4/16] crypto: xts - Convert to skcipher
From: Eric Biggers @ 2016-11-14 2:10 UTC (permalink / raw)
To: Herbert Xu; +Cc: Linux Crypto Mailing List
In-Reply-To: <E1c5tE7-00029P-L0@gondolin.me.apana.org.au>
On Sun, Nov 13, 2016 at 07:45:35PM +0800, Herbert Xu wrote:
> +static int do_encrypt(struct skcipher_request *req, int err)
> +{
> + struct rctx *rctx = skcipher_request_ctx(req);
> + struct skcipher_request *subreq;
> +
> + subreq = &rctx->subreq;
> +
> + while (!err && rctx->left) {
> + err = pre_crypt(req) ?:
> + crypto_skcipher_encrypt(subreq) ?:
> + post_crypt(req);
> +
> + if (err == -EINPROGRESS ||
> + (err == -EBUSY &&
> + req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
> + return err;
> + }
> +
> + exit_crypt(req);
> + return err;
> +}
> +
> +static void encrypt_done(struct crypto_async_request *areq, int err)
> +{
> + struct skcipher_request *req = areq->data;
> + struct skcipher_request *subreq;
> + struct rctx *rctx;
> +
> + rctx = skcipher_request_ctx(req);
> + subreq = &rctx->subreq;
> + subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;
> +
> + err = do_encrypt(req, err ?: post_crypt(req));
> + if (rctx->left)
> + return;
> +
> + skcipher_request_complete(req, err);
> +}
> +
> +static int encrypt(struct skcipher_request *req)
> +{
> + return do_encrypt(req, init_crypt(req, encrypt_done));
> +}
> +
> +static int do_decrypt(struct skcipher_request *req, int err)
> +{
> + struct rctx *rctx = skcipher_request_ctx(req);
> + struct skcipher_request *subreq;
> +
> + subreq = &rctx->subreq;
> +
> + while (!err && rctx->left) {
> + err = pre_crypt(req) ?:
> + crypto_skcipher_decrypt(subreq) ?:
> + post_crypt(req);
> +
> + if (err == -EINPROGRESS ||
> + (err == -EBUSY &&
> + req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
> + return err;
> + }
> +
> + exit_crypt(req);
> + return err;
> +}
> +
> +static void decrypt_done(struct crypto_async_request *areq, int err)
> +{
> + struct skcipher_request *req = areq->data;
> + struct skcipher_request *subreq;
> + struct rctx *rctx;
> +
> + rctx = skcipher_request_ctx(req);
> + subreq = &rctx->subreq;
> + subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;
> +
> + err = do_decrypt(req, err ?: post_crypt(req));
> + if (rctx->left)
> + return;
> +
> + skcipher_request_complete(req, err);
> +}
> +
> +static int decrypt(struct skcipher_request *req)
> +{
> + return do_decrypt(req, init_crypt(req, decrypt_done));
> }
There's duplicated code for encryption and decryption here. AFAICS, the only
difference between XTS encryption and decryption is whether the block cipher is
used in encryption or decryption mode for the ECB step. So I suggest storing a
function pointer in 'struct rctx' to either crypto_skcipher_encrypt or
crypto_skcipher_decrypt, then calling through it for the ECB step. Then this
code can be shared. In other words I'd like the top-level functions to look
like this:
static int encrypt(struct skcipher_request *req)
{
struct rctx *rctx = skcipher_request_ctx(req);
rctx->crypt = crypto_skcipher_encrypt;
return do_crypt(req);
}
static int decrypt(struct skcipher_request *req)
{
struct rctx *rctx = skcipher_request_ctx(req);
rctx->crypt = crypto_skcipher_decrypt;
return do_crypt(req);
}
I'm also wondering about the line which does
'subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;'.
Is the real intent of that to clear the CRYPTO_TFM_REQ_MAY_SLEEP flag because
the completion callback may be called in an atomic context, and if so shouldn't
it just clear that flag only, rather than all flags except
CRYPTO_TFM_REQ_MAY_BACKLOG?
> + if (req->cryptlen > XTS_BUFFER_SIZE) {
> + subreq->cryptlen = min(req->cryptlen, (unsigned)PAGE_SIZE);
> + rctx->ext = kmalloc(subreq->cryptlen, gfp);
> + }
There's no check for failure to allocate the 'rctx->ext' memory.
> + /* Alas we screwed up the naming so we have to mangle the
> + * cipher name.
> + */
> + if (!strncmp(cipher_name, "ecb(", 4)) {
> + unsigned len;
>
> - inst->alg.cra_ctxsize = sizeof(struct priv);
> + len = strlcpy(ctx->name, cipher_name + 4, sizeof(ctx->name));
> + if (len < 2 || len >= sizeof(ctx->name))
> + goto err_drop_spawn;
>
> - inst->alg.cra_init = init_tfm;
> - inst->alg.cra_exit = exit_tfm;
> + if (ctx->name[len - 1] != ')')
> + goto err_drop_spawn;
>
> - inst->alg.cra_blkcipher.setkey = setkey;
> - inst->alg.cra_blkcipher.encrypt = encrypt;
> - inst->alg.cra_blkcipher.decrypt = decrypt;
> + ctx->name[len - 1] = 0;
>
> -out_put_alg:
> - crypto_mod_put(alg);
> - return inst;
> -}
> + if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
> + "xts(%s)", ctx->name) >= CRYPTO_MAX_ALG_NAME)
> + return -ENAMETOOLONG;
> + } else
> + goto err_drop_spawn;
There should be a line which sets 'err = -EINVAL' before here.
> +static int init_crypt(struct skcipher_request *req, crypto_completion_t done)
> {
> - struct priv *ctx = crypto_blkcipher_ctx(desc->tfm);
> - struct blkcipher_walk w;
> + struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
> + struct rctx *rctx = skcipher_request_ctx(req);
> + struct skcipher_request *subreq;
> + be128 *buf;
...
> + /* calculate first value of T */
> + buf = rctx->ext ?: rctx->buf;
> + crypto_cipher_encrypt_one(ctx->tweak, (u8 *)&rctx->t, req->iv);
> +
> + return 0;
The 'buf' variable is assigned to but never used.
> int xts_crypt(struct blkcipher_desc *desc, struct scatterlist *sdst,
> @@ -233,112 +416,167 @@ int xts_crypt(struct blkcipher_desc *desc, struct scatterlist *sdst,
> }
> EXPORT_SYMBOL_GPL(xts_crypt);
xts_crypt() is still here. Is there a plan for its removal, since now the
generic XTS algorithm can use an accelerated ECB algorithm?
^ permalink raw reply
* Re: [v2 PATCH 7/16] crypto: simd - Add simd skcipher helper
From: Eric Biggers @ 2016-11-14 2:27 UTC (permalink / raw)
To: Herbert Xu; +Cc: Linux Crypto Mailing List
In-Reply-To: <E1c5tEA-0002AE-UP@gondolin.me.apana.org.au>
On Sun, Nov 13, 2016 at 07:45:38PM +0800, Herbert Xu wrote:
> This patch adds the simd skcipher helper which is meant to be
> a replacement for ablk helper. It replaces the underlying blkcipher
> interface with skcipher, and also presents the top-level algorithm
> as an skcipher.
I assume this means it's planned for all users of ablk_helper to be migrated to
crypto_simd, and ablk_helper will be removed?
> + salg = kzalloc(sizeof(*alg), GFP_KERNEL);
> + if (!salg) {
> + salg = ERR_PTR(-ENOMEM);
> + goto out_put_tfm;
> + }
Shouldn't this be 'sizeof(*salg)'?
> + tfm = crypto_alloc_skcipher(basename, CRYPTO_ALG_INTERNAL,
> + CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC);
> + if (IS_ERR(tfm))
> + return ERR_CAST(tfm);
> +
> + ialg = crypto_skcipher_alg(tfm);
It seems this really just needs an algorithm and not a transform. Perhaps it
should be calling crypto_find_alg() directly?
> + err = -ENAMETOOLONG;
> + if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", algname) >=
> + CRYPTO_MAX_ALG_NAME)
> + goto out_free_salg;
> +
> + if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
> + drvname) >= CRYPTO_MAX_ALG_NAME)
> + goto out_free_salg;
Could use strscpy() or strlcpy() here.
> +static int simd_skcipher_encrypt(struct skcipher_request *req)
> +{
> + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
> + struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
> + struct skcipher_request *subreq;
> + struct crypto_skcipher *child;
> +
> + subreq = skcipher_request_ctx(req);
> + *subreq = *req;
> +
> + if (!may_use_simd() ||
> + (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm)))
> + child = &ctx->cryptd_tfm->base;
> + else
> + child = cryptd_skcipher_child(ctx->cryptd_tfm);
> +
> + skcipher_request_set_tfm(subreq, child);
> +
> + return crypto_skcipher_encrypt(subreq);
> +}
> +
> +static int simd_skcipher_decrypt(struct skcipher_request *req)
> +{
> + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
> + struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
> + struct skcipher_request *subreq;
> + struct crypto_skcipher *child;
> +
> + subreq = skcipher_request_ctx(req);
> + *subreq = *req;
> +
> + if (!may_use_simd() ||
> + (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm)))
> + child = &ctx->cryptd_tfm->base;
> + else
> + child = cryptd_skcipher_child(ctx->cryptd_tfm);
> +
> + skcipher_request_set_tfm(subreq, child);
> +
> + return crypto_skcipher_decrypt(subreq);
> +}
These are the same except for the
crypto_skcipher_encrypt/crypto_skcipher_decrypt at the end, so they could be
mostly shared.
^ permalink raw reply
* [PATCH] crypto: add virtio-crypto driver
From: Gonglei @ 2016-11-14 6:47 UTC (permalink / raw)
To: qemu-devel, virtio-dev, virtualization, linux-crypto
Cc: luonengjun, mst, stefanha, weidong.huang, wu.wubin, xin.zeng,
claudio.fontana, herbert, pasic, davem, jianjay.zhou, hanweidong,
peter.huangpeng, arei.gonglei, cornelia.huck, xuquan8, Gonglei
This patch introduces virtio-crypto driver for Linux Kernel.
The virtio crypto device is a virtual cryptography device
as well as a kind of virtual hardware accelerator for
virtual machines. The encryption anddecryption requests
are placed in the data queue and are ultimately handled by
thebackend crypto accelerators. The second queue is the
control queue used to create or destroy sessions for
symmetric algorithms and will control some advanced features
in the future. The virtio crypto device provides the following
cryptoservices: CIPHER, MAC, HASH, and AEAD.
For more information about virtio-crypto device, please see:
http://qemu-project.org/Features/VirtioCrypto
CC: Michael S. Tsirkin <mst@redhat.com>
CC: Cornelia Huck <cornelia.huck@de.ibm.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
CC: Herbert Xu <herbert@gondor.apana.org.au>
CC: Halil Pasic <pasic@linux.vnet.ibm.com>
CC: David S. Miller <davem@davemloft.net>
CC: Zeng Xin <xin.zeng@intel.com>
Signed-off-by: Gonglei <arei.gonglei@huawei.com>
---
MAINTAINERS | 8 +
drivers/crypto/Kconfig | 2 +
drivers/crypto/Makefile | 1 +
drivers/crypto/virtio/Kconfig | 10 +
drivers/crypto/virtio/Makefile | 5 +
drivers/crypto/virtio/virtio_crypto.c | 437 +++++++++++++++++++++++
drivers/crypto/virtio/virtio_crypto_algs.c | 496 +++++++++++++++++++++++++++
drivers/crypto/virtio/virtio_crypto_common.h | 115 +++++++
drivers/crypto/virtio/virtio_crypto_mgr.c | 261 ++++++++++++++
include/uapi/linux/Kbuild | 1 +
include/uapi/linux/virtio_crypto.h | 436 +++++++++++++++++++++++
include/uapi/linux/virtio_ids.h | 1 +
12 files changed, 1773 insertions(+)
create mode 100644 drivers/crypto/virtio/Kconfig
create mode 100644 drivers/crypto/virtio/Makefile
create mode 100644 drivers/crypto/virtio/virtio_crypto.c
create mode 100644 drivers/crypto/virtio/virtio_crypto_algs.c
create mode 100644 drivers/crypto/virtio/virtio_crypto_common.h
create mode 100644 drivers/crypto/virtio/virtio_crypto_mgr.c
create mode 100644 include/uapi/linux/virtio_crypto.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 411e3b8..d6b18bb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12844,6 +12844,14 @@ S: Maintained
F: drivers/virtio/virtio_input.c
F: include/uapi/linux/virtio_input.h
+VIRTIO CRYPTO DRIVER
+M: Gonglei <arei.gonglei@huawei.com>
+L: virtualization@lists.linux-foundation.org
+L: linux-crypto@vger.kernel.org
+S: Maintained
+F: drivers/crypto/virtio/
+F: include/uapi/linux/virtio_crypto.h
+
VIA RHINE NETWORK DRIVER
S: Orphan
F: drivers/net/ethernet/via/via-rhine.c
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 4d2b81f..7956478 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -555,4 +555,6 @@ config CRYPTO_DEV_ROCKCHIP
source "drivers/crypto/chelsio/Kconfig"
+source "drivers/crypto/virtio/Kconfig"
+
endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index ad7250f..bc53cb8 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -32,3 +32,4 @@ obj-$(CONFIG_CRYPTO_DEV_VMX) += vmx/
obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sunxi-ss/
obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rockchip/
obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chelsio/
+obj-$(CONFIG_CRYPTO_DEV_VIRTIO) += virtio/
diff --git a/drivers/crypto/virtio/Kconfig b/drivers/crypto/virtio/Kconfig
new file mode 100644
index 0000000..ceae88c
--- /dev/null
+++ b/drivers/crypto/virtio/Kconfig
@@ -0,0 +1,10 @@
+config CRYPTO_DEV_VIRTIO
+ tristate "VirtIO crypto driver"
+ depends on VIRTIO
+ select CRYPTO_AEAD
+ select CRYPTO_AUTHENC
+ select CRYPTO_BLKCIPHER
+ default m
+ help
+ This driver provides support for virtio crypto device. If you
+ choose 'M' here, this module will be called virtio-crypto.
diff --git a/drivers/crypto/virtio/Makefile b/drivers/crypto/virtio/Makefile
new file mode 100644
index 0000000..a316e92
--- /dev/null
+++ b/drivers/crypto/virtio/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_CRYPTO_DEV_VIRTIO) += virtio-crypto.o
+virtio-crypto-objs := \
+ virtio_crypto_algs.o \
+ virtio_crypto_mgr.o \
+ virtio_crypto.o
diff --git a/drivers/crypto/virtio/virtio_crypto.c b/drivers/crypto/virtio/virtio_crypto.c
new file mode 100644
index 0000000..6c9de18
--- /dev/null
+++ b/drivers/crypto/virtio/virtio_crypto.c
@@ -0,0 +1,437 @@
+ /* Driver for Virtio crypto device.
+ *
+ * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/virtio_config.h>
+#include <linux/cpu.h>
+
+#include <uapi/linux/virtio_crypto.h>
+#include "virtio_crypto_common.h"
+
+
+static void virtcrypto_dataq_callback(struct virtqueue *vq)
+{
+ struct virtio_crypto *vcrypto = vq->vdev->priv;
+ struct virtio_crypto_request *vc_req;
+ unsigned long flags;
+ unsigned int len;
+ struct ablkcipher_request *ablk_req;
+ int error;
+
+ spin_lock_irqsave(&vcrypto->lock, flags);
+ do {
+ virtqueue_disable_cb(vq);
+ while ((vc_req = virtqueue_get_buf(vq, &len)) != NULL) {
+ if (vc_req->type == VIRTIO_CRYPTO_SYM_OP_CIPHER) {
+ switch (vc_req->status) {
+ case VIRTIO_CRYPTO_OK:
+ error = 0;
+ break;
+ case VIRTIO_CRYPTO_INVSESS:
+ case VIRTIO_CRYPTO_ERR:
+ error = -EINVAL;
+ break;
+ case VIRTIO_CRYPTO_BADMSG:
+ error = -EBADMSG;
+ break;
+ default:
+ error = -EIO;
+ break;
+ }
+ ablk_req = vc_req->ablkcipher_req;
+ /* Finish the encrypt or decrypt process */
+ ablk_req->base.complete(&ablk_req->base, error);
+ }
+
+ kfree(vc_req->req_data);
+ kfree(vc_req->sgs);
+ }
+ } while (!virtqueue_enable_cb(vq));
+ spin_unlock_irqrestore(&vcrypto->lock, flags);
+}
+
+static int virtcrypto_find_vqs(struct virtio_crypto *vi)
+{
+ vq_callback_t **callbacks;
+ struct virtqueue **vqs;
+ int ret = -ENOMEM;
+ int i, total_vqs;
+ const char **names;
+
+ /* We expect 1 data virtqueue, followed by
+ * possible N-1 data queues used in multiqueue mode, followed by
+ * control vq.
+ */
+ total_vqs = vi->max_data_queues + 1;
+
+ /* Allocate space for find_vqs parameters */
+ vqs = kcalloc(total_vqs, sizeof(*vqs), GFP_KERNEL);
+ if (!vqs)
+ goto err_vq;
+ callbacks = kcalloc(total_vqs, sizeof(*callbacks), GFP_KERNEL);
+ if (!callbacks)
+ goto err_callback;
+ names = kcalloc(total_vqs, sizeof(*names), GFP_KERNEL);
+ if (!names)
+ goto err_names;
+
+ /* Parameters for control virtqueue */
+ callbacks[total_vqs - 1] = NULL;
+ names[total_vqs - 1] = "controlq";
+
+ /* Allocate/initialize parameters for data virtqueues */
+ for (i = 0; i < vi->max_data_queues; i++) {
+ callbacks[i] = virtcrypto_dataq_callback;
+ snprintf(vi->data_vq[i].name, sizeof(vi->data_vq[i].name),
+ "dataq.%d", i);
+ names[i] = vi->data_vq[i].name;
+ }
+
+ ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
+ names);
+ if (ret)
+ goto err_find;
+
+ vi->ctrl_vq = vqs[total_vqs - 1];
+
+ for (i = 0; i < vi->max_data_queues; i++)
+ vi->data_vq[i].vq = vqs[i];
+
+ kfree(names);
+ kfree(callbacks);
+ kfree(vqs);
+
+ return 0;
+
+err_find:
+ kfree(names);
+err_names:
+ kfree(callbacks);
+err_callback:
+ kfree(vqs);
+err_vq:
+ return ret;
+}
+
+static int virtcrypto_alloc_queues(struct virtio_crypto *vi)
+{
+ vi->data_vq = kcalloc(vi->max_data_queues, sizeof(*vi->data_vq),
+ GFP_KERNEL);
+ if (!vi->data_vq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void virtcrypto_clean_affinity(struct virtio_crypto *vi, long hcpu)
+{
+ int i;
+
+ if (vi->affinity_hint_set) {
+ for (i = 0; i < vi->max_data_queues; i++)
+ virtqueue_set_affinity(vi->data_vq[i].vq, -1);
+
+ vi->affinity_hint_set = false;
+ }
+}
+
+static void virtcrypto_set_affinity(struct virtio_crypto *vi)
+{
+ int i;
+ int cpu;
+
+ /*
+ * In multiqueue mode, when the number of cpu is equal to the number
+ * of queue, we let the queue to be private to one cpu by
+ * setting the affinity hint to eliminate the contention.
+ */
+ if (vi->curr_queue == 1 ||
+ vi->max_data_queues != num_online_cpus()) {
+ virtcrypto_clean_affinity(vi, -1);
+ return;
+ }
+
+ i = 0;
+ for_each_online_cpu(cpu) {
+ virtqueue_set_affinity(vi->data_vq[i].vq, cpu);
+ i++;
+ }
+
+ vi->affinity_hint_set = true;
+}
+
+static void virtcrypto_free_queues(struct virtio_crypto *vi)
+{
+ kfree(vi->data_vq);
+}
+
+static int virtcrypto_init_vqs(struct virtio_crypto *vi)
+{
+ int ret;
+
+ /* Allocate send & receive queues */
+ ret = virtcrypto_alloc_queues(vi);
+ if (ret)
+ goto err;
+
+ ret = virtcrypto_find_vqs(vi);
+ if (ret)
+ goto err_free;
+
+ get_online_cpus();
+ virtcrypto_set_affinity(vi);
+ put_online_cpus();
+
+ return 0;
+
+err_free:
+ virtcrypto_free_queues(vi);
+err:
+ return ret;
+}
+
+static void virtcrypto_update_status(struct virtio_crypto *vcrypto)
+{
+ u32 v;
+
+ virtio_cread(vcrypto->vdev, struct virtio_crypto_config, status, &v);
+
+ /* Ignore unknown (future) status bits */
+ v &= VIRTIO_CRYPTO_S_HW_READY;
+
+ if (vcrypto->status == v)
+ return;
+
+ vcrypto->status = v;
+
+ if (vcrypto->status & VIRTIO_CRYPTO_S_HW_READY)
+ pr_info("virtio_crypto: accelerator is ready\n");
+ else
+ pr_info("virtio_crypto: accelerator is not ready\n");
+}
+
+static int virtcrypto_probe(struct virtio_device *vdev)
+{
+ int err = -EFAULT;
+ struct virtio_crypto *vcrypto;
+ u32 max_data_queues = 0, max_cipher_key_len = 0;
+ u32 max_auth_key_len = 0;
+ u64 max_size = 0;
+
+ if (!vdev->config->get) {
+ dev_err(&vdev->dev, "%s failure: config access disabled\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (num_possible_nodes() > 1 && dev_to_node(&vdev->dev) < 0) {
+ /*
+ * If the accelerator is connected to a node with no memory
+ * there is no point in using the accelerator since the remote
+ * memory transaction will be very slow.
+ */
+ dev_err(&vdev->dev, "Invalid NUMA configuration.\n");
+ return -EINVAL;
+ }
+
+ virtio_cread(vdev, struct virtio_crypto_config,
+ max_dataqueues, &max_data_queues);
+ if (max_data_queues < 1)
+ max_data_queues = 1;
+
+ dev_info(&vdev->dev, "max_queues: %u\n", max_data_queues);
+
+ virtio_cread(vdev, struct virtio_crypto_config,
+ max_cipher_key_len, &max_cipher_key_len);
+ virtio_cread(vdev, struct virtio_crypto_config,
+ max_auth_key_len, &max_auth_key_len);
+ virtio_cread(vdev, struct virtio_crypto_config,
+ max_size, &max_size);
+
+ vcrypto = kzalloc_node(sizeof(*vcrypto), GFP_KERNEL,
+ dev_to_node(&vdev->dev));
+ if (!vcrypto)
+ return -ENOMEM;
+
+ /* Add virtio crypto device to global table */
+ err = virtcrypto_devmgr_add_dev(vcrypto);
+ if (err) {
+ dev_err(&vdev->dev, "Failed to add new virtio crypto device.\n");
+ goto free;
+ }
+ vcrypto->owner = THIS_MODULE;
+ vcrypto = vdev->priv = vcrypto;
+ vcrypto->vdev = vdev;
+ spin_lock_init(&vcrypto->lock);
+
+ /* Use sigle data queue as default */
+ vcrypto->curr_queue = 1;
+ vcrypto->max_data_queues = max_data_queues;
+ vcrypto->max_cipher_key_len = max_cipher_key_len;
+ vcrypto->max_auth_key_len = max_auth_key_len;
+ vcrypto->max_size = max_size;
+
+ err = virtcrypto_init_vqs(vcrypto);
+ if (err) {
+ dev_err(&vdev->dev, "Failed to initialize vqs.\n");
+ goto free_dev;
+ }
+ virtio_device_ready(vdev);
+
+ virtcrypto_update_status(vcrypto);
+
+ if (vcrypto->status & VIRTIO_CRYPTO_S_HW_READY) {
+ err = virtcrypto_dev_start(vcrypto);
+ if (err) {
+ dev_err(&vdev->dev, "Failed to start virtio crypto device.\n");
+ goto free_start;
+ }
+ }
+
+ return 0;
+
+free_start:
+ virtcrypto_dev_stop(vcrypto);
+free_dev:
+ virtcrypto_devmgr_rm_dev(vcrypto);
+free:
+ kfree(vcrypto);
+ return err;
+}
+
+static void virtcrypto_del_vqs(struct virtio_crypto *vcrypto)
+{
+ struct virtio_device *vdev = vcrypto->vdev;
+
+ virtcrypto_clean_affinity(vcrypto, -1);
+
+ vdev->config->del_vqs(vdev);
+
+ virtcrypto_free_queues(vcrypto);
+}
+
+static void virtcrypto_free_unused_reqs(struct virtio_crypto *vcrypto)
+{
+ struct virtio_crypto_request *vc_req;
+ int i;
+ struct virtqueue *vq;
+
+ for (i = 0; i < vcrypto->max_data_queues; i++) {
+ vq = vcrypto->data_vq[i].vq;
+ while ((vc_req = virtqueue_detach_unused_buf(vq)) != NULL) {
+ kfree(vc_req->req_data);
+ kfree(vc_req->sgs);
+ }
+ }
+}
+
+static void virtcrypto_remove(struct virtio_device *vdev)
+{
+ struct virtio_crypto *vcrypto = vdev->priv;
+
+ dev_info(&vdev->dev, "Start virtcrypto_remove.\n");
+
+ if (virtcrypto_dev_started(vcrypto))
+ virtcrypto_dev_stop(vcrypto);
+ vdev->config->reset(vdev);
+ virtcrypto_free_unused_reqs(vcrypto);
+ virtcrypto_del_vqs(vcrypto);
+ virtcrypto_devmgr_rm_dev(vcrypto);
+ kfree(vcrypto);
+}
+
+static void virtcrypto_config_changed(struct virtio_device *vdev)
+{
+ struct virtio_crypto *vcrypto = vdev->priv;
+
+ virtcrypto_update_status(vcrypto);
+
+ if (vcrypto->status & VIRTIO_CRYPTO_S_HW_READY) {
+ /* Set started status bit for device */
+ vcrypto->status |= VIRTIO_CRYPTO_S_STARTED;
+ }
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int virtcrypto_freeze(struct virtio_device *vdev)
+{
+ struct virtio_crypto *vcrypto = vdev->priv;
+ unsigned long flags;
+
+ virtcrypto_free_unused_reqs(vcrypto);
+ spin_lock_irqsave(&vcrypto->lock, flags);
+ if (virtcrypto_dev_started(vcrypto))
+ virtcrypto_dev_stop(vcrypto);
+ spin_unlock_irqrestore(&vcrypto->lock, flags);
+
+ virtcrypto_del_vqs(vcrypto);
+ return 0;
+}
+
+static int virtcrypto_restore(struct virtio_device *vdev)
+{
+ struct virtio_crypto *vcrypto = vdev->priv;
+ int err;
+
+ err = virtcrypto_init_vqs(vcrypto);
+ if (err)
+ return err;
+
+ virtio_device_ready(vdev);
+ err = virtcrypto_dev_start(vcrypto);
+ if (err) {
+ dev_err(&vdev->dev, "Failed to start virtio crypto device.\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+#endif
+
+
+static unsigned int features[] = {
+ /* none */
+};
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_CRYPTO, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static struct virtio_driver virtio_crypto_driver = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
+ .id_table = id_table,
+ .probe = virtcrypto_probe,
+ .remove = virtcrypto_remove,
+ .config_changed = virtcrypto_config_changed,
+#ifdef CONFIG_PM_SLEEP
+ .freeze = virtcrypto_freeze,
+ .restore = virtcrypto_restore,
+#endif
+};
+
+module_virtio_driver(virtio_crypto_driver);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("virtio crypto device driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gonglei <arei.gonglei@huawei.com>");
diff --git a/drivers/crypto/virtio/virtio_crypto_algs.c b/drivers/crypto/virtio/virtio_crypto_algs.c
new file mode 100644
index 0000000..83c077f
--- /dev/null
+++ b/drivers/crypto/virtio/virtio_crypto_algs.c
@@ -0,0 +1,496 @@
+ /* Algorithms supported by virtio crypto device
+ *
+ * Authors: Gonglei <arei.gonglei@huawei.com>
+ *
+ * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/scatterlist.h>
+#include <crypto/algapi.h>
+#include <linux/err.h>
+#include <crypto/scatterwalk.h>
+#include <linux/atomic.h>
+
+#include <uapi/linux/virtio_crypto.h>
+#include "virtio_crypto_common.h"
+
+static DEFINE_MUTEX(algs_lock);
+static unsigned int virtio_crypto_active_devs;
+
+static u64 sg_nents_length(struct scatterlist *sg)
+{
+ u64 total = 0;
+
+ for (total = 0; sg; sg = sg_next(sg))
+ total += sg->length;
+
+ return total;
+}
+
+static int virtio_crypto_alg_validate_key(int key_len, int *alg)
+{
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ case AES_KEYSIZE_192:
+ case AES_KEYSIZE_256:
+ *alg = VIRTIO_CRYPTO_CIPHER_AES_CBC;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int virtio_crypto_alg_ablkcipher_init_session(
+ struct virtio_crypto_ablkcipher_ctx *ctx,
+ int alg, const uint8_t *key,
+ unsigned int keylen,
+ int encrypt)
+{
+ struct scatterlist outhdr, key_sg, inhdr, *sgs[3];
+ unsigned int tmp;
+ struct virtio_crypto_session_input input;
+ struct virtio_crypto_op_ctrl_req ctrl;
+ struct virtio_crypto *vcrypto = ctx->vcrypto;
+ int op = encrypt ? VIRTIO_CRYPTO_OP_ENCRYPT : VIRTIO_CRYPTO_OP_DECRYPT;
+ int err;
+ unsigned int num_out = 0, num_in = 0;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ memset(&input, 0, sizeof(input));
+ /* Pad ctrl header */
+ ctrl.header.opcode = cpu_to_le32(VIRTIO_CRYPTO_CIPHER_CREATE_SESSION);
+ ctrl.header.algo = cpu_to_le32((uint32_t)alg);
+ /* Set the default dataqueue id to 0 */
+ ctrl.header.queue_id = 0;
+
+ input.status = cpu_to_le32(VIRTIO_CRYPTO_ERR);
+ /* Pad cipher's parameters */
+ ctrl.u.sym_create_session.op_type =
+ cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER);
+ ctrl.u.sym_create_session.u.cipher.para.algo = ctrl.header.algo;
+ ctrl.u.sym_create_session.u.cipher.para.keylen = cpu_to_le32(keylen);
+ ctrl.u.sym_create_session.u.cipher.para.op = cpu_to_le32(op);
+
+ sg_init_one(&outhdr, &ctrl, sizeof(ctrl));
+ sgs[num_out++] = &outhdr;
+
+ /* Set key */
+ sg_init_one(&key_sg, key, keylen);
+ sgs[num_out++] = &key_sg;
+
+ /* Return status and session id back */
+ sg_init_one(&inhdr, &input, sizeof(input));
+ sgs[num_out + num_in++] = &inhdr;
+
+ err = virtqueue_add_sgs(vcrypto->ctrl_vq, sgs, num_out,
+ num_in, vcrypto, GFP_ATOMIC);
+ if (err < 0)
+ return err;
+ virtqueue_kick(vcrypto->ctrl_vq);
+
+ /*
+ * Spin for a response, the kick causes an ioport write, trapping
+ * into the hypervisor, so the request should be handled immediately.
+ */
+ while (!virtqueue_get_buf(vcrypto->ctrl_vq, &tmp) &&
+ !virtqueue_is_broken(vcrypto->ctrl_vq))
+ cpu_relax();
+
+ if (le32_to_cpu(input.status) != VIRTIO_CRYPTO_OK) {
+ pr_err("virtio_crypto: Create session failed status: %u, session_id: 0x%llx\n",
+ input.status, input.session_id);
+ return -EINVAL;
+ }
+
+ spin_lock(&ctx->lock);
+ if (encrypt)
+ ctx->enc_sess_info.session_id = le32_to_cpu(input.session_id);
+ else
+ ctx->dec_sess_info.session_id = le32_to_cpu(input.session_id);
+ spin_unlock(&ctx->lock);
+
+ return 0;
+}
+
+static int virtio_crypto_alg_ablkcipher_close_session(
+ struct virtio_crypto_ablkcipher_ctx *ctx,
+ int encrypt)
+{
+ struct scatterlist outhdr, status_sg, *sgs[2];
+ unsigned int tmp;
+ struct virtio_crypto_destroy_session_req *destroy_session;
+ struct virtio_crypto_op_ctrl_req ctrl;
+ struct virtio_crypto *vcrypto = ctx->vcrypto;
+ int err;
+ unsigned int num_out = 0, num_in = 0;
+ uint8_t status = VIRTIO_CRYPTO_ERR;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+
+ /* Pad ctrl header */
+ ctrl.header.opcode = cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION);
+ /* Set the default virtqueue id to 0 */
+ ctrl.header.queue_id = 0;
+
+ destroy_session = &ctrl.u.destroy_session;
+
+ if (encrypt)
+ destroy_session->session_id =
+ cpu_to_le64(ctx->enc_sess_info.session_id);
+ else
+ destroy_session->session_id =
+ cpu_to_le64(ctx->dec_sess_info.session_id);
+
+ pr_debug("virtio_crypto: Close session, session_id=0x%llx\n",
+ destroy_session->session_id);
+
+ sg_init_one(&outhdr, &ctrl, sizeof(ctrl));
+ sgs[num_out++] = &outhdr;
+
+ /* Return status and session id back */
+ sg_init_one(&status_sg, &status, sizeof(status));
+ sgs[num_out + num_in++] = &status_sg;
+
+ err = virtqueue_add_sgs(vcrypto->ctrl_vq, sgs, num_out,
+ num_in, vcrypto, GFP_ATOMIC);
+ if (err < 0)
+ return err;
+ virtqueue_kick(vcrypto->ctrl_vq);
+
+ while (!virtqueue_get_buf(vcrypto->ctrl_vq, &tmp) &&
+ !virtqueue_is_broken(vcrypto->ctrl_vq))
+ cpu_relax();
+
+ if (status != VIRTIO_CRYPTO_OK) {
+ pr_err("virtio_crypto: Close session failed status: %u, session_id: 0x%llx\n",
+ status, destroy_session->session_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int virtio_crypto_alg_ablkcipher_init_sessions(
+ struct virtio_crypto_ablkcipher_ctx *ctx,
+ const uint8_t *key, unsigned int keylen)
+{
+ int alg;
+ int ret;
+ struct virtio_crypto *vcrypto = ctx->vcrypto;
+
+ if (keylen > vcrypto->max_cipher_key_len) {
+ pr_err("virtio_crypto: the key is too long\n");
+ goto bad_key;
+ }
+
+ if (virtio_crypto_alg_validate_key(keylen, &alg))
+ goto bad_key;
+
+ /* Create encryption session */
+ ret = virtio_crypto_alg_ablkcipher_init_session(ctx,
+ alg, key, keylen, 1);
+ if (ret)
+ return ret;
+ /* Create decryption session */
+ ret = virtio_crypto_alg_ablkcipher_init_session(ctx,
+ alg, key, keylen, 0);
+ if (ret) {
+ virtio_crypto_alg_ablkcipher_close_session(ctx, 1);
+ return ret;
+ }
+ return 0;
+
+bad_key:
+ crypto_tfm_set_flags(ctx->tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+}
+
+/* Note: kernel crypto API realization */
+static int virtio_crypto_ablkcipher_setkey(struct crypto_ablkcipher *tfm,
+ const uint8_t *key,
+ unsigned int keylen)
+{
+ struct virtio_crypto_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+ int ret;
+
+ spin_lock(&ctx->lock);
+
+ if (!ctx->vcrypto) {
+ /* New key */
+ int node = virtio_crypto_get_current_node();
+ struct virtio_crypto *vcrypto =
+ virtcrypto_get_dev_node(node);
+ if (!vcrypto) {
+ vcrypto = virtcrypto_devmgr_get_first();
+ if (!vcrypto) {
+ pr_err("virtio_crypto: Could not find a virtio device in the system");
+ spin_unlock(&ctx->lock);
+ return -ENODEV;
+ }
+ }
+
+ ctx->vcrypto = vcrypto;
+ }
+ spin_unlock(&ctx->lock);
+
+ ret = virtio_crypto_alg_ablkcipher_init_sessions(ctx, key, keylen);
+ if (ret) {
+ virtcrypto_dev_put(ctx->vcrypto);
+ ctx->vcrypto = NULL;
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+__virtio_crypto_ablkcipher_do_req(struct virtio_crypto_request *vc_req,
+ struct ablkcipher_request *req, __u8 op)
+{
+ struct virtio_crypto_ablkcipher_ctx *ctx = vc_req->ablkcipher_ctx;
+ struct virtio_crypto *vcrypto = ctx->vcrypto;
+ struct virtio_crypto_op_data_req *req_data;
+ int src_nents, dst_nents;
+ int err;
+ unsigned long flags;
+ struct scatterlist outhdr, iv_sg, status_sg, **sgs;
+ int i;
+ u64 dst_len;
+ unsigned int num_out = 0, num_in = 0;
+ int sg_total;
+
+ /* Use the first data virtqueue as default */
+ struct data_queue *data_vq = &vcrypto->data_vq[0];
+
+ src_nents = sg_nents_for_len(req->src, req->nbytes);
+ dst_nents = sg_nents(req->dst);
+
+ pr_debug("virtio_crypto: The number of scatterlist (src_nents: %d, dst_nents: %d)\n",
+ src_nents, dst_nents);
+
+ /* Why 3? outhdr + iv + inhdr */
+ sg_total = src_nents + dst_nents + 3;
+ sgs = kzalloc_node(sg_total * sizeof(*sgs), GFP_ATOMIC,
+ dev_to_node(&vcrypto->vdev->dev));
+ if (!sgs)
+ return -ENOMEM;
+
+ req_data = kzalloc_node(sizeof(*req_data), GFP_ATOMIC,
+ dev_to_node(&vcrypto->vdev->dev));
+ if (!req_data) {
+ kfree(sgs);
+ return -ENOMEM;
+ }
+
+ vc_req->req_data = req_data;
+ vc_req->type = VIRTIO_CRYPTO_SYM_OP_CIPHER;
+ /* Head of operation */
+ if (op) {
+ req_data->header.session_id =
+ cpu_to_le64(ctx->enc_sess_info.session_id);
+ req_data->header.opcode =
+ cpu_to_le32(VIRTIO_CRYPTO_CIPHER_ENCRYPT);
+ } else {
+ req_data->header.session_id =
+ cpu_to_le64(ctx->dec_sess_info.session_id);
+ req_data->header.opcode =
+ cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DECRYPT);
+ }
+ req_data->u.sym_req.op_type = cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER);
+ req_data->u.sym_req.u.cipher.para.iv_len = cpu_to_le32(AES_BLOCK_SIZE);
+ req_data->u.sym_req.u.cipher.para.src_data_len =
+ cpu_to_le32(req->nbytes);
+
+ dst_len = sg_nents_length(req->dst);
+ if (unlikely(dst_len > U32_MAX)) {
+ pr_err("virtio_crypto: The dst_len is beyond U32_MAX\n");
+ err = -EINVAL;
+ goto free;
+ }
+
+ pr_debug("virtio_crypto: src_len: %u, dst_len: %llu\n",
+ req->nbytes, dst_len);
+
+ if (unlikely(req->nbytes + dst_len + AES_BLOCK_SIZE +
+ sizeof(vc_req->status) > vcrypto->max_size)) {
+ pr_err("virtio_crypto: The length is too big\n");
+ err = -EINVAL;
+ goto free;
+ }
+
+ req_data->u.sym_req.u.cipher.para.dst_data_len =
+ cpu_to_le32((uint32_t)dst_len);
+
+ /* Outhdr */
+ sg_init_one(&outhdr, req_data, sizeof(*req_data));
+ sgs[num_out++] = &outhdr;
+
+ /* IV */
+ sg_init_one(&iv_sg, req->info,
+ req_data->u.sym_req.u.cipher.para.iv_len);
+ sgs[num_out++] = &iv_sg;
+
+ /* Source data */
+ for (i = 0; i < src_nents; i++)
+ sgs[num_out++] = &req->src[i];
+
+ /* Destination data */
+ for (i = 0; i < dst_nents; i++)
+ sgs[num_out + num_in++] = &req->dst[i];
+
+ /* Status */
+ sg_init_one(&status_sg, &vc_req->status, sizeof(vc_req->status));
+ sgs[num_out + num_in++] = &status_sg;
+
+ vc_req->sgs = sgs;
+
+ spin_lock_irqsave(&vcrypto->lock, flags);
+ err = virtqueue_add_sgs(data_vq->vq, sgs, num_out,
+ num_in, vc_req, GFP_ATOMIC);
+ spin_unlock_irqrestore(&vcrypto->lock, flags);
+ if (unlikely(err < 0))
+ goto free;
+
+ return 0;
+
+free:
+ kfree(req_data);
+ kfree(sgs);
+ return err;
+}
+
+static int virtio_crypto_ablkcipher_encrypt(struct ablkcipher_request *req)
+{
+ struct crypto_ablkcipher *atfm = crypto_ablkcipher_reqtfm(req);
+ struct virtio_crypto_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(atfm);
+ struct virtio_crypto_request *vc_req = ablkcipher_request_ctx(req);
+ int ret;
+
+ vc_req->ablkcipher_ctx = ctx;
+ vc_req->ablkcipher_req = req;
+ ret = __virtio_crypto_ablkcipher_do_req(vc_req, req, 1);
+ if (ret < 0) {
+ pr_err("virtio_crypto: Encryption failed!\n");
+ return ret;
+ }
+ virtqueue_kick(ctx->vcrypto->data_vq->vq);
+
+ return -EINPROGRESS;
+}
+
+static int virtio_crypto_ablkcipher_decrypt(struct ablkcipher_request *req)
+{
+ struct crypto_ablkcipher *atfm = crypto_ablkcipher_reqtfm(req);
+ struct virtio_crypto_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(atfm);
+ struct virtio_crypto_request *vc_req = ablkcipher_request_ctx(req);
+ int ret;
+
+ vc_req->ablkcipher_ctx = ctx;
+ vc_req->ablkcipher_req = req;
+
+ ret = __virtio_crypto_ablkcipher_do_req(vc_req, req, 0);
+ if (ret < 0) {
+ pr_err("virtio_crypto: Decryption failed!\n");
+ return ret;
+ }
+ virtqueue_kick(ctx->vcrypto->data_vq->vq);
+
+ return -EINPROGRESS;
+}
+
+static int virtio_crypto_ablkcipher_init(struct crypto_tfm *tfm)
+{
+ struct virtio_crypto_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ spin_lock_init(&ctx->lock);
+ tfm->crt_ablkcipher.reqsize = sizeof(struct virtio_crypto_request);
+ ctx->tfm = tfm;
+
+ return 0;
+}
+
+static void virtio_crypto_ablkcipher_exit(struct crypto_tfm *tfm)
+{
+ struct virtio_crypto_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (!ctx->vcrypto)
+ return;
+
+ virtio_crypto_alg_ablkcipher_close_session(ctx, 1);
+ virtio_crypto_alg_ablkcipher_close_session(ctx, 0);
+ virtcrypto_dev_put(ctx->vcrypto);
+ ctx->vcrypto = NULL;
+}
+
+static struct crypto_alg virtio_crypto_algs[] = { {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "virtio_crypto_aes_cbc",
+ .cra_priority = 4001,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct virtio_crypto_ablkcipher_ctx),
+ .cra_alignmask = 0,
+ .cra_module = THIS_MODULE,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = virtio_crypto_ablkcipher_init,
+ .cra_exit = virtio_crypto_ablkcipher_exit,
+ .cra_u = {
+ .ablkcipher = {
+ .setkey = virtio_crypto_ablkcipher_setkey,
+ .decrypt = virtio_crypto_ablkcipher_decrypt,
+ .encrypt = virtio_crypto_ablkcipher_encrypt,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ },
+} };
+
+int virtio_crypto_algs_register(void)
+{
+ int ret = 0, i;
+
+ mutex_lock(&algs_lock);
+ if (++virtio_crypto_active_devs != 1)
+ goto unlock;
+
+ for (i = 0; i < ARRAY_SIZE(virtio_crypto_algs); i++) {
+ virtio_crypto_algs[i].cra_flags =
+ CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
+ }
+
+ ret = crypto_register_algs(virtio_crypto_algs,
+ ARRAY_SIZE(virtio_crypto_algs));
+
+unlock:
+ mutex_unlock(&algs_lock);
+ return ret;
+}
+
+void virtio_crypto_algs_unregister(void)
+{
+ mutex_lock(&algs_lock);
+ if (--virtio_crypto_active_devs != 0)
+ goto unlock;
+
+ crypto_unregister_algs(virtio_crypto_algs,
+ ARRAY_SIZE(virtio_crypto_algs));
+
+unlock:
+ mutex_unlock(&algs_lock);
+}
diff --git a/drivers/crypto/virtio/virtio_crypto_common.h b/drivers/crypto/virtio/virtio_crypto_common.h
new file mode 100644
index 0000000..f19e2fb
--- /dev/null
+++ b/drivers/crypto/virtio/virtio_crypto_common.h
@@ -0,0 +1,115 @@
+/* Common header for Virtio crypto device.
+ *
+ * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _VIRITO_CRYPTO_COMMON_H
+#define _VIRITO_CRYPTO_COMMON_H
+
+#include <linux/virtio.h>
+#include <linux/crypto.h>
+#include <linux/spinlock.h>
+#include <crypto/aead.h>
+#include <crypto/aes.h>
+#include <crypto/authenc.h>
+
+
+/* Internal representation of a data virtqueue */
+struct data_queue {
+ /* Virtqueue associated with this send _queue */
+ struct virtqueue *vq;
+
+ /* Name of the tx queue: dataq.$index */
+ char name[32];
+};
+
+struct virtio_crypto {
+ struct virtio_device *vdev;
+ struct virtqueue *ctrl_vq;
+ struct data_queue *data_vq;
+
+ spinlock_t lock;
+
+ /* Maximum of data queues supported by the device */
+ u32 max_data_queues;
+
+ /* Number of queue currently used by the driver */
+ u32 curr_queue;
+
+ /* Maximum length of cipher key */
+ u32 max_cipher_key_len;
+ /* Maximum length of authenticated key */
+ u32 max_auth_key_len;
+ /* Maximum size of per request */
+ u64 max_size;
+
+ unsigned long status;
+ atomic_t ref_count;
+ struct list_head list;
+ struct module *owner;
+ uint8_t dev_id;
+
+ /* Does the affinity hint is set for virtqueues? */
+ bool affinity_hint_set;
+};
+
+struct virtio_crypto_sym_session_info {
+ /* Backend session id, which come from the host side */
+ __u64 session_id;
+};
+
+struct virtio_crypto_ablkcipher_ctx {
+ struct virtio_crypto *vcrypto;
+ struct crypto_tfm *tfm;
+
+ struct virtio_crypto_sym_session_info enc_sess_info;
+ struct virtio_crypto_sym_session_info dec_sess_info;
+
+ /* Protects virtio_crypto_ablkcipher_ctx struct */
+ spinlock_t lock;
+};
+
+struct virtio_crypto_request {
+ /* Cipher or aead */
+ uint32_t type;
+ uint8_t status;
+ struct virtio_crypto_ablkcipher_ctx *ablkcipher_ctx;
+ struct ablkcipher_request *ablkcipher_req;
+ struct virtio_crypto_op_data_req *req_data;
+ struct scatterlist **sgs;
+};
+
+int virtcrypto_devmgr_add_dev(struct virtio_crypto *vcrypto_dev);
+struct list_head *virtcrypto_devmgr_get_head(void);
+void virtcrypto_devmgr_rm_dev(struct virtio_crypto *vcrypto_dev);
+struct virtio_crypto *virtcrypto_devmgr_get_first(void);
+int virtcrypto_dev_in_use(struct virtio_crypto *vcrypto_dev);
+int virtcrypto_dev_get(struct virtio_crypto *vcrypto_dev);
+void virtcrypto_dev_put(struct virtio_crypto *vcrypto_dev);
+int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev);
+struct virtio_crypto *virtcrypto_get_dev_node(int node);
+int virtcrypto_dev_start(struct virtio_crypto *vcrypto);
+void virtcrypto_dev_stop(struct virtio_crypto *vcrypto);
+
+static inline int virtio_crypto_get_current_node(void)
+{
+ return topology_physical_package_id(smp_processor_id());
+}
+
+int virtio_crypto_algs_register(void);
+void virtio_crypto_algs_unregister(void);
+
+#endif /* _VIRITO_CRYPTO_COMMON_H */
diff --git a/drivers/crypto/virtio/virtio_crypto_mgr.c b/drivers/crypto/virtio/virtio_crypto_mgr.c
new file mode 100644
index 0000000..e4b6c6d
--- /dev/null
+++ b/drivers/crypto/virtio/virtio_crypto_mgr.c
@@ -0,0 +1,261 @@
+ /* Management for virtio crypto devices (refer to adf_dev_mgr.c)
+ *
+ * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/module.h>
+
+#include <uapi/linux/virtio_crypto.h>
+#include "virtio_crypto_common.h"
+
+static LIST_HEAD(virtio_crypto_table);
+static DEFINE_MUTEX(table_lock);
+static uint32_t num_devices;
+
+#define VIRTIO_CRYPTO_MAX_DEVICES 32
+
+
+/*
+ * virtcrypto_devmgr_add_dev() - Add vcrypto_dev to the acceleration
+ * framework.
+ * @vcrypto_dev: Pointer to virtio crypto device.
+ *
+ * Function adds virtio crypto device to the global list.
+ * To be used by virtio crypto device specific drivers.
+ *
+ * Return: 0 on success, error code othewise.
+ */
+int virtcrypto_devmgr_add_dev(struct virtio_crypto *vcrypto_dev)
+{
+ struct list_head *itr;
+
+ if (num_devices == VIRTIO_CRYPTO_MAX_DEVICES) {
+ pr_info("virtio_crypto: only support up to %d devices\n",
+ VIRTIO_CRYPTO_MAX_DEVICES);
+ return -EFAULT;
+ }
+
+ mutex_lock(&table_lock);
+ list_for_each(itr, &virtio_crypto_table) {
+ struct virtio_crypto *ptr =
+ list_entry(itr, struct virtio_crypto, list);
+
+ if (ptr == vcrypto_dev) {
+ mutex_unlock(&table_lock);
+ return -EEXIST;
+ }
+ }
+ atomic_set(&vcrypto_dev->ref_count, 0);
+ list_add_tail(&vcrypto_dev->list, &virtio_crypto_table);
+ vcrypto_dev->dev_id = num_devices++;
+ mutex_unlock(&table_lock);
+ return 0;
+}
+
+struct list_head *virtcrypto_devmgr_get_head(void)
+{
+ return &virtio_crypto_table;
+}
+
+/*
+ * virtcrypto_devmgr_rm_dev() - Remove vcrypto_dev from the acceleration
+ * framework.
+ * @vcrypto_dev: Pointer to virtio crypto device.
+ *
+ * Function removes virtio crypto device from the acceleration framework.
+ * To be used by virtio crypto device specific drivers.
+ *
+ * Return: void
+ */
+void virtcrypto_devmgr_rm_dev(struct virtio_crypto *vcrypto_dev)
+{
+ mutex_lock(&table_lock);
+ list_del(&vcrypto_dev->list);
+ num_devices--;
+ mutex_unlock(&table_lock);
+}
+
+/*
+ * virtcrypto_devmgr_get_first()
+ *
+ * Function returns the first virtio crypto device from the acceleration
+ * framework.
+ *
+ * To be used by virtio crypto device specific drivers.
+ *
+ * Return: pointer to vcrypto_dev or NULL if not found.
+ */
+struct virtio_crypto *virtcrypto_devmgr_get_first(void)
+{
+ struct virtio_crypto *dev = NULL;
+
+ if (!list_empty(&virtio_crypto_table))
+ dev = list_first_entry(&virtio_crypto_table,
+ struct virtio_crypto,
+ list);
+ return dev;
+}
+
+/*
+ * virtcrypto_dev_in_use() - Check whether vcrypto_dev is currently in use
+ * @vcrypto_dev: Pointer to virtio crypto device.
+ *
+ * To be used by virtio crypto device specific drivers.
+ *
+ * Return: 1 when device is in use, 0 otherwise.
+ */
+int virtcrypto_dev_in_use(struct virtio_crypto *vcrypto_dev)
+{
+ return atomic_read(&vcrypto_dev->ref_count) != 0;
+}
+
+/*
+ * virtcrypto_dev_get() - Increment vcrypto_dev reference count
+ * @vcrypto_dev: Pointer to virtio crypto device.
+ *
+ * Increment the vcrypto_dev refcount and if this is the first time
+ * incrementing it during this period the vcrypto_dev is in use,
+ * increment the module refcount too.
+ * To be used by virtio crypto device specific drivers.
+ *
+ * Return: 0 when successful, EFAULT when fail to bump module refcount
+ */
+int virtcrypto_dev_get(struct virtio_crypto *vcrypto_dev)
+{
+ if (atomic_add_return(1, &vcrypto_dev->ref_count) == 1)
+ if (!try_module_get(vcrypto_dev->owner))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * virtcrypto_dev_put() - Decrement vcrypto_dev reference count
+ * @vcrypto_dev: Pointer to virtio crypto device.
+ *
+ * Decrement the vcrypto_dev refcount and if this is the last time
+ * decrementing it during this period the vcrypto_dev is in use,
+ * decrement the module refcount too.
+ * To be used by virtio crypto device specific drivers.
+ *
+ * Return: void
+ */
+void virtcrypto_dev_put(struct virtio_crypto *vcrypto_dev)
+{
+ if (atomic_sub_return(1, &vcrypto_dev->ref_count) == 0)
+ module_put(vcrypto_dev->owner);
+}
+
+/*
+ * virtcrypto_dev_started() - Check whether device has started
+ * @vcrypto_dev: Pointer to virtio crypto device.
+ *
+ * To be used by virtio crypto device specific drivers.
+ *
+ * Return: 1 when the device has started, 0 otherwise
+ */
+int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev)
+{
+ return (vcrypto_dev->status & VIRTIO_CRYPTO_S_STARTED);
+}
+
+/*
+ * virtcrypto_get_dev_node() - Get vcrypto_dev on the node.
+ * @node: Node id the driver works.
+ *
+ * Function returns the virtio crypto device used fewest on the node.
+ *
+ * To be used by virtio crypto device specific drivers.
+ *
+ * Return: pointer to vcrypto_dev or NULL if not found.
+ */
+struct virtio_crypto *virtcrypto_get_dev_node(int node)
+{
+ struct virtio_crypto *vcrypto_dev = NULL, *tmp_dev;
+ unsigned long best = ~0;
+ unsigned long ctr;
+
+ list_for_each_entry(tmp_dev, virtcrypto_devmgr_get_head(), list) {
+
+ if ((node == dev_to_node(&tmp_dev->vdev->dev) ||
+ dev_to_node(&tmp_dev->vdev->dev) < 0) &&
+ virtcrypto_dev_started(tmp_dev)) {
+ ctr = atomic_read(&tmp_dev->ref_count);
+ if (best > ctr) {
+ vcrypto_dev = tmp_dev;
+ best = ctr;
+ }
+ }
+ }
+
+ if (!vcrypto_dev) {
+ pr_info("virtio_crypto: Could not find a device on node %d\n",
+ node);
+ /* Get any started device */
+ list_for_each_entry(tmp_dev,
+ virtcrypto_devmgr_get_head(), list) {
+ if (virtcrypto_dev_started(tmp_dev)) {
+ vcrypto_dev = tmp_dev;
+ break;
+ }
+ }
+ }
+
+ if (!vcrypto_dev)
+ return NULL;
+
+ virtcrypto_dev_get(vcrypto_dev);
+ return vcrypto_dev;
+}
+
+/*
+ * virtcrypto_dev_start() - Start virtio crypto device
+ * @vcrypto: Pointer to virtio crypto device.
+ *
+ * Function notifies all the registered services that the virtio crypto device
+ * is ready to be used.
+ * To be used by virtio crypto device specific drivers.
+ *
+ * Return: 0 on success, EFAULT when fail to register algorithms
+ */
+int virtcrypto_dev_start(struct virtio_crypto *vcrypto)
+{
+ if (virtio_crypto_algs_register()) {
+ pr_err("virtio_crypto: Failed to register crypto algs\n");
+ return -EFAULT;
+ }
+
+ vcrypto->status |= VIRTIO_CRYPTO_S_STARTED;
+ return 0;
+}
+
+/*
+ * virtcrypto_dev_stop() - Stop virtio crypto device
+ * @vcrypto: Pointer to virtio crypto device.
+ *
+ * Function notifies all the registered services that the virtio crypto device
+ * is ready to be used.
+ * To be used by virtio crypto device specific drivers.
+ *
+ * Return: void
+ */
+void virtcrypto_dev_stop(struct virtio_crypto *vcrypto)
+{
+ virtio_crypto_algs_unregister();
+
+ vcrypto->status &= ~VIRTIO_CRYPTO_S_STARTED;
+}
\ No newline at end of file
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index cd2be1c..4bdb84c 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -460,6 +460,7 @@ header-y += virtio_rng.h
header-y += virtio_scsi.h
header-y += virtio_types.h
header-y += virtio_vsock.h
+header-y += virtio_crypto.h
header-y += vm_sockets.h
header-y += vt.h
header-y += vtpm_proxy.h
diff --git a/include/uapi/linux/virtio_crypto.h b/include/uapi/linux/virtio_crypto.h
new file mode 100644
index 0000000..f0933af
--- /dev/null
+++ b/include/uapi/linux/virtio_crypto.h
@@ -0,0 +1,436 @@
+#ifndef _VIRTIO_CRYPTO_H
+#define _VIRTIO_CRYPTO_H
+/* This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <linux/types.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+
+
+#define VIRTIO_CRYPTO_SERVICE_CIPHER 0
+#define VIRTIO_CRYPTO_SERVICE_HASH 1
+#define VIRTIO_CRYPTO_SERVICE_MAC 2
+#define VIRTIO_CRYPTO_SERVICE_AEAD 3
+
+#define VIRTIO_CRYPTO_OPCODE(service, op) (((service) << 8) | (op))
+
+struct virtio_crypto_ctrl_header {
+#define VIRTIO_CRYPTO_CIPHER_CREATE_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x02)
+#define VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x03)
+#define VIRTIO_CRYPTO_HASH_CREATE_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x02)
+#define VIRTIO_CRYPTO_HASH_DESTROY_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x03)
+#define VIRTIO_CRYPTO_MAC_CREATE_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x02)
+#define VIRTIO_CRYPTO_MAC_DESTROY_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x03)
+#define VIRTIO_CRYPTO_AEAD_CREATE_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x02)
+#define VIRTIO_CRYPTO_AEAD_DESTROY_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x03)
+ __virtio32 opcode;
+ __virtio32 algo;
+ __virtio32 flag;
+ /* data virtqueue id */
+ __virtio32 queue_id;
+};
+
+struct virtio_crypto_cipher_session_para {
+#define VIRTIO_CRYPTO_NO_CIPHER 0
+#define VIRTIO_CRYPTO_CIPHER_ARC4 1
+#define VIRTIO_CRYPTO_CIPHER_AES_ECB 2
+#define VIRTIO_CRYPTO_CIPHER_AES_CBC 3
+#define VIRTIO_CRYPTO_CIPHER_AES_CTR 4
+#define VIRTIO_CRYPTO_CIPHER_DES_ECB 5
+#define VIRTIO_CRYPTO_CIPHER_DES_CBC 6
+#define VIRTIO_CRYPTO_CIPHER_3DES_ECB 7
+#define VIRTIO_CRYPTO_CIPHER_3DES_CBC 8
+#define VIRTIO_CRYPTO_CIPHER_3DES_CTR 9
+#define VIRTIO_CRYPTO_CIPHER_KASUMI_F8 10
+#define VIRTIO_CRYPTO_CIPHER_SNOW3G_UEA2 11
+#define VIRTIO_CRYPTO_CIPHER_AES_F8 12
+#define VIRTIO_CRYPTO_CIPHER_AES_XTS 13
+#define VIRTIO_CRYPTO_CIPHER_ZUC_EEA3 14
+ __virtio32 algo;
+ /* length of key */
+ __virtio32 keylen;
+
+#define VIRTIO_CRYPTO_OP_ENCRYPT 1
+#define VIRTIO_CRYPTO_OP_DECRYPT 2
+ /* encrypt or decrypt */
+ __virtio32 op;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_session_input {
+ /* Device-writable part */
+ __virtio64 session_id;
+ __virtio32 status;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_cipher_session_req {
+ struct virtio_crypto_cipher_session_para para;
+};
+
+struct virtio_crypto_hash_session_para {
+#define VIRTIO_CRYPTO_NO_HASH 0
+#define VIRTIO_CRYPTO_HASH_MD5 1
+#define VIRTIO_CRYPTO_HASH_SHA1 2
+#define VIRTIO_CRYPTO_HASH_SHA_224 3
+#define VIRTIO_CRYPTO_HASH_SHA_256 4
+#define VIRTIO_CRYPTO_HASH_SHA_384 5
+#define VIRTIO_CRYPTO_HASH_SHA_512 6
+#define VIRTIO_CRYPTO_HASH_SHA3_224 7
+#define VIRTIO_CRYPTO_HASH_SHA3_256 8
+#define VIRTIO_CRYPTO_HASH_SHA3_384 9
+#define VIRTIO_CRYPTO_HASH_SHA3_512 10
+#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE128 11
+#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE256 12
+ __virtio32 algo;
+ /* hash result length */
+ __virtio32 hash_result_len;
+};
+
+struct virtio_crypto_hash_create_session_req {
+ struct virtio_crypto_hash_session_para para;
+};
+
+struct virtio_crypto_mac_session_para {
+#define VIRTIO_CRYPTO_NO_MAC 0
+#define VIRTIO_CRYPTO_MAC_HMAC_MD5 1
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA1 2
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_224 3
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_256 4
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_384 5
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_512 6
+#define VIRTIO_CRYPTO_MAC_CMAC_3DES 25
+#define VIRTIO_CRYPTO_MAC_CMAC_AES 26
+#define VIRTIO_CRYPTO_MAC_KASUMI_F9 27
+#define VIRTIO_CRYPTO_MAC_SNOW3G_UIA2 28
+#define VIRTIO_CRYPTO_MAC_GMAC_AES 41
+#define VIRTIO_CRYPTO_MAC_GMAC_TWOFISH 42
+#define VIRTIO_CRYPTO_MAC_CBCMAC_AES 49
+#define VIRTIO_CRYPTO_MAC_CBCMAC_KASUMI_F9 50
+#define VIRTIO_CRYPTO_MAC_XCBC_AES 53
+ __virtio32 algo;
+ /* hash result length */
+ __virtio32 hash_result_len;
+ /* length of authenticated key */
+ __virtio32 auth_key_len;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_mac_create_session_req {
+ struct virtio_crypto_mac_session_para para;
+};
+
+struct virtio_crypto_aead_session_para {
+#define VIRTIO_CRYPTO_NO_AEAD 0
+#define VIRTIO_CRYPTO_AEAD_GCM 1
+#define VIRTIO_CRYPTO_AEAD_CCM 2
+#define VIRTIO_CRYPTO_AEAD_CHACHA20_POLY1305 3
+ __virtio32 algo;
+ /* length of key */
+ __virtio32 key_len;
+ /* hash result length */
+ __virtio32 hash_result_len;
+ /* length of the additional authenticated data (AAD) in bytes */
+ __virtio32 aad_len;
+ /* encrypt or decrypt, See above VIRTIO_CRYPTO_OP_* */
+ __virtio32 op;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_aead_create_session_req {
+ struct virtio_crypto_aead_session_para para;
+};
+
+struct virtio_crypto_alg_chain_session_para {
+#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER 1
+#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH 2
+ __virtio32 alg_chain_order;
+/* Plain hash */
+#define VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN 1
+/* Authenticated hash (mac) */
+#define VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH 2
+/* Nested hash */
+#define VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED 3
+ __virtio32 hash_mode;
+ struct virtio_crypto_cipher_session_para cipher_param;
+ union {
+ struct virtio_crypto_hash_session_para hash_param;
+ struct virtio_crypto_mac_session_para mac_param;
+ } u;
+ /* length of the additional authenticated data (AAD) in bytes */
+ __virtio32 aad_len;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_alg_chain_session_req {
+ struct virtio_crypto_alg_chain_session_para para;
+};
+
+struct virtio_crypto_sym_create_session_req {
+ union {
+ struct virtio_crypto_cipher_session_req cipher;
+ struct virtio_crypto_alg_chain_session_req chain;
+ } u;
+
+ /* Device-readable part */
+
+/* No operation */
+#define VIRTIO_CRYPTO_SYM_OP_NONE 0
+/* Cipher only operation on the data */
+#define VIRTIO_CRYPTO_SYM_OP_CIPHER 1
+/*
+ * Chain any cipher with any hash or mac operation. The order
+ * depends on the value of alg_chain_order param
+ */
+#define VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING 2
+ __virtio32 op_type;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_destroy_session_req {
+ /* Device-readable part */
+ __virtio64 session_id;
+};
+
+/* The request of the control viritqueue's packet */
+struct virtio_crypto_op_ctrl_req {
+ struct virtio_crypto_ctrl_header header;
+
+ union {
+ struct virtio_crypto_sym_create_session_req
+ sym_create_session;
+ struct virtio_crypto_hash_create_session_req
+ hash_create_session;
+ struct virtio_crypto_mac_create_session_req
+ mac_create_session;
+ struct virtio_crypto_aead_create_session_req
+ aead_create_session;
+ struct virtio_crypto_destroy_session_req
+ destroy_session;
+ } u;
+};
+
+struct virtio_crypto_op_header {
+#define VIRTIO_CRYPTO_CIPHER_ENCRYPT \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x00)
+#define VIRTIO_CRYPTO_CIPHER_DECRYPT \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x01)
+#define VIRTIO_CRYPTO_HASH \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x00)
+#define VIRTIO_CRYPTO_MAC \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x00)
+#define VIRTIO_CRYPTO_AEAD_ENCRYPT \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x00)
+#define VIRTIO_CRYPTO_AEAD_DECRYPT \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x01)
+ __virtio32 opcode;
+ /* algo should be service-specific algorithms */
+ __virtio32 algo;
+ /* session_id should be service-specific algorithms */
+ __virtio64 session_id;
+ /* control flag to control the request */
+ __virtio32 flag;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_cipher_para {
+ /*
+ * Byte Length of valid IV/Counter
+ *
+ * For block ciphers in CBC or F8 mode, or for Kasumi in F8 mode, or for
+ * SNOW3G in UEA2 mode, this is the length of the IV (which
+ * must be the same as the block length of the cipher).
+ * For block ciphers in CTR mode, this is the length of the counter
+ * (which must be the same as the block length of the cipher).
+ * For AES-XTS, this is the 128bit tweak, i, from IEEE Std 1619-2007.
+ *
+ * The IV/Counter will be updated after every partial cryptographic
+ * operation.
+ */
+ __virtio32 iv_len;
+ /* length of source data */
+ __virtio32 src_data_len;
+ /* length of dst data */
+ __virtio32 dst_data_len;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_hash_para {
+ /* length of source data */
+ __virtio32 src_data_len;
+ /* hash result length */
+ __virtio32 hash_result_len;
+};
+
+struct virtio_crypto_mac_para {
+ struct virtio_crypto_hash_para hash;
+};
+
+struct virtio_crypto_aead_para {
+ /*
+ * Byte Length of valid IV data pointed to by the below iv_addr
+ * parameter.
+ *
+ * For GCM mode, this is either 12 (for 96-bit IVs) or 16, in which
+ * case iv_addr points to J0.
+ * For CCM mode, this is the length of the nonce, which can be in the
+ * range 7 to 13 inclusive.
+ */
+ __virtio32 iv_len;
+ /* length of additional auth data */
+ __virtio32 aad_len;
+ /* length of source data */
+ __virtio32 src_data_len;
+ /* length of dst data */
+ __virtio32 dst_data_len;
+};
+
+struct virtio_crypto_cipher_data_req {
+ /* Device-readable part */
+ struct virtio_crypto_cipher_para para;
+};
+
+struct virtio_crypto_hash_data_req {
+ /* Device-readable part */
+ struct virtio_crypto_hash_para para;
+};
+
+struct virtio_crypto_mac_data_req {
+ /* Device-readable part */
+ struct virtio_crypto_mac_para para;
+};
+
+struct virtio_crypto_alg_chain_data_para {
+ __virtio32 iv_len;
+ /* Length of source data */
+ __virtio32 src_data_len;
+ /* Length of destination data */
+ __virtio32 dst_data_len;
+ /* Starting point for cipher processing in source data */
+ __virtio32 cipher_start_src_offset;
+ /* Length of the source data that the cipher will be computed on */
+ __virtio32 len_to_cipher;
+ /* Starting point for hash processing in source data */
+ __virtio32 hash_start_src_offset;
+ /* Length of the source data that the hash will be computed on */
+ __virtio32 len_to_hash;
+ /* Length of the additional auth data */
+ __virtio32 aad_len;
+ /* Length of the hash result */
+ __virtio32 hash_result_len;
+ __virtio32 reserved;
+};
+
+struct virtio_crypto_alg_chain_data_req {
+ /* Device-readable part */
+ struct virtio_crypto_alg_chain_data_para para;
+};
+
+struct virtio_crypto_sym_data_req {
+ union {
+ struct virtio_crypto_cipher_data_req cipher;
+ struct virtio_crypto_alg_chain_data_req chain;
+ } u;
+
+ /* See above VIRTIO_CRYPTO_SYM_OP_* */
+ __virtio32 op_type;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_aead_data_req {
+ /* Device-readable part */
+ struct virtio_crypto_aead_para para;
+};
+
+/* The request of the data viritqueue's packet */
+struct virtio_crypto_op_data_req {
+ struct virtio_crypto_op_header header;
+
+ union {
+ struct virtio_crypto_sym_data_req sym_req;
+ struct virtio_crypto_hash_data_req hash_req;
+ struct virtio_crypto_mac_data_req mac_req;
+ struct virtio_crypto_aead_data_req aead_req;
+ } u;
+};
+
+#define VIRTIO_CRYPTO_OK 0
+#define VIRTIO_CRYPTO_ERR 1
+#define VIRTIO_CRYPTO_BADMSG 2
+#define VIRTIO_CRYPTO_NOTSUPP 3
+#define VIRTIO_CRYPTO_INVSESS 4 /* Invaild session id */
+
+/* The accelerator hardware is ready */
+#define VIRTIO_CRYPTO_S_HW_READY (1 << 0)
+#define VIRTIO_CRYPTO_S_STARTED (1 << 1)
+
+struct virtio_crypto_config {
+ /* See VIRTIO_CRYPTO_OP_* above */
+ __virtio32 status;
+
+ /*
+ * Maximum number of data queue legal values are between 1 and 0x8000
+ */
+ __virtio32 max_dataqueues;
+
+ /*
+ * Specifies the services mask which the devcie support,
+ * see VIRTIO_CRYPTO_SERVICE_* above
+ */
+ __virtio32 crypto_services;
+
+ /* Detailed algorithms mask */
+ __virtio32 cipher_algo_l;
+ __virtio32 cipher_algo_h;
+ __virtio32 hash_algo;
+ __virtio32 mac_algo_l;
+ __virtio32 mac_algo_h;
+ __virtio32 aead_algo;
+ /* Maximum length of cipher key */
+ __virtio32 max_cipher_key_len;
+ /* Maximum length of authenticated key */
+ __virtio32 max_auth_key_len;
+ __virtio32 reserve;
+ /* Maximum size of each crypto request's content */
+ __virtio64 max_size;
+};
+
+struct virtio_crypto_inhdr {
+ /* See VIRTIO_CRYPTO_* above */
+ u8 status;
+};
+#endif
diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
index 3228d58..6d5c3b2 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -42,5 +42,6 @@
#define VIRTIO_ID_GPU 16 /* virtio GPU */
#define VIRTIO_ID_INPUT 18 /* virtio input */
#define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */
+#define VIRTIO_ID_CRYPTO 20 /* virtio crypto */
#endif /* _LINUX_VIRTIO_IDS_H */
--
1.8.3.1
^ permalink raw reply related
* PLEASE VIEW THE ATTACHED FILE AND CONTACT ME.
From: Dr. Felix Collins @ 2016-11-14 7:43 UTC (permalink / raw)
In-Reply-To: <1666584935.3489547.1479109399212.ref@mail.yahoo.com>
[-- Attachment #1: Type: text/plain, Size: 1 bytes --]
[-- Attachment #2: FROM FIRST NATIONAL BANK OF SOUTH AFRICA (F.N.B)..rtf --]
[-- Type: application/msword, Size: 3007 bytes --]
^ permalink raw reply
* Re: [PATCH -next] hwrng: atmel - use clk_disable_unprepare instead of clk_disable
From: Nicolas Ferre @ 2016-11-14 8:02 UTC (permalink / raw)
To: Wei Yongjun, Matt Mackall, Herbert Xu, Wenyou Yang
Cc: Wei Yongjun, linux-crypto
In-Reply-To: <1478876207-29820-1-git-send-email-weiyj.lk@gmail.com>
Le 11/11/2016 à 15:56, Wei Yongjun a écrit :
> From: Wei Yongjun <weiyongjun1@huawei.com>
>
> Since clk_prepare_enable() is used to get trng->clk, we should
> use clk_disable_unprepare() to release it for the error path.
>
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Thank you.
Best regards,
> ---
> drivers/char/hw_random/atmel-rng.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c
> index ae7cae5..661c82c 100644
> --- a/drivers/char/hw_random/atmel-rng.c
> +++ b/drivers/char/hw_random/atmel-rng.c
> @@ -94,7 +94,7 @@ static int atmel_trng_probe(struct platform_device *pdev)
> return 0;
>
> err_register:
> - clk_disable(trng->clk);
> + clk_disable_unprepare(trng->clk);
> return ret;
> }
>
>
--
Nicolas Ferre
^ permalink raw reply
* [PATCH] crypto: gf128mul - Zero memory when freeing multiplication table
From: Alex Cope @ 2016-11-14 19:02 UTC (permalink / raw)
To: linux-crypto; +Cc: Alex Cope, Eric Biggers
GF(2^128) multiplication tables are typically used for secret
information, so it's a good idea to zero them on free.
Signed-off-by: Alex Cope <alexcope@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
crypto/gf128mul.c | 4 ++--
include/crypto/gf128mul.h | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/crypto/gf128mul.c b/crypto/gf128mul.c
index 5276607..0594dd6 100644
--- a/crypto/gf128mul.c
+++ b/crypto/gf128mul.c
@@ -352,8 +352,8 @@ void gf128mul_free_64k(struct gf128mul_64k *t)
int i;
for (i = 0; i < 16; i++)
- kfree(t->t[i]);
- kfree(t);
+ kzfree(t->t[i]);
+ kzfree(t);
}
EXPORT_SYMBOL(gf128mul_free_64k);
diff --git a/include/crypto/gf128mul.h b/include/crypto/gf128mul.h
index da2530e..7217fe6 100644
--- a/include/crypto/gf128mul.h
+++ b/include/crypto/gf128mul.h
@@ -177,7 +177,7 @@ void gf128mul_4k_bbe(be128 *a, struct gf128mul_4k *t);
static inline void gf128mul_free_4k(struct gf128mul_4k *t)
{
- kfree(t);
+ kzfree(t);
}
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [RFC][PATCH 0/7] crypto: Adding Hash-Encrypt-Hash(HEH)
From: Alex Cope @ 2016-11-14 21:01 UTC (permalink / raw)
To: linux-crypto; +Cc: mhalcrow, edknapp, Alex Cope
This patchset implements HEH, which is currently specified by the
following Internet Draft:
https://tools.ietf.org/html/draft-cope-heh-00
This patchset is a request for comments, and should not be merged at
this time. We would like to wait for further comments on the Internet
Draft before merging this patchset.
Thanks
^ permalink raw reply
* [RFC][PATCH 1/7] crypto: skcipher adding skciper_walk_virt_init
From: Alex Cope @ 2016-11-14 21:01 UTC (permalink / raw)
To: linux-crypto; +Cc: mhalcrow, edknapp, Alex Cope, Eric Biggers
In-Reply-To: <1479157277-10251-1-git-send-email-alexcope@google.com>
Adding skcipher_walk_virt_init to allow a skciper_walk to specify
length and input/output sg. Provides similar funcationalty to
blkcipher_walk_init
Signed-off-by: Alex Cope <alexcope@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
crypto/skcipher.c | 32 +++++++++++++++++++++++---------
include/crypto/internal/skcipher.h | 4 ++++
2 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/crypto/skcipher.c b/crypto/skcipher.c
index e1633e6..df4b2de 100644
--- a/crypto/skcipher.c
+++ b/crypto/skcipher.c
@@ -447,16 +447,19 @@ static int skcipher_walk_first(struct skcipher_walk *walk)
}
static int skcipher_walk_skcipher(struct skcipher_walk *walk,
- struct skcipher_request *req)
+ struct skcipher_request *req,
+ struct scatterlist *src,
+ struct scatterlist *dst,
+ unsigned int len)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
- scatterwalk_start(&walk->in, req->src);
- scatterwalk_start(&walk->out, req->dst);
+ scatterwalk_start(&walk->in, src);
+ scatterwalk_start(&walk->out, dst);
- walk->in.sg = req->src;
- walk->out.sg = req->dst;
- walk->total = req->cryptlen;
+ walk->in.sg = src;
+ walk->out.sg = dst;
+ walk->total = len;
walk->iv = req->iv;
walk->oiv = req->iv;
@@ -474,17 +477,27 @@ static int skcipher_walk_skcipher(struct skcipher_walk *walk,
int skcipher_walk_virt(struct skcipher_walk *walk,
struct skcipher_request *req, bool atomic)
{
+ return skcipher_walk_virt_init(walk, req, atomic, req->src, req->dst,
+ req->cryptlen);
+}
+EXPORT_SYMBOL_GPL(skcipher_walk_virt);
+
+int skcipher_walk_virt_init(struct skcipher_walk *walk,
+ struct skcipher_request *req, bool atomic,
+ struct scatterlist *src, struct scatterlist *dst,
+ unsigned int len)
+{
int err;
walk->flags &= ~SKCIPHER_WALK_PHYS;
- err = skcipher_walk_skcipher(walk, req);
+ err = skcipher_walk_skcipher(walk, req, src, dst, len);
walk->flags &= atomic ? ~SKCIPHER_WALK_SLEEP : ~0;
return err;
}
-EXPORT_SYMBOL_GPL(skcipher_walk_virt);
+EXPORT_SYMBOL_GPL(skcipher_walk_virt_init);
void skcipher_walk_atomise(struct skcipher_walk *walk)
{
@@ -499,7 +512,8 @@ int skcipher_walk_async(struct skcipher_walk *walk,
INIT_LIST_HEAD(&walk->buffers);
- return skcipher_walk_skcipher(walk, req);
+ return skcipher_walk_skcipher(walk, req, req->src, req->dst,
+ req->cryptlen);
}
EXPORT_SYMBOL_GPL(skcipher_walk_async);
diff --git a/include/crypto/internal/skcipher.h b/include/crypto/internal/skcipher.h
index 26934a6..1173701 100644
--- a/include/crypto/internal/skcipher.h
+++ b/include/crypto/internal/skcipher.h
@@ -144,6 +144,10 @@ int skcipher_walk_done(struct skcipher_walk *walk, int err);
int skcipher_walk_virt(struct skcipher_walk *walk,
struct skcipher_request *req,
bool atomic);
+int skcipher_walk_virt_init(struct skcipher_walk *walk,
+ struct skcipher_request *req,
+ bool atomic, struct scatterlist *src,
+ struct scatterlist *dst, unsigned int len);
void skcipher_walk_atomise(struct skcipher_walk *walk);
int skcipher_walk_async(struct skcipher_walk *walk,
struct skcipher_request *req);
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [RFC][PATCH 2/7] crypto: gf128mul - Refactor gf128 overflow macros
From: Alex Cope @ 2016-11-14 21:01 UTC (permalink / raw)
To: linux-crypto; +Cc: mhalcrow, edknapp, Alex Cope, Eric Biggers
In-Reply-To: <1479157277-10251-1-git-send-email-alexcope@google.com>
Rename and clean up the overflow macros. Their usage is more general
than the name suggested.
Signed-off-by: Alex Cope <alexcope@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
crypto/gf128mul.c | 68 +++++++++++++++++++++++++++++++++----------------------
1 file changed, 41 insertions(+), 27 deletions(-)
diff --git a/crypto/gf128mul.c b/crypto/gf128mul.c
index 0594dd6..8b65b1e 100644
--- a/crypto/gf128mul.c
+++ b/crypto/gf128mul.c
@@ -88,33 +88,47 @@
q(0xf8), q(0xf9), q(0xfa), q(0xfb), q(0xfc), q(0xfd), q(0xfe), q(0xff) \
}
-/* Given the value i in 0..255 as the byte overflow when a field element
- in GHASH is multiplied by x^8, this function will return the values that
- are generated in the lo 16-bit word of the field value by applying the
- modular polynomial. The values lo_byte and hi_byte are returned via the
- macro xp_fun(lo_byte, hi_byte) so that the values can be assembled into
- memory as required by a suitable definition of this macro operating on
- the table above
-*/
-
-#define xx(p, q) 0x##p##q
+/*
+ * Given a value i in 0..255 as the byte overflow when a field element
+ * in GF(2^128) is multiplied by x^8, the following macro returns the
+ * 16-bit value that must be XOR-ed into the low-degree end of the
+ * product to reduce it modulo the irreducible polynomial x^128 + x^7 +
+ * x^2 + x + 1.
+ *
+ * There are two versions of the macro, and hence two tables: one for
+ * the "be" convention where the highest-order bit is the coefficient of
+ * the highest-degree polynomial term, and one for the "le" convention
+ * where the highest-order bit is the coefficient of the lowest-degree
+ * polynomial term. In both cases the values are stored in CPU byte
+ * endianness such that the coefficients are ordered consistently across
+ * bytes, i.e. in the "be" table bits 15..0 of the stored value
+ * correspond to the coefficients of x^15..x^0, and in the "le" table
+ * bits 15..0 correspond to the coefficients of x^0..x^15.
+ *
+ * Therefore, provided that the appropriate byte endianness conversions
+ * are done by the multiplication functions (and these must be in place
+ * anyway to support both little endian and big endian CPUs), the "be"
+ * table can be used for multiplications of both "bbe" and "ble"
+ * elements, and the "le" table can be used for multiplications of both
+ * "lle" and "lbe" elements.
+ */
-#define xda_bbe(i) ( \
- (i & 0x80 ? xx(43, 80) : 0) ^ (i & 0x40 ? xx(21, c0) : 0) ^ \
- (i & 0x20 ? xx(10, e0) : 0) ^ (i & 0x10 ? xx(08, 70) : 0) ^ \
- (i & 0x08 ? xx(04, 38) : 0) ^ (i & 0x04 ? xx(02, 1c) : 0) ^ \
- (i & 0x02 ? xx(01, 0e) : 0) ^ (i & 0x01 ? xx(00, 87) : 0) \
+#define xda_be(i) ( \
+ (i & 0x80 ? 0x4380 : 0) ^ (i & 0x40 ? 0x21c0 : 0) ^ \
+ (i & 0x20 ? 0x10e0 : 0) ^ (i & 0x10 ? 0x0870 : 0) ^ \
+ (i & 0x08 ? 0x0438 : 0) ^ (i & 0x04 ? 0x021c : 0) ^ \
+ (i & 0x02 ? 0x010e : 0) ^ (i & 0x01 ? 0x0087 : 0) \
)
-#define xda_lle(i) ( \
- (i & 0x80 ? xx(e1, 00) : 0) ^ (i & 0x40 ? xx(70, 80) : 0) ^ \
- (i & 0x20 ? xx(38, 40) : 0) ^ (i & 0x10 ? xx(1c, 20) : 0) ^ \
- (i & 0x08 ? xx(0e, 10) : 0) ^ (i & 0x04 ? xx(07, 08) : 0) ^ \
- (i & 0x02 ? xx(03, 84) : 0) ^ (i & 0x01 ? xx(01, c2) : 0) \
+#define xda_le(i) ( \
+ (i & 0x80 ? 0xe100 : 0) ^ (i & 0x40 ? 0x7080 : 0) ^ \
+ (i & 0x20 ? 0x3840 : 0) ^ (i & 0x10 ? 0x1c20 : 0) ^ \
+ (i & 0x08 ? 0x0e10 : 0) ^ (i & 0x04 ? 0x0708 : 0) ^ \
+ (i & 0x02 ? 0x0384 : 0) ^ (i & 0x01 ? 0x01c2 : 0) \
)
-static const u16 gf128mul_table_lle[256] = gf128mul_dat(xda_lle);
-static const u16 gf128mul_table_bbe[256] = gf128mul_dat(xda_bbe);
+static const u16 gf128mul_table_le[256] = gf128mul_dat(xda_le);
+static const u16 gf128mul_table_be[256] = gf128mul_dat(xda_be);
/* These functions multiply a field element by x, by x^4 and by x^8
* in the polynomial field representation. It uses 32-bit word operations
@@ -126,7 +140,7 @@ static void gf128mul_x_lle(be128 *r, const be128 *x)
{
u64 a = be64_to_cpu(x->a);
u64 b = be64_to_cpu(x->b);
- u64 _tt = gf128mul_table_lle[(b << 7) & 0xff];
+ u64 _tt = gf128mul_table_le[(b << 7) & 0xff];
r->b = cpu_to_be64((b >> 1) | (a << 63));
r->a = cpu_to_be64((a >> 1) ^ (_tt << 48));
@@ -136,7 +150,7 @@ static void gf128mul_x_bbe(be128 *r, const be128 *x)
{
u64 a = be64_to_cpu(x->a);
u64 b = be64_to_cpu(x->b);
- u64 _tt = gf128mul_table_bbe[a >> 63];
+ u64 _tt = gf128mul_table_be[a >> 63];
r->a = cpu_to_be64((a << 1) | (b >> 63));
r->b = cpu_to_be64((b << 1) ^ _tt);
@@ -146,7 +160,7 @@ void gf128mul_x_ble(be128 *r, const be128 *x)
{
u64 a = le64_to_cpu(x->a);
u64 b = le64_to_cpu(x->b);
- u64 _tt = gf128mul_table_bbe[b >> 63];
+ u64 _tt = gf128mul_table_be[b >> 63];
r->a = cpu_to_le64((a << 1) ^ _tt);
r->b = cpu_to_le64((b << 1) | (a >> 63));
@@ -157,7 +171,7 @@ static void gf128mul_x8_lle(be128 *x)
{
u64 a = be64_to_cpu(x->a);
u64 b = be64_to_cpu(x->b);
- u64 _tt = gf128mul_table_lle[b & 0xff];
+ u64 _tt = gf128mul_table_le[b & 0xff];
x->b = cpu_to_be64((b >> 8) | (a << 56));
x->a = cpu_to_be64((a >> 8) ^ (_tt << 48));
@@ -167,7 +181,7 @@ static void gf128mul_x8_bbe(be128 *x)
{
u64 a = be64_to_cpu(x->a);
u64 b = be64_to_cpu(x->b);
- u64 _tt = gf128mul_table_bbe[a >> 56];
+ u64 _tt = gf128mul_table_be[a >> 56];
x->a = cpu_to_be64((a << 8) | (b >> 56));
x->b = cpu_to_be64((b << 8) ^ _tt);
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [RFC][PATCH 3/7] crypto: gf128mul - Add ble multiplication functions
From: Alex Cope @ 2016-11-14 21:01 UTC (permalink / raw)
To: linux-crypto; +Cc: mhalcrow, edknapp, Alex Cope, Eric Biggers
In-Reply-To: <1479157277-10251-1-git-send-email-alexcope@google.com>
Adding ble multiplication to GF128mul, and fixing up comments.
The ble multiplication functions multiply GF(2^128) elements in the
ble format. This format is preferable because the bits within each
byte map to polynomial coefficients in the natural order (lowest order
bit = coefficient of lowest degree polynomial term), and the bytes are
stored in little endian order which matches the endianness of most
modern CPUs.
These new functions will be used by the HEH algorithm.
Signed-off-by: Alex Cope <alexcope@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
crypto/gf128mul.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---
include/crypto/gf128mul.h | 45 +++++++++++----------
2 files changed, 117 insertions(+), 27 deletions(-)
diff --git a/crypto/gf128mul.c b/crypto/gf128mul.c
index 8b65b1e..f3d9f6d 100644
--- a/crypto/gf128mul.c
+++ b/crypto/gf128mul.c
@@ -44,7 +44,7 @@
---------------------------------------------------------------------------
Issue 31/01/2006
- This file provides fast multiplication in GF(128) as required by several
+ This file provides fast multiplication in GF(2^128) as required by several
cryptographic authentication modes
*/
@@ -130,9 +130,10 @@
static const u16 gf128mul_table_le[256] = gf128mul_dat(xda_le);
static const u16 gf128mul_table_be[256] = gf128mul_dat(xda_be);
-/* These functions multiply a field element by x, by x^4 and by x^8
- * in the polynomial field representation. It uses 32-bit word operations
- * to gain speed but compensates for machine endianess and hence works
+/*
+ * The following functions multiply a field element by x or by x^8 in
+ * the polynomial field representation. They use 64-bit word operations
+ * to gain speed but compensate for machine endianness and hence work
* correctly on both styles of machine.
*/
@@ -187,6 +188,16 @@ static void gf128mul_x8_bbe(be128 *x)
x->b = cpu_to_be64((b << 8) ^ _tt);
}
+static void gf128mul_x8_ble(be128 *x)
+{
+ u64 a = le64_to_cpu(x->b);
+ u64 b = le64_to_cpu(x->a);
+ u64 _tt = gf128mul_table_be[a >> 56];
+
+ x->b = cpu_to_le64((a << 8) | (b >> 56));
+ x->a = cpu_to_le64((b << 8) ^ _tt);
+}
+
void gf128mul_lle(be128 *r, const be128 *b)
{
be128 p[8];
@@ -263,9 +274,48 @@ void gf128mul_bbe(be128 *r, const be128 *b)
}
EXPORT_SYMBOL(gf128mul_bbe);
+void gf128mul_ble(be128 *r, const be128 *b)
+{
+ be128 p[8];
+ int i;
+
+ p[0] = *r;
+ for (i = 0; i < 7; ++i)
+ gf128mul_x_ble((be128 *)&p[i + 1], (be128 *)&p[i]);
+
+ memset(r, 0, sizeof(*r));
+ for (i = 0;;) {
+ u8 ch = ((u8 *)b)[15 - i];
+
+ if (ch & 0x80)
+ be128_xor(r, r, &p[7]);
+ if (ch & 0x40)
+ be128_xor(r, r, &p[6]);
+ if (ch & 0x20)
+ be128_xor(r, r, &p[5]);
+ if (ch & 0x10)
+ be128_xor(r, r, &p[4]);
+ if (ch & 0x08)
+ be128_xor(r, r, &p[3]);
+ if (ch & 0x04)
+ be128_xor(r, r, &p[2]);
+ if (ch & 0x02)
+ be128_xor(r, r, &p[1]);
+ if (ch & 0x01)
+ be128_xor(r, r, &p[0]);
+
+ if (++i >= 16)
+ break;
+
+ gf128mul_x8_ble(r);
+ }
+}
+EXPORT_SYMBOL(gf128mul_ble);
+
+
/* This version uses 64k bytes of table space.
A 16 byte buffer has to be multiplied by a 16 byte key
- value in GF(128). If we consider a GF(128) value in
+ value in GF(2^128). If we consider a GF(2^128) value in
the buffer's lowest byte, we can construct a table of
the 256 16 byte values that result from the 256 values
of this byte. This requires 4096 bytes. But we also
@@ -399,7 +449,7 @@ EXPORT_SYMBOL(gf128mul_64k_bbe);
/* This version uses 4k bytes of table space.
A 16 byte buffer has to be multiplied by a 16 byte key
- value in GF(128). If we consider a GF(128) value in a
+ value in GF(2^128). If we consider a GF(2^128) value in a
single byte, we can construct a table of the 256 16 byte
values that result from the 256 values of this byte.
This requires 4096 bytes. If we take the highest byte in
@@ -457,6 +507,28 @@ struct gf128mul_4k *gf128mul_init_4k_bbe(const be128 *g)
}
EXPORT_SYMBOL(gf128mul_init_4k_bbe);
+struct gf128mul_4k *gf128mul_init_4k_ble(const be128 *g)
+{
+ struct gf128mul_4k *t;
+ int j, k;
+
+ t = kzalloc(sizeof(*t), GFP_KERNEL);
+ if (!t)
+ goto out;
+
+ t->t[1] = *g;
+ for (j = 1; j <= 64; j <<= 1)
+ gf128mul_x_ble(&t->t[j + j], &t->t[j]);
+
+ for (j = 2; j < 256; j += j)
+ for (k = 1; k < j; ++k)
+ be128_xor(&t->t[j + k], &t->t[j], &t->t[k]);
+
+out:
+ return t;
+}
+EXPORT_SYMBOL(gf128mul_init_4k_ble);
+
void gf128mul_4k_lle(be128 *a, struct gf128mul_4k *t)
{
u8 *ap = (u8 *)a;
@@ -487,5 +559,20 @@ void gf128mul_4k_bbe(be128 *a, struct gf128mul_4k *t)
}
EXPORT_SYMBOL(gf128mul_4k_bbe);
+void gf128mul_4k_ble(be128 *a, struct gf128mul_4k *t)
+{
+ u8 *ap = (u8 *)a;
+ be128 r[1];
+ int i = 15;
+
+ *r = t->t[ap[15]];
+ while (i--) {
+ gf128mul_x8_ble(r);
+ be128_xor(r, r, &t->t[ap[i]]);
+ }
+ *a = *r;
+}
+EXPORT_SYMBOL(gf128mul_4k_ble);
+
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Functions for multiplying elements of GF(2^128)");
diff --git a/include/crypto/gf128mul.h b/include/crypto/gf128mul.h
index 7217fe6..230760a 100644
--- a/include/crypto/gf128mul.h
+++ b/include/crypto/gf128mul.h
@@ -43,7 +43,7 @@
---------------------------------------------------------------------------
Issue Date: 31/01/2006
- An implementation of field multiplication in Galois Field GF(128)
+ An implementation of field multiplication in Galois Field GF(2^128)
*/
#ifndef _CRYPTO_GF128MUL_H
@@ -65,7 +65,7 @@
* are left and the lsb's are right. char b[16] is an array and b[0] is
* the first octet.
*
- * 80000000 00000000 00000000 00000000 .... 00000000 00000000 00000000
+ * 10000000 00000000 00000000 00000000 .... 00000000 00000000 00000000
* b[0] b[1] b[2] b[3] b[13] b[14] b[15]
*
* Every bit is a coefficient of some power of X. We can store the bits
@@ -99,21 +99,21 @@
*
* bbe on a little endian machine u32 x[4]:
*
- * MS x[0] LS MS x[1] LS
+ * MS x[0] LS MS x[1] LS
* ms ls ms ls ms ls ms ls ms ls ms ls ms ls ms ls
* 103..96 111.104 119.112 127.120 71...64 79...72 87...80 95...88
*
- * MS x[2] LS MS x[3] LS
+ * MS x[2] LS MS x[3] LS
* ms ls ms ls ms ls ms ls ms ls ms ls ms ls ms ls
* 39...32 47...40 55...48 63...56 07...00 15...08 23...16 31...24
*
* ble on a little endian machine
*
- * MS x[0] LS MS x[1] LS
+ * MS x[0] LS MS x[1] LS
* ms ls ms ls ms ls ms ls ms ls ms ls ms ls ms ls
* 31...24 23...16 15...08 07...00 63...56 55...48 47...40 39...32
*
- * MS x[2] LS MS x[3] LS
+ * MS x[2] LS MS x[3] LS
* ms ls ms ls ms ls ms ls ms ls ms ls ms ls ms ls
* 95...88 87...80 79...72 71...64 127.120 199.112 111.104 103..96
*
@@ -127,7 +127,7 @@
* machines this will automatically aligned to wordsize and on a 64-bit
* machine also.
*/
-/* Multiply a GF128 field element by x. Field elements are held in arrays
+/* Multiply a GF128 field element by x. Field elements are held in arrays
of bytes in which field bits 8n..8n + 7 are held in byte[n], with lower
indexed bits placed in the more numerically significant bit positions
within bytes.
@@ -135,45 +135,47 @@
On little endian machines the bit indexes translate into the bit
positions within four 32-bit words in the following way
- MS x[0] LS MS x[1] LS
+ MS x[0] LS MS x[1] LS
ms ls ms ls ms ls ms ls ms ls ms ls ms ls ms ls
24...31 16...23 08...15 00...07 56...63 48...55 40...47 32...39
- MS x[2] LS MS x[3] LS
+ MS x[2] LS MS x[3] LS
ms ls ms ls ms ls ms ls ms ls ms ls ms ls ms ls
88...95 80...87 72...79 64...71 120.127 112.119 104.111 96..103
On big endian machines the bit indexes translate into the bit
positions within four 32-bit words in the following way
- MS x[0] LS MS x[1] LS
+ MS x[0] LS MS x[1] LS
ms ls ms ls ms ls ms ls ms ls ms ls ms ls ms ls
00...07 08...15 16...23 24...31 32...39 40...47 48...55 56...63
- MS x[2] LS MS x[3] LS
+ MS x[2] LS MS x[3] LS
ms ls ms ls ms ls ms ls ms ls ms ls ms ls ms ls
64...71 72...79 80...87 88...95 96..103 104.111 112.119 120.127
*/
-/* A slow generic version of gf_mul, implemented for lle and bbe
- * It multiplies a and b and puts the result in a */
+/* A slow generic version of gf_mul, implemented for lle, bbe, and ble.
+ * It multiplies a and b and puts the result in a
+ */
void gf128mul_lle(be128 *a, const be128 *b);
-
void gf128mul_bbe(be128 *a, const be128 *b);
+void gf128mul_ble(be128 *a, const be128 *b);
-/* multiply by x in ble format, needed by XTS */
+/* multiply by x in ble format, needed by XTS and HEH */
void gf128mul_x_ble(be128 *a, const be128 *b);
/* 4k table optimization */
-
struct gf128mul_4k {
be128 t[256];
};
struct gf128mul_4k *gf128mul_init_4k_lle(const be128 *g);
struct gf128mul_4k *gf128mul_init_4k_bbe(const be128 *g);
+struct gf128mul_4k *gf128mul_init_4k_ble(const be128 *g);
void gf128mul_4k_lle(be128 *a, struct gf128mul_4k *t);
void gf128mul_4k_bbe(be128 *a, struct gf128mul_4k *t);
+void gf128mul_4k_ble(be128 *a, struct gf128mul_4k *t);
static inline void gf128mul_free_4k(struct gf128mul_4k *t)
{
@@ -181,16 +183,17 @@ static inline void gf128mul_free_4k(struct gf128mul_4k *t)
}
-/* 64k table optimization, implemented for lle and bbe */
+/* 64k table optimization, implemented for lle, ble, and bbe */
struct gf128mul_64k {
struct gf128mul_4k *t[16];
};
-/* first initialize with the constant factor with which you
- * want to multiply and then call gf128_64k_lle with the other
- * factor in the first argument, the table in the second and a
- * scratch register in the third. Afterwards *a = *r. */
+/* First initialize with the constant factor with which you
+ * want to multiply and then call gf128mul_64k_bbe with the other
+ * factor in the first argument, and the table in the second.
+ * Afterwards, the result is stored in *a.
+ */
struct gf128mul_64k *gf128mul_init_64k_lle(const be128 *g);
struct gf128mul_64k *gf128mul_init_64k_bbe(const be128 *g);
void gf128mul_free_64k(struct gf128mul_64k *t);
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [RFC][PATCH 4/7] crypto: shash - Add crypto_grab_shash() and crypto_spawn_shash_alg()
From: Alex Cope @ 2016-11-14 21:01 UTC (permalink / raw)
To: linux-crypto; +Cc: mhalcrow, edknapp, Alex Cope, Eric Biggers
In-Reply-To: <1479157277-10251-1-git-send-email-alexcope@google.com>
Analogous to crypto_grab_skcipher() and crypto_spawn_skcipher_alg(),
these are useful for algorithms that need to use a shash sub-algorithm,
possibly in addition to other sub-algorithms.
Signed-off-by: Alex Cope <alexcope@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
crypto/shash.c | 8 ++++++++
include/crypto/internal/hash.h | 8 ++++++++
2 files changed, 16 insertions(+)
diff --git a/crypto/shash.c b/crypto/shash.c
index a051541..55a5535 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -536,6 +536,14 @@ void shash_free_instance(struct crypto_instance *inst)
}
EXPORT_SYMBOL_GPL(shash_free_instance);
+int crypto_grab_shash(struct crypto_shash_spawn *spawn,
+ const char *name, u32 type, u32 mask)
+{
+ spawn->base.frontend = &crypto_shash_type;
+ return crypto_grab_spawn(&spawn->base, name, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_grab_shash);
+
int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn,
struct shash_alg *alg,
struct crypto_instance *inst)
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
index 1d4f365..54e4425 100644
--- a/include/crypto/internal/hash.h
+++ b/include/crypto/internal/hash.h
@@ -99,6 +99,8 @@ int shash_register_instance(struct crypto_template *tmpl,
struct shash_instance *inst);
void shash_free_instance(struct crypto_instance *inst);
+int crypto_grab_shash(struct crypto_shash_spawn *spawn,
+ const char *name, u32 type, u32 mask);
int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn,
struct shash_alg *alg,
struct crypto_instance *inst);
@@ -108,6 +110,12 @@ static inline void crypto_drop_shash(struct crypto_shash_spawn *spawn)
crypto_drop_spawn(&spawn->base);
}
+static inline struct shash_alg *crypto_spawn_shash_alg(
+ struct crypto_shash_spawn *spawn)
+{
+ return container_of(spawn->base.alg, struct shash_alg, base);
+}
+
struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask);
int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc);
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [RFC][PATCH 5/7] crypto: heh - Add Hash Encrypt Hash(HEH) algorithm
From: Alex Cope @ 2016-11-14 21:01 UTC (permalink / raw)
To: linux-crypto; +Cc: mhalcrow, edknapp, Alex Cope, Eric Biggers
In-Reply-To: <1479157277-10251-1-git-send-email-alexcope@google.com>
Hash Encrypt Hash (HEH) is a proposed block cipher mode of operation
which extends the strong pseudo-random permutation property of block
ciphers (e.g. AES) to arbitrary length input strings. This provides a
stronger notion of security than existing block cipher modes of
operation (e.g. CBC, CTR, XTS), though it is less performant. It uses
two keyed invertible hash functions with a layer of ECB encryption
applied in-between.
This patch adds HEH as a skcipher. Support for HEH as an AEAD is not
yet implemented.
HEH will use existing accelerated ecb(block_cipher) implementation for
the encrypt step if available. Accelerated versions of the hash step
are planned but not yet implemented.
HEH will be used for filename encryption in ext4 and f2fs.
The algorithm is currently specified by the following Internet Draft:
https://tools.ietf.org/html/draft-cope-heh-00
Signed-off-by: Alex Cope <alexcope@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
crypto/Kconfig | 17 ++
crypto/Makefile | 1 +
crypto/heh.c | 814 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 832 insertions(+)
create mode 100644 crypto/heh.c
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 1db2a19..78b0e93 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -316,6 +316,23 @@ config CRYPTO_CBC
CBC: Cipher Block Chaining mode
This block cipher algorithm is required for IPSec.
+config CRYPTO_HEH
+ tristate "HEH support"
+ select CRYPTO_CMAC
+ select CRYPTO_ECB
+ select CRYPTO_GF128MUL
+ select CRYPTO_MANAGER
+ help
+ HEH: Hash Encrypt Hash mode
+ HEH is a proposed block cipher mode of operation which extends the
+ strong pseudo-random permutation (SPRP) property of block ciphers to
+ arbitrary-length input strings. This provides a stronger notion of
+ security than existing block cipher modes of operation (e.g. CBC, CTR,
+ XTS), though it is less performant. Applications include disk
+ encryption and encryption of file names and contents. Currently, this
+ implementation only provides a symmetric cipher interface, so it can't
+ yet be used as an AEAD.
+
config CRYPTO_CTR
tristate "CTR support"
select CRYPTO_BLKCIPHER
diff --git a/crypto/Makefile b/crypto/Makefile
index 82ffeee..1458d3f 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o
obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o
obj-$(CONFIG_CRYPTO_ECB) += ecb.o
obj-$(CONFIG_CRYPTO_CBC) += cbc.o
+obj-$(CONFIG_CRYPTO_HEH) += heh.o
obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o
obj-$(CONFIG_CRYPTO_CTS) += cts.o
obj-$(CONFIG_CRYPTO_LRW) += lrw.o
diff --git a/crypto/heh.c b/crypto/heh.c
new file mode 100644
index 0000000..efd49cc
--- /dev/null
+++ b/crypto/heh.c
@@ -0,0 +1,814 @@
+/*
+ * HEH: Hash Encrypt Hash mode
+ *
+ * Copyright (c) 2016 Google Inc.
+ *
+ * Authors:
+ * Alex Cope <alexcope@google.com>
+ * Eric Biggers <ebiggers@google.com>
+ */
+
+/*
+ * Hash Encrypt Hash (HEH) is a proposed block cipher mode of operation which
+ * extends the strong pseudo-random permutation (SPRP) property of block ciphers
+ * (e.g. AES) to arbitrary length input strings. It uses two keyed invertible
+ * hash functions with a layer of ECB encryption applied in-between. The
+ * algorithm is specified by the following Internet Draft:
+ *
+ * https://tools.ietf.org/html/draft-cope-heh-00
+ *
+ * Although HEH can be used as either a regular symmetric cipher or as an AEAD,
+ * currently this module only provides it as a symmetric cipher (skcipher).
+ * Additionally, only 48-byte keys and 16-byte nonces are supported.
+ */
+
+#include <crypto/gf128mul.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/skcipher.h>
+#include "internal.h"
+
+/*
+ * The block size is the size of GF(2^128) elements and also the required block
+ * size of the underlying block cipher.
+ */
+#define HEH_BLOCK_SIZE 16
+
+/* Required key size in bytes */
+#define HEH_KEY_SIZE 48
+#define HEH_PRF_KEY_OFFSET 16
+#define HEH_BLK_KEY_OFFSET 32
+
+/*
+ * Macro to get the offset in bytes to the last full block
+ * (or equivalently the length of all full blocks excluding the last)
+ */
+#define HEH_TAIL_OFFSET(len) (((len) - HEH_BLOCK_SIZE) & ~(HEH_BLOCK_SIZE - 1))
+
+struct heh_instance_ctx {
+ struct crypto_shash_spawn cmac;
+ struct crypto_skcipher_spawn ecb;
+};
+
+struct heh_tfm_ctx {
+ struct crypto_shash *cmac;
+ struct crypto_skcipher *ecb;
+ struct gf128mul_4k *tau_key;
+};
+
+struct heh_cmac_data {
+ u8 nonce[HEH_BLOCK_SIZE];
+ __le32 nonce_length;
+ __le32 aad_length;
+ __le32 message_length;
+ __le32 padding;
+};
+
+struct heh_req_ctx { /* aligned to alignmask */
+ be128 beta1_key;
+ be128 beta2_key;
+ union {
+ struct {
+ struct heh_cmac_data data;
+ struct shash_desc desc;
+ /* + crypto_shash_descsize(cmac) */
+ } cmac;
+ struct {
+ u8 tail[2 * HEH_BLOCK_SIZE];
+ int (*crypt)(struct skcipher_request *);
+ struct scatterlist tmp_sgl[2];
+ struct skcipher_request req;
+ /* + crypto_skcipher_reqsize(ecb) */
+ } ecb;
+ } u;
+};
+
+static inline struct heh_req_ctx *heh_req_ctx(struct skcipher_request *req)
+{
+ unsigned int alignmask = crypto_skcipher_alignmask(
+ crypto_skcipher_reqtfm(req));
+
+ return (void *)PTR_ALIGN((u8 *)skcipher_request_ctx(req),
+ alignmask + 1);
+}
+
+static inline void async_done(struct crypto_async_request *areq, int err,
+ int (*next_step)(struct skcipher_request *, u32))
+{
+ struct skcipher_request *req = areq->data;
+
+ if (err)
+ goto out;
+
+ err = next_step(req, req->base.flags & ~CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (err == -EINPROGRESS ||
+ (err == -EBUSY && (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)))
+ return;
+out:
+ skcipher_request_complete(req, err);
+}
+
+/*
+ * Generate the per-message "beta" keys used by the hashing layers of HEH. The
+ * first beta key is the CMAC of the nonce, the additional authenticated data
+ * (AAD), and the lengths in bytes of the nonce, AAD, and message. The nonce
+ * and AAD are each zero-padded to the next 16-byte block boundary, and the
+ * lengths are serialized as 4-byte little endian integers and zero-padded to
+ * the next 16-byte block boundary. The second beta key is the first one
+ * interpreted as an element in GF(2^128) and multiplied by x.
+ *
+ * Note that because the nonce and AAD may, in general, be variable-length, the
+ * key generation must be done by a pseudo-random function (PRF) on
+ * variable-length inputs. CBC-MAC does not satisfy this, as it is only a PRF
+ * on fixed-length inputs. CMAC remedies this flaw. Including the lengths of
+ * the nonce, AAD, and message is also critical to avoid collisions.
+ *
+ * That being said, this implementation does not yet operate as an AEAD and
+ * therefore there is never any AAD, nor are variable-length nonces supported.
+ */
+static int generate_betas(struct skcipher_request *req,
+ be128 *beta1_key, be128 *beta2_key)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct heh_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct heh_req_ctx *rctx = heh_req_ctx(req);
+ struct heh_cmac_data *data = &rctx->u.cmac.data;
+ struct shash_desc *desc = &rctx->u.cmac.desc;
+ int err;
+
+ BUILD_BUG_ON(sizeof(*data) != HEH_BLOCK_SIZE + 16);
+ memcpy(data->nonce, req->iv, HEH_BLOCK_SIZE);
+ data->nonce_length = cpu_to_le32(HEH_BLOCK_SIZE);
+ data->aad_length = cpu_to_le32(0);
+ data->message_length = cpu_to_le32(req->cryptlen);
+ data->padding = cpu_to_le32(0);
+
+ desc->tfm = ctx->cmac;
+ desc->flags = req->base.flags;
+
+ err = crypto_shash_digest(desc, (const u8 *)data, sizeof(*data),
+ (u8 *)beta1_key);
+ if (err)
+ return err;
+
+ gf128mul_x_ble(beta2_key, beta1_key);
+ return 0;
+}
+
+/*
+ * Evaluation of a polynomial over GF(2^128) using Horner's rule. The
+ * polynomial is evaluated at 'point'. The polynomial's coefficients are taken
+ * from 'coeffs_sgl' and are for terms with consecutive descending degree ending
+ * at degree 1. 'bytes_of_coeffs' is 16 times the number of terms.
+ */
+static be128 evaluate_polynomial(struct gf128mul_4k *point,
+ struct scatterlist *coeffs_sgl,
+ unsigned int bytes_of_coeffs)
+{
+ be128 value = {0};
+ struct sg_mapping_iter miter;
+ unsigned int remaining = bytes_of_coeffs;
+ unsigned int needed = 0;
+
+ sg_miter_start(&miter, coeffs_sgl, sg_nents(coeffs_sgl),
+ SG_MITER_FROM_SG | SG_MITER_ATOMIC);
+ while (remaining) {
+ be128 coeff;
+ const u8 *src;
+ unsigned int srclen;
+ u8 *dst = (u8 *)&value;
+
+ /*
+ * Note: scatterlist elements are not necessarily evenly
+ * divisible into blocks, nor are they necessarily aligned to
+ * __alignof__(be128).
+ */
+ sg_miter_next(&miter);
+
+ src = miter.addr;
+ srclen = min_t(unsigned int, miter.length, remaining);
+ remaining -= srclen;
+
+ if (needed) {
+ unsigned int n = min(srclen, needed);
+ u8 *pos = dst + (HEH_BLOCK_SIZE - needed);
+
+ needed -= n;
+ srclen -= n;
+
+ while (n--)
+ *pos++ ^= *src++;
+
+ if (!needed)
+ gf128mul_4k_ble(&value, point);
+ }
+
+ while (srclen >= HEH_BLOCK_SIZE) {
+ memcpy(&coeff, src, HEH_BLOCK_SIZE);
+ be128_xor(&value, &value, &coeff);
+ gf128mul_4k_ble(&value, point);
+ src += HEH_BLOCK_SIZE;
+ srclen -= HEH_BLOCK_SIZE;
+ }
+
+ if (srclen) {
+ needed = HEH_BLOCK_SIZE - srclen;
+ do {
+ *dst++ ^= *src++;
+ } while (--srclen);
+ }
+ }
+ sg_miter_stop(&miter);
+ return value;
+}
+
+/*
+ * Split the message into 16 byte blocks, padding out the last block, and use
+ * the blocks as coefficients in the evaluation of a polynomial over GF(2^128)
+ * at the secret point 'tau_key'. For ease of implementing the higher-level
+ * heh_hash_inv() function, the constant and degree-1 coefficients are swapped.
+ *
+ * Mathematically, compute:
+ * t^N * m_0 + ... + t^2 * m_{N-2} + t * m_N + m_{N-1}
+ *
+ * where:
+ * t is tau_key
+ * N is the number of full blocks in the message
+ * m_i is the i-th full block in the message for i = 0 to N-1 inclusive
+ * m_N is the (possibly empty) partial block of the message padded up to 16
+ * bytes with a 0x01 byte followed by 0x00 bytes
+ *
+ * Note that when the message length is a multiple of 16, m_N is composed
+ * entirely of padding, i.e. 0x0100...00.
+ */
+static be128 poly_hash(struct crypto_skcipher *tfm, struct scatterlist *sgl,
+ unsigned int len)
+{
+ struct heh_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ unsigned int tail_offset = HEH_TAIL_OFFSET(len);
+ unsigned int tail_len = len - tail_offset;
+ be128 hash;
+ be128 tail[2];
+
+ /* Handle all full blocks except the last */
+ hash = evaluate_polynomial(ctx->tau_key, sgl, tail_offset);
+
+ /* Handle the last full block and the partial block */
+
+ scatterwalk_map_and_copy(tail, sgl, tail_offset, tail_len, 0);
+ *((u8 *)tail + tail_len) = 0x01;
+ memset((u8 *)tail + tail_len + 1, 0, sizeof(tail) - 1 - tail_len);
+
+ be128_xor(&hash, &hash, &tail[1]);
+ gf128mul_4k_ble(&hash, ctx->tau_key);
+ be128_xor(&hash, &hash, &tail[0]);
+ return hash;
+}
+
+/*
+ * Transform all full blocks except the last.
+ * This is used by both the hash and inverse hash phases.
+ */
+static int heh_tfm_blocks(struct skcipher_request *req,
+ struct scatterlist *src_sgl,
+ struct scatterlist *dst_sgl, unsigned int len,
+ const be128 *hash, const be128 *beta_key)
+{
+ struct skcipher_walk walk;
+ be128 e = *beta_key;
+ int err;
+ unsigned int nbytes;
+
+ err = skcipher_walk_virt_init(&walk, req, false, src_sgl, dst_sgl, len);
+ while ((nbytes = walk.nbytes)) {
+ const be128 *src = (be128 *)walk.src.virt.addr;
+ be128 *dst = (be128 *)walk.dst.virt.addr;
+
+ do {
+ gf128mul_x_ble(&e, &e);
+ be128_xor(dst, src, hash);
+ be128_xor(dst, dst, &e);
+ src++;
+ dst++;
+ } while ((nbytes -= HEH_BLOCK_SIZE) >= HEH_BLOCK_SIZE);
+ err = skcipher_walk_done(&walk, nbytes);
+ }
+ return err;
+}
+
+/*
+ * The hash phase of HEH. Given a message, compute:
+ *
+ * (m_0 + H, ..., m_{N-2} + H, H, m_N) + (xb, x^2b, ..., x^{N-1}b, b, 0)
+ *
+ * where:
+ * N is the number of full blocks in the message
+ * m_i is the i-th full block in the message for i = 0 to N-1 inclusive
+ * m_N is the unpadded partial block, possibly empty
+ * H is the poly_hash() of the message, keyed by tau_key
+ * b is beta_key
+ * x is the element x in our representation of GF(2^128)
+ *
+ * Note that the partial block remains unchanged, but it does affect the result
+ * of poly_hash() and therefore the transformation of all the full blocks.
+ */
+static int heh_hash(struct skcipher_request *req, const be128 *beta_key)
+{
+ be128 hash;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ unsigned int tail_offset = HEH_TAIL_OFFSET(req->cryptlen);
+ unsigned int partial_len = req->cryptlen % HEH_BLOCK_SIZE;
+ int err;
+
+ /* poly_hash() the full message including the partial block */
+ hash = poly_hash(tfm, req->src, req->cryptlen);
+
+ /* Transform all full blocks except the last */
+ err = heh_tfm_blocks(req, req->src, req->dst, tail_offset, &hash,
+ beta_key);
+ if (err)
+ return err;
+
+ /* Set the last full block to hash XOR beta_key */
+ be128_xor(&hash, &hash, beta_key);
+ scatterwalk_map_and_copy(&hash, req->dst, tail_offset, HEH_BLOCK_SIZE,
+ 1);
+
+ /* Copy the partial block if needed */
+ if (partial_len != 0 && req->src != req->dst) {
+ unsigned int offs = tail_offset + HEH_BLOCK_SIZE;
+
+ scatterwalk_map_and_copy(&hash, req->src, offs, partial_len, 0);
+ scatterwalk_map_and_copy(&hash, req->dst, offs, partial_len, 1);
+ }
+ return 0;
+}
+
+/*
+ * The inverse hash phase of HEH. This undoes the result of heh_hash().
+ */
+static int heh_hash_inv(struct skcipher_request *req, const be128 *beta_key)
+{
+ be128 hash;
+ be128 tmp;
+ struct scatterlist tmp_sgl[2];
+ struct scatterlist *tail_sgl;
+ unsigned int len = req->cryptlen;
+ unsigned int tail_offset = HEH_TAIL_OFFSET(len);
+ struct scatterlist *sgl = req->dst;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ int err;
+
+ /*
+ * The last full block was computed as hash XOR beta_key, so XOR it with
+ * beta_key to recover hash.
+ */
+ tail_sgl = scatterwalk_ffwd(tmp_sgl, sgl, tail_offset);
+ scatterwalk_map_and_copy(&hash, tail_sgl, 0, HEH_BLOCK_SIZE, 0);
+ be128_xor(&hash, &hash, beta_key);
+
+ /* Transform all full blocks except the last */
+ err = heh_tfm_blocks(req, sgl, sgl, tail_offset, &hash, beta_key);
+ if (err)
+ return err;
+
+ /*
+ * Recover the last full block. We know 'hash', i.e. the poly_hash() of
+ * the the original message. The last full block was the constant term
+ * of the polynomial. To recover the last full block, temporarily zero
+ * it, compute the poly_hash(), and take the difference from 'hash'.
+ */
+ memset(&tmp, 0, sizeof(tmp));
+ scatterwalk_map_and_copy(&tmp, tail_sgl, 0, HEH_BLOCK_SIZE, 1);
+ tmp = poly_hash(tfm, sgl, len);
+ be128_xor(&tmp, &tmp, &hash);
+ scatterwalk_map_and_copy(&tmp, tail_sgl, 0, HEH_BLOCK_SIZE, 1);
+ return 0;
+}
+
+static int heh_hash_inv_step(struct skcipher_request *req, u32 flags)
+{
+ struct heh_req_ctx *rctx = heh_req_ctx(req);
+
+ return heh_hash_inv(req, &rctx->beta2_key);
+}
+
+static void heh_ecb_tail_done(struct crypto_async_request *areq, int err)
+{
+ return async_done(areq, err, heh_hash_inv_step);
+}
+
+static int heh_ecb_tail(struct skcipher_request *req, u32 flags)
+{
+ struct heh_req_ctx *rctx = heh_req_ctx(req);
+ unsigned int partial_len = req->cryptlen % HEH_BLOCK_SIZE;
+ struct scatterlist *tail_sgl;
+ int err;
+
+ if (partial_len == 0) /* no partial block? */
+ goto next_step;
+
+ /*
+ * Extract the already encrypted/decrypted last full block and the not
+ * yet encrypted/decrypted partial block. The former will be used as a
+ * pad to encrypt/decrypt the partial block.
+ */
+ tail_sgl = scatterwalk_ffwd(rctx->u.ecb.tmp_sgl, req->dst,
+ HEH_TAIL_OFFSET(req->cryptlen));
+ scatterwalk_map_and_copy(rctx->u.ecb.tail, tail_sgl, 0,
+ HEH_BLOCK_SIZE + partial_len, 0);
+
+ /* Encrypt/decrypt the partial block using the pad */
+ crypto_xor(&rctx->u.ecb.tail[HEH_BLOCK_SIZE], rctx->u.ecb.tail,
+ partial_len);
+ scatterwalk_map_and_copy(&rctx->u.ecb.tail[HEH_BLOCK_SIZE], tail_sgl,
+ HEH_BLOCK_SIZE, partial_len, 1);
+
+ /* Encrypt/decrypt the last full block again */
+ skcipher_request_set_callback(&rctx->u.ecb.req, flags,
+ heh_ecb_tail_done, req);
+ skcipher_request_set_crypt(&rctx->u.ecb.req, tail_sgl, tail_sgl,
+ HEH_BLOCK_SIZE, NULL);
+ err = rctx->u.ecb.crypt(&rctx->u.ecb.req);
+ if (err)
+ return err;
+next_step:
+ return heh_hash_inv_step(req, flags);
+}
+
+static void heh_ecb_full_done(struct crypto_async_request *areq, int err)
+{
+ return async_done(areq, err, heh_ecb_tail);
+}
+
+/*
+ * The encrypt phase of HEH. This uses ECB encryption, with special handling
+ * for the partial block at the end if any. The source data is already in
+ * req->dst, so the encryption happens in-place.
+ *
+ * After the encrypt phase we continue on to the inverse hash phase. The
+ * functions calls are chained to support asynchronous ECB algorithms.
+ */
+static int heh_ecb(struct skcipher_request *req, bool decrypt)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct heh_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct heh_req_ctx *rctx = heh_req_ctx(req);
+ struct skcipher_request *ecb_req = &rctx->u.ecb.req;
+ unsigned int full_len = HEH_TAIL_OFFSET(req->cryptlen) + HEH_BLOCK_SIZE;
+
+ rctx->u.ecb.crypt = decrypt ? crypto_skcipher_decrypt :
+ crypto_skcipher_encrypt;
+
+ /* Encrypt/decrypt all full blocks */
+ skcipher_request_set_tfm(ecb_req, ctx->ecb);
+ skcipher_request_set_callback(ecb_req, req->base.flags,
+ heh_ecb_full_done, req);
+ skcipher_request_set_crypt(ecb_req, req->dst, req->dst, full_len, NULL);
+ return rctx->u.ecb.crypt(ecb_req) ?: heh_ecb_tail(req, req->base.flags);
+}
+
+static int heh_crypt(struct skcipher_request *req, bool decrypt)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct heh_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct heh_req_ctx *rctx = heh_req_ctx(req);
+ int err;
+
+ /* Inputs must be at least one full block */
+ if (req->cryptlen < HEH_BLOCK_SIZE)
+ return -EINVAL;
+
+ /* Key must have been set */
+ if (!ctx->tau_key)
+ return -ENOKEY;
+
+ err = generate_betas(req, &rctx->beta1_key, &rctx->beta2_key);
+ if (err)
+ return err;
+
+ if (decrypt)
+ swap(rctx->beta1_key, rctx->beta2_key);
+
+ err = heh_hash(req, &rctx->beta1_key);
+ if (err)
+ return err;
+
+ return heh_ecb(req, decrypt);
+}
+
+static int heh_encrypt(struct skcipher_request *req)
+{
+ return heh_crypt(req, false);
+}
+
+static int heh_decrypt(struct skcipher_request *req)
+{
+ return heh_crypt(req, true);
+}
+
+static int heh_setkey(struct crypto_skcipher *parent, const u8 *key,
+ unsigned int keylen)
+{
+ struct heh_tfm_ctx *ctx = crypto_skcipher_ctx(parent);
+ struct crypto_shash *cmac = ctx->cmac;
+ struct crypto_skcipher *ecb = ctx->ecb;
+ const u8 *prf_key, *blk_key;
+ int err;
+
+ if (keylen != HEH_KEY_SIZE) {
+ crypto_skcipher_set_flags(parent, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ prf_key = key + HEH_PRF_KEY_OFFSET;
+ blk_key = key + HEH_BLK_KEY_OFFSET;
+
+ /* tau_key */
+ if (ctx->tau_key)
+ gf128mul_free_4k(ctx->tau_key);
+ ctx->tau_key = gf128mul_init_4k_ble((const be128 *)key);
+ if (!ctx->tau_key)
+ return -ENOMEM;
+
+ /* prf_key */
+ crypto_shash_clear_flags(cmac, CRYPTO_TFM_REQ_MASK);
+ crypto_shash_set_flags(cmac, crypto_skcipher_get_flags(parent) &
+ CRYPTO_TFM_REQ_MASK);
+ err = crypto_shash_setkey(cmac, prf_key, 16);
+ crypto_skcipher_set_flags(parent, crypto_shash_get_flags(cmac) &
+ CRYPTO_TFM_RES_MASK);
+ if (err)
+ return err;
+
+ /* blk_key */
+ crypto_skcipher_clear_flags(ecb, CRYPTO_TFM_REQ_MASK);
+ crypto_skcipher_set_flags(ecb, crypto_skcipher_get_flags(parent) &
+ CRYPTO_TFM_REQ_MASK);
+ err = crypto_skcipher_setkey(ecb, blk_key, 16);
+ crypto_skcipher_set_flags(parent, crypto_skcipher_get_flags(ecb) &
+ CRYPTO_TFM_RES_MASK);
+ return err;
+}
+
+static int heh_init_tfm(struct crypto_skcipher *tfm)
+{
+ struct skcipher_instance *inst = skcipher_alg_instance(tfm);
+ struct heh_instance_ctx *ictx = skcipher_instance_ctx(inst);
+ struct heh_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct crypto_shash *cmac;
+ struct crypto_skcipher *ecb;
+ unsigned int reqsize;
+ int err;
+
+ cmac = crypto_spawn_shash(&ictx->cmac);
+ if (IS_ERR(cmac))
+ return PTR_ERR(cmac);
+
+ ecb = crypto_spawn_skcipher(&ictx->ecb);
+ err = PTR_ERR(ecb);
+ if (IS_ERR(ecb))
+ goto err_free_cmac;
+
+ ctx->cmac = cmac;
+ ctx->ecb = ecb;
+
+ reqsize = crypto_skcipher_alignmask(tfm) &
+ ~(crypto_tfm_ctx_alignment() - 1);
+ reqsize += max(offsetof(struct heh_req_ctx, u.cmac.desc) +
+ sizeof(struct shash_desc) +
+ crypto_shash_descsize(cmac),
+ offsetof(struct heh_req_ctx, u.ecb.req) +
+ sizeof(struct skcipher_request) +
+ crypto_skcipher_reqsize(ecb));
+ crypto_skcipher_set_reqsize(tfm, reqsize);
+ return 0;
+
+err_free_cmac:
+ crypto_free_shash(cmac);
+ return err;
+}
+
+static void heh_exit_tfm(struct crypto_skcipher *tfm)
+{
+ struct heh_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+ gf128mul_free_4k(ctx->tau_key);
+ crypto_free_shash(ctx->cmac);
+ crypto_free_skcipher(ctx->ecb);
+}
+
+static void heh_free_instance(struct skcipher_instance *inst)
+{
+ struct heh_instance_ctx *ctx = skcipher_instance_ctx(inst);
+
+ crypto_drop_shash(&ctx->cmac);
+ crypto_drop_skcipher(&ctx->ecb);
+ kfree(inst);
+}
+
+/*
+ * Create an instance of HEH as a skcipher.
+ *
+ * This relies on underlying CMAC and ECB algorithms, usually cmac(aes) and
+ * ecb(aes). For performance reasons we support asynchronous ECB algorithms.
+ * However, we do not yet support asynchronous CMAC algorithms because CMAC is
+ * only used on a small fixed amount of data per request, independent of the
+ * request length. This would change if AEAD or variable-length nonce support
+ * were to be exposed.
+ */
+static int heh_create_common(struct crypto_template *tmpl, struct rtattr **tb,
+ const char *full_name, const char *cmac_name,
+ const char *ecb_name)
+{
+ struct crypto_attr_type *algt;
+ struct skcipher_instance *inst;
+ struct heh_instance_ctx *ctx;
+ struct shash_alg *cmac;
+ struct skcipher_alg *ecb;
+ int err;
+
+ algt = crypto_get_attr_type(tb);
+ if (IS_ERR(algt))
+ return PTR_ERR(algt);
+
+ /* User must be asking for something compatible with skcipher */
+ if ((algt->type ^ CRYPTO_ALG_TYPE_SKCIPHER) & algt->mask)
+ return -EINVAL;
+
+ /* Allocate the skcipher instance */
+ inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ ctx = skcipher_instance_ctx(inst);
+
+ /* Set up the cmac and ecb spawns */
+
+ ctx->cmac.base.inst = skcipher_crypto_instance(inst);
+ err = crypto_grab_shash(&ctx->cmac, cmac_name, 0, CRYPTO_ALG_ASYNC);
+ if (err)
+ goto err_free_inst;
+ cmac = crypto_spawn_shash_alg(&ctx->cmac);
+
+ ctx->ecb.base.inst = skcipher_crypto_instance(inst);
+ err = crypto_grab_skcipher(&ctx->ecb, ecb_name, 0,
+ crypto_requires_sync(algt->type,
+ algt->mask));
+ if (err)
+ goto err_drop_cmac;
+ ecb = crypto_spawn_skcipher_alg(&ctx->ecb);
+
+ /* HEH only supports block ciphers with 16 byte block size */
+ err = -EINVAL;
+ if (ecb->base.cra_blocksize != HEH_BLOCK_SIZE)
+ goto err_drop_ecb;
+
+ /* The underlying "ECB" algorithm must not require an IV */
+ err = -EINVAL;
+ if (crypto_skcipher_alg_ivsize(ecb) != 0)
+ goto err_drop_ecb;
+
+ /* Set the instance names */
+
+ err = -ENAMETOOLONG;
+ if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+ "heh_base(%s,%s)", cmac->base.cra_driver_name,
+ ecb->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+ goto err_drop_ecb;
+
+ strcpy(inst->alg.base.cra_name, full_name); /* guaranteed to fit */
+
+ /* Finish initializing the instance */
+
+ inst->alg.base.cra_flags = (cmac->base.cra_flags |
+ ecb->base.cra_flags) & CRYPTO_ALG_ASYNC;
+ inst->alg.base.cra_blocksize = HEH_BLOCK_SIZE;
+ inst->alg.base.cra_ctxsize = sizeof(struct heh_tfm_ctx);
+ inst->alg.base.cra_alignmask = ecb->base.cra_alignmask |
+ (__alignof__(be128) - 1);
+ inst->alg.base.cra_priority = ecb->base.cra_priority;
+
+ inst->alg.ivsize = HEH_BLOCK_SIZE;
+ inst->alg.min_keysize = HEH_KEY_SIZE;
+ inst->alg.max_keysize = HEH_KEY_SIZE;
+
+ inst->alg.init = heh_init_tfm;
+ inst->alg.exit = heh_exit_tfm;
+ inst->alg.setkey = heh_setkey;
+ inst->alg.encrypt = heh_encrypt;
+ inst->alg.decrypt = heh_decrypt;
+ inst->free = heh_free_instance;
+
+ /* Register the instance */
+ err = skcipher_register_instance(tmpl, inst);
+ if (err)
+ goto err_drop_ecb;
+ return 0;
+
+err_drop_ecb:
+ crypto_drop_skcipher(&ctx->ecb);
+err_drop_cmac:
+ crypto_drop_shash(&ctx->cmac);
+err_free_inst:
+ kfree(inst);
+ return err;
+}
+
+static int heh_create(struct crypto_template *tmpl, struct rtattr **tb)
+{
+ const char *cipher_name;
+ char full_name[CRYPTO_MAX_ALG_NAME];
+ char cmac_name[CRYPTO_MAX_ALG_NAME];
+ char ecb_name[CRYPTO_MAX_ALG_NAME];
+
+ /* Get the name of the requested block cipher (e.g. aes) */
+ cipher_name = crypto_attr_alg_name(tb[1]);
+ if (IS_ERR(cipher_name))
+ return PTR_ERR(cipher_name);
+
+ if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "heh(%s)", cipher_name) >=
+ CRYPTO_MAX_ALG_NAME)
+ return -ENAMETOOLONG;
+
+ if (snprintf(cmac_name, CRYPTO_MAX_ALG_NAME, "cmac(%s)", cipher_name) >=
+ CRYPTO_MAX_ALG_NAME)
+ return -ENAMETOOLONG;
+
+ if (snprintf(ecb_name, CRYPTO_MAX_ALG_NAME, "ecb(%s)", cipher_name) >=
+ CRYPTO_MAX_ALG_NAME)
+ return -ENAMETOOLONG;
+
+ return heh_create_common(tmpl, tb, full_name, cmac_name, ecb_name);
+}
+
+static struct crypto_template heh_tmpl = {
+ .name = "heh",
+ .create = heh_create,
+ .module = THIS_MODULE,
+};
+
+static int heh_base_create(struct crypto_template *tmpl, struct rtattr **tb)
+{
+ char full_name[CRYPTO_MAX_ALG_NAME];
+ const char *cmac_name;
+ const char *ecb_name;
+
+ cmac_name = crypto_attr_alg_name(tb[1]);
+ if (IS_ERR(cmac_name))
+ return PTR_ERR(cmac_name);
+
+ ecb_name = crypto_attr_alg_name(tb[2]);
+ if (IS_ERR(ecb_name))
+ return PTR_ERR(ecb_name);
+
+ if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "heh_base(%s,%s)",
+ cmac_name, ecb_name) >= CRYPTO_MAX_ALG_NAME)
+ return -ENAMETOOLONG;
+
+ return heh_create_common(tmpl, tb, full_name, cmac_name, ecb_name);
+}
+
+/*
+ * If HEH is instantiated as "heh_base" instead of "heh", then specific
+ * implementations of cmac and ecb can be specified instead of just the cipher
+ */
+static struct crypto_template heh_base_tmpl = {
+ .name = "heh_base",
+ .create = heh_base_create,
+ .module = THIS_MODULE,
+};
+
+static int __init heh_module_init(void)
+{
+ int err;
+
+ err = crypto_register_template(&heh_tmpl);
+ if (err)
+ return err;
+
+ err = crypto_register_template(&heh_base_tmpl);
+ if (err)
+ goto out_undo_heh;
+
+ return 0;
+
+out_undo_heh:
+ crypto_unregister_template(&heh_tmpl);
+ return err;
+}
+
+static void __exit heh_module_exit(void)
+{
+ crypto_unregister_template(&heh_tmpl);
+ crypto_unregister_template(&heh_base_tmpl);
+}
+
+module_init(heh_module_init);
+module_exit(heh_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Hash-Encrypt-Hash block cipher mode");
+MODULE_ALIAS_CRYPTO("heh");
+MODULE_ALIAS_CRYPTO("heh_base");
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [RFC][PATCH 6/7] crypto: testmgr - Add test vectors for HEH
From: Alex Cope @ 2016-11-14 21:01 UTC (permalink / raw)
To: linux-crypto; +Cc: mhalcrow, edknapp, Alex Cope, Eric Biggers
In-Reply-To: <1479157277-10251-1-git-send-email-alexcope@google.com>
Adding test vectors from
https://tools.ietf.org/html/draft-cope-heh-00
Signed-off-by: Alex Cope <alexcope@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
crypto/testmgr.c | 15 ++++
crypto/testmgr.h | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 241 insertions(+)
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index ded50b6..bab027b 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -3481,6 +3481,21 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "heh(aes)",
+ .test = alg_test_skcipher,
+ .suite = {
+ .cipher = {
+ .enc = {
+ .vecs = aes_heh_enc_tv_template,
+ .count = AES_HEH_ENC_TEST_VECTORS
+ },
+ .dec = {
+ .vecs = aes_heh_dec_tv_template,
+ .count = AES_HEH_DEC_TEST_VECTORS
+ }
+ }
+ }
+ }, {
.alg = "hmac(crc32)",
.test = alg_test_hash,
.suite = {
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index e64a4ef..b2daad3 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -15172,6 +15172,8 @@ static struct cipher_testvec cast6_xts_dec_tv_template[] = {
#define AES_DEC_TEST_VECTORS 4
#define AES_CBC_ENC_TEST_VECTORS 5
#define AES_CBC_DEC_TEST_VECTORS 5
+#define AES_HEH_ENC_TEST_VECTORS 4
+#define AES_HEH_DEC_TEST_VECTORS 4
#define HMAC_MD5_ECB_CIPHER_NULL_ENC_TEST_VECTORS 2
#define HMAC_MD5_ECB_CIPHER_NULL_DEC_TEST_VECTORS 2
#define HMAC_SHA1_ECB_CIPHER_NULL_ENC_TEST_VEC 2
@@ -15544,6 +15546,230 @@ static struct cipher_testvec aes_dec_tv_template[] = {
},
};
+static struct cipher_testvec aes_heh_enc_tv_template[] = {
+ {
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+ .klen = 48,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+ .ilen = 16,
+ .result = "\x61\x76\x38\xa5\x12\x0b\x6d\x89"
+ "\x92\x68\x30\x7e\x0d\x6e\x81\xe3",
+ .rlen = 16,
+ .also_non_np = 1,
+ .np = 2,
+ .tap = { 8, 8 },
+ }, {
+ .key = "\x68\xf8\x27\x87\xdc\x30\x33\xfd"
+ "\x65\x5b\x8e\x51\x2e\x02\xff\x9d"
+ "\x21\x28\x1e\x64\xcd\x9c\x33\x88"
+ "\xf6\x2c\x43\x8f\xf5\x6f\xf5\x8f"
+ "\xa8\xda\x24\x9b\x5e\xfa\x13\xc2"
+ "\xc1\x94\xbf\x32\xba\x38\xa3\x77",
+ .klen = 48,
+ .iv = "\x4d\x47\x61\x37\x2b\x47\x86\xf0"
+ "\xd6\x47\xb5\xc2\xe8\xcf\x85\x27",
+ .input = "\xb8\xee\x29\xe4\xa5\xd1\xe7\x55"
+ "\xd0\xfd\xe7\x22\x63\x76\x36\xe2"
+ "\xf8\x0c\xf8\xfe\x65\x76\xe7\xca"
+ "\xc1\x42\xf5\xca\x5a\xa8\xac\x2a",
+ .ilen = 32,
+ .result = "\x1f\x4c\x6a\x1e\x1d\x20\x0d\x99"
+ "\xdf\xbb\x13\xd8\x35\xdc\x1d\xbe"
+ "\xed\x50\x0a\x9f\xfd\xd6\x94\x85"
+ "\xd0\x8b\xf7\xb4\x49\x7f\x70\x6d",
+ .rlen = 32,
+ .also_non_np = 1,
+ .np = 3,
+ .tap = { 16, 13, 3 },
+ }, {
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+ .klen = 48,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00",
+ .ilen = 63,
+ .result = "\xfb\x30\x90\x47\xc5\x4e\xcc\xfd"
+ "\xc4\x90\xa2\x9f\x7c\x03\x63\xc3"
+ "\xcb\xaf\x2e\xee\x62\x18\xeb\x20"
+ "\x62\x97\xe4\x9b\xf2\x8b\xf3\x3f"
+ "\x76\x3b\xaa\xab\xf0\x19\x54\xdb"
+ "\xb4\xaf\x2e\xd9\xa7\xe0\x92\x04"
+ "\x5a\xe4\x81\xfc\x58\xf2\xda\xbf"
+ "\x5d\xc9\xb1\x47\xd5\x08\xb1",
+ .rlen = 63,
+ .also_non_np = 1,
+ .np = 8,
+ .tap = { 20, 20, 10, 8, 2, 1, 1, 1 },
+ }, {
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+ .klen = 48,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x01"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00",
+ .ilen = 63,
+ .result = "\x9c\xdf\xa5\x50\x83\xe0\xa3\xb5"
+ "\x0d\x35\x83\x34\x6e\x6e\x40\xd6"
+ "\x0f\x81\xc8\x1a\x9c\x40\x81\xfb"
+ "\xb3\x6e\xb4\xbf\xfc\xca\xc9\x50"
+ "\xcd\x33\xfd\xb3\x43\x11\xe6\x32"
+ "\x02\x3d\x3e\xc6\x49\x6e\xcf\x58"
+ "\x3e\x14\x15\x6d\x39\x2a\x58\x99"
+ "\x83\xaf\xdd\x22\x3e\x7f\x6c",
+ .rlen = 63,
+ .also_non_np = 1,
+ .np = 8,
+ .tap = { 20, 20, 10, 8, 2, 1, 1, 1 },
+ }
+};
+
+static struct cipher_testvec aes_heh_dec_tv_template[] = {
+ {
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+ .klen = 48,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x61\x76\x38\xa5\x12\x0b\x6d\x89"
+ "\x92\x68\x30\x7e\x0d\x6e\x81\xe3",
+ .ilen = 16,
+ .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+ .rlen = 16,
+ .also_non_np = 1,
+ .np = 2,
+ .tap = { 8, 8 },
+ }, {
+ .key = "\x68\xf8\x27\x87\xdc\x30\x33\xfd"
+ "\x65\x5b\x8e\x51\x2e\x02\xff\x9d"
+ "\x21\x28\x1e\x64\xcd\x9c\x33\x88"
+ "\xf6\x2c\x43\x8f\xf5\x6f\xf5\x8f"
+ "\xa8\xda\x24\x9b\x5e\xfa\x13\xc2"
+ "\xc1\x94\xbf\x32\xba\x38\xa3\x77",
+ .klen = 48,
+ .iv = "\x4d\x47\x61\x37\x2b\x47\x86\xf0"
+ "\xd6\x47\xb5\xc2\xe8\xcf\x85\x27",
+ .input = "\x1f\x4c\x6a\x1e\x1d\x20\x0d\x99"
+ "\xdf\xbb\x13\xd8\x35\xdc\x1d\xbe"
+ "\xed\x50\x0a\x9f\xfd\xd6\x94\x85"
+ "\xd0\x8b\xf7\xb4\x49\x7f\x70\x6d",
+ .ilen = 32,
+ .result = "\xb8\xee\x29\xe4\xa5\xd1\xe7\x55"
+ "\xd0\xfd\xe7\x22\x63\x76\x36\xe2"
+ "\xf8\x0c\xf8\xfe\x65\x76\xe7\xca"
+ "\xc1\x42\xf5\xca\x5a\xa8\xac\x2a",
+ .rlen = 32,
+ .also_non_np = 1,
+ .np = 3,
+ .tap = { 16, 13, 3 },
+ }, {
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+ .klen = 48,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .result = "\xfb\x30\x90\x47\xc5\x4e\xcc\xfd"
+ "\xc4\x90\xa2\x9f\x7c\x03\x63\xc3"
+ "\xcb\xaf\x2e\xee\x62\x18\xeb\x20"
+ "\x62\x97\xe4\x9b\xf2\x8b\xf3\x3f"
+ "\x76\x3b\xaa\xab\xf0\x19\x54\xdb"
+ "\xb4\xaf\x2e\xd9\xa7\xe0\x92\x04"
+ "\x5a\xe4\x81\xfc\x58\xf2\xda\xbf"
+ "\x5d\xc9\xb1\x47\xd5\x08\xb1",
+ .ilen = 63,
+ .input = "\xfb\x30\x90\x47\xc5\x4e\xcc\xfd"
+ "\xc4\x90\xa2\x9f\x7c\x03\x63\xc3"
+ "\xcb\xaf\x2e\xee\x62\x18\xeb\x20"
+ "\x62\x97\xe4\x9b\xf2\x8b\xf3\x3f"
+ "\x76\x3b\xaa\xab\xf0\x19\x54\xdb"
+ "\xb4\xaf\x2e\xd9\xa7\xe0\x92\x04"
+ "\x5a\xe4\x81\xfc\x58\xf2\xda\xbf"
+ "\x5d\xc9\xb1\x47\xd5\x08\xb1",
+ .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00",
+ .rlen = 63,
+ .also_non_np = 1,
+ .np = 8,
+ .tap = { 20, 20, 10, 8, 2, 1, 1, 1 },
+ }, {
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+ .klen = 48,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x9c\xdf\xa5\x50\x83\xe0\xa3\xb5"
+ "\x0d\x35\x83\x34\x6e\x6e\x40\xd6"
+ "\x0f\x81\xc8\x1a\x9c\x40\x81\xfb"
+ "\xb3\x6e\xb4\xbf\xfc\xca\xc9\x50"
+ "\xcd\x33\xfd\xb3\x43\x11\xe6\x32"
+ "\x02\x3d\x3e\xc6\x49\x6e\xcf\x58"
+ "\x3e\x14\x15\x6d\x39\x2a\x58\x99"
+ "\x83\xaf\xdd\x22\x3e\x7f\x6c",
+ .ilen = 63,
+ .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x01"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00",
+ .rlen = 63,
+ .also_non_np = 1,
+ .np = 8,
+ .tap = { 20, 20, 10, 8, 2, 1, 1, 1 },
+ }
+};
+
static struct cipher_testvec aes_cbc_enc_tv_template[] = {
{ /* From RFC 3602 */
.key = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH] crypto: sha*-mb Fix total_len for correct hash when larger than 512MB
From: Greg Tucker @ 2016-11-14 23:11 UTC (permalink / raw)
To: herbert, linux-crypto; +Cc: megha.dey, tim.c.chen, xiaodong.liu, Greg Tucker
Current multi-buffer hash implementations have a restriction on the total
length of a hash job to 512MB. Hashing larger buffers will result in an
incorrect hash. This extends the limit to 2^62 - 1.
Signed-off-by: Greg Tucker <greg.b.tucker@intel.com>
---
arch/x86/crypto/sha1-mb/sha1_mb.c | 2 +-
arch/x86/crypto/sha1-mb/sha1_mb_ctx.h | 2 +-
arch/x86/crypto/sha256-mb/sha256_mb.c | 2 +-
arch/x86/crypto/sha256-mb/sha256_mb_ctx.h | 2 +-
arch/x86/crypto/sha512-mb/sha512_mb.c | 2 +-
arch/x86/crypto/sha512-mb/sha512_mb_ctx.h | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/x86/crypto/sha1-mb/sha1_mb.c b/arch/x86/crypto/sha1-mb/sha1_mb.c
index 9e5b671..acf9fdf 100644
--- a/arch/x86/crypto/sha1-mb/sha1_mb.c
+++ b/arch/x86/crypto/sha1-mb/sha1_mb.c
@@ -114,7 +114,7 @@ static inline void sha1_init_digest(uint32_t *digest)
}
static inline uint32_t sha1_pad(uint8_t padblock[SHA1_BLOCK_SIZE * 2],
- uint32_t total_len)
+ uint64_t total_len)
{
uint32_t i = total_len & (SHA1_BLOCK_SIZE - 1);
diff --git a/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h b/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h
index 98a35bc..13590cc 100644
--- a/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h
+++ b/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h
@@ -125,7 +125,7 @@ struct sha1_hash_ctx {
/* error flag */
int error;
- uint32_t total_length;
+ uint64_t total_length;
const void *incoming_buffer;
uint32_t incoming_buffer_length;
uint8_t partial_block_buffer[SHA1_BLOCK_SIZE * 2];
diff --git a/arch/x86/crypto/sha256-mb/sha256_mb.c b/arch/x86/crypto/sha256-mb/sha256_mb.c
index 6f97fb3..7926a22 100644
--- a/arch/x86/crypto/sha256-mb/sha256_mb.c
+++ b/arch/x86/crypto/sha256-mb/sha256_mb.c
@@ -115,7 +115,7 @@ inline void sha256_init_digest(uint32_t *digest)
}
inline uint32_t sha256_pad(uint8_t padblock[SHA256_BLOCK_SIZE * 2],
- uint32_t total_len)
+ uint64_t total_len)
{
uint32_t i = total_len & (SHA256_BLOCK_SIZE - 1);
diff --git a/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h b/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h
index edd252b..aabb303 100644
--- a/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h
+++ b/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h
@@ -125,7 +125,7 @@ struct sha256_hash_ctx {
/* error flag */
int error;
- uint32_t total_length;
+ uint64_t total_length;
const void *incoming_buffer;
uint32_t incoming_buffer_length;
uint8_t partial_block_buffer[SHA256_BLOCK_SIZE * 2];
diff --git a/arch/x86/crypto/sha512-mb/sha512_mb.c b/arch/x86/crypto/sha512-mb/sha512_mb.c
index d210174..9c1bb6d 100644
--- a/arch/x86/crypto/sha512-mb/sha512_mb.c
+++ b/arch/x86/crypto/sha512-mb/sha512_mb.c
@@ -117,7 +117,7 @@ inline void sha512_init_digest(uint64_t *digest)
}
inline uint32_t sha512_pad(uint8_t padblock[SHA512_BLOCK_SIZE * 2],
- uint32_t total_len)
+ uint64_t total_len)
{
uint32_t i = total_len & (SHA512_BLOCK_SIZE - 1);
diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h b/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h
index 9d4b2c8..e4653f5 100644
--- a/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h
+++ b/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h
@@ -119,7 +119,7 @@ struct sha512_hash_ctx {
/* error flag */
int error;
- uint32_t total_length;
+ uint64_t total_length;
const void *incoming_buffer;
uint32_t incoming_buffer_length;
uint8_t partial_block_buffer[SHA512_BLOCK_SIZE * 2];
--
2.5.5
^ permalink raw reply related
* Re: [v2 PATCH 1/16] crypto: skcipher - Add skcipher walk interface
From: Herbert Xu @ 2016-11-15 13:58 UTC (permalink / raw)
To: Eric Biggers; +Cc: Linux Crypto Mailing List
In-Reply-To: <20161114013548.GA4778@google.com>
Hi Eric:
On Sun, Nov 13, 2016 at 05:35:48PM -0800, Eric Biggers wrote:
> Hi Herbert,
>
> On Sun, Nov 13, 2016 at 07:45:32PM +0800, Herbert Xu wrote:
> > +int skcipher_walk_done(struct skcipher_walk *walk, int err)
> > +{
> > + unsigned int nbytes = 0;
> > + unsigned int n = 0;
> > +
> > + if (likely(err >= 0)) {
> > + n = walk->nbytes - err;
> > + nbytes = walk->total - n;
> > + }
> > +
> > + if (likely(!(walk->flags & (SKCIPHER_WALK_PHYS |
> > + SKCIPHER_WALK_SLOW |
> > + SKCIPHER_WALK_COPY |
> > + SKCIPHER_WALK_DIFF)))) {
> > +unmap_src:
> > + skcipher_unmap_src(walk);
>
> Isn't it wrong to unmap the buffers when err < 0? They won't have been mapped
> yet, e.g. if the 'skcipher_walk_done(walk, -EINVAL)' case is hit.
Indeed. The unmapping code needs to be inside the first if clause.
I'll rearrange it.
> > + /* Short-circuit for the common/fast path. */
> > + if (!(((unsigned long)walk->iv ^ (unsigned long)walk->oiv) |
> > + ((unsigned long)walk->buffer ^ (unsigned long)walk->page) |
> > + (unsigned long)walk->page))
> > + goto out;
>
> This is really saying that the IV wasn't copied and that walk->buffer and
> walk->page are both NULL. But if walk->buffer is NULL then the IV wasn't
> copied. So this can be simplified to:
>
> if (!((unsigned long)walk->buffer | (unsigned long)walk->page))
> goto out;
Nice, I'll use this.
> > +int skcipher_walk_next(struct skcipher_walk *walk)
> > +{
>
> Shouldn't this be static? There's even a static declaration earlier in the
> file.
Yes, static added.
> > +static int skcipher_next_slow(struct skcipher_walk *walk)
> > +{
> > + bool phys = walk->flags & SKCIPHER_WALK_PHYS;
> > + unsigned alignmask = walk->alignmask;
> > + unsigned bsize = walk->chunksize;
> ...
> > + walk->nbytes = bsize;
>
> skcipher_next_slow() is always setting up 'chunksize' bytes to be processed.
> Isn't this wrong in the 'blocksize < chunksize' case because fewer than
> 'chunksize' bytes may need to be processed?
Good catch. This is supposed to be the bsize from the caller
which is capped by walk->total.
> > +static inline void *skcipher_map(struct scatter_walk *walk)
> > +{
> > + struct page *page = scatterwalk_page(walk);
> > +
> > + return (PageHighMem(page) ? kmap_atomic(page) : page_address(page)) +
> > + offset_in_page(walk->offset);
> > +}
>
> Is the PageHighMem() optimization really worthwhile? It will skip kmap_atomic()
> and hence preempt_disable() for non-highmem pages, so it may make it harder to
> find bugs where users are sleeping when they shouldn't be. It also seems
> inconsistent that skcipher_map() will do this optimization but scatterwalk_map()
> won't.
It did make a big difference on my machine. Because users such
as lrw will call the walker a lot more often after the conversion
to skcipher this is now worthwhile as an optimisation. With the
old code the blkcipher walk was not called as often.
> > + if (!walk->page) {
> > + gfp_t gfp = skcipher_walk_gfp(walk);
> > +
> > + walk->page = (void *)__get_free_page(gfp);
> > + if (!walk->page)
> > + goto slow_path;
> > + }
> > +
> > + walk->nbytes = min_t(unsigned, n,
> > + PAGE_SIZE - offset_in_page(walk->page));
>
> walk->page will be page-aligned, so there's no need for offset_in_page(). Also,
> 'n' has already been clamped to at most one page. So AFAICS this can simply be
> 'walk->nbytes = n;'.
This is valid for the sync walk, but not for the async case. In
the async case, we will reuse the page if the previous copy did
not completely consume it.
> > +int skcipher_walk_done(struct skcipher_walk *walk, int err);
> ...
> > +void skcipher_walk_complete(struct skcipher_walk *walk, int err);
>
> The naming is confusing: "done" vs. "complete". They can easily be mixed up.
> Would it make more sense to have something with "async" in the name for the
> second one, like skcipher_walk_async_done()?
I see your point. But I think async_done would also be confusing
because the async case needs to call both skcipher_walk_done and
skcipher_walk_async_done.
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [v2 PATCH 4/16] crypto: xts - Convert to skcipher
From: Herbert Xu @ 2016-11-15 14:41 UTC (permalink / raw)
To: Eric Biggers; +Cc: Linux Crypto Mailing List
In-Reply-To: <20161114021029.GC4778@google.com>
On Sun, Nov 13, 2016 at 06:10:29PM -0800, Eric Biggers wrote:
>
> There's duplicated code for encryption and decryption here. AFAICS, the only
> difference between XTS encryption and decryption is whether the block cipher is
> used in encryption or decryption mode for the ECB step. So I suggest storing a
> function pointer in 'struct rctx' to either crypto_skcipher_encrypt or
> crypto_skcipher_decrypt, then calling through it for the ECB step. Then this
> code can be shared. In other words I'd like the top-level functions to look
> like this:
I'm all for getting rid of duplicate code. However, I'd also
prefer to do it without using indirect function calls in this
case.
> I'm also wondering about the line which does
> 'subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;'.
> Is the real intent of that to clear the CRYPTO_TFM_REQ_MAY_SLEEP flag because
> the completion callback may be called in an atomic context, and if so shouldn't
> it just clear that flag only, rather than all flags except
> CRYPTO_TFM_REQ_MAY_BACKLOG?
The intent here is that this is the only flag that we want to
pass along. Of course in the absence of any other flags it's a
moot point.
> > + if (req->cryptlen > XTS_BUFFER_SIZE) {
> > + subreq->cryptlen = min(req->cryptlen, (unsigned)PAGE_SIZE);
> > + rctx->ext = kmalloc(subreq->cryptlen, gfp);
> > + }
>
> There's no check for failure to allocate the 'rctx->ext' memory.
The code is supposed to handle a NULL rctx->ext gracefully. Did
you find a spot where it is used without checking?
> > + if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
> > + "xts(%s)", ctx->name) >= CRYPTO_MAX_ALG_NAME)
> > + return -ENAMETOOLONG;
> > + } else
> > + goto err_drop_spawn;
>
> There should be a line which sets 'err = -EINVAL' before here.
Indeed. Fixed here as well as in lrw.
> > +static int init_crypt(struct skcipher_request *req, crypto_completion_t done)
> > {
> > - struct priv *ctx = crypto_blkcipher_ctx(desc->tfm);
> > - struct blkcipher_walk w;
> > + struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
> > + struct rctx *rctx = skcipher_request_ctx(req);
> > + struct skcipher_request *subreq;
> > + be128 *buf;
> ...
> > + /* calculate first value of T */
> > + buf = rctx->ext ?: rctx->buf;
> > + crypto_cipher_encrypt_one(ctx->tweak, (u8 *)&rctx->t, req->iv);
> > +
> > + return 0;
>
> The 'buf' variable is assigned to but never used.
OK, deleted.
> > int xts_crypt(struct blkcipher_desc *desc, struct scatterlist *sdst,
> > @@ -233,112 +416,167 @@ int xts_crypt(struct blkcipher_desc *desc, struct scatterlist *sdst,
> > }
> > EXPORT_SYMBOL_GPL(xts_crypt);
>
> xts_crypt() is still here. Is there a plan for its removal, since now the
> generic XTS algorithm can use an accelerated ECB algorithm?
It will be removed once all the arch code that uses it are converted.
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [v2 PATCH 7/16] crypto: simd - Add simd skcipher helper
From: Herbert Xu @ 2016-11-15 14:55 UTC (permalink / raw)
To: Eric Biggers; +Cc: Linux Crypto Mailing List
In-Reply-To: <20161114022740.GD4778@google.com>
On Sun, Nov 13, 2016 at 06:27:40PM -0800, Eric Biggers wrote:
> On Sun, Nov 13, 2016 at 07:45:38PM +0800, Herbert Xu wrote:
> > This patch adds the simd skcipher helper which is meant to be
> > a replacement for ablk helper. It replaces the underlying blkcipher
> > interface with skcipher, and also presents the top-level algorithm
> > as an skcipher.
>
> I assume this means it's planned for all users of ablk_helper to be migrated to
> crypto_simd, and ablk_helper will be removed?
Yes that's the idea.
> > + salg = kzalloc(sizeof(*alg), GFP_KERNEL);
> > + if (!salg) {
> > + salg = ERR_PTR(-ENOMEM);
> > + goto out_put_tfm;
> > + }
>
> Shouldn't this be 'sizeof(*salg)'?
Good catch. I'll fix this.
> > + tfm = crypto_alloc_skcipher(basename, CRYPTO_ALG_INTERNAL,
> > + CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC);
> > + if (IS_ERR(tfm))
> > + return ERR_CAST(tfm);
> > +
> > + ialg = crypto_skcipher_alg(tfm);
>
> It seems this really just needs an algorithm and not a transform. Perhaps it
> should be calling crypto_find_alg() directly?
crypto_find_alg is an internal API function that should not be used
unless you're implementing a crypto_type. Ugh I see that it is being
abused already. I'll get this fixed.
As a rule internal.h should only be used by API implementors, not
algorithm implementors.
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH 1/2] fscrypto: don't use on-stack buffer for filename encryption
From: Theodore Ts'o @ 2016-11-15 16:46 UTC (permalink / raw)
To: Eric Biggers
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-crypto,
jaegeuk, richard, luto
In-Reply-To: <1478210582-86338-1-git-send-email-ebiggers@google.com>
On Thu, Nov 03, 2016 at 03:03:01PM -0700, Eric Biggers wrote:
> With the new (in 4.9) option to use a virtually-mapped stack
> (CONFIG_VMAP_STACK), stack buffers cannot be used as input/output for
> the scatterlist crypto API because they may not be directly mappable to
> struct page. For short filenames, fname_encrypt() was encrypting a
> stack buffer holding the padded filename. Fix it by encrypting the
> filename in-place in the output buffer, thereby making the temporary
> buffer unnecessary.
>
> This bug could most easily be observed in a CONFIG_DEBUG_SG kernel
> because this allowed the BUG in sg_set_buf() to be triggered.
>
> Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is on the fscrypt and dev branches on ext4.git.
- Ted
^ permalink raw reply
* Re: [PATCH 2/2] fscrypto: don't use on-stack buffer for key derivation
From: Theodore Ts'o @ 2016-11-15 16:47 UTC (permalink / raw)
To: Eric Biggers
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-crypto,
jaegeuk, richard, luto
In-Reply-To: <1478210582-86338-2-git-send-email-ebiggers@google.com>
On Thu, Nov 03, 2016 at 03:03:02PM -0700, Eric Biggers wrote:
> With the new (in 4.9) option to use a virtually-mapped stack
> (CONFIG_VMAP_STACK), stack buffers cannot be used as input/output for
> the scatterlist crypto API because they may not be directly mappable to
> struct page. get_crypt_info() was using a stack buffer to hold the
> output from the encryption operation used to derive the per-file key.
> Fix it by using a heap buffer.
>
> This bug could most easily be observed in a CONFIG_DEBUG_SG kernel
> because this allowed the BUG in sg_set_buf() to be triggered.
>
> Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is on the fscrypt and dev branches on ext4.git.
- Ted
^ permalink raw reply
* Re: [PATCH] crypto: sha*-mb Fix total_len for correct hash when larger than 512MB
From: Tim Chen @ 2016-11-15 16:50 UTC (permalink / raw)
To: Greg Tucker, herbert, linux-crypto; +Cc: megha.dey, xiaodong.liu
In-Reply-To: <1479165104-24356-1-git-send-email-greg.b.tucker@intel.com>
On Mon, 2016-11-14 at 16:11 -0700, Greg Tucker wrote:
> Current multi-buffer hash implementations have a restriction on the total
> length of a hash job to 512MB. Hashing larger buffers will result in an
> incorrect hash. This extends the limit to 2^62 - 1.
>
> Signed-off-by: Greg Tucker <greg.b.tucker@intel.com>
Acked-by: Tim Chen <tim.c.chen@linux.intel.com>
> ---
> arch/x86/crypto/sha1-mb/sha1_mb.c | 2 +-
> arch/x86/crypto/sha1-mb/sha1_mb_ctx.h | 2 +-
> arch/x86/crypto/sha256-mb/sha256_mb.c | 2 +-
> arch/x86/crypto/sha256-mb/sha256_mb_ctx.h | 2 +-
> arch/x86/crypto/sha512-mb/sha512_mb.c | 2 +-
> arch/x86/crypto/sha512-mb/sha512_mb_ctx.h | 2 +-
> 6 files changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/arch/x86/crypto/sha1-mb/sha1_mb.c b/arch/x86/crypto/sha1-mb/sha1_mb.c
> index 9e5b671..acf9fdf 100644
> --- a/arch/x86/crypto/sha1-mb/sha1_mb.c
> +++ b/arch/x86/crypto/sha1-mb/sha1_mb.c
> @@ -114,7 +114,7 @@ static inline void sha1_init_digest(uint32_t *digest)
> }
>
> static inline uint32_t sha1_pad(uint8_t padblock[SHA1_BLOCK_SIZE * 2],
> - uint32_t total_len)
> + uint64_t total_len)
> {
> uint32_t i = total_len & (SHA1_BLOCK_SIZE - 1);
>
> diff --git a/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h b/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h
> index 98a35bc..13590cc 100644
> --- a/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h
> +++ b/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h
> @@ -125,7 +125,7 @@ struct sha1_hash_ctx {
> /* error flag */
> int error;
>
> - uint32_t total_length;
> + uint64_t total_length;
> const void *incoming_buffer;
> uint32_t incoming_buffer_length;
> uint8_t partial_block_buffer[SHA1_BLOCK_SIZE * 2];
> diff --git a/arch/x86/crypto/sha256-mb/sha256_mb.c b/arch/x86/crypto/sha256-mb/sha256_mb.c
> index 6f97fb3..7926a22 100644
> --- a/arch/x86/crypto/sha256-mb/sha256_mb.c
> +++ b/arch/x86/crypto/sha256-mb/sha256_mb.c
> @@ -115,7 +115,7 @@ inline void sha256_init_digest(uint32_t *digest)
> }
>
> inline uint32_t sha256_pad(uint8_t padblock[SHA256_BLOCK_SIZE * 2],
> - uint32_t total_len)
> + uint64_t total_len)
> {
> uint32_t i = total_len & (SHA256_BLOCK_SIZE - 1);
>
> diff --git a/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h b/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h
> index edd252b..aabb303 100644
> --- a/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h
> +++ b/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h
> @@ -125,7 +125,7 @@ struct sha256_hash_ctx {
> /* error flag */
> int error;
>
> - uint32_t total_length;
> + uint64_t total_length;
> const void *incoming_buffer;
> uint32_t incoming_buffer_length;
> uint8_t partial_block_buffer[SHA256_BLOCK_SIZE * 2];
> diff --git a/arch/x86/crypto/sha512-mb/sha512_mb.c b/arch/x86/crypto/sha512-mb/sha512_mb.c
> index d210174..9c1bb6d 100644
> --- a/arch/x86/crypto/sha512-mb/sha512_mb.c
> +++ b/arch/x86/crypto/sha512-mb/sha512_mb.c
> @@ -117,7 +117,7 @@ inline void sha512_init_digest(uint64_t *digest)
> }
>
> inline uint32_t sha512_pad(uint8_t padblock[SHA512_BLOCK_SIZE * 2],
> - uint32_t total_len)
> + uint64_t total_len)
> {
> uint32_t i = total_len & (SHA512_BLOCK_SIZE - 1);
>
> diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h b/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h
> index 9d4b2c8..e4653f5 100644
> --- a/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h
> +++ b/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h
> @@ -119,7 +119,7 @@ struct sha512_hash_ctx {
> /* error flag */
> int error;
>
> - uint32_t total_length;
> + uint64_t total_length;
> const void *incoming_buffer;
> uint32_t incoming_buffer_length;
> uint8_t partial_block_buffer[SHA512_BLOCK_SIZE * 2];
^ permalink raw reply
* [RFC PATCH] powerpc: crypto/vmx: clean up generated files
From: Naveen N. Rao @ 2016-11-15 17:05 UTC (permalink / raw)
To: Leonidas S. Barbosa, Herbert Xu
Cc: Paulo Flabiano Smorigo, linux-crypto, linuxppc-dev,
Michael Ellerman
..as stray .S files result in build errors, especially when using
cross-compilers.
More specifically, the generated .S files are endian-specific and will break
subsequent builds targeting the other endian architecture.
Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
---
drivers/crypto/vmx/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/crypto/vmx/Makefile b/drivers/crypto/vmx/Makefile
index de6e241..31b25cb 100644
--- a/drivers/crypto/vmx/Makefile
+++ b/drivers/crypto/vmx/Makefile
@@ -16,4 +16,4 @@ $(src)/aesp8-ppc.S: $(src)/aesp8-ppc.pl
$(src)/ghashp8-ppc.S: $(src)/ghashp8-ppc.pl
$(call cmd,perl)
-.PRECIOUS: $(obj)/aesp8-ppc.S $(obj)/ghashp8-ppc.S
+clean-files := aesp8-ppc.S ghashp8-ppc.S
--
2.10.2
^ permalink raw reply related
* Re: [PATCH 2/2] fscrypto: don't use on-stack buffer for key derivation
From: Eric Biggers @ 2016-11-15 18:53 UTC (permalink / raw)
To: Theodore Ts'o
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-crypto,
jaegeuk, richard, luto
In-Reply-To: <20161115164704.5tzvm2g2x2fyetyu@thunk.org>
On Tue, Nov 15, 2016 at 11:47:04AM -0500, Theodore Ts'o wrote:
> On Thu, Nov 03, 2016 at 03:03:02PM -0700, Eric Biggers wrote:
> > With the new (in 4.9) option to use a virtually-mapped stack
> > (CONFIG_VMAP_STACK), stack buffers cannot be used as input/output for
> > the scatterlist crypto API because they may not be directly mappable to
> > struct page. get_crypt_info() was using a stack buffer to hold the
> > output from the encryption operation used to derive the per-file key.
> > Fix it by using a heap buffer.
> >
> > This bug could most easily be observed in a CONFIG_DEBUG_SG kernel
> > because this allowed the BUG in sg_set_buf() to be triggered.
> >
> > Signed-off-by: Eric Biggers <ebiggers@google.com>
>
> This commit is on the fscrypt and dev branches on ext4.git.
>
> - Ted
Hi Ted,
Would it make any sense to send these two patches to Linus for v4.9-rc6, given
that they fix bugs introduced in 4.9 with the virtually-mapped stack feature?
Or would you prefer to wait and have them go to 4.9 via stable?
Note that CONFIG_VMAP_STACK defaults to y on x86_64.
Thanks,
Eric
^ permalink raw reply
* Re: [PATCH 2/3] crypto: AF_ALG - disregard AAD buffer space for output
From: Stephan Mueller @ 2016-11-15 19:06 UTC (permalink / raw)
To: Herbert Xu; +Cc: mathew.j.martineau, linux-crypto
In-Reply-To: <20161112021302.GA32425@gondor.apana.org.au>
Am Samstag, 12. November 2016, 10:13:02 CET schrieb Herbert Xu:
Hi Herbert,
> On Sat, Nov 12, 2016 at 03:03:36AM +0100, Stephan Mueller wrote:
> > When you have separate buffers, the kernel does not seem to copy the AD
> > over to the target buffer.
>
> OK we should definitely fix that.
Shall the fix be rolled into the patch together with the fix for the tag value
as well as the crash fix? Or can we have a stand-alone patch fixing this.
Btw., how do you suggest that should be fixed? I would assume that this needs
to be fixed on a per-implementation basis. I tested authenc and it copies the
buffers over. gcm_base(ctr-aes-aesni,ghash-clmulni), rfc4106-gcm-aesni or
ccm_base(ctr-aes-aesni,aes-aesni) do not copy the AD over.
Ciao
Stephan
^ permalink raw reply
* Re: [RFC][PATCH 0/6] crypto: Adding Hash-Encrypt-Hash(HEH)
From: Alex Cope @ 2016-11-15 20:40 UTC (permalink / raw)
To: linux-crypto; +Cc: Michael Halcrow, Ed Knapp, Alex Cope
I accidentally had an off-by-one in this patch set. There is no patch
7/7. I've edited this subject but don't plan to resend the rest of the
patches to fix the subject lines.
To clarify, this patchset is on top of "crypto: skcipher - skcipher
algorithm conversion part 3" that Herbert currently has out for
review.
Cheers,
-Alex
On Mon, Nov 14, 2016 at 1:01 PM, Alex Cope <alexcope@google.com> wrote:
> This patchset implements HEH, which is currently specified by the
> following Internet Draft:
>
> https://tools.ietf.org/html/draft-cope-heh-00
>
> This patchset is a request for comments, and should not be merged at
> this time. We would like to wait for further comments on the Internet
> Draft before merging this patchset.
>
> Thanks
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox