12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20a270321SHerbert Xu /*
30a270321SHerbert Xu * seqiv: Sequence Number IV Generator
40a270321SHerbert Xu *
50a270321SHerbert Xu * This generator generates an IV based on a sequence number by xoring it
60a270321SHerbert Xu * with a salt. This algorithm is mainly useful for CTR and similar modes.
70a270321SHerbert Xu *
80a270321SHerbert Xu * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
90a270321SHerbert Xu */
100a270321SHerbert Xu
11661cfd0eSHerbert Xu #include <crypto/internal/geniv.h>
12856e3f40SHerbert Xu #include <crypto/scatterwalk.h>
133a01d0eeSHerbert Xu #include <crypto/skcipher.h>
140a270321SHerbert Xu #include <linux/err.h>
150a270321SHerbert Xu #include <linux/init.h>
160a270321SHerbert Xu #include <linux/kernel.h>
170a270321SHerbert Xu #include <linux/module.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
190a270321SHerbert Xu #include <linux/string.h>
200a270321SHerbert Xu
seqiv_aead_encrypt_complete2(struct aead_request * req,int err)21856e3f40SHerbert Xu static void seqiv_aead_encrypt_complete2(struct aead_request *req, int err)
22856e3f40SHerbert Xu {
23856e3f40SHerbert Xu struct aead_request *subreq = aead_request_ctx(req);
24856e3f40SHerbert Xu struct crypto_aead *geniv;
25856e3f40SHerbert Xu
2632e62025SHerbert Xu if (err == -EINPROGRESS || err == -EBUSY)
27856e3f40SHerbert Xu return;
28856e3f40SHerbert Xu
29856e3f40SHerbert Xu if (err)
30856e3f40SHerbert Xu goto out;
31856e3f40SHerbert Xu
32856e3f40SHerbert Xu geniv = crypto_aead_reqtfm(req);
33856e3f40SHerbert Xu memcpy(req->iv, subreq->iv, crypto_aead_ivsize(geniv));
34856e3f40SHerbert Xu
35856e3f40SHerbert Xu out:
36453431a5SWaiman Long kfree_sensitive(subreq->iv);
37856e3f40SHerbert Xu }
38856e3f40SHerbert Xu
seqiv_aead_encrypt_complete(void * data,int err)39*255e48ebSHerbert Xu static void seqiv_aead_encrypt_complete(void *data, int err)
40856e3f40SHerbert Xu {
41*255e48ebSHerbert Xu struct aead_request *req = data;
42856e3f40SHerbert Xu
43856e3f40SHerbert Xu seqiv_aead_encrypt_complete2(req, err);
44856e3f40SHerbert Xu aead_request_complete(req, err);
45856e3f40SHerbert Xu }
46856e3f40SHerbert Xu
seqiv_aead_encrypt(struct aead_request * req)47856e3f40SHerbert Xu static int seqiv_aead_encrypt(struct aead_request *req)
48856e3f40SHerbert Xu {
49856e3f40SHerbert Xu struct crypto_aead *geniv = crypto_aead_reqtfm(req);
50659e7f52SHerbert Xu struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
51856e3f40SHerbert Xu struct aead_request *subreq = aead_request_ctx(req);
52856e3f40SHerbert Xu crypto_completion_t compl;
53856e3f40SHerbert Xu void *data;
54856e3f40SHerbert Xu u8 *info;
55dd04446eSHerbert Xu unsigned int ivsize = 8;
56856e3f40SHerbert Xu int err;
57856e3f40SHerbert Xu
58dd04446eSHerbert Xu if (req->cryptlen < ivsize)
59dd04446eSHerbert Xu return -EINVAL;
60dd04446eSHerbert Xu
61659e7f52SHerbert Xu aead_request_set_tfm(subreq, ctx->child);
62856e3f40SHerbert Xu
63856e3f40SHerbert Xu compl = req->base.complete;
64856e3f40SHerbert Xu data = req->base.data;
65856e3f40SHerbert Xu info = req->iv;
66856e3f40SHerbert Xu
67856e3f40SHerbert Xu if (req->src != req->dst) {
688d605398SKees Cook SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
69856e3f40SHerbert Xu
708d605398SKees Cook skcipher_request_set_sync_tfm(nreq, ctx->sknull);
71ef22871fSHerbert Xu skcipher_request_set_callback(nreq, req->base.flags,
72ef22871fSHerbert Xu NULL, NULL);
73ef22871fSHerbert Xu skcipher_request_set_crypt(nreq, req->src, req->dst,
74ef22871fSHerbert Xu req->assoclen + req->cryptlen,
75ef22871fSHerbert Xu NULL);
76ef22871fSHerbert Xu
77ef22871fSHerbert Xu err = crypto_skcipher_encrypt(nreq);
78856e3f40SHerbert Xu if (err)
79856e3f40SHerbert Xu return err;
80856e3f40SHerbert Xu }
81856e3f40SHerbert Xu
82856e3f40SHerbert Xu if (unlikely(!IS_ALIGNED((unsigned long)info,
83856e3f40SHerbert Xu crypto_aead_alignmask(geniv) + 1))) {
847e33d4d4SYueHaibing info = kmemdup(req->iv, ivsize, req->base.flags &
85856e3f40SHerbert Xu CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
86856e3f40SHerbert Xu GFP_ATOMIC);
87856e3f40SHerbert Xu if (!info)
88856e3f40SHerbert Xu return -ENOMEM;
89856e3f40SHerbert Xu
90856e3f40SHerbert Xu compl = seqiv_aead_encrypt_complete;
91856e3f40SHerbert Xu data = req;
92856e3f40SHerbert Xu }
93856e3f40SHerbert Xu
94856e3f40SHerbert Xu aead_request_set_callback(subreq, req->base.flags, compl, data);
95856e3f40SHerbert Xu aead_request_set_crypt(subreq, req->dst, req->dst,
96856e3f40SHerbert Xu req->cryptlen - ivsize, info);
97374d4ad1SHerbert Xu aead_request_set_ad(subreq, req->assoclen + ivsize);
98856e3f40SHerbert Xu
99856e3f40SHerbert Xu crypto_xor(info, ctx->salt, ivsize);
100856e3f40SHerbert Xu scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1);
101856e3f40SHerbert Xu
102856e3f40SHerbert Xu err = crypto_aead_encrypt(subreq);
103856e3f40SHerbert Xu if (unlikely(info != req->iv))
104856e3f40SHerbert Xu seqiv_aead_encrypt_complete2(req, err);
105856e3f40SHerbert Xu return err;
106856e3f40SHerbert Xu }
107856e3f40SHerbert Xu
seqiv_aead_decrypt(struct aead_request * req)108856e3f40SHerbert Xu static int seqiv_aead_decrypt(struct aead_request *req)
109856e3f40SHerbert Xu {
110856e3f40SHerbert Xu struct crypto_aead *geniv = crypto_aead_reqtfm(req);
111659e7f52SHerbert Xu struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
112856e3f40SHerbert Xu struct aead_request *subreq = aead_request_ctx(req);
113856e3f40SHerbert Xu crypto_completion_t compl;
114856e3f40SHerbert Xu void *data;
115dd04446eSHerbert Xu unsigned int ivsize = 8;
116dd04446eSHerbert Xu
117dd04446eSHerbert Xu if (req->cryptlen < ivsize + crypto_aead_authsize(geniv))
118dd04446eSHerbert Xu return -EINVAL;
119856e3f40SHerbert Xu
120659e7f52SHerbert Xu aead_request_set_tfm(subreq, ctx->child);
121856e3f40SHerbert Xu
122856e3f40SHerbert Xu compl = req->base.complete;
123856e3f40SHerbert Xu data = req->base.data;
124856e3f40SHerbert Xu
125856e3f40SHerbert Xu aead_request_set_callback(subreq, req->base.flags, compl, data);
126856e3f40SHerbert Xu aead_request_set_crypt(subreq, req->src, req->dst,
127856e3f40SHerbert Xu req->cryptlen - ivsize, req->iv);
128374d4ad1SHerbert Xu aead_request_set_ad(subreq, req->assoclen + ivsize);
129856e3f40SHerbert Xu
130856e3f40SHerbert Xu scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0);
131856e3f40SHerbert Xu
132856e3f40SHerbert Xu return crypto_aead_decrypt(subreq);
133856e3f40SHerbert Xu }
134856e3f40SHerbert Xu
seqiv_aead_create(struct crypto_template * tmpl,struct rtattr ** tb)1350677157bSHerbert Xu static int seqiv_aead_create(struct crypto_template *tmpl, struct rtattr **tb)
13614df4d80SHerbert Xu {
137856e3f40SHerbert Xu struct aead_instance *inst;
1380677157bSHerbert Xu int err;
13914df4d80SHerbert Xu
140e72b48c5SEric Biggers inst = aead_geniv_alloc(tmpl, tb);
14114df4d80SHerbert Xu
14214df4d80SHerbert Xu if (IS_ERR(inst))
1430677157bSHerbert Xu return PTR_ERR(inst);
1440677157bSHerbert Xu
1450677157bSHerbert Xu err = -EINVAL;
146dd04446eSHerbert Xu if (inst->alg.ivsize != sizeof(u64))
1470677157bSHerbert Xu goto free_inst;
148c0ecf891SHerbert Xu
149b7dcfab4SHerbert Xu inst->alg.encrypt = seqiv_aead_encrypt;
150856e3f40SHerbert Xu inst->alg.decrypt = seqiv_aead_decrypt;
15114df4d80SHerbert Xu
152659e7f52SHerbert Xu inst->alg.init = aead_init_geniv;
153659e7f52SHerbert Xu inst->alg.exit = aead_exit_geniv;
154856e3f40SHerbert Xu
155659e7f52SHerbert Xu inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx);
1565964f26cSHerbert Xu inst->alg.base.cra_ctxsize += inst->alg.ivsize;
157856e3f40SHerbert Xu
1580677157bSHerbert Xu err = aead_register_instance(tmpl, inst);
1590f8f6d86SEric Biggers if (err) {
1600677157bSHerbert Xu free_inst:
1610f8f6d86SEric Biggers inst->free(inst);
1620f8f6d86SEric Biggers }
1630f8f6d86SEric Biggers return err;
16414df4d80SHerbert Xu }
16514df4d80SHerbert Xu
1660a270321SHerbert Xu static struct crypto_template seqiv_tmpl = {
1670a270321SHerbert Xu .name = "seqiv",
1684688111eSEric Biggers .create = seqiv_aead_create,
1690a270321SHerbert Xu .module = THIS_MODULE,
1700a270321SHerbert Xu };
1710a270321SHerbert Xu
seqiv_module_init(void)1720a270321SHerbert Xu static int __init seqiv_module_init(void)
1730a270321SHerbert Xu {
1748a2cd1c4SHerbert Xu return crypto_register_template(&seqiv_tmpl);
1750a270321SHerbert Xu }
1760a270321SHerbert Xu
seqiv_module_exit(void)1770a270321SHerbert Xu static void __exit seqiv_module_exit(void)
1780a270321SHerbert Xu {
1790a270321SHerbert Xu crypto_unregister_template(&seqiv_tmpl);
1800a270321SHerbert Xu }
1810a270321SHerbert Xu
182c4741b23SEric Biggers subsys_initcall(seqiv_module_init);
1830a270321SHerbert Xu module_exit(seqiv_module_exit);
1840a270321SHerbert Xu
1850a270321SHerbert Xu MODULE_LICENSE("GPL");
1860a270321SHerbert Xu MODULE_DESCRIPTION("Sequence Number IV Generator");
1874943ba16SKees Cook MODULE_ALIAS_CRYPTO("seqiv");
188