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 35*0f8f6d86SEric Biggers static void aead_geniv_free(struct aead_instance *inst) 36*0f8f6d86SEric Biggers { 37*0f8f6d86SEric Biggers crypto_drop_aead(aead_instance_ctx(inst)); 38*0f8f6d86SEric Biggers kfree(inst); 39*0f8f6d86SEric Biggers } 40*0f8f6d86SEric Biggers 4120cc01baSHerbert Xu struct aead_instance *aead_geniv_alloc(struct crypto_template *tmpl, 4220cc01baSHerbert Xu struct rtattr **tb, u32 type, u32 mask) 4320cc01baSHerbert Xu { 4420cc01baSHerbert Xu const char *name; 4520cc01baSHerbert Xu struct crypto_aead_spawn *spawn; 4620cc01baSHerbert Xu struct crypto_attr_type *algt; 4720cc01baSHerbert Xu struct aead_instance *inst; 4820cc01baSHerbert Xu struct aead_alg *alg; 4920cc01baSHerbert Xu unsigned int ivsize; 5020cc01baSHerbert Xu unsigned int maxauthsize; 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 name = crypto_attr_alg_name(tb[1]); 6120cc01baSHerbert Xu if (IS_ERR(name)) 6220cc01baSHerbert Xu return ERR_CAST(name); 6320cc01baSHerbert Xu 6420cc01baSHerbert Xu inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); 6520cc01baSHerbert Xu if (!inst) 6620cc01baSHerbert Xu return ERR_PTR(-ENOMEM); 6720cc01baSHerbert Xu 6820cc01baSHerbert Xu spawn = aead_instance_ctx(inst); 6920cc01baSHerbert Xu 7020cc01baSHerbert Xu /* Ignore async algorithms if necessary. */ 7120cc01baSHerbert Xu mask |= crypto_requires_sync(algt->type, algt->mask); 7220cc01baSHerbert Xu 73cd900f0cSEric Biggers err = crypto_grab_aead(spawn, aead_crypto_instance(inst), 74cd900f0cSEric Biggers name, type, mask); 7520cc01baSHerbert Xu if (err) 7620cc01baSHerbert Xu goto err_free_inst; 7720cc01baSHerbert Xu 7820cc01baSHerbert Xu alg = crypto_spawn_aead_alg(spawn); 7920cc01baSHerbert Xu 8020cc01baSHerbert Xu ivsize = crypto_aead_alg_ivsize(alg); 8120cc01baSHerbert Xu maxauthsize = crypto_aead_alg_maxauthsize(alg); 8220cc01baSHerbert Xu 8320cc01baSHerbert Xu err = -EINVAL; 8420cc01baSHerbert Xu if (ivsize < sizeof(u64)) 8520cc01baSHerbert Xu goto err_drop_alg; 8620cc01baSHerbert Xu 8720cc01baSHerbert Xu err = -ENAMETOOLONG; 8820cc01baSHerbert Xu if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, 8920cc01baSHerbert Xu "%s(%s)", tmpl->name, alg->base.cra_name) >= 9020cc01baSHerbert Xu CRYPTO_MAX_ALG_NAME) 9120cc01baSHerbert Xu goto err_drop_alg; 9220cc01baSHerbert Xu if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 9320cc01baSHerbert Xu "%s(%s)", tmpl->name, alg->base.cra_driver_name) >= 9420cc01baSHerbert Xu CRYPTO_MAX_ALG_NAME) 9520cc01baSHerbert Xu goto err_drop_alg; 9620cc01baSHerbert Xu 9720cc01baSHerbert Xu inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC; 9820cc01baSHerbert Xu inst->alg.base.cra_priority = alg->base.cra_priority; 9920cc01baSHerbert Xu inst->alg.base.cra_blocksize = alg->base.cra_blocksize; 10020cc01baSHerbert Xu inst->alg.base.cra_alignmask = alg->base.cra_alignmask; 10120cc01baSHerbert Xu inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx); 10220cc01baSHerbert Xu 10320cc01baSHerbert Xu inst->alg.setkey = aead_geniv_setkey; 10420cc01baSHerbert Xu inst->alg.setauthsize = aead_geniv_setauthsize; 10520cc01baSHerbert Xu 10620cc01baSHerbert Xu inst->alg.ivsize = ivsize; 10720cc01baSHerbert Xu inst->alg.maxauthsize = maxauthsize; 10820cc01baSHerbert Xu 109*0f8f6d86SEric Biggers inst->free = aead_geniv_free; 110*0f8f6d86SEric Biggers 11120cc01baSHerbert Xu out: 11220cc01baSHerbert Xu return inst; 11320cc01baSHerbert Xu 11420cc01baSHerbert Xu err_drop_alg: 11520cc01baSHerbert Xu crypto_drop_aead(spawn); 11620cc01baSHerbert Xu err_free_inst: 11720cc01baSHerbert Xu kfree(inst); 11820cc01baSHerbert Xu inst = ERR_PTR(err); 11920cc01baSHerbert Xu goto out; 12020cc01baSHerbert Xu } 12120cc01baSHerbert Xu EXPORT_SYMBOL_GPL(aead_geniv_alloc); 12220cc01baSHerbert Xu 12320cc01baSHerbert Xu int aead_init_geniv(struct crypto_aead *aead) 12420cc01baSHerbert Xu { 12520cc01baSHerbert Xu struct aead_geniv_ctx *ctx = crypto_aead_ctx(aead); 12620cc01baSHerbert Xu struct aead_instance *inst = aead_alg_instance(aead); 12720cc01baSHerbert Xu struct crypto_aead *child; 12820cc01baSHerbert Xu int err; 12920cc01baSHerbert Xu 13020cc01baSHerbert Xu spin_lock_init(&ctx->lock); 13120cc01baSHerbert Xu 13220cc01baSHerbert Xu err = crypto_get_default_rng(); 13320cc01baSHerbert Xu if (err) 13420cc01baSHerbert Xu goto out; 13520cc01baSHerbert Xu 13620cc01baSHerbert Xu err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, 13720cc01baSHerbert Xu crypto_aead_ivsize(aead)); 13820cc01baSHerbert Xu crypto_put_default_rng(); 13920cc01baSHerbert Xu if (err) 14020cc01baSHerbert Xu goto out; 14120cc01baSHerbert Xu 14220cc01baSHerbert Xu ctx->sknull = crypto_get_default_null_skcipher(); 14320cc01baSHerbert Xu err = PTR_ERR(ctx->sknull); 14420cc01baSHerbert Xu if (IS_ERR(ctx->sknull)) 14520cc01baSHerbert Xu goto out; 14620cc01baSHerbert Xu 14720cc01baSHerbert Xu child = crypto_spawn_aead(aead_instance_ctx(inst)); 14820cc01baSHerbert Xu err = PTR_ERR(child); 14920cc01baSHerbert Xu if (IS_ERR(child)) 15020cc01baSHerbert Xu goto drop_null; 15120cc01baSHerbert Xu 15220cc01baSHerbert Xu ctx->child = child; 15320cc01baSHerbert Xu crypto_aead_set_reqsize(aead, crypto_aead_reqsize(child) + 15420cc01baSHerbert Xu sizeof(struct aead_request)); 15520cc01baSHerbert Xu 15620cc01baSHerbert Xu err = 0; 15720cc01baSHerbert Xu 15820cc01baSHerbert Xu out: 15920cc01baSHerbert Xu return err; 16020cc01baSHerbert Xu 16120cc01baSHerbert Xu drop_null: 16220cc01baSHerbert Xu crypto_put_default_null_skcipher(); 16320cc01baSHerbert Xu goto out; 16420cc01baSHerbert Xu } 16520cc01baSHerbert Xu EXPORT_SYMBOL_GPL(aead_init_geniv); 16620cc01baSHerbert Xu 16720cc01baSHerbert Xu void aead_exit_geniv(struct crypto_aead *tfm) 16820cc01baSHerbert Xu { 16920cc01baSHerbert Xu struct aead_geniv_ctx *ctx = crypto_aead_ctx(tfm); 17020cc01baSHerbert Xu 17120cc01baSHerbert Xu crypto_free_aead(ctx->child); 17220cc01baSHerbert Xu crypto_put_default_null_skcipher(); 17320cc01baSHerbert Xu } 17420cc01baSHerbert Xu EXPORT_SYMBOL_GPL(aead_exit_geniv); 17520cc01baSHerbert Xu 17620cc01baSHerbert Xu MODULE_LICENSE("GPL"); 17720cc01baSHerbert Xu MODULE_DESCRIPTION("Shared IV generator code"); 178