From 14a21b9e58a568596eab3fdc28e8028db17012b7 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 21 May 2015 15:11:15 +0800 Subject: crypto: echainiv - Add encrypted chain IV generator This patch adds a new AEAD IV generator echainiv. It is intended to replace the existing skcipher IV generator eseqiv. If the underlying AEAD algorithm is using the old AEAD interface, then echainiv will simply use its IV generator. Otherwise, echainiv will encrypt a counter just like eseqiv but it'll first xor it against a previously stored IV similar to chainiv. Signed-off-by: Herbert Xu --- crypto/echainiv.c | 531 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 531 insertions(+) create mode 100644 crypto/echainiv.c (limited to 'crypto/echainiv.c') diff --git a/crypto/echainiv.c b/crypto/echainiv.c new file mode 100644 index 00000000..e5a9878e --- /dev/null +++ b/crypto/echainiv.c @@ -0,0 +1,531 @@ +/* + * echainiv: Encrypted Chain IV Generator + * + * This generator generates an IV based on a sequence number by xoring it + * with a salt and then encrypting it with the same key as used to encrypt + * the plain text. This algorithm requires that the block size be equal + * to the IV size. It is mainly useful for CBC. + * + * This generator can only be used by algorithms where authentication + * is performed after encryption (i.e., authenc). + * + * Copyright (c) 2015 Herbert Xu + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_IV_SIZE 16 + +struct echainiv_request_ctx { + struct scatterlist src[2]; + struct scatterlist dst[2]; + struct scatterlist ivbuf[2]; + struct scatterlist *ivsg; + struct aead_givcrypt_request subreq; +}; + +struct echainiv_ctx { + struct crypto_aead *child; + spinlock_t lock; + struct crypto_blkcipher *null; + u8 salt[] __attribute__ ((aligned(__alignof__(u32)))); +}; + +static DEFINE_PER_CPU(u32 [MAX_IV_SIZE / sizeof(u32)], echainiv_iv); + +static int echainiv_setkey(struct crypto_aead *tfm, + const u8 *key, unsigned int keylen) +{ + struct echainiv_ctx *ctx = crypto_aead_ctx(tfm); + + return crypto_aead_setkey(ctx->child, key, keylen); +} + +static int echainiv_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) +{ + struct echainiv_ctx *ctx = crypto_aead_ctx(tfm); + + return crypto_aead_setauthsize(ctx->child, authsize); +} + +/* We don't care if we get preempted and read/write IVs from the next CPU. */ +void echainiv_read_iv(u8 *dst, unsigned size) +{ + u32 *a = (u32 *)dst; + u32 __percpu *b = echainiv_iv; + + for (; size >= 4; size -= 4) { + *a++ = this_cpu_read(*b); + b++; + } +} + +void echainiv_write_iv(const u8 *src, unsigned size) +{ + const u32 *a = (const u32 *)src; + u32 __percpu *b = echainiv_iv; + + for (; size >= 4; size -= 4) { + this_cpu_write(*b, *a); + a++; + b++; + } +} + +static void echainiv_encrypt_compat_complete2(struct aead_request *req, + int err) +{ + struct echainiv_request_ctx *rctx = aead_request_ctx(req); + struct aead_givcrypt_request *subreq = &rctx->subreq; + struct crypto_aead *geniv; + + if (err == -EINPROGRESS) + return; + + if (err) + goto out; + + geniv = crypto_aead_reqtfm(req); + scatterwalk_map_and_copy(subreq->giv, rctx->ivsg, 0, + crypto_aead_ivsize(geniv), 1); + +out: + kzfree(subreq->giv); +} + +static void echainiv_encrypt_compat_complete( + struct crypto_async_request *base, int err) +{ + struct aead_request *req = base->data; + + echainiv_encrypt_compat_complete2(req, err); + aead_request_complete(req, err); +} + +static void echainiv_encrypt_complete2(struct aead_request *req, int err) +{ + struct aead_request *subreq = aead_request_ctx(req); + struct crypto_aead *geniv; + unsigned int ivsize; + + if (err == -EINPROGRESS) + return; + + if (err) + goto out; + + geniv = crypto_aead_reqtfm(req); + ivsize = crypto_aead_ivsize(geniv); + + echainiv_write_iv(subreq->iv, ivsize); + + if (req->iv != subreq->iv) + memcpy(req->iv, subreq->iv, ivsize); + +out: + if (req->iv != subreq->iv) + kzfree(subreq->iv); +} + +static void echainiv_encrypt_complete(struct crypto_async_request *base, + int err) +{ + struct aead_request *req = base->data; + + echainiv_encrypt_complete2(req, err); + aead_request_complete(req, err); +} + +static int echainiv_encrypt_compat(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); + struct echainiv_request_ctx *rctx = aead_request_ctx(req); + struct aead_givcrypt_request *subreq = &rctx->subreq; + unsigned int ivsize = crypto_aead_ivsize(geniv); + crypto_completion_t compl; + void *data; + u8 *info; + __be64 seq; + int err; + + compl = req->base.complete; + data = req->base.data; + + rctx->ivsg = scatterwalk_ffwd(rctx->ivbuf, req->dst, req->assoclen); + info = PageHighMem(sg_page(rctx->ivsg)) ? NULL : sg_virt(rctx->ivsg); + + if (!info) { + info = kmalloc(ivsize, req->base.flags & + CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL: + GFP_ATOMIC); + if (!info) + return -ENOMEM; + + compl = echainiv_encrypt_compat_complete; + data = req; + } + + memcpy(&seq, req->iv + ivsize - sizeof(seq), sizeof(seq)); + + aead_givcrypt_set_tfm(subreq, ctx->child); + aead_givcrypt_set_callback(subreq, req->base.flags, + req->base.complete, req->base.data); + aead_givcrypt_set_crypt(subreq, + scatterwalk_ffwd(rctx->src, req->src, + req->assoclen + ivsize), + scatterwalk_ffwd(rctx->dst, rctx->ivsg, + ivsize), + req->cryptlen - ivsize, req->iv); + aead_givcrypt_set_assoc(subreq, req->src, req->assoclen); + aead_givcrypt_set_giv(subreq, info, be64_to_cpu(seq)); + + err = crypto_aead_givencrypt(subreq); + if (unlikely(PageHighMem(sg_page(rctx->ivsg)))) + echainiv_encrypt_compat_complete2(req, err); + return err; +} + +static int echainiv_encrypt(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); + struct aead_request *subreq = aead_request_ctx(req); + crypto_completion_t compl; + void *data; + u8 *info; + unsigned int ivsize; + int err; + + aead_request_set_tfm(subreq, ctx->child); + + compl = echainiv_encrypt_complete; + data = req; + info = req->iv; + + ivsize = crypto_aead_ivsize(geniv); + + if (req->src != req->dst) { + struct scatterlist src[2]; + struct scatterlist dst[2]; + struct blkcipher_desc desc = { + .tfm = ctx->null, + }; + + err = crypto_blkcipher_encrypt( + &desc, + scatterwalk_ffwd(dst, req->dst, + req->assoclen + ivsize), + scatterwalk_ffwd(src, req->src, + req->assoclen + ivsize), + req->cryptlen - ivsize); + if (err) + return err; + } + + if (unlikely(!IS_ALIGNED((unsigned long)info, + crypto_aead_alignmask(geniv) + 1))) { + info = kmalloc(ivsize, req->base.flags & + CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL: + GFP_ATOMIC); + if (!info) + return -ENOMEM; + + memcpy(info, req->iv, ivsize); + } + + aead_request_set_callback(subreq, req->base.flags, compl, data); + aead_request_set_crypt(subreq, req->dst, req->dst, + req->cryptlen - ivsize, info); + aead_request_set_ad(subreq, req->assoclen + ivsize, 0); + + crypto_xor(info, ctx->salt, ivsize); + scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1); + echainiv_read_iv(info, ivsize); + + err = crypto_aead_encrypt(subreq); + echainiv_encrypt_complete2(req, err); + return err; +} + +static int echainiv_decrypt_compat(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); + struct aead_request *subreq = aead_request_ctx(req); + crypto_completion_t compl; + void *data; + unsigned int ivsize; + + aead_request_set_tfm(subreq, ctx->child); + + compl = req->base.complete; + data = req->base.data; + + ivsize = crypto_aead_ivsize(geniv); + + aead_request_set_callback(subreq, req->base.flags, compl, data); + aead_request_set_crypt(subreq, req->src, req->dst, + req->cryptlen - ivsize, req->iv); + aead_request_set_ad(subreq, req->assoclen, ivsize); + + scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); + + return crypto_aead_decrypt(subreq); +} + +static int echainiv_decrypt(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); + struct aead_request *subreq = aead_request_ctx(req); + crypto_completion_t compl; + void *data; + unsigned int ivsize; + + aead_request_set_tfm(subreq, ctx->child); + + compl = req->base.complete; + data = req->base.data; + + ivsize = crypto_aead_ivsize(geniv); + + aead_request_set_callback(subreq, req->base.flags, compl, data); + aead_request_set_crypt(subreq, req->src, req->dst, + req->cryptlen - ivsize, req->iv); + aead_request_set_ad(subreq, req->assoclen + ivsize, 0); + + scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); + if (req->src != req->dst) + scatterwalk_map_and_copy(req->iv, req->dst, + req->assoclen, ivsize, 1); + + return crypto_aead_decrypt(subreq); +} + +static int echainiv_encrypt_compat_first(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); + int err = 0; + + spin_lock_bh(&ctx->lock); + if (geniv->encrypt != echainiv_encrypt_compat_first) + goto unlock; + + geniv->encrypt = echainiv_encrypt_compat; + err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, + crypto_aead_ivsize(geniv)); + +unlock: + spin_unlock_bh(&ctx->lock); + + if (err) + return err; + + return echainiv_encrypt_compat(req); +} + +static int echainiv_encrypt_first(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); + int err = 0; + + spin_lock_bh(&ctx->lock); + if (geniv->encrypt != echainiv_encrypt_first) + goto unlock; + + geniv->encrypt = echainiv_encrypt; + err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, + crypto_aead_ivsize(geniv)); + +unlock: + spin_unlock_bh(&ctx->lock); + + if (err) + return err; + + return echainiv_encrypt(req); +} + +static int echainiv_compat_init(struct crypto_tfm *tfm) +{ + struct crypto_aead *geniv = __crypto_aead_cast(tfm); + struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); + int err; + + spin_lock_init(&ctx->lock); + + crypto_aead_set_reqsize(geniv, sizeof(struct echainiv_request_ctx)); + + err = aead_geniv_init(tfm); + + ctx->child = geniv->child; + geniv->child = geniv; + + return err; +} + +static int echainiv_init(struct crypto_tfm *tfm) +{ + struct crypto_aead *geniv = __crypto_aead_cast(tfm); + struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); + int err; + + spin_lock_init(&ctx->lock); + + crypto_aead_set_reqsize(geniv, sizeof(struct aead_request)); + + ctx->null = crypto_get_default_null_skcipher(); + err = PTR_ERR(ctx->null); + if (IS_ERR(ctx->null)) + goto out; + + err = aead_geniv_init(tfm); + if (err) + goto drop_null; + + ctx->child = geniv->child; + geniv->child = geniv; + +out: + return err; + +drop_null: + crypto_put_default_null_skcipher(); + goto out; +} + +static void echainiv_compat_exit(struct crypto_tfm *tfm) +{ + struct echainiv_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_aead(ctx->child); +} + +static void echainiv_exit(struct crypto_tfm *tfm) +{ + struct echainiv_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_aead(ctx->child); + crypto_put_default_null_skcipher(); +} + +static struct crypto_template echainiv_tmpl; + +static struct crypto_instance *echainiv_aead_alloc(struct rtattr **tb) +{ + struct aead_instance *inst; + struct crypto_aead_spawn *spawn; + struct aead_alg *alg; + + inst = aead_geniv_alloc(&echainiv_tmpl, tb, 0, 0); + + if (IS_ERR(inst)) + goto out; + + if (inst->alg.ivsize < sizeof(u64) || + inst->alg.ivsize & (sizeof(u32) - 1) || + inst->alg.ivsize > MAX_IV_SIZE) { + aead_geniv_free(inst); + inst = ERR_PTR(-EINVAL); + goto out; + } + + spawn = aead_instance_ctx(inst); + alg = crypto_spawn_aead_alg(spawn); + + inst->alg.setkey = echainiv_setkey; + inst->alg.setauthsize = echainiv_setauthsize; + inst->alg.encrypt = echainiv_encrypt_first; + inst->alg.decrypt = echainiv_decrypt; + + inst->alg.base.cra_init = echainiv_init; + inst->alg.base.cra_exit = echainiv_exit; + + inst->alg.base.cra_alignmask |= __alignof__(u32) - 1; + inst->alg.base.cra_ctxsize = sizeof(struct echainiv_ctx); + inst->alg.base.cra_ctxsize += inst->alg.base.cra_aead.ivsize; + + if (alg->base.cra_aead.encrypt) { + inst->alg.encrypt = echainiv_encrypt_compat_first; + inst->alg.decrypt = echainiv_decrypt_compat; + + inst->alg.base.cra_init = echainiv_compat_init; + inst->alg.base.cra_exit = echainiv_compat_exit; + } + +out: + return aead_crypto_instance(inst); +} + +static struct crypto_instance *echainiv_alloc(struct rtattr **tb) +{ + struct crypto_instance *inst; + int err; + + err = crypto_get_default_rng(); + if (err) + return ERR_PTR(err); + + inst = echainiv_aead_alloc(tb); + + if (IS_ERR(inst)) + goto put_rng; + +out: + return inst; + +put_rng: + crypto_put_default_rng(); + goto out; +} + +static void echainiv_free(struct crypto_instance *inst) +{ + aead_geniv_free(aead_instance(inst)); + crypto_put_default_rng(); +} + +static struct crypto_template echainiv_tmpl = { + .name = "echainiv", + .alloc = echainiv_alloc, + .free = echainiv_free, + .module = THIS_MODULE, +}; + +static int __init echainiv_module_init(void) +{ + return crypto_register_template(&echainiv_tmpl); +} + +static void __exit echainiv_module_exit(void) +{ + crypto_unregister_template(&echainiv_tmpl); +} + +module_init(echainiv_module_init); +module_exit(echainiv_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Encrypted Chain IV Generator"); +MODULE_ALIAS_CRYPTO("echainiv"); -- cgit v1.2.3 From e17a5cfe0ff226cad9791e910f70d7863ae88830 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 23 May 2015 11:22:47 +0800 Subject: crypto: echainiv - echainiv_read_iv() can be static Signed-off-by: Fengguang Wu Signed-off-by: Herbert Xu --- crypto/echainiv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crypto/echainiv.c') diff --git a/crypto/echainiv.c b/crypto/echainiv.c index e5a9878e..d0e325d0 100644 --- a/crypto/echainiv.c +++ b/crypto/echainiv.c @@ -67,7 +67,7 @@ static int echainiv_setauthsize(struct crypto_aead *tfm, } /* We don't care if we get preempted and read/write IVs from the next CPU. */ -void echainiv_read_iv(u8 *dst, unsigned size) +static void echainiv_read_iv(u8 *dst, unsigned size) { u32 *a = (u32 *)dst; u32 __percpu *b = echainiv_iv; @@ -78,7 +78,7 @@ void echainiv_read_iv(u8 *dst, unsigned size) } } -void echainiv_write_iv(const u8 *src, unsigned size) +static void echainiv_write_iv(const u8 *src, unsigned size) { const u32 *a = (const u32 *)src; u32 __percpu *b = echainiv_iv; -- cgit v1.2.3 From 61f3d6de397ac1ad78fa426eec0959dfb734e48b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 23 May 2015 15:41:52 +0800 Subject: crypto: echainiv - Use aead_register_instance New style AEAD instances must use aead_register_instance. This worked by chance because aead_geniv_alloc is still setting things the old way. This patch converts the template over to the create model where we are responsible for instance registration so that we can call the correct function. Signed-off-by: Herbert Xu --- crypto/echainiv.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'crypto/echainiv.c') diff --git a/crypto/echainiv.c b/crypto/echainiv.c index d0e325d0..9018c87b 100644 --- a/crypto/echainiv.c +++ b/crypto/echainiv.c @@ -430,26 +430,24 @@ static void echainiv_exit(struct crypto_tfm *tfm) crypto_put_default_null_skcipher(); } -static struct crypto_template echainiv_tmpl; - -static struct crypto_instance *echainiv_aead_alloc(struct rtattr **tb) +static int echainiv_aead_create(struct crypto_template *tmpl, + struct rtattr **tb) { struct aead_instance *inst; struct crypto_aead_spawn *spawn; struct aead_alg *alg; + int err; - inst = aead_geniv_alloc(&echainiv_tmpl, tb, 0, 0); + inst = aead_geniv_alloc(tmpl, tb, 0, 0); if (IS_ERR(inst)) - goto out; + return PTR_ERR(inst); + err = -EINVAL; if (inst->alg.ivsize < sizeof(u64) || inst->alg.ivsize & (sizeof(u32) - 1) || - inst->alg.ivsize > MAX_IV_SIZE) { - aead_geniv_free(inst); - inst = ERR_PTR(-EINVAL); - goto out; - } + inst->alg.ivsize > MAX_IV_SIZE) + goto free_inst; spawn = aead_instance_ctx(inst); alg = crypto_spawn_aead_alg(spawn); @@ -474,26 +472,32 @@ static struct crypto_instance *echainiv_aead_alloc(struct rtattr **tb) inst->alg.base.cra_exit = echainiv_compat_exit; } + err = aead_register_instance(tmpl, inst); + if (err) + goto free_inst; + out: - return aead_crypto_instance(inst); + return err; + +free_inst: + aead_geniv_free(inst); + goto out; } -static struct crypto_instance *echainiv_alloc(struct rtattr **tb) +static int echainiv_create(struct crypto_template *tmpl, struct rtattr **tb) { - struct crypto_instance *inst; int err; err = crypto_get_default_rng(); if (err) - return ERR_PTR(err); - - inst = echainiv_aead_alloc(tb); + goto out; - if (IS_ERR(inst)) + err = echainiv_aead_create(tmpl, tb); + if (err) goto put_rng; out: - return inst; + return err; put_rng: crypto_put_default_rng(); @@ -508,7 +512,7 @@ static void echainiv_free(struct crypto_instance *inst) static struct crypto_template echainiv_tmpl = { .name = "echainiv", - .alloc = echainiv_alloc, + .create = echainiv_create, .free = echainiv_free, .module = THIS_MODULE, }; -- cgit v1.2.3 From f91b1adfc32638b7e53ea6b575113cf3c1675a53 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 23 May 2015 15:41:54 +0800 Subject: crypto: echainiv - Stop using cryptoff The cryptoff parameter was added to facilitate the skipping of IVs that sit between the AD and the plain/cipher text. However, it was never implemented correctly as and we do not handle users such as IPsec setting cryptoff. It is simply ignored. Implementing correctly is in fact more trouble than what it's worth. This patch removes the uses of cryptoff and simply falls back to using the old AEAD interface as it's only needed for old AEAD implementations. Signed-off-by: Herbert Xu --- crypto/echainiv.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'crypto/echainiv.c') diff --git a/crypto/echainiv.c b/crypto/echainiv.c index 9018c87b..149d8fb8 100644 --- a/crypto/echainiv.c +++ b/crypto/echainiv.c @@ -167,6 +167,9 @@ static int echainiv_encrypt_compat(struct aead_request *req) __be64 seq; int err; + if (req->cryptlen < ivsize) + return -EINVAL; + compl = req->base.complete; data = req->base.data; @@ -212,17 +215,18 @@ static int echainiv_encrypt(struct aead_request *req) crypto_completion_t compl; void *data; u8 *info; - unsigned int ivsize; + unsigned int ivsize = crypto_aead_ivsize(geniv); int err; + if (req->cryptlen < ivsize) + return -EINVAL; + aead_request_set_tfm(subreq, ctx->child); compl = echainiv_encrypt_complete; data = req; info = req->iv; - ivsize = crypto_aead_ivsize(geniv); - if (req->src != req->dst) { struct scatterlist src[2]; struct scatterlist dst[2]; @@ -270,22 +274,28 @@ static int echainiv_decrypt_compat(struct aead_request *req) { struct crypto_aead *geniv = crypto_aead_reqtfm(req); struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); - struct aead_request *subreq = aead_request_ctx(req); + struct echainiv_request_ctx *rctx = aead_request_ctx(req); + struct aead_request *subreq = &rctx->subreq.areq; crypto_completion_t compl; void *data; - unsigned int ivsize; + unsigned int ivsize = crypto_aead_ivsize(geniv); + + if (req->cryptlen < ivsize + crypto_aead_authsize(geniv)) + return -EINVAL; aead_request_set_tfm(subreq, ctx->child); compl = req->base.complete; data = req->base.data; - ivsize = crypto_aead_ivsize(geniv); - aead_request_set_callback(subreq, req->base.flags, compl, data); - aead_request_set_crypt(subreq, req->src, req->dst, + aead_request_set_crypt(subreq, + scatterwalk_ffwd(rctx->src, req->src, + req->assoclen + ivsize), + scatterwalk_ffwd(rctx->dst, req->dst, + req->assoclen + ivsize), req->cryptlen - ivsize, req->iv); - aead_request_set_ad(subreq, req->assoclen, ivsize); + aead_request_set_assoc(subreq, req->src, req->assoclen); scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); @@ -299,15 +309,16 @@ static int echainiv_decrypt(struct aead_request *req) struct aead_request *subreq = aead_request_ctx(req); crypto_completion_t compl; void *data; - unsigned int ivsize; + unsigned int ivsize = crypto_aead_ivsize(geniv); + + if (req->cryptlen < ivsize + crypto_aead_authsize(geniv)) + return -EINVAL; aead_request_set_tfm(subreq, ctx->child); compl = req->base.complete; data = req->base.data; - ivsize = crypto_aead_ivsize(geniv); - aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen - ivsize, req->iv); -- cgit v1.2.3 From 7cd298d06cad210c681a4c3f5d77ca6d173ebc4d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 23 May 2015 15:41:57 +0800 Subject: crypto: aead - Remove unused cryptoff parameter This patch removes the cryptoff parameter now that all users set it to zero. Signed-off-by: Herbert Xu --- crypto/aead.c | 6 ++---- crypto/echainiv.c | 4 ++-- crypto/seqiv.c | 8 ++++---- 3 files changed, 8 insertions(+), 10 deletions(-) (limited to 'crypto/echainiv.c') diff --git a/crypto/aead.c b/crypto/aead.c index 070e4b9e..7c3d725b 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -106,10 +106,8 @@ static int old_crypt(struct aead_request *req, if (req->old) return crypt(req); - src = scatterwalk_ffwd(nreq->srcbuf, req->src, - req->assoclen + req->cryptoff); - dst = scatterwalk_ffwd(nreq->dstbuf, req->dst, - req->assoclen + req->cryptoff); + src = scatterwalk_ffwd(nreq->srcbuf, req->src, req->assoclen); + dst = scatterwalk_ffwd(nreq->dstbuf, req->dst, req->assoclen); aead_request_set_tfm(&nreq->subreq, aead); aead_request_set_callback(&nreq->subreq, aead_request_flags(req), diff --git a/crypto/echainiv.c b/crypto/echainiv.c index 149d8fb8..bd85dcc4 100644 --- a/crypto/echainiv.c +++ b/crypto/echainiv.c @@ -259,7 +259,7 @@ static int echainiv_encrypt(struct aead_request *req) aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, req->dst, req->dst, req->cryptlen - ivsize, info); - aead_request_set_ad(subreq, req->assoclen + ivsize, 0); + aead_request_set_ad(subreq, req->assoclen + ivsize); crypto_xor(info, ctx->salt, ivsize); scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1); @@ -322,7 +322,7 @@ static int echainiv_decrypt(struct aead_request *req) aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen - ivsize, req->iv); - aead_request_set_ad(subreq, req->assoclen + ivsize, 0); + aead_request_set_ad(subreq, req->assoclen + ivsize); scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); if (req->src != req->dst) diff --git a/crypto/seqiv.c b/crypto/seqiv.c index 16738c5f..127970a6 100644 --- a/crypto/seqiv.c +++ b/crypto/seqiv.c @@ -337,7 +337,7 @@ static int seqiv_aead_encrypt_compat(struct aead_request *req) aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, dst, dst, req->cryptlen - ivsize, req->iv); - aead_request_set_ad(subreq, req->assoclen, 0); + aead_request_set_ad(subreq, req->assoclen); memcpy(buf, req->iv, ivsize); crypto_xor(buf, ctx->salt, ivsize); @@ -406,7 +406,7 @@ static int seqiv_aead_encrypt(struct aead_request *req) aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, req->dst, req->dst, req->cryptlen - ivsize, info); - aead_request_set_ad(subreq, req->assoclen + ivsize, 0); + aead_request_set_ad(subreq, req->assoclen + ivsize); crypto_xor(info, ctx->salt, ivsize); scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1); @@ -473,7 +473,7 @@ static int seqiv_aead_decrypt_compat(struct aead_request *req) aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, dst, dst, req->cryptlen - ivsize, req->iv); - aead_request_set_ad(subreq, req->assoclen, 0); + aead_request_set_ad(subreq, req->assoclen); err = crypto_aead_decrypt(subreq); if (req->assoclen > 8) @@ -501,7 +501,7 @@ static int seqiv_aead_decrypt(struct aead_request *req) aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen - ivsize, req->iv); - aead_request_set_ad(subreq, req->assoclen + ivsize, 0); + aead_request_set_ad(subreq, req->assoclen + ivsize); scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); if (req->src != req->dst) -- cgit v1.2.3 From 239c934a33529b995f475d8e681b0b1706af2f18 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 27 May 2015 14:37:31 +0800 Subject: crypto: echainiv - Copy AD along with plain text As the AD does not necessarily exist in the destination buffer it must be copied along with the plain text. Signed-off-by: Herbert Xu --- crypto/echainiv.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'crypto/echainiv.c') diff --git a/crypto/echainiv.c b/crypto/echainiv.c index bd85dcc4..02d05430 100644 --- a/crypto/echainiv.c +++ b/crypto/echainiv.c @@ -228,19 +228,13 @@ static int echainiv_encrypt(struct aead_request *req) info = req->iv; if (req->src != req->dst) { - struct scatterlist src[2]; - struct scatterlist dst[2]; struct blkcipher_desc desc = { .tfm = ctx->null, }; err = crypto_blkcipher_encrypt( - &desc, - scatterwalk_ffwd(dst, req->dst, - req->assoclen + ivsize), - scatterwalk_ffwd(src, req->src, - req->assoclen + ivsize), - req->cryptlen - ivsize); + &desc, req->dst, req->src, + req->assoclen + req->cryptlen); if (err) return err; } -- cgit v1.2.3 From 8878c89d9b3214301b10e619de7bad9129ab326d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 27 May 2015 14:37:33 +0800 Subject: crypto: echainiv - Use common IV generation code This patch makes use of the new common IV generation code. Signed-off-by: Herbert Xu --- crypto/echainiv.c | 230 +++++------------------------------------------------- 1 file changed, 18 insertions(+), 212 deletions(-) (limited to 'crypto/echainiv.c') diff --git a/crypto/echainiv.c b/crypto/echainiv.c index 02d05430..0f79fc66 100644 --- a/crypto/echainiv.c +++ b/crypto/echainiv.c @@ -18,7 +18,7 @@ * */ -#include +#include #include #include #include @@ -33,39 +33,15 @@ #define MAX_IV_SIZE 16 -struct echainiv_request_ctx { - struct scatterlist src[2]; - struct scatterlist dst[2]; - struct scatterlist ivbuf[2]; - struct scatterlist *ivsg; - struct aead_givcrypt_request subreq; -}; - struct echainiv_ctx { - struct crypto_aead *child; - spinlock_t lock; + /* aead_geniv_ctx must be first the element */ + struct aead_geniv_ctx geniv; struct crypto_blkcipher *null; u8 salt[] __attribute__ ((aligned(__alignof__(u32)))); }; static DEFINE_PER_CPU(u32 [MAX_IV_SIZE / sizeof(u32)], echainiv_iv); -static int echainiv_setkey(struct crypto_aead *tfm, - const u8 *key, unsigned int keylen) -{ - struct echainiv_ctx *ctx = crypto_aead_ctx(tfm); - - return crypto_aead_setkey(ctx->child, key, keylen); -} - -static int echainiv_setauthsize(struct crypto_aead *tfm, - unsigned int authsize) -{ - struct echainiv_ctx *ctx = crypto_aead_ctx(tfm); - - return crypto_aead_setauthsize(ctx->child, authsize); -} - /* We don't care if we get preempted and read/write IVs from the next CPU. */ static void echainiv_read_iv(u8 *dst, unsigned size) { @@ -90,36 +66,6 @@ static void echainiv_write_iv(const u8 *src, unsigned size) } } -static void echainiv_encrypt_compat_complete2(struct aead_request *req, - int err) -{ - struct echainiv_request_ctx *rctx = aead_request_ctx(req); - struct aead_givcrypt_request *subreq = &rctx->subreq; - struct crypto_aead *geniv; - - if (err == -EINPROGRESS) - return; - - if (err) - goto out; - - geniv = crypto_aead_reqtfm(req); - scatterwalk_map_and_copy(subreq->giv, rctx->ivsg, 0, - crypto_aead_ivsize(geniv), 1); - -out: - kzfree(subreq->giv); -} - -static void echainiv_encrypt_compat_complete( - struct crypto_async_request *base, int err) -{ - struct aead_request *req = base->data; - - echainiv_encrypt_compat_complete2(req, err); - aead_request_complete(req, err); -} - static void echainiv_encrypt_complete2(struct aead_request *req, int err) { struct aead_request *subreq = aead_request_ctx(req); @@ -154,59 +100,6 @@ static void echainiv_encrypt_complete(struct crypto_async_request *base, aead_request_complete(req, err); } -static int echainiv_encrypt_compat(struct aead_request *req) -{ - struct crypto_aead *geniv = crypto_aead_reqtfm(req); - struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); - struct echainiv_request_ctx *rctx = aead_request_ctx(req); - struct aead_givcrypt_request *subreq = &rctx->subreq; - unsigned int ivsize = crypto_aead_ivsize(geniv); - crypto_completion_t compl; - void *data; - u8 *info; - __be64 seq; - int err; - - if (req->cryptlen < ivsize) - return -EINVAL; - - compl = req->base.complete; - data = req->base.data; - - rctx->ivsg = scatterwalk_ffwd(rctx->ivbuf, req->dst, req->assoclen); - info = PageHighMem(sg_page(rctx->ivsg)) ? NULL : sg_virt(rctx->ivsg); - - if (!info) { - info = kmalloc(ivsize, req->base.flags & - CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL: - GFP_ATOMIC); - if (!info) - return -ENOMEM; - - compl = echainiv_encrypt_compat_complete; - data = req; - } - - memcpy(&seq, req->iv + ivsize - sizeof(seq), sizeof(seq)); - - aead_givcrypt_set_tfm(subreq, ctx->child); - aead_givcrypt_set_callback(subreq, req->base.flags, - req->base.complete, req->base.data); - aead_givcrypt_set_crypt(subreq, - scatterwalk_ffwd(rctx->src, req->src, - req->assoclen + ivsize), - scatterwalk_ffwd(rctx->dst, rctx->ivsg, - ivsize), - req->cryptlen - ivsize, req->iv); - aead_givcrypt_set_assoc(subreq, req->src, req->assoclen); - aead_givcrypt_set_giv(subreq, info, be64_to_cpu(seq)); - - err = crypto_aead_givencrypt(subreq); - if (unlikely(PageHighMem(sg_page(rctx->ivsg)))) - echainiv_encrypt_compat_complete2(req, err); - return err; -} - static int echainiv_encrypt(struct aead_request *req) { struct crypto_aead *geniv = crypto_aead_reqtfm(req); @@ -221,7 +114,7 @@ static int echainiv_encrypt(struct aead_request *req) if (req->cryptlen < ivsize) return -EINVAL; - aead_request_set_tfm(subreq, ctx->child); + aead_request_set_tfm(subreq, ctx->geniv.child); compl = echainiv_encrypt_complete; data = req; @@ -264,38 +157,6 @@ static int echainiv_encrypt(struct aead_request *req) return err; } -static int echainiv_decrypt_compat(struct aead_request *req) -{ - struct crypto_aead *geniv = crypto_aead_reqtfm(req); - struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); - struct echainiv_request_ctx *rctx = aead_request_ctx(req); - struct aead_request *subreq = &rctx->subreq.areq; - crypto_completion_t compl; - void *data; - unsigned int ivsize = crypto_aead_ivsize(geniv); - - if (req->cryptlen < ivsize + crypto_aead_authsize(geniv)) - return -EINVAL; - - aead_request_set_tfm(subreq, ctx->child); - - compl = req->base.complete; - data = req->base.data; - - aead_request_set_callback(subreq, req->base.flags, compl, data); - aead_request_set_crypt(subreq, - scatterwalk_ffwd(rctx->src, req->src, - req->assoclen + ivsize), - scatterwalk_ffwd(rctx->dst, req->dst, - req->assoclen + ivsize), - req->cryptlen - ivsize, req->iv); - aead_request_set_assoc(subreq, req->src, req->assoclen); - - scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); - - return crypto_aead_decrypt(subreq); -} - static int echainiv_decrypt(struct aead_request *req) { struct crypto_aead *geniv = crypto_aead_reqtfm(req); @@ -308,7 +169,7 @@ static int echainiv_decrypt(struct aead_request *req) if (req->cryptlen < ivsize + crypto_aead_authsize(geniv)) return -EINVAL; - aead_request_set_tfm(subreq, ctx->child); + aead_request_set_tfm(subreq, ctx->geniv.child); compl = req->base.complete; data = req->base.data; @@ -326,36 +187,13 @@ static int echainiv_decrypt(struct aead_request *req) return crypto_aead_decrypt(subreq); } -static int echainiv_encrypt_compat_first(struct aead_request *req) -{ - struct crypto_aead *geniv = crypto_aead_reqtfm(req); - struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); - int err = 0; - - spin_lock_bh(&ctx->lock); - if (geniv->encrypt != echainiv_encrypt_compat_first) - goto unlock; - - geniv->encrypt = echainiv_encrypt_compat; - err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, - crypto_aead_ivsize(geniv)); - -unlock: - spin_unlock_bh(&ctx->lock); - - if (err) - return err; - - return echainiv_encrypt_compat(req); -} - static int echainiv_encrypt_first(struct aead_request *req) { struct crypto_aead *geniv = crypto_aead_reqtfm(req); struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); int err = 0; - spin_lock_bh(&ctx->lock); + spin_lock_bh(&ctx->geniv.lock); if (geniv->encrypt != echainiv_encrypt_first) goto unlock; @@ -364,7 +202,7 @@ static int echainiv_encrypt_first(struct aead_request *req) crypto_aead_ivsize(geniv)); unlock: - spin_unlock_bh(&ctx->lock); + spin_unlock_bh(&ctx->geniv.lock); if (err) return err; @@ -372,31 +210,13 @@ unlock: return echainiv_encrypt(req); } -static int echainiv_compat_init(struct crypto_tfm *tfm) -{ - struct crypto_aead *geniv = __crypto_aead_cast(tfm); - struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); - int err; - - spin_lock_init(&ctx->lock); - - crypto_aead_set_reqsize(geniv, sizeof(struct echainiv_request_ctx)); - - err = aead_geniv_init(tfm); - - ctx->child = geniv->child; - geniv->child = geniv; - - return err; -} - static int echainiv_init(struct crypto_tfm *tfm) { struct crypto_aead *geniv = __crypto_aead_cast(tfm); struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); int err; - spin_lock_init(&ctx->lock); + spin_lock_init(&ctx->geniv.lock); crypto_aead_set_reqsize(geniv, sizeof(struct aead_request)); @@ -409,7 +229,7 @@ static int echainiv_init(struct crypto_tfm *tfm) if (err) goto drop_null; - ctx->child = geniv->child; + ctx->geniv.child = geniv->child; geniv->child = geniv; out: @@ -420,18 +240,11 @@ drop_null: goto out; } -static void echainiv_compat_exit(struct crypto_tfm *tfm) -{ - struct echainiv_ctx *ctx = crypto_tfm_ctx(tfm); - - crypto_free_aead(ctx->child); -} - static void echainiv_exit(struct crypto_tfm *tfm) { struct echainiv_ctx *ctx = crypto_tfm_ctx(tfm); - crypto_free_aead(ctx->child); + crypto_free_aead(ctx->geniv.child); crypto_put_default_null_skcipher(); } @@ -448,17 +261,17 @@ static int echainiv_aead_create(struct crypto_template *tmpl, if (IS_ERR(inst)) return PTR_ERR(inst); + spawn = aead_instance_ctx(inst); + alg = crypto_spawn_aead_alg(spawn); + + if (alg->base.cra_aead.encrypt) + goto done; + err = -EINVAL; - if (inst->alg.ivsize < sizeof(u64) || - inst->alg.ivsize & (sizeof(u32) - 1) || + if (inst->alg.ivsize & (sizeof(u32) - 1) || inst->alg.ivsize > MAX_IV_SIZE) goto free_inst; - spawn = aead_instance_ctx(inst); - alg = crypto_spawn_aead_alg(spawn); - - inst->alg.setkey = echainiv_setkey; - inst->alg.setauthsize = echainiv_setauthsize; inst->alg.encrypt = echainiv_encrypt_first; inst->alg.decrypt = echainiv_decrypt; @@ -469,14 +282,7 @@ static int echainiv_aead_create(struct crypto_template *tmpl, inst->alg.base.cra_ctxsize = sizeof(struct echainiv_ctx); inst->alg.base.cra_ctxsize += inst->alg.base.cra_aead.ivsize; - if (alg->base.cra_aead.encrypt) { - inst->alg.encrypt = echainiv_encrypt_compat_first; - inst->alg.decrypt = echainiv_decrypt_compat; - - inst->alg.base.cra_init = echainiv_compat_init; - inst->alg.base.cra_exit = echainiv_compat_exit; - } - +done: err = aead_register_instance(tmpl, inst); if (err) goto free_inst; -- cgit v1.2.3 From c30bee79f02af12a7560cada0e4c7f34595e60ba Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 27 May 2015 14:37:34 +0800 Subject: crypto: echainiv - Fix IV size in context size calculation This patch fixes a bug in the context size calculation where we were still referring to the old cra_aead. Signed-off-by: Herbert Xu --- crypto/echainiv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crypto/echainiv.c') diff --git a/crypto/echainiv.c b/crypto/echainiv.c index 0f79fc66..62a817fa 100644 --- a/crypto/echainiv.c +++ b/crypto/echainiv.c @@ -280,7 +280,7 @@ static int echainiv_aead_create(struct crypto_template *tmpl, inst->alg.base.cra_alignmask |= __alignof__(u32) - 1; inst->alg.base.cra_ctxsize = sizeof(struct echainiv_ctx); - inst->alg.base.cra_ctxsize += inst->alg.base.cra_aead.ivsize; + inst->alg.base.cra_ctxsize += inst->alg.ivsize; done: err = aead_register_instance(tmpl, inst); -- cgit v1.2.3 From afdca0239a63191c3d67c852683ac4332c89177a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 3 Jun 2015 14:49:24 +0800 Subject: crypto: echainiv - Move IV seeding into init function We currently do the IV seeding on the first givencrypt call in order to conserve entropy. However, this does not work with DRBG which cannot be called from interrupt context. In fact, with DRBG we don't need to conserve entropy anyway. So this patch moves the seeding into the init function. Signed-off-by: Herbert Xu --- crypto/echainiv.c | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) (limited to 'crypto/echainiv.c') diff --git a/crypto/echainiv.c b/crypto/echainiv.c index 62a817fa..08d33367 100644 --- a/crypto/echainiv.c +++ b/crypto/echainiv.c @@ -187,29 +187,6 @@ static int echainiv_decrypt(struct aead_request *req) return crypto_aead_decrypt(subreq); } -static int echainiv_encrypt_first(struct aead_request *req) -{ - struct crypto_aead *geniv = crypto_aead_reqtfm(req); - struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); - int err = 0; - - spin_lock_bh(&ctx->geniv.lock); - if (geniv->encrypt != echainiv_encrypt_first) - goto unlock; - - geniv->encrypt = echainiv_encrypt; - err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, - crypto_aead_ivsize(geniv)); - -unlock: - spin_unlock_bh(&ctx->geniv.lock); - - if (err) - return err; - - return echainiv_encrypt(req); -} - static int echainiv_init(struct crypto_tfm *tfm) { struct crypto_aead *geniv = __crypto_aead_cast(tfm); @@ -220,6 +197,11 @@ static int echainiv_init(struct crypto_tfm *tfm) crypto_aead_set_reqsize(geniv, sizeof(struct aead_request)); + err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, + crypto_aead_ivsize(geniv)); + if (err) + goto out; + ctx->null = crypto_get_default_null_skcipher(); err = PTR_ERR(ctx->null); if (IS_ERR(ctx->null)) @@ -272,7 +254,7 @@ static int echainiv_aead_create(struct crypto_template *tmpl, inst->alg.ivsize > MAX_IV_SIZE) goto free_inst; - inst->alg.encrypt = echainiv_encrypt_first; + inst->alg.encrypt = echainiv_encrypt; inst->alg.decrypt = echainiv_decrypt; inst->alg.base.cra_init = echainiv_init; -- cgit v1.2.3 From a5da65199cc69ff13260292888c6d4644872e34a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 21 Jun 2015 19:11:50 +0800 Subject: crypto: echainiv - Only hold RNG during initialisation This patch changes the RNG allocation so that we only hold a reference to the RNG during initialisation. Signed-off-by: Herbert Xu --- crypto/echainiv.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) (limited to 'crypto/echainiv.c') diff --git a/crypto/echainiv.c b/crypto/echainiv.c index 08d33367..b6e43dc6 100644 --- a/crypto/echainiv.c +++ b/crypto/echainiv.c @@ -197,8 +197,13 @@ static int echainiv_init(struct crypto_tfm *tfm) crypto_aead_set_reqsize(geniv, sizeof(struct aead_request)); + err = crypto_get_default_rng(); + if (err) + goto out; + err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, crypto_aead_ivsize(geniv)); + crypto_put_default_rng(); if (err) goto out; @@ -277,35 +282,14 @@ free_inst: goto out; } -static int echainiv_create(struct crypto_template *tmpl, struct rtattr **tb) -{ - int err; - - err = crypto_get_default_rng(); - if (err) - goto out; - - err = echainiv_aead_create(tmpl, tb); - if (err) - goto put_rng; - -out: - return err; - -put_rng: - crypto_put_default_rng(); - goto out; -} - static void echainiv_free(struct crypto_instance *inst) { aead_geniv_free(aead_instance(inst)); - crypto_put_default_rng(); } static struct crypto_template echainiv_tmpl = { .name = "echainiv", - .create = echainiv_create, + .create = echainiv_aead_create, .free = echainiv_free, .module = THIS_MODULE, }; -- cgit v1.2.3