xref: /linux/crypto/echainiv.c (revision 84a73014d86fd660822a20c032625e3afe99ca58)
1a10f554fSHerbert Xu /*
2a10f554fSHerbert Xu  * echainiv: Encrypted Chain IV Generator
3a10f554fSHerbert Xu  *
4a10f554fSHerbert Xu  * This generator generates an IV based on a sequence number by xoring it
5a10f554fSHerbert Xu  * with a salt and then encrypting it with the same key as used to encrypt
6a10f554fSHerbert Xu  * the plain text.  This algorithm requires that the block size be equal
7a10f554fSHerbert Xu  * to the IV size.  It is mainly useful for CBC.
8a10f554fSHerbert Xu  *
9a10f554fSHerbert Xu  * This generator can only be used by algorithms where authentication
10a10f554fSHerbert Xu  * is performed after encryption (i.e., authenc).
11a10f554fSHerbert Xu  *
12a10f554fSHerbert Xu  * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au>
13a10f554fSHerbert Xu  *
14a10f554fSHerbert Xu  * This program is free software; you can redistribute it and/or modify it
15a10f554fSHerbert Xu  * under the terms of the GNU General Public License as published by the Free
16a10f554fSHerbert Xu  * Software Foundation; either version 2 of the License, or (at your option)
17a10f554fSHerbert Xu  * any later version.
18a10f554fSHerbert Xu  *
19a10f554fSHerbert Xu  */
20a10f554fSHerbert Xu 
21d97de47cSHerbert Xu #include <crypto/internal/geniv.h>
22a10f554fSHerbert Xu #include <crypto/scatterwalk.h>
23a10f554fSHerbert Xu #include <linux/err.h>
24a10f554fSHerbert Xu #include <linux/init.h>
25a10f554fSHerbert Xu #include <linux/kernel.h>
26a10f554fSHerbert Xu #include <linux/mm.h>
27a10f554fSHerbert Xu #include <linux/module.h>
28a10f554fSHerbert Xu #include <linux/percpu.h>
29a10f554fSHerbert Xu #include <linux/spinlock.h>
30a10f554fSHerbert Xu #include <linux/string.h>
31a10f554fSHerbert Xu 
32a10f554fSHerbert Xu #define MAX_IV_SIZE 16
33a10f554fSHerbert Xu 
34a10f554fSHerbert Xu static DEFINE_PER_CPU(u32 [MAX_IV_SIZE / sizeof(u32)], echainiv_iv);
35a10f554fSHerbert Xu 
36a10f554fSHerbert Xu /* We don't care if we get preempted and read/write IVs from the next CPU. */
37622ff875SWu Fengguang static void echainiv_read_iv(u8 *dst, unsigned size)
38a10f554fSHerbert Xu {
39a10f554fSHerbert Xu 	u32 *a = (u32 *)dst;
40a10f554fSHerbert Xu 	u32 __percpu *b = echainiv_iv;
41a10f554fSHerbert Xu 
42a10f554fSHerbert Xu 	for (; size >= 4; size -= 4) {
43a10f554fSHerbert Xu 		*a++ = this_cpu_read(*b);
44a10f554fSHerbert Xu 		b++;
45a10f554fSHerbert Xu 	}
46a10f554fSHerbert Xu }
47a10f554fSHerbert Xu 
48622ff875SWu Fengguang static void echainiv_write_iv(const u8 *src, unsigned size)
49a10f554fSHerbert Xu {
50a10f554fSHerbert Xu 	const u32 *a = (const u32 *)src;
51a10f554fSHerbert Xu 	u32 __percpu *b = echainiv_iv;
52a10f554fSHerbert Xu 
53a10f554fSHerbert Xu 	for (; size >= 4; size -= 4) {
54a10f554fSHerbert Xu 		this_cpu_write(*b, *a);
55a10f554fSHerbert Xu 		a++;
56a10f554fSHerbert Xu 		b++;
57a10f554fSHerbert Xu 	}
58a10f554fSHerbert Xu }
59a10f554fSHerbert Xu 
60a10f554fSHerbert Xu static void echainiv_encrypt_complete2(struct aead_request *req, int err)
61a10f554fSHerbert Xu {
62a10f554fSHerbert Xu 	struct aead_request *subreq = aead_request_ctx(req);
63a10f554fSHerbert Xu 	struct crypto_aead *geniv;
64a10f554fSHerbert Xu 	unsigned int ivsize;
65a10f554fSHerbert Xu 
66a10f554fSHerbert Xu 	if (err == -EINPROGRESS)
67a10f554fSHerbert Xu 		return;
68a10f554fSHerbert Xu 
69a10f554fSHerbert Xu 	if (err)
70a10f554fSHerbert Xu 		goto out;
71a10f554fSHerbert Xu 
72a10f554fSHerbert Xu 	geniv = crypto_aead_reqtfm(req);
73a10f554fSHerbert Xu 	ivsize = crypto_aead_ivsize(geniv);
74a10f554fSHerbert Xu 
75a10f554fSHerbert Xu 	echainiv_write_iv(subreq->iv, ivsize);
76a10f554fSHerbert Xu 
77a10f554fSHerbert Xu 	if (req->iv != subreq->iv)
78a10f554fSHerbert Xu 		memcpy(req->iv, subreq->iv, ivsize);
79a10f554fSHerbert Xu 
80a10f554fSHerbert Xu out:
81a10f554fSHerbert Xu 	if (req->iv != subreq->iv)
82a10f554fSHerbert Xu 		kzfree(subreq->iv);
83a10f554fSHerbert Xu }
84a10f554fSHerbert Xu 
85a10f554fSHerbert Xu static void echainiv_encrypt_complete(struct crypto_async_request *base,
86a10f554fSHerbert Xu 					 int err)
87a10f554fSHerbert Xu {
88a10f554fSHerbert Xu 	struct aead_request *req = base->data;
89a10f554fSHerbert Xu 
90a10f554fSHerbert Xu 	echainiv_encrypt_complete2(req, err);
91a10f554fSHerbert Xu 	aead_request_complete(req, err);
92a10f554fSHerbert Xu }
93a10f554fSHerbert Xu 
94a10f554fSHerbert Xu static int echainiv_encrypt(struct aead_request *req)
95a10f554fSHerbert Xu {
96a10f554fSHerbert Xu 	struct crypto_aead *geniv = crypto_aead_reqtfm(req);
97376e0d69SHerbert Xu 	struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
98a10f554fSHerbert Xu 	struct aead_request *subreq = aead_request_ctx(req);
99a10f554fSHerbert Xu 	crypto_completion_t compl;
100a10f554fSHerbert Xu 	void *data;
101a10f554fSHerbert Xu 	u8 *info;
102823655c9SHerbert Xu 	unsigned int ivsize = crypto_aead_ivsize(geniv);
103a10f554fSHerbert Xu 	int err;
104a10f554fSHerbert Xu 
105823655c9SHerbert Xu 	if (req->cryptlen < ivsize)
106823655c9SHerbert Xu 		return -EINVAL;
107823655c9SHerbert Xu 
108376e0d69SHerbert Xu 	aead_request_set_tfm(subreq, ctx->child);
109a10f554fSHerbert Xu 
110a10f554fSHerbert Xu 	compl = echainiv_encrypt_complete;
111a10f554fSHerbert Xu 	data = req;
112a10f554fSHerbert Xu 	info = req->iv;
113a10f554fSHerbert Xu 
114a10f554fSHerbert Xu 	if (req->src != req->dst) {
115a10f554fSHerbert Xu 		struct blkcipher_desc desc = {
116a10f554fSHerbert Xu 			.tfm = ctx->null,
117a10f554fSHerbert Xu 		};
118a10f554fSHerbert Xu 
119a10f554fSHerbert Xu 		err = crypto_blkcipher_encrypt(
120838c9d56SHerbert Xu 			&desc, req->dst, req->src,
121838c9d56SHerbert Xu 			req->assoclen + req->cryptlen);
122a10f554fSHerbert Xu 		if (err)
123a10f554fSHerbert Xu 			return err;
124a10f554fSHerbert Xu 	}
125a10f554fSHerbert Xu 
126a10f554fSHerbert Xu 	if (unlikely(!IS_ALIGNED((unsigned long)info,
127a10f554fSHerbert Xu 				 crypto_aead_alignmask(geniv) + 1))) {
128a10f554fSHerbert Xu 		info = kmalloc(ivsize, req->base.flags &
129a10f554fSHerbert Xu 				       CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
130a10f554fSHerbert Xu 								  GFP_ATOMIC);
131a10f554fSHerbert Xu 		if (!info)
132a10f554fSHerbert Xu 			return -ENOMEM;
133a10f554fSHerbert Xu 
134a10f554fSHerbert Xu 		memcpy(info, req->iv, ivsize);
135a10f554fSHerbert Xu 	}
136a10f554fSHerbert Xu 
137a10f554fSHerbert Xu 	aead_request_set_callback(subreq, req->base.flags, compl, data);
138a10f554fSHerbert Xu 	aead_request_set_crypt(subreq, req->dst, req->dst,
1395499b1a7SHerbert Xu 			       req->cryptlen, info);
1405499b1a7SHerbert Xu 	aead_request_set_ad(subreq, req->assoclen);
141a10f554fSHerbert Xu 
142a10f554fSHerbert Xu 	crypto_xor(info, ctx->salt, ivsize);
143a10f554fSHerbert Xu 	scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1);
144a10f554fSHerbert Xu 	echainiv_read_iv(info, ivsize);
145a10f554fSHerbert Xu 
146a10f554fSHerbert Xu 	err = crypto_aead_encrypt(subreq);
147a10f554fSHerbert Xu 	echainiv_encrypt_complete2(req, err);
148a10f554fSHerbert Xu 	return err;
149a10f554fSHerbert Xu }
150a10f554fSHerbert Xu 
151a10f554fSHerbert Xu static int echainiv_decrypt(struct aead_request *req)
152a10f554fSHerbert Xu {
153a10f554fSHerbert Xu 	struct crypto_aead *geniv = crypto_aead_reqtfm(req);
154376e0d69SHerbert Xu 	struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
155a10f554fSHerbert Xu 	struct aead_request *subreq = aead_request_ctx(req);
156a10f554fSHerbert Xu 	crypto_completion_t compl;
157a10f554fSHerbert Xu 	void *data;
158823655c9SHerbert Xu 	unsigned int ivsize = crypto_aead_ivsize(geniv);
159823655c9SHerbert Xu 
1605499b1a7SHerbert Xu 	if (req->cryptlen < ivsize)
161823655c9SHerbert Xu 		return -EINVAL;
162a10f554fSHerbert Xu 
163376e0d69SHerbert Xu 	aead_request_set_tfm(subreq, ctx->child);
164a10f554fSHerbert Xu 
165a10f554fSHerbert Xu 	compl = req->base.complete;
166a10f554fSHerbert Xu 	data = req->base.data;
167a10f554fSHerbert Xu 
168a10f554fSHerbert Xu 	aead_request_set_callback(subreq, req->base.flags, compl, data);
169a10f554fSHerbert Xu 	aead_request_set_crypt(subreq, req->src, req->dst,
170a10f554fSHerbert Xu 			       req->cryptlen - ivsize, req->iv);
171374d4ad1SHerbert Xu 	aead_request_set_ad(subreq, req->assoclen + ivsize);
172a10f554fSHerbert Xu 
173a10f554fSHerbert Xu 	scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0);
174a10f554fSHerbert Xu 
175a10f554fSHerbert Xu 	return crypto_aead_decrypt(subreq);
176a10f554fSHerbert Xu }
177a10f554fSHerbert Xu 
1781e419c79SHerbert Xu static int echainiv_aead_create(struct crypto_template *tmpl,
1791e419c79SHerbert Xu 				struct rtattr **tb)
180a10f554fSHerbert Xu {
181a10f554fSHerbert Xu 	struct aead_instance *inst;
182a10f554fSHerbert Xu 	struct crypto_aead_spawn *spawn;
183a10f554fSHerbert Xu 	struct aead_alg *alg;
1841e419c79SHerbert Xu 	int err;
185a10f554fSHerbert Xu 
1861e419c79SHerbert Xu 	inst = aead_geniv_alloc(tmpl, tb, 0, 0);
187a10f554fSHerbert Xu 
188a10f554fSHerbert Xu 	if (IS_ERR(inst))
1891e419c79SHerbert Xu 		return PTR_ERR(inst);
190a10f554fSHerbert Xu 
191a10f554fSHerbert Xu 	spawn = aead_instance_ctx(inst);
192a10f554fSHerbert Xu 	alg = crypto_spawn_aead_alg(spawn);
193a10f554fSHerbert Xu 
194d97de47cSHerbert Xu 	err = -EINVAL;
195d97de47cSHerbert Xu 	if (inst->alg.ivsize & (sizeof(u32) - 1) ||
196d97de47cSHerbert Xu 	    inst->alg.ivsize > MAX_IV_SIZE)
197d97de47cSHerbert Xu 		goto free_inst;
198d97de47cSHerbert Xu 
199f261c5fbSHerbert Xu 	inst->alg.encrypt = echainiv_encrypt;
200a10f554fSHerbert Xu 	inst->alg.decrypt = echainiv_decrypt;
201a10f554fSHerbert Xu 
202376e0d69SHerbert Xu 	inst->alg.init = aead_init_geniv;
203376e0d69SHerbert Xu 	inst->alg.exit = aead_exit_geniv;
204a10f554fSHerbert Xu 
205a10f554fSHerbert Xu 	inst->alg.base.cra_alignmask |= __alignof__(u32) - 1;
206376e0d69SHerbert Xu 	inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx);
2079d03aee1SHerbert Xu 	inst->alg.base.cra_ctxsize += inst->alg.ivsize;
208a10f554fSHerbert Xu 
2095499b1a7SHerbert Xu 	inst->free = aead_geniv_free;
2105499b1a7SHerbert Xu 
2111e419c79SHerbert Xu 	err = aead_register_instance(tmpl, inst);
2121e419c79SHerbert Xu 	if (err)
2131e419c79SHerbert Xu 		goto free_inst;
2141e419c79SHerbert Xu 
215a10f554fSHerbert Xu out:
2161e419c79SHerbert Xu 	return err;
2171e419c79SHerbert Xu 
2181e419c79SHerbert Xu free_inst:
2191e419c79SHerbert Xu 	aead_geniv_free(inst);
2201e419c79SHerbert Xu 	goto out;
221a10f554fSHerbert Xu }
222a10f554fSHerbert Xu 
223a10f554fSHerbert Xu static void echainiv_free(struct crypto_instance *inst)
224a10f554fSHerbert Xu {
225a10f554fSHerbert Xu 	aead_geniv_free(aead_instance(inst));
226a10f554fSHerbert Xu }
227a10f554fSHerbert Xu 
228a10f554fSHerbert Xu static struct crypto_template echainiv_tmpl = {
229a10f554fSHerbert Xu 	.name = "echainiv",
2309fcc704dSHerbert Xu 	.create = echainiv_aead_create,
231a10f554fSHerbert Xu 	.free = echainiv_free,
232a10f554fSHerbert Xu 	.module = THIS_MODULE,
233a10f554fSHerbert Xu };
234a10f554fSHerbert Xu 
235a10f554fSHerbert Xu static int __init echainiv_module_init(void)
236a10f554fSHerbert Xu {
237a10f554fSHerbert Xu 	return crypto_register_template(&echainiv_tmpl);
238a10f554fSHerbert Xu }
239a10f554fSHerbert Xu 
240a10f554fSHerbert Xu static void __exit echainiv_module_exit(void)
241a10f554fSHerbert Xu {
242a10f554fSHerbert Xu 	crypto_unregister_template(&echainiv_tmpl);
243a10f554fSHerbert Xu }
244a10f554fSHerbert Xu 
245a10f554fSHerbert Xu module_init(echainiv_module_init);
246a10f554fSHerbert Xu module_exit(echainiv_module_exit);
247a10f554fSHerbert Xu 
248a10f554fSHerbert Xu MODULE_LICENSE("GPL");
249a10f554fSHerbert Xu MODULE_DESCRIPTION("Encrypted Chain IV Generator");
250a10f554fSHerbert Xu MODULE_ALIAS_CRYPTO("echainiv");
251