xref: /openbmc/linux/crypto/xts.c (revision 64170e83)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f19f5111SRik Snel /* XTS: as defined in IEEE1619/D16
3f19f5111SRik Snel  *	http://grouper.ieee.org/groups/1619/email/pdf00086.pdf
4f19f5111SRik Snel  *
5f19f5111SRik Snel  * Copyright (c) 2007 Rik Snel <rsnel@cube.dyndns.org>
6f19f5111SRik Snel  *
7ddbc7361SCorentin LABBE  * Based on ecb.c
8f19f5111SRik Snel  * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
9f19f5111SRik Snel  */
100eb76ba2SArd Biesheuvel #include <crypto/internal/cipher.h>
11f1c131b4SHerbert Xu #include <crypto/internal/skcipher.h>
12f1c131b4SHerbert Xu #include <crypto/scatterwalk.h>
13f19f5111SRik Snel #include <linux/err.h>
14f19f5111SRik Snel #include <linux/init.h>
15f19f5111SRik Snel #include <linux/kernel.h>
16f19f5111SRik Snel #include <linux/module.h>
17f19f5111SRik Snel #include <linux/scatterlist.h>
18f19f5111SRik Snel #include <linux/slab.h>
19f19f5111SRik Snel 
20ce004556SJussi Kivilinna #include <crypto/xts.h>
21f19f5111SRik Snel #include <crypto/b128ops.h>
22f19f5111SRik Snel #include <crypto/gf128mul.h>
23f19f5111SRik Snel 
24a874f591SEric Biggers struct xts_tfm_ctx {
25f1c131b4SHerbert Xu 	struct crypto_skcipher *child;
26f19f5111SRik Snel 	struct crypto_cipher *tweak;
27f19f5111SRik Snel };
28f19f5111SRik Snel 
29f1c131b4SHerbert Xu struct xts_instance_ctx {
30f1c131b4SHerbert Xu 	struct crypto_skcipher_spawn spawn;
31*64170e83SEric Biggers 	struct crypto_cipher_spawn tweak_spawn;
32f1c131b4SHerbert Xu };
33f1c131b4SHerbert Xu 
34a874f591SEric Biggers struct xts_request_ctx {
35e55318c8SOndrej Mosnáček 	le128 t;
368083b1bfSArd Biesheuvel 	struct scatterlist *tail;
378083b1bfSArd Biesheuvel 	struct scatterlist sg[2];
38f1c131b4SHerbert Xu 	struct skcipher_request subreq;
39f1c131b4SHerbert Xu };
40f1c131b4SHerbert Xu 
xts_setkey(struct crypto_skcipher * parent,const u8 * key,unsigned int keylen)41a874f591SEric Biggers static int xts_setkey(struct crypto_skcipher *parent, const u8 *key,
42f19f5111SRik Snel 		      unsigned int keylen)
43f19f5111SRik Snel {
44a874f591SEric Biggers 	struct xts_tfm_ctx *ctx = crypto_skcipher_ctx(parent);
45f1c131b4SHerbert Xu 	struct crypto_skcipher *child;
46f1c131b4SHerbert Xu 	struct crypto_cipher *tweak;
47f19f5111SRik Snel 	int err;
48f19f5111SRik Snel 
49f1c131b4SHerbert Xu 	err = xts_verify_key(parent, key, keylen);
5028856a9eSStephan Mueller 	if (err)
5128856a9eSStephan Mueller 		return err;
52f19f5111SRik Snel 
53f1c131b4SHerbert Xu 	keylen /= 2;
54f1c131b4SHerbert Xu 
5525985edcSLucas De Marchi 	/* we need two cipher instances: one to compute the initial 'tweak'
56f19f5111SRik Snel 	 * by encrypting the IV (usually the 'plain' iv) and the other
57f19f5111SRik Snel 	 * one to encrypt and decrypt the data */
58f19f5111SRik Snel 
59f19f5111SRik Snel 	/* tweak cipher, uses Key2 i.e. the second half of *key */
60f1c131b4SHerbert Xu 	tweak = ctx->tweak;
61f1c131b4SHerbert Xu 	crypto_cipher_clear_flags(tweak, CRYPTO_TFM_REQ_MASK);
62f1c131b4SHerbert Xu 	crypto_cipher_set_flags(tweak, crypto_skcipher_get_flags(parent) &
63f19f5111SRik Snel 				       CRYPTO_TFM_REQ_MASK);
64f1c131b4SHerbert Xu 	err = crypto_cipher_setkey(tweak, key + keylen, keylen);
65f19f5111SRik Snel 	if (err)
66f19f5111SRik Snel 		return err;
67f19f5111SRik Snel 
68f19f5111SRik Snel 	/* data cipher, uses Key1 i.e. the first half of *key */
69f1c131b4SHerbert Xu 	child = ctx->child;
70f1c131b4SHerbert Xu 	crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
71f1c131b4SHerbert Xu 	crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(parent) &
72f19f5111SRik Snel 					 CRYPTO_TFM_REQ_MASK);
73af5034e8SEric Biggers 	return crypto_skcipher_setkey(child, key, keylen);
74f1c131b4SHerbert Xu }
75f1c131b4SHerbert Xu 
7678105c7eSOndrej Mosnacek /*
7778105c7eSOndrej Mosnacek  * We compute the tweak masks twice (both before and after the ECB encryption or
7878105c7eSOndrej Mosnacek  * decryption) to avoid having to allocate a temporary buffer and/or make
7978105c7eSOndrej Mosnacek  * mutliple calls to the 'ecb(..)' instance, which usually would be slower than
8078105c7eSOndrej Mosnacek  * just doing the gf128mul_x_ble() calls again.
8178105c7eSOndrej Mosnacek  */
xts_xor_tweak(struct skcipher_request * req,bool second_pass,bool enc)82a874f591SEric Biggers static int xts_xor_tweak(struct skcipher_request *req, bool second_pass,
83a874f591SEric Biggers 			 bool enc)
84f1c131b4SHerbert Xu {
85a874f591SEric Biggers 	struct xts_request_ctx *rctx = skcipher_request_ctx(req);
8678105c7eSOndrej Mosnacek 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
878083b1bfSArd Biesheuvel 	const bool cts = (req->cryptlen % XTS_BLOCK_SIZE);
88f1c131b4SHerbert Xu 	const int bs = XTS_BLOCK_SIZE;
89f1c131b4SHerbert Xu 	struct skcipher_walk w;
9078105c7eSOndrej Mosnacek 	le128 t = rctx->t;
91f1c131b4SHerbert Xu 	int err;
92f1c131b4SHerbert Xu 
9378105c7eSOndrej Mosnacek 	if (second_pass) {
9478105c7eSOndrej Mosnacek 		req = &rctx->subreq;
9578105c7eSOndrej Mosnacek 		/* set to our TFM to enforce correct alignment: */
9678105c7eSOndrej Mosnacek 		skcipher_request_set_tfm(req, tfm);
97f1c131b4SHerbert Xu 	}
9878105c7eSOndrej Mosnacek 	err = skcipher_walk_virt(&w, req, false);
99f1c131b4SHerbert Xu 
100f1c131b4SHerbert Xu 	while (w.nbytes) {
101f1c131b4SHerbert Xu 		unsigned int avail = w.nbytes;
102e55318c8SOndrej Mosnáček 		le128 *wsrc;
103e55318c8SOndrej Mosnáček 		le128 *wdst;
104f1c131b4SHerbert Xu 
105f1c131b4SHerbert Xu 		wsrc = w.src.virt.addr;
106f1c131b4SHerbert Xu 		wdst = w.dst.virt.addr;
107f1c131b4SHerbert Xu 
108f1c131b4SHerbert Xu 		do {
1098083b1bfSArd Biesheuvel 			if (unlikely(cts) &&
1108083b1bfSArd Biesheuvel 			    w.total - w.nbytes + avail < 2 * XTS_BLOCK_SIZE) {
1118083b1bfSArd Biesheuvel 				if (!enc) {
1128083b1bfSArd Biesheuvel 					if (second_pass)
1138083b1bfSArd Biesheuvel 						rctx->t = t;
1148083b1bfSArd Biesheuvel 					gf128mul_x_ble(&t, &t);
1158083b1bfSArd Biesheuvel 				}
1168083b1bfSArd Biesheuvel 				le128_xor(wdst, &t, wsrc);
1178083b1bfSArd Biesheuvel 				if (enc && second_pass)
1188083b1bfSArd Biesheuvel 					gf128mul_x_ble(&rctx->t, &t);
1198083b1bfSArd Biesheuvel 				skcipher_walk_done(&w, avail - bs);
1208083b1bfSArd Biesheuvel 				return 0;
1218083b1bfSArd Biesheuvel 			}
1228083b1bfSArd Biesheuvel 
12378105c7eSOndrej Mosnacek 			le128_xor(wdst++, &t, wsrc++);
12478105c7eSOndrej Mosnacek 			gf128mul_x_ble(&t, &t);
125f1c131b4SHerbert Xu 		} while ((avail -= bs) >= bs);
126f1c131b4SHerbert Xu 
127f1c131b4SHerbert Xu 		err = skcipher_walk_done(&w, avail);
128f1c131b4SHerbert Xu 	}
129f1c131b4SHerbert Xu 
130f1c131b4SHerbert Xu 	return err;
131f1c131b4SHerbert Xu }
132f1c131b4SHerbert Xu 
xts_xor_tweak_pre(struct skcipher_request * req,bool enc)133a874f591SEric Biggers static int xts_xor_tweak_pre(struct skcipher_request *req, bool enc)
13478105c7eSOndrej Mosnacek {
135a874f591SEric Biggers 	return xts_xor_tweak(req, false, enc);
13678105c7eSOndrej Mosnacek }
13778105c7eSOndrej Mosnacek 
xts_xor_tweak_post(struct skcipher_request * req,bool enc)138a874f591SEric Biggers static int xts_xor_tweak_post(struct skcipher_request *req, bool enc)
13978105c7eSOndrej Mosnacek {
140a874f591SEric Biggers 	return xts_xor_tweak(req, true, enc);
14178105c7eSOndrej Mosnacek }
14278105c7eSOndrej Mosnacek 
xts_cts_done(void * data,int err)143255e48ebSHerbert Xu static void xts_cts_done(void *data, int err)
1448083b1bfSArd Biesheuvel {
145255e48ebSHerbert Xu 	struct skcipher_request *req = data;
1468083b1bfSArd Biesheuvel 	le128 b;
1478083b1bfSArd Biesheuvel 
1488083b1bfSArd Biesheuvel 	if (!err) {
149a874f591SEric Biggers 		struct xts_request_ctx *rctx = skcipher_request_ctx(req);
1508083b1bfSArd Biesheuvel 
1518083b1bfSArd Biesheuvel 		scatterwalk_map_and_copy(&b, rctx->tail, 0, XTS_BLOCK_SIZE, 0);
1528083b1bfSArd Biesheuvel 		le128_xor(&b, &rctx->t, &b);
1538083b1bfSArd Biesheuvel 		scatterwalk_map_and_copy(&b, rctx->tail, 0, XTS_BLOCK_SIZE, 1);
1548083b1bfSArd Biesheuvel 	}
1558083b1bfSArd Biesheuvel 
1568083b1bfSArd Biesheuvel 	skcipher_request_complete(req, err);
1578083b1bfSArd Biesheuvel }
1588083b1bfSArd Biesheuvel 
xts_cts_final(struct skcipher_request * req,int (* crypt)(struct skcipher_request * req))159a874f591SEric Biggers static int xts_cts_final(struct skcipher_request *req,
1608083b1bfSArd Biesheuvel 			 int (*crypt)(struct skcipher_request *req))
1618083b1bfSArd Biesheuvel {
162a874f591SEric Biggers 	const struct xts_tfm_ctx *ctx =
163a874f591SEric Biggers 		crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
1648083b1bfSArd Biesheuvel 	int offset = req->cryptlen & ~(XTS_BLOCK_SIZE - 1);
165a874f591SEric Biggers 	struct xts_request_ctx *rctx = skcipher_request_ctx(req);
1668083b1bfSArd Biesheuvel 	struct skcipher_request *subreq = &rctx->subreq;
1678083b1bfSArd Biesheuvel 	int tail = req->cryptlen % XTS_BLOCK_SIZE;
1688083b1bfSArd Biesheuvel 	le128 b[2];
1698083b1bfSArd Biesheuvel 	int err;
1708083b1bfSArd Biesheuvel 
1718083b1bfSArd Biesheuvel 	rctx->tail = scatterwalk_ffwd(rctx->sg, req->dst,
1728083b1bfSArd Biesheuvel 				      offset - XTS_BLOCK_SIZE);
1738083b1bfSArd Biesheuvel 
1748083b1bfSArd Biesheuvel 	scatterwalk_map_and_copy(b, rctx->tail, 0, XTS_BLOCK_SIZE, 0);
175958ea4e0SArd Biesheuvel 	b[1] = b[0];
1768083b1bfSArd Biesheuvel 	scatterwalk_map_and_copy(b, req->src, offset, tail, 0);
1778083b1bfSArd Biesheuvel 
1788083b1bfSArd Biesheuvel 	le128_xor(b, &rctx->t, b);
1798083b1bfSArd Biesheuvel 
1808083b1bfSArd Biesheuvel 	scatterwalk_map_and_copy(b, rctx->tail, 0, XTS_BLOCK_SIZE + tail, 1);
1818083b1bfSArd Biesheuvel 
1828083b1bfSArd Biesheuvel 	skcipher_request_set_tfm(subreq, ctx->child);
183a874f591SEric Biggers 	skcipher_request_set_callback(subreq, req->base.flags, xts_cts_done,
184a874f591SEric Biggers 				      req);
1858083b1bfSArd Biesheuvel 	skcipher_request_set_crypt(subreq, rctx->tail, rctx->tail,
1868083b1bfSArd Biesheuvel 				   XTS_BLOCK_SIZE, NULL);
1878083b1bfSArd Biesheuvel 
1888083b1bfSArd Biesheuvel 	err = crypt(subreq);
1898083b1bfSArd Biesheuvel 	if (err)
1908083b1bfSArd Biesheuvel 		return err;
1918083b1bfSArd Biesheuvel 
1928083b1bfSArd Biesheuvel 	scatterwalk_map_and_copy(b, rctx->tail, 0, XTS_BLOCK_SIZE, 0);
1938083b1bfSArd Biesheuvel 	le128_xor(b, &rctx->t, b);
1948083b1bfSArd Biesheuvel 	scatterwalk_map_and_copy(b, rctx->tail, 0, XTS_BLOCK_SIZE, 1);
1958083b1bfSArd Biesheuvel 
1968083b1bfSArd Biesheuvel 	return 0;
1978083b1bfSArd Biesheuvel }
1988083b1bfSArd Biesheuvel 
xts_encrypt_done(void * data,int err)199255e48ebSHerbert Xu static void xts_encrypt_done(void *data, int err)
20078105c7eSOndrej Mosnacek {
201255e48ebSHerbert Xu 	struct skcipher_request *req = data;
20278105c7eSOndrej Mosnacek 
20344427c0fSHerbert Xu 	if (!err) {
204a874f591SEric Biggers 		struct xts_request_ctx *rctx = skcipher_request_ctx(req);
20544427c0fSHerbert Xu 
20651c08251SHerbert Xu 		rctx->subreq.base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;
207a874f591SEric Biggers 		err = xts_xor_tweak_post(req, true);
2088083b1bfSArd Biesheuvel 
2098083b1bfSArd Biesheuvel 		if (!err && unlikely(req->cryptlen % XTS_BLOCK_SIZE)) {
210a874f591SEric Biggers 			err = xts_cts_final(req, crypto_skcipher_encrypt);
21151c08251SHerbert Xu 			if (err == -EINPROGRESS || err == -EBUSY)
2128083b1bfSArd Biesheuvel 				return;
2138083b1bfSArd Biesheuvel 		}
21444427c0fSHerbert Xu 	}
21578105c7eSOndrej Mosnacek 
21678105c7eSOndrej Mosnacek 	skcipher_request_complete(req, err);
21778105c7eSOndrej Mosnacek }
21878105c7eSOndrej Mosnacek 
xts_decrypt_done(void * data,int err)219255e48ebSHerbert Xu static void xts_decrypt_done(void *data, int err)
2208083b1bfSArd Biesheuvel {
221255e48ebSHerbert Xu 	struct skcipher_request *req = data;
2228083b1bfSArd Biesheuvel 
2238083b1bfSArd Biesheuvel 	if (!err) {
224a874f591SEric Biggers 		struct xts_request_ctx *rctx = skcipher_request_ctx(req);
2258083b1bfSArd Biesheuvel 
22651c08251SHerbert Xu 		rctx->subreq.base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;
227a874f591SEric Biggers 		err = xts_xor_tweak_post(req, false);
2288083b1bfSArd Biesheuvel 
2298083b1bfSArd Biesheuvel 		if (!err && unlikely(req->cryptlen % XTS_BLOCK_SIZE)) {
230a874f591SEric Biggers 			err = xts_cts_final(req, crypto_skcipher_decrypt);
23151c08251SHerbert Xu 			if (err == -EINPROGRESS || err == -EBUSY)
2328083b1bfSArd Biesheuvel 				return;
2338083b1bfSArd Biesheuvel 		}
2348083b1bfSArd Biesheuvel 	}
2358083b1bfSArd Biesheuvel 
2368083b1bfSArd Biesheuvel 	skcipher_request_complete(req, err);
2378083b1bfSArd Biesheuvel }
2388083b1bfSArd Biesheuvel 
xts_init_crypt(struct skcipher_request * req,crypto_completion_t compl)239a874f591SEric Biggers static int xts_init_crypt(struct skcipher_request *req,
240a874f591SEric Biggers 			  crypto_completion_t compl)
241f1c131b4SHerbert Xu {
242a874f591SEric Biggers 	const struct xts_tfm_ctx *ctx =
243a874f591SEric Biggers 		crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
244a874f591SEric Biggers 	struct xts_request_ctx *rctx = skcipher_request_ctx(req);
24578105c7eSOndrej Mosnacek 	struct skcipher_request *subreq = &rctx->subreq;
246f1c131b4SHerbert Xu 
2478083b1bfSArd Biesheuvel 	if (req->cryptlen < XTS_BLOCK_SIZE)
2488083b1bfSArd Biesheuvel 		return -EINVAL;
2498083b1bfSArd Biesheuvel 
250f1c131b4SHerbert Xu 	skcipher_request_set_tfm(subreq, ctx->child);
2518083b1bfSArd Biesheuvel 	skcipher_request_set_callback(subreq, req->base.flags, compl, req);
25278105c7eSOndrej Mosnacek 	skcipher_request_set_crypt(subreq, req->dst, req->dst,
2538083b1bfSArd Biesheuvel 				   req->cryptlen & ~(XTS_BLOCK_SIZE - 1), NULL);
254f1c131b4SHerbert Xu 
255f1c131b4SHerbert Xu 	/* calculate first value of T */
256f1c131b4SHerbert Xu 	crypto_cipher_encrypt_one(ctx->tweak, (u8 *)&rctx->t, req->iv);
2578083b1bfSArd Biesheuvel 
2588083b1bfSArd Biesheuvel 	return 0;
259f1c131b4SHerbert Xu }
260f1c131b4SHerbert Xu 
xts_encrypt(struct skcipher_request * req)261a874f591SEric Biggers static int xts_encrypt(struct skcipher_request *req)
262f1c131b4SHerbert Xu {
263a874f591SEric Biggers 	struct xts_request_ctx *rctx = skcipher_request_ctx(req);
26478105c7eSOndrej Mosnacek 	struct skcipher_request *subreq = &rctx->subreq;
2658083b1bfSArd Biesheuvel 	int err;
266f1c131b4SHerbert Xu 
267a874f591SEric Biggers 	err = xts_init_crypt(req, xts_encrypt_done) ?:
268a874f591SEric Biggers 	      xts_xor_tweak_pre(req, true) ?:
26978105c7eSOndrej Mosnacek 	      crypto_skcipher_encrypt(subreq) ?:
270a874f591SEric Biggers 	      xts_xor_tweak_post(req, true);
2718083b1bfSArd Biesheuvel 
2728083b1bfSArd Biesheuvel 	if (err || likely((req->cryptlen % XTS_BLOCK_SIZE) == 0))
2738083b1bfSArd Biesheuvel 		return err;
2748083b1bfSArd Biesheuvel 
275a874f591SEric Biggers 	return xts_cts_final(req, crypto_skcipher_encrypt);
276f1c131b4SHerbert Xu }
277f1c131b4SHerbert Xu 
xts_decrypt(struct skcipher_request * req)278a874f591SEric Biggers static int xts_decrypt(struct skcipher_request *req)
279f1c131b4SHerbert Xu {
280a874f591SEric Biggers 	struct xts_request_ctx *rctx = skcipher_request_ctx(req);
28178105c7eSOndrej Mosnacek 	struct skcipher_request *subreq = &rctx->subreq;
2828083b1bfSArd Biesheuvel 	int err;
28378105c7eSOndrej Mosnacek 
284a874f591SEric Biggers 	err = xts_init_crypt(req, xts_decrypt_done) ?:
285a874f591SEric Biggers 	      xts_xor_tweak_pre(req, false) ?:
28678105c7eSOndrej Mosnacek 	      crypto_skcipher_decrypt(subreq) ?:
287a874f591SEric Biggers 	      xts_xor_tweak_post(req, false);
2888083b1bfSArd Biesheuvel 
2898083b1bfSArd Biesheuvel 	if (err || likely((req->cryptlen % XTS_BLOCK_SIZE) == 0))
2908083b1bfSArd Biesheuvel 		return err;
2918083b1bfSArd Biesheuvel 
292a874f591SEric Biggers 	return xts_cts_final(req, crypto_skcipher_decrypt);
293f19f5111SRik Snel }
294f19f5111SRik Snel 
xts_init_tfm(struct crypto_skcipher * tfm)295a874f591SEric Biggers static int xts_init_tfm(struct crypto_skcipher *tfm)
296f19f5111SRik Snel {
297f1c131b4SHerbert Xu 	struct skcipher_instance *inst = skcipher_alg_instance(tfm);
298f1c131b4SHerbert Xu 	struct xts_instance_ctx *ictx = skcipher_instance_ctx(inst);
299a874f591SEric Biggers 	struct xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
300f1c131b4SHerbert Xu 	struct crypto_skcipher *child;
301f1c131b4SHerbert Xu 	struct crypto_cipher *tweak;
302f19f5111SRik Snel 
303f1c131b4SHerbert Xu 	child = crypto_spawn_skcipher(&ictx->spawn);
304f1c131b4SHerbert Xu 	if (IS_ERR(child))
305f1c131b4SHerbert Xu 		return PTR_ERR(child);
306f19f5111SRik Snel 
307f1c131b4SHerbert Xu 	ctx->child = child;
308f1c131b4SHerbert Xu 
309*64170e83SEric Biggers 	tweak = crypto_spawn_cipher(&ictx->tweak_spawn);
310f1c131b4SHerbert Xu 	if (IS_ERR(tweak)) {
311f1c131b4SHerbert Xu 		crypto_free_skcipher(ctx->child);
312f1c131b4SHerbert Xu 		return PTR_ERR(tweak);
313f19f5111SRik Snel 	}
314f19f5111SRik Snel 
315f1c131b4SHerbert Xu 	ctx->tweak = tweak;
316f19f5111SRik Snel 
317f1c131b4SHerbert Xu 	crypto_skcipher_set_reqsize(tfm, crypto_skcipher_reqsize(child) +
318a874f591SEric Biggers 					 sizeof(struct xts_request_ctx));
319f19f5111SRik Snel 
320f19f5111SRik Snel 	return 0;
321f19f5111SRik Snel }
322f19f5111SRik Snel 
xts_exit_tfm(struct crypto_skcipher * tfm)323a874f591SEric Biggers static void xts_exit_tfm(struct crypto_skcipher *tfm)
324f19f5111SRik Snel {
325a874f591SEric Biggers 	struct xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
326f1c131b4SHerbert Xu 
327f1c131b4SHerbert Xu 	crypto_free_skcipher(ctx->child);
328f19f5111SRik Snel 	crypto_free_cipher(ctx->tweak);
329f19f5111SRik Snel }
330f19f5111SRik Snel 
xts_free_instance(struct skcipher_instance * inst)331a874f591SEric Biggers static void xts_free_instance(struct skcipher_instance *inst)
332f19f5111SRik Snel {
333a874f591SEric Biggers 	struct xts_instance_ctx *ictx = skcipher_instance_ctx(inst);
334a874f591SEric Biggers 
335a874f591SEric Biggers 	crypto_drop_skcipher(&ictx->spawn);
336*64170e83SEric Biggers 	crypto_drop_cipher(&ictx->tweak_spawn);
337f1c131b4SHerbert Xu 	kfree(inst);
338f19f5111SRik Snel }
339f19f5111SRik Snel 
xts_create(struct crypto_template * tmpl,struct rtattr ** tb)340a874f591SEric Biggers static int xts_create(struct crypto_template *tmpl, struct rtattr **tb)
341f19f5111SRik Snel {
342*64170e83SEric Biggers 	char name[CRYPTO_MAX_ALG_NAME];
343f1c131b4SHerbert Xu 	struct skcipher_instance *inst;
344f1c131b4SHerbert Xu 	struct xts_instance_ctx *ctx;
345f1c131b4SHerbert Xu 	struct skcipher_alg *alg;
346f1c131b4SHerbert Xu 	const char *cipher_name;
34789027579SHerbert Xu 	u32 mask;
348f1c131b4SHerbert Xu 	int err;
349f1c131b4SHerbert Xu 
3507bcb2c99SEric Biggers 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER, &mask);
3517bcb2c99SEric Biggers 	if (err)
3527bcb2c99SEric Biggers 		return err;
353f1c131b4SHerbert Xu 
354f1c131b4SHerbert Xu 	cipher_name = crypto_attr_alg_name(tb[1]);
355f1c131b4SHerbert Xu 	if (IS_ERR(cipher_name))
356f1c131b4SHerbert Xu 		return PTR_ERR(cipher_name);
357f1c131b4SHerbert Xu 
358f1c131b4SHerbert Xu 	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
359f1c131b4SHerbert Xu 	if (!inst)
360f1c131b4SHerbert Xu 		return -ENOMEM;
361f1c131b4SHerbert Xu 
362f1c131b4SHerbert Xu 	ctx = skcipher_instance_ctx(inst);
363f1c131b4SHerbert Xu 
364b9f76dddSEric Biggers 	err = crypto_grab_skcipher(&ctx->spawn, skcipher_crypto_instance(inst),
365b9f76dddSEric Biggers 				   cipher_name, 0, mask);
366f1c131b4SHerbert Xu 	if (err == -ENOENT) {
367f1c131b4SHerbert Xu 		err = -ENAMETOOLONG;
368*64170e83SEric Biggers 		if (snprintf(name, CRYPTO_MAX_ALG_NAME, "ecb(%s)",
369f1c131b4SHerbert Xu 			     cipher_name) >= CRYPTO_MAX_ALG_NAME)
370f1c131b4SHerbert Xu 			goto err_free_inst;
371f1c131b4SHerbert Xu 
372b9f76dddSEric Biggers 		err = crypto_grab_skcipher(&ctx->spawn,
373b9f76dddSEric Biggers 					   skcipher_crypto_instance(inst),
374*64170e83SEric Biggers 					   name, 0, mask);
375f1c131b4SHerbert Xu 	}
376f1c131b4SHerbert Xu 
377f1c131b4SHerbert Xu 	if (err)
378f1c131b4SHerbert Xu 		goto err_free_inst;
379f1c131b4SHerbert Xu 
380f1c131b4SHerbert Xu 	alg = crypto_skcipher_spawn_alg(&ctx->spawn);
381f1c131b4SHerbert Xu 
382f1c131b4SHerbert Xu 	err = -EINVAL;
383f1c131b4SHerbert Xu 	if (alg->base.cra_blocksize != XTS_BLOCK_SIZE)
384732e5409SEric Biggers 		goto err_free_inst;
385f1c131b4SHerbert Xu 
386f1c131b4SHerbert Xu 	if (crypto_skcipher_alg_ivsize(alg))
387732e5409SEric Biggers 		goto err_free_inst;
388f1c131b4SHerbert Xu 
389f1c131b4SHerbert Xu 	err = crypto_inst_setname(skcipher_crypto_instance(inst), "xts",
390f1c131b4SHerbert Xu 				  &alg->base);
391f1c131b4SHerbert Xu 	if (err)
392732e5409SEric Biggers 		goto err_free_inst;
393f1c131b4SHerbert Xu 
394f1c131b4SHerbert Xu 	err = -EINVAL;
395f1c131b4SHerbert Xu 	cipher_name = alg->base.cra_name;
396f1c131b4SHerbert Xu 
397f1c131b4SHerbert Xu 	/* Alas we screwed up the naming so we have to mangle the
398f1c131b4SHerbert Xu 	 * cipher name.
399f1c131b4SHerbert Xu 	 */
400f1c131b4SHerbert Xu 	if (!strncmp(cipher_name, "ecb(", 4)) {
401babb80b3SAzeem Shaikh 		int len;
402f1c131b4SHerbert Xu 
403*64170e83SEric Biggers 		len = strscpy(name, cipher_name + 4, sizeof(name));
404babb80b3SAzeem Shaikh 		if (len < 2)
405732e5409SEric Biggers 			goto err_free_inst;
406f1c131b4SHerbert Xu 
407*64170e83SEric Biggers 		if (name[len - 1] != ')')
408732e5409SEric Biggers 			goto err_free_inst;
409f1c131b4SHerbert Xu 
410*64170e83SEric Biggers 		name[len - 1] = 0;
411f1c131b4SHerbert Xu 
412f1c131b4SHerbert Xu 		if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
413*64170e83SEric Biggers 			     "xts(%s)", name) >= CRYPTO_MAX_ALG_NAME) {
4145125e4e8SChristophe Jaillet 			err = -ENAMETOOLONG;
415732e5409SEric Biggers 			goto err_free_inst;
4165125e4e8SChristophe Jaillet 		}
417f1c131b4SHerbert Xu 	} else
418732e5409SEric Biggers 		goto err_free_inst;
419f1c131b4SHerbert Xu 
420*64170e83SEric Biggers 	err = crypto_grab_cipher(&ctx->tweak_spawn,
421*64170e83SEric Biggers 				 skcipher_crypto_instance(inst), name, 0, mask);
422*64170e83SEric Biggers 	if (err)
423*64170e83SEric Biggers 		goto err_free_inst;
424*64170e83SEric Biggers 
425f1c131b4SHerbert Xu 	inst->alg.base.cra_priority = alg->base.cra_priority;
426f1c131b4SHerbert Xu 	inst->alg.base.cra_blocksize = XTS_BLOCK_SIZE;
427f1c131b4SHerbert Xu 	inst->alg.base.cra_alignmask = alg->base.cra_alignmask |
428f1c131b4SHerbert Xu 				       (__alignof__(u64) - 1);
429f1c131b4SHerbert Xu 
430f1c131b4SHerbert Xu 	inst->alg.ivsize = XTS_BLOCK_SIZE;
431f1c131b4SHerbert Xu 	inst->alg.min_keysize = crypto_skcipher_alg_min_keysize(alg) * 2;
432f1c131b4SHerbert Xu 	inst->alg.max_keysize = crypto_skcipher_alg_max_keysize(alg) * 2;
433f1c131b4SHerbert Xu 
434a874f591SEric Biggers 	inst->alg.base.cra_ctxsize = sizeof(struct xts_tfm_ctx);
435f1c131b4SHerbert Xu 
436a874f591SEric Biggers 	inst->alg.init = xts_init_tfm;
437a874f591SEric Biggers 	inst->alg.exit = xts_exit_tfm;
438f1c131b4SHerbert Xu 
439a874f591SEric Biggers 	inst->alg.setkey = xts_setkey;
440a874f591SEric Biggers 	inst->alg.encrypt = xts_encrypt;
441a874f591SEric Biggers 	inst->alg.decrypt = xts_decrypt;
442f1c131b4SHerbert Xu 
443a874f591SEric Biggers 	inst->free = xts_free_instance;
444f1c131b4SHerbert Xu 
445f1c131b4SHerbert Xu 	err = skcipher_register_instance(tmpl, inst);
446732e5409SEric Biggers 	if (err) {
447f1c131b4SHerbert Xu err_free_inst:
448a874f591SEric Biggers 		xts_free_instance(inst);
449732e5409SEric Biggers 	}
450732e5409SEric Biggers 	return err;
451f19f5111SRik Snel }
452f19f5111SRik Snel 
453a874f591SEric Biggers static struct crypto_template xts_tmpl = {
454f19f5111SRik Snel 	.name = "xts",
455a874f591SEric Biggers 	.create = xts_create,
456f19f5111SRik Snel 	.module = THIS_MODULE,
457f19f5111SRik Snel };
458f19f5111SRik Snel 
xts_module_init(void)459a874f591SEric Biggers static int __init xts_module_init(void)
460f19f5111SRik Snel {
461a874f591SEric Biggers 	return crypto_register_template(&xts_tmpl);
462f19f5111SRik Snel }
463f19f5111SRik Snel 
xts_module_exit(void)464a874f591SEric Biggers static void __exit xts_module_exit(void)
465f19f5111SRik Snel {
466a874f591SEric Biggers 	crypto_unregister_template(&xts_tmpl);
467f19f5111SRik Snel }
468f19f5111SRik Snel 
469a874f591SEric Biggers subsys_initcall(xts_module_init);
470a874f591SEric Biggers module_exit(xts_module_exit);
471f19f5111SRik Snel 
472f19f5111SRik Snel MODULE_LICENSE("GPL");
473f19f5111SRik Snel MODULE_DESCRIPTION("XTS block cipher mode");
4744943ba16SKees Cook MODULE_ALIAS_CRYPTO("xts");
4750eb76ba2SArd Biesheuvel MODULE_IMPORT_NS(CRYPTO_INTERNAL);
476dfe085d8SHerbert Xu MODULE_SOFTDEP("pre: ecb");
477