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