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