From 6b87393bd9524c315fd0180506b6c733663f007d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 3 Jun 2015 14:49:23 +0800 Subject: crypto: chainiv - 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/chainiv.c | 66 ++++++++------------------------------------------------ 1 file changed, 9 insertions(+), 57 deletions(-) (limited to 'crypto/chainiv.c') diff --git a/crypto/chainiv.c b/crypto/chainiv.c index 63c17d59..be0bd521 100644 --- a/crypto/chainiv.c +++ b/crypto/chainiv.c @@ -80,35 +80,15 @@ unlock: return err; } -static int chainiv_givencrypt_first(struct skcipher_givcrypt_request *req) +static int chainiv_init_common(struct crypto_tfm *tfm, char iv[]) { - struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); - struct chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); - int err = 0; - - spin_lock_bh(&ctx->lock); - if (crypto_ablkcipher_crt(geniv)->givencrypt != - chainiv_givencrypt_first) - goto unlock; - - crypto_ablkcipher_crt(geniv)->givencrypt = chainiv_givencrypt; - err = crypto_rng_get_bytes(crypto_default_rng, ctx->iv, - crypto_ablkcipher_ivsize(geniv)); - -unlock: - spin_unlock_bh(&ctx->lock); + struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm); - if (err) - return err; - - return chainiv_givencrypt(req); -} - -static int chainiv_init_common(struct crypto_tfm *tfm) -{ tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request); - return skcipher_geniv_init(tfm); + return crypto_rng_get_bytes(crypto_default_rng, iv, + crypto_ablkcipher_ivsize(geniv)) ?: + skcipher_geniv_init(tfm); } static int chainiv_init(struct crypto_tfm *tfm) @@ -117,7 +97,7 @@ static int chainiv_init(struct crypto_tfm *tfm) spin_lock_init(&ctx->lock); - return chainiv_init_common(tfm); + return chainiv_init_common(tfm, ctx->iv); } static int async_chainiv_schedule_work(struct async_chainiv_ctx *ctx) @@ -205,33 +185,6 @@ postpone: return async_chainiv_postpone_request(req); } -static int async_chainiv_givencrypt_first(struct skcipher_givcrypt_request *req) -{ - struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); - struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); - int err = 0; - - if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state)) - goto out; - - if (crypto_ablkcipher_crt(geniv)->givencrypt != - async_chainiv_givencrypt_first) - goto unlock; - - crypto_ablkcipher_crt(geniv)->givencrypt = async_chainiv_givencrypt; - err = crypto_rng_get_bytes(crypto_default_rng, ctx->iv, - crypto_ablkcipher_ivsize(geniv)); - -unlock: - clear_bit(CHAINIV_STATE_INUSE, &ctx->state); - - if (err) - return err; - -out: - return async_chainiv_givencrypt(req); -} - static void async_chainiv_do_postponed(struct work_struct *work) { struct async_chainiv_ctx *ctx = container_of(work, @@ -270,7 +223,7 @@ static int async_chainiv_init(struct crypto_tfm *tfm) crypto_init_queue(&ctx->queue, 100); INIT_WORK(&ctx->postponed, async_chainiv_do_postponed); - return chainiv_init_common(tfm); + return chainiv_init_common(tfm, ctx->iv); } static void async_chainiv_exit(struct crypto_tfm *tfm) @@ -302,7 +255,7 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb) if (IS_ERR(inst)) goto put_rng; - inst->alg.cra_ablkcipher.givencrypt = chainiv_givencrypt_first; + inst->alg.cra_ablkcipher.givencrypt = chainiv_givencrypt; inst->alg.cra_init = chainiv_init; inst->alg.cra_exit = skcipher_geniv_exit; @@ -312,8 +265,7 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb) if (!crypto_requires_sync(algt->type, algt->mask)) { inst->alg.cra_flags |= CRYPTO_ALG_ASYNC; - inst->alg.cra_ablkcipher.givencrypt = - async_chainiv_givencrypt_first; + inst->alg.cra_ablkcipher.givencrypt = async_chainiv_givencrypt; inst->alg.cra_init = async_chainiv_init; inst->alg.cra_exit = async_chainiv_exit; -- cgit v1.2.3 From e0058ad2114f29fa95a18f198be6e3a317f37373 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 21 Jun 2015 19:11:46 +0800 Subject: crypto: chainiv - Offer normal cipher functionality without RNG The RNG may not be available during early boot, e.g., the relevant modules may not be included in the initramfs. As the RNG Is only needed for IPsec, we should not let this prevent use of ciphers without IV generators, e.g., for disk encryption. This patch postpones the RNG allocation to the init function so that one failure during early boot does not make the RNG unavailable for all subsequent users of the same cipher. More importantly, it lets the cipher live even if RNG allocation fails. Of course we no longer offer IV generation and which will fail with an error if invoked. But all other cipher capabilities will function as usual. Signed-off-by: Herbert Xu --- crypto/chainiv.c | 55 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) (limited to 'crypto/chainiv.c') diff --git a/crypto/chainiv.c b/crypto/chainiv.c index be0bd521..b4340018 100644 --- a/crypto/chainiv.c +++ b/crypto/chainiv.c @@ -83,21 +83,34 @@ unlock: static int chainiv_init_common(struct crypto_tfm *tfm, char iv[]) { struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm); + int err = 0; tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request); - return crypto_rng_get_bytes(crypto_default_rng, iv, - crypto_ablkcipher_ivsize(geniv)) ?: - skcipher_geniv_init(tfm); + if (iv) { + err = crypto_rng_get_bytes(crypto_default_rng, iv, + crypto_ablkcipher_ivsize(geniv)); + crypto_put_default_rng(); + } + + return err ?: skcipher_geniv_init(tfm); } static int chainiv_init(struct crypto_tfm *tfm) { + struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm); struct chainiv_ctx *ctx = crypto_tfm_ctx(tfm); + char *iv; spin_lock_init(&ctx->lock); - return chainiv_init_common(tfm, ctx->iv); + iv = NULL; + if (!crypto_get_default_rng()) { + crypto_ablkcipher_crt(geniv)->givencrypt = chainiv_givencrypt; + iv = ctx->iv; + } + + return chainiv_init_common(tfm, iv); } static int async_chainiv_schedule_work(struct async_chainiv_ctx *ctx) @@ -216,14 +229,23 @@ static void async_chainiv_do_postponed(struct work_struct *work) static int async_chainiv_init(struct crypto_tfm *tfm) { + struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm); struct async_chainiv_ctx *ctx = crypto_tfm_ctx(tfm); + char *iv; spin_lock_init(&ctx->lock); crypto_init_queue(&ctx->queue, 100); INIT_WORK(&ctx->postponed, async_chainiv_do_postponed); - return chainiv_init_common(tfm, ctx->iv); + iv = NULL; + if (!crypto_get_default_rng()) { + crypto_ablkcipher_crt(geniv)->givencrypt = + async_chainiv_givencrypt; + iv = ctx->iv; + } + + return chainiv_init_common(tfm, iv); } static void async_chainiv_exit(struct crypto_tfm *tfm) @@ -241,21 +263,14 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb) { struct crypto_attr_type *algt; struct crypto_instance *inst; - int err; algt = crypto_get_attr_type(tb); if (IS_ERR(algt)) return ERR_CAST(algt); - err = crypto_get_default_rng(); - if (err) - return ERR_PTR(err); - inst = skcipher_geniv_alloc(&chainiv_tmpl, tb, 0, 0); if (IS_ERR(inst)) - goto put_rng; - - inst->alg.cra_ablkcipher.givencrypt = chainiv_givencrypt; + goto out; inst->alg.cra_init = chainiv_init; inst->alg.cra_exit = skcipher_geniv_exit; @@ -265,8 +280,6 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb) if (!crypto_requires_sync(algt->type, algt->mask)) { inst->alg.cra_flags |= CRYPTO_ALG_ASYNC; - inst->alg.cra_ablkcipher.givencrypt = async_chainiv_givencrypt; - inst->alg.cra_init = async_chainiv_init; inst->alg.cra_exit = async_chainiv_exit; @@ -277,22 +290,12 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb) out: return inst; - -put_rng: - crypto_put_default_rng(); - goto out; -} - -static void chainiv_free(struct crypto_instance *inst) -{ - skcipher_geniv_free(inst); - crypto_put_default_rng(); } static struct crypto_template chainiv_tmpl = { .name = "chainiv", .alloc = chainiv_alloc, - .free = chainiv_free, + .free = skcipher_geniv_free, .module = THIS_MODULE, }; -- cgit v1.2.3