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