X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=crypto%2Fechainiv.c;h=b6e43dc6135653eddb3e31f9659d54bc774bc6d1;hb=099bfbfc7fbbe22356c02f0caf709ac32e1126ea;hp=02d054300a9ab84ae36e0b3c8906a9a53db41dca;hpb=838c9d561aaae4bc3f4b44046ea08b048ecaffe7;p=deliverable%2Flinux.git diff --git a/crypto/echainiv.c b/crypto/echainiv.c index 02d054300a9a..b6e43dc61356 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,79 +187,25 @@ static int echainiv_decrypt(struct aead_request *req) return crypto_aead_decrypt(subreq); } -static int echainiv_encrypt_compat_first(struct aead_request *req) +static int echainiv_init(struct crypto_tfm *tfm) { - struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct crypto_aead *geniv = __crypto_aead_cast(tfm); 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; + int err; - geniv->encrypt = echainiv_encrypt_compat; - err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, - crypto_aead_ivsize(geniv)); + spin_lock_init(&ctx->geniv.lock); -unlock: - spin_unlock_bh(&ctx->lock); + crypto_aead_set_reqsize(geniv, sizeof(struct aead_request)); + err = crypto_get_default_rng(); 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; + goto out; - geniv->encrypt = echainiv_encrypt; err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, crypto_aead_ivsize(geniv)); - -unlock: - spin_unlock_bh(&ctx->lock); - + crypto_put_default_rng(); 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)); + goto out; ctx->null = crypto_get_default_null_skcipher(); err = PTR_ERR(ctx->null); @@ -409,7 +216,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 +227,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,18 +248,18 @@ 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.encrypt = echainiv_encrypt; inst->alg.decrypt = echainiv_decrypt; inst->alg.base.cra_init = echainiv_init; @@ -467,16 +267,9 @@ 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; - - 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; - } + inst->alg.base.cra_ctxsize += inst->alg.ivsize; +done: err = aead_register_instance(tmpl, inst); if (err) goto free_inst; @@ -489,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, };