xref: /openbmc/linux/crypto/seqiv.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
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