162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * seqiv: Sequence Number IV Generator 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This generator generates an IV based on a sequence number by xoring it 662306a36Sopenharmony_ci * with a salt. This algorithm is mainly useful for CTR and similar modes. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <crypto/internal/geniv.h> 1262306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 1362306a36Sopenharmony_ci#include <crypto/skcipher.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/string.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void seqiv_aead_encrypt_complete2(struct aead_request *req, int err) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct aead_request *subreq = aead_request_ctx(req); 2462306a36Sopenharmony_ci struct crypto_aead *geniv; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (err == -EINPROGRESS || err == -EBUSY) 2762306a36Sopenharmony_ci return; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (err) 3062306a36Sopenharmony_ci goto out; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci geniv = crypto_aead_reqtfm(req); 3362306a36Sopenharmony_ci memcpy(req->iv, subreq->iv, crypto_aead_ivsize(geniv)); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciout: 3662306a36Sopenharmony_ci kfree_sensitive(subreq->iv); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic void seqiv_aead_encrypt_complete(void *data, int err) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct aead_request *req = data; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci seqiv_aead_encrypt_complete2(req, err); 4462306a36Sopenharmony_ci aead_request_complete(req, err); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic int seqiv_aead_encrypt(struct aead_request *req) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct crypto_aead *geniv = crypto_aead_reqtfm(req); 5062306a36Sopenharmony_ci struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv); 5162306a36Sopenharmony_ci struct aead_request *subreq = aead_request_ctx(req); 5262306a36Sopenharmony_ci crypto_completion_t compl; 5362306a36Sopenharmony_ci void *data; 5462306a36Sopenharmony_ci u8 *info; 5562306a36Sopenharmony_ci unsigned int ivsize = 8; 5662306a36Sopenharmony_ci int err; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (req->cryptlen < ivsize) 5962306a36Sopenharmony_ci return -EINVAL; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci aead_request_set_tfm(subreq, ctx->child); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci compl = req->base.complete; 6462306a36Sopenharmony_ci data = req->base.data; 6562306a36Sopenharmony_ci info = req->iv; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (req->src != req->dst) { 6862306a36Sopenharmony_ci SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci skcipher_request_set_sync_tfm(nreq, ctx->sknull); 7162306a36Sopenharmony_ci skcipher_request_set_callback(nreq, req->base.flags, 7262306a36Sopenharmony_ci NULL, NULL); 7362306a36Sopenharmony_ci skcipher_request_set_crypt(nreq, req->src, req->dst, 7462306a36Sopenharmony_ci req->assoclen + req->cryptlen, 7562306a36Sopenharmony_ci NULL); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci err = crypto_skcipher_encrypt(nreq); 7862306a36Sopenharmony_ci if (err) 7962306a36Sopenharmony_ci return err; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (unlikely(!IS_ALIGNED((unsigned long)info, 8362306a36Sopenharmony_ci crypto_aead_alignmask(geniv) + 1))) { 8462306a36Sopenharmony_ci info = kmemdup(req->iv, ivsize, req->base.flags & 8562306a36Sopenharmony_ci CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : 8662306a36Sopenharmony_ci GFP_ATOMIC); 8762306a36Sopenharmony_ci if (!info) 8862306a36Sopenharmony_ci return -ENOMEM; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci compl = seqiv_aead_encrypt_complete; 9162306a36Sopenharmony_ci data = req; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci aead_request_set_callback(subreq, req->base.flags, compl, data); 9562306a36Sopenharmony_ci aead_request_set_crypt(subreq, req->dst, req->dst, 9662306a36Sopenharmony_ci req->cryptlen - ivsize, info); 9762306a36Sopenharmony_ci aead_request_set_ad(subreq, req->assoclen + ivsize); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci crypto_xor(info, ctx->salt, ivsize); 10062306a36Sopenharmony_ci scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci err = crypto_aead_encrypt(subreq); 10362306a36Sopenharmony_ci if (unlikely(info != req->iv)) 10462306a36Sopenharmony_ci seqiv_aead_encrypt_complete2(req, err); 10562306a36Sopenharmony_ci return err; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int seqiv_aead_decrypt(struct aead_request *req) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct crypto_aead *geniv = crypto_aead_reqtfm(req); 11162306a36Sopenharmony_ci struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv); 11262306a36Sopenharmony_ci struct aead_request *subreq = aead_request_ctx(req); 11362306a36Sopenharmony_ci crypto_completion_t compl; 11462306a36Sopenharmony_ci void *data; 11562306a36Sopenharmony_ci unsigned int ivsize = 8; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (req->cryptlen < ivsize + crypto_aead_authsize(geniv)) 11862306a36Sopenharmony_ci return -EINVAL; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci aead_request_set_tfm(subreq, ctx->child); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci compl = req->base.complete; 12362306a36Sopenharmony_ci data = req->base.data; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci aead_request_set_callback(subreq, req->base.flags, compl, data); 12662306a36Sopenharmony_ci aead_request_set_crypt(subreq, req->src, req->dst, 12762306a36Sopenharmony_ci req->cryptlen - ivsize, req->iv); 12862306a36Sopenharmony_ci aead_request_set_ad(subreq, req->assoclen + ivsize); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return crypto_aead_decrypt(subreq); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic int seqiv_aead_create(struct crypto_template *tmpl, struct rtattr **tb) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct aead_instance *inst; 13862306a36Sopenharmony_ci int err; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci inst = aead_geniv_alloc(tmpl, tb); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (IS_ERR(inst)) 14362306a36Sopenharmony_ci return PTR_ERR(inst); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci err = -EINVAL; 14662306a36Sopenharmony_ci if (inst->alg.ivsize != sizeof(u64)) 14762306a36Sopenharmony_ci goto free_inst; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci inst->alg.encrypt = seqiv_aead_encrypt; 15062306a36Sopenharmony_ci inst->alg.decrypt = seqiv_aead_decrypt; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci inst->alg.init = aead_init_geniv; 15362306a36Sopenharmony_ci inst->alg.exit = aead_exit_geniv; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx); 15662306a36Sopenharmony_ci inst->alg.base.cra_ctxsize += inst->alg.ivsize; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci err = aead_register_instance(tmpl, inst); 15962306a36Sopenharmony_ci if (err) { 16062306a36Sopenharmony_cifree_inst: 16162306a36Sopenharmony_ci inst->free(inst); 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci return err; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic struct crypto_template seqiv_tmpl = { 16762306a36Sopenharmony_ci .name = "seqiv", 16862306a36Sopenharmony_ci .create = seqiv_aead_create, 16962306a36Sopenharmony_ci .module = THIS_MODULE, 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic int __init seqiv_module_init(void) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci return crypto_register_template(&seqiv_tmpl); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void __exit seqiv_module_exit(void) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci crypto_unregister_template(&seqiv_tmpl); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cisubsys_initcall(seqiv_module_init); 18362306a36Sopenharmony_cimodule_exit(seqiv_module_exit); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 18662306a36Sopenharmony_ciMODULE_DESCRIPTION("Sequence Number IV Generator"); 18762306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("seqiv"); 188