120cc01baSHerbert Xu // SPDX-License-Identifier: GPL-2.0-or-later 220cc01baSHerbert Xu /* 320cc01baSHerbert Xu * geniv: Shared IV generator code 420cc01baSHerbert Xu * 520cc01baSHerbert Xu * This file provides common code to IV generators such as seqiv. 620cc01baSHerbert Xu * 720cc01baSHerbert Xu * Copyright (c) 2007-2019 Herbert Xu <herbert@gondor.apana.org.au> 820cc01baSHerbert Xu */ 920cc01baSHerbert Xu 1020cc01baSHerbert Xu #include <crypto/internal/geniv.h> 1120cc01baSHerbert Xu #include <crypto/internal/rng.h> 1220cc01baSHerbert Xu #include <crypto/null.h> 1320cc01baSHerbert Xu #include <linux/err.h> 1420cc01baSHerbert Xu #include <linux/kernel.h> 1520cc01baSHerbert Xu #include <linux/module.h> 1620cc01baSHerbert Xu #include <linux/rtnetlink.h> 1720cc01baSHerbert Xu #include <linux/slab.h> 1820cc01baSHerbert Xu 1920cc01baSHerbert Xu static int aead_geniv_setkey(struct crypto_aead *tfm, 2020cc01baSHerbert Xu const u8 *key, unsigned int keylen) 2120cc01baSHerbert Xu { 2220cc01baSHerbert Xu struct aead_geniv_ctx *ctx = crypto_aead_ctx(tfm); 2320cc01baSHerbert Xu 2420cc01baSHerbert Xu return crypto_aead_setkey(ctx->child, key, keylen); 2520cc01baSHerbert Xu } 2620cc01baSHerbert Xu 2720cc01baSHerbert Xu static int aead_geniv_setauthsize(struct crypto_aead *tfm, 2820cc01baSHerbert Xu unsigned int authsize) 2920cc01baSHerbert Xu { 3020cc01baSHerbert Xu struct aead_geniv_ctx *ctx = crypto_aead_ctx(tfm); 3120cc01baSHerbert Xu 3220cc01baSHerbert Xu return crypto_aead_setauthsize(ctx->child, authsize); 3320cc01baSHerbert Xu } 3420cc01baSHerbert Xu 350f8f6d86SEric Biggers static void aead_geniv_free(struct aead_instance *inst) 360f8f6d86SEric Biggers { 370f8f6d86SEric Biggers crypto_drop_aead(aead_instance_ctx(inst)); 380f8f6d86SEric Biggers kfree(inst); 390f8f6d86SEric Biggers } 400f8f6d86SEric Biggers 4120cc01baSHerbert Xu struct aead_instance *aead_geniv_alloc(struct crypto_template *tmpl, 42*e72b48c5SEric Biggers struct rtattr **tb) 4320cc01baSHerbert Xu { 4420cc01baSHerbert Xu struct crypto_aead_spawn *spawn; 4520cc01baSHerbert Xu struct crypto_attr_type *algt; 4620cc01baSHerbert Xu struct aead_instance *inst; 4720cc01baSHerbert Xu struct aead_alg *alg; 4820cc01baSHerbert Xu unsigned int ivsize; 4920cc01baSHerbert Xu unsigned int maxauthsize; 50*e72b48c5SEric Biggers u32 mask; 5120cc01baSHerbert Xu int err; 5220cc01baSHerbert Xu 5320cc01baSHerbert Xu algt = crypto_get_attr_type(tb); 5420cc01baSHerbert Xu if (IS_ERR(algt)) 5520cc01baSHerbert Xu return ERR_CAST(algt); 5620cc01baSHerbert Xu 5720cc01baSHerbert Xu if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) 5820cc01baSHerbert Xu return ERR_PTR(-EINVAL); 5920cc01baSHerbert Xu 6020cc01baSHerbert Xu inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); 6120cc01baSHerbert Xu if (!inst) 6220cc01baSHerbert Xu return ERR_PTR(-ENOMEM); 6320cc01baSHerbert Xu 6420cc01baSHerbert Xu spawn = aead_instance_ctx(inst); 6520cc01baSHerbert Xu 6620cc01baSHerbert Xu /* Ignore async algorithms if necessary. */ 67*e72b48c5SEric Biggers mask = crypto_requires_sync(algt->type, algt->mask); 6820cc01baSHerbert Xu 69cd900f0cSEric Biggers err = crypto_grab_aead(spawn, aead_crypto_instance(inst), 70*e72b48c5SEric Biggers crypto_attr_alg_name(tb[1]), 0, mask); 7120cc01baSHerbert Xu if (err) 7220cc01baSHerbert Xu goto err_free_inst; 7320cc01baSHerbert Xu 7420cc01baSHerbert Xu alg = crypto_spawn_aead_alg(spawn); 7520cc01baSHerbert Xu 7620cc01baSHerbert Xu ivsize = crypto_aead_alg_ivsize(alg); 7720cc01baSHerbert Xu maxauthsize = crypto_aead_alg_maxauthsize(alg); 7820cc01baSHerbert Xu 7920cc01baSHerbert Xu err = -EINVAL; 8020cc01baSHerbert Xu if (ivsize < sizeof(u64)) 81376ffe1aSEric Biggers goto err_free_inst; 8220cc01baSHerbert Xu 8320cc01baSHerbert Xu err = -ENAMETOOLONG; 8420cc01baSHerbert Xu if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, 8520cc01baSHerbert Xu "%s(%s)", tmpl->name, alg->base.cra_name) >= 8620cc01baSHerbert Xu CRYPTO_MAX_ALG_NAME) 87376ffe1aSEric Biggers goto err_free_inst; 8820cc01baSHerbert Xu if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 8920cc01baSHerbert Xu "%s(%s)", tmpl->name, alg->base.cra_driver_name) >= 9020cc01baSHerbert Xu CRYPTO_MAX_ALG_NAME) 91376ffe1aSEric Biggers goto err_free_inst; 9220cc01baSHerbert Xu 9320cc01baSHerbert Xu inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC; 9420cc01baSHerbert Xu inst->alg.base.cra_priority = alg->base.cra_priority; 9520cc01baSHerbert Xu inst->alg.base.cra_blocksize = alg->base.cra_blocksize; 9620cc01baSHerbert Xu inst->alg.base.cra_alignmask = alg->base.cra_alignmask; 9720cc01baSHerbert Xu inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx); 9820cc01baSHerbert Xu 9920cc01baSHerbert Xu inst->alg.setkey = aead_geniv_setkey; 10020cc01baSHerbert Xu inst->alg.setauthsize = aead_geniv_setauthsize; 10120cc01baSHerbert Xu 10220cc01baSHerbert Xu inst->alg.ivsize = ivsize; 10320cc01baSHerbert Xu inst->alg.maxauthsize = maxauthsize; 10420cc01baSHerbert Xu 1050f8f6d86SEric Biggers inst->free = aead_geniv_free; 1060f8f6d86SEric Biggers 10720cc01baSHerbert Xu out: 10820cc01baSHerbert Xu return inst; 10920cc01baSHerbert Xu 11020cc01baSHerbert Xu err_free_inst: 111376ffe1aSEric Biggers aead_geniv_free(inst); 11220cc01baSHerbert Xu inst = ERR_PTR(err); 11320cc01baSHerbert Xu goto out; 11420cc01baSHerbert Xu } 11520cc01baSHerbert Xu EXPORT_SYMBOL_GPL(aead_geniv_alloc); 11620cc01baSHerbert Xu 11720cc01baSHerbert Xu int aead_init_geniv(struct crypto_aead *aead) 11820cc01baSHerbert Xu { 11920cc01baSHerbert Xu struct aead_geniv_ctx *ctx = crypto_aead_ctx(aead); 12020cc01baSHerbert Xu struct aead_instance *inst = aead_alg_instance(aead); 12120cc01baSHerbert Xu struct crypto_aead *child; 12220cc01baSHerbert Xu int err; 12320cc01baSHerbert Xu 12420cc01baSHerbert Xu spin_lock_init(&ctx->lock); 12520cc01baSHerbert Xu 12620cc01baSHerbert Xu err = crypto_get_default_rng(); 12720cc01baSHerbert Xu if (err) 12820cc01baSHerbert Xu goto out; 12920cc01baSHerbert Xu 13020cc01baSHerbert Xu err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, 13120cc01baSHerbert Xu crypto_aead_ivsize(aead)); 13220cc01baSHerbert Xu crypto_put_default_rng(); 13320cc01baSHerbert Xu if (err) 13420cc01baSHerbert Xu goto out; 13520cc01baSHerbert Xu 13620cc01baSHerbert Xu ctx->sknull = crypto_get_default_null_skcipher(); 13720cc01baSHerbert Xu err = PTR_ERR(ctx->sknull); 13820cc01baSHerbert Xu if (IS_ERR(ctx->sknull)) 13920cc01baSHerbert Xu goto out; 14020cc01baSHerbert Xu 14120cc01baSHerbert Xu child = crypto_spawn_aead(aead_instance_ctx(inst)); 14220cc01baSHerbert Xu err = PTR_ERR(child); 14320cc01baSHerbert Xu if (IS_ERR(child)) 14420cc01baSHerbert Xu goto drop_null; 14520cc01baSHerbert Xu 14620cc01baSHerbert Xu ctx->child = child; 14720cc01baSHerbert Xu crypto_aead_set_reqsize(aead, crypto_aead_reqsize(child) + 14820cc01baSHerbert Xu sizeof(struct aead_request)); 14920cc01baSHerbert Xu 15020cc01baSHerbert Xu err = 0; 15120cc01baSHerbert Xu 15220cc01baSHerbert Xu out: 15320cc01baSHerbert Xu return err; 15420cc01baSHerbert Xu 15520cc01baSHerbert Xu drop_null: 15620cc01baSHerbert Xu crypto_put_default_null_skcipher(); 15720cc01baSHerbert Xu goto out; 15820cc01baSHerbert Xu } 15920cc01baSHerbert Xu EXPORT_SYMBOL_GPL(aead_init_geniv); 16020cc01baSHerbert Xu 16120cc01baSHerbert Xu void aead_exit_geniv(struct crypto_aead *tfm) 16220cc01baSHerbert Xu { 16320cc01baSHerbert Xu struct aead_geniv_ctx *ctx = crypto_aead_ctx(tfm); 16420cc01baSHerbert Xu 16520cc01baSHerbert Xu crypto_free_aead(ctx->child); 16620cc01baSHerbert Xu crypto_put_default_null_skcipher(); 16720cc01baSHerbert Xu } 16820cc01baSHerbert Xu EXPORT_SYMBOL_GPL(aead_exit_geniv); 16920cc01baSHerbert Xu 17020cc01baSHerbert Xu MODULE_LICENSE("GPL"); 17120cc01baSHerbert Xu MODULE_DESCRIPTION("Shared IV generator code"); 172