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)
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)
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,
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)
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;
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;