xref: /openbmc/linux/crypto/cts.c (revision 7185ad26)
176cb9521SKevin Coffman /*
276cb9521SKevin Coffman  * CTS: Cipher Text Stealing mode
376cb9521SKevin Coffman  *
476cb9521SKevin Coffman  * COPYRIGHT (c) 2008
576cb9521SKevin Coffman  * The Regents of the University of Michigan
676cb9521SKevin Coffman  * ALL RIGHTS RESERVED
776cb9521SKevin Coffman  *
876cb9521SKevin Coffman  * Permission is granted to use, copy, create derivative works
976cb9521SKevin Coffman  * and redistribute this software and such derivative works
1076cb9521SKevin Coffman  * for any purpose, so long as the name of The University of
1176cb9521SKevin Coffman  * Michigan is not used in any advertising or publicity
1276cb9521SKevin Coffman  * pertaining to the use of distribution of this software
1376cb9521SKevin Coffman  * without specific, written prior authorization.  If the
1476cb9521SKevin Coffman  * above copyright notice or any other identification of the
1576cb9521SKevin Coffman  * University of Michigan is included in any copy of any
1676cb9521SKevin Coffman  * portion of this software, then the disclaimer below must
1776cb9521SKevin Coffman  * also be included.
1876cb9521SKevin Coffman  *
1976cb9521SKevin Coffman  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
2076cb9521SKevin Coffman  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
2176cb9521SKevin Coffman  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
2276cb9521SKevin Coffman  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
2376cb9521SKevin Coffman  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
2476cb9521SKevin Coffman  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
2576cb9521SKevin Coffman  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
2676cb9521SKevin Coffman  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
2776cb9521SKevin Coffman  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
2876cb9521SKevin Coffman  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
2976cb9521SKevin Coffman  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
3076cb9521SKevin Coffman  * SUCH DAMAGES.
3176cb9521SKevin Coffman  */
3276cb9521SKevin Coffman 
3376cb9521SKevin Coffman /* Derived from various:
3476cb9521SKevin Coffman  *	Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
3576cb9521SKevin Coffman  */
3676cb9521SKevin Coffman 
3776cb9521SKevin Coffman /*
3876cb9521SKevin Coffman  * This is the Cipher Text Stealing mode as described by
3976cb9521SKevin Coffman  * Section 8 of rfc2040 and referenced by rfc3962.
4076cb9521SKevin Coffman  * rfc3962 includes errata information in its Appendix A.
4176cb9521SKevin Coffman  */
4276cb9521SKevin Coffman 
4376cb9521SKevin Coffman #include <crypto/algapi.h>
4476cb9521SKevin Coffman #include <linux/err.h>
4576cb9521SKevin Coffman #include <linux/init.h>
4676cb9521SKevin Coffman #include <linux/kernel.h>
4776cb9521SKevin Coffman #include <linux/log2.h>
4876cb9521SKevin Coffman #include <linux/module.h>
4976cb9521SKevin Coffman #include <linux/scatterlist.h>
5076cb9521SKevin Coffman #include <crypto/scatterwalk.h>
5176cb9521SKevin Coffman #include <linux/slab.h>
5276cb9521SKevin Coffman 
5376cb9521SKevin Coffman struct crypto_cts_ctx {
5476cb9521SKevin Coffman 	struct crypto_blkcipher *child;
5576cb9521SKevin Coffman };
5676cb9521SKevin Coffman 
5776cb9521SKevin Coffman static int crypto_cts_setkey(struct crypto_tfm *parent, const u8 *key,
5876cb9521SKevin Coffman 			     unsigned int keylen)
5976cb9521SKevin Coffman {
6076cb9521SKevin Coffman 	struct crypto_cts_ctx *ctx = crypto_tfm_ctx(parent);
6176cb9521SKevin Coffman 	struct crypto_blkcipher *child = ctx->child;
6276cb9521SKevin Coffman 	int err;
6376cb9521SKevin Coffman 
6476cb9521SKevin Coffman 	crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
6576cb9521SKevin Coffman 	crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) &
6676cb9521SKevin Coffman 				       CRYPTO_TFM_REQ_MASK);
6776cb9521SKevin Coffman 	err = crypto_blkcipher_setkey(child, key, keylen);
6876cb9521SKevin Coffman 	crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) &
6976cb9521SKevin Coffman 				     CRYPTO_TFM_RES_MASK);
7076cb9521SKevin Coffman 	return err;
7176cb9521SKevin Coffman }
7276cb9521SKevin Coffman 
7376cb9521SKevin Coffman static int cts_cbc_encrypt(struct crypto_cts_ctx *ctx,
7476cb9521SKevin Coffman 			   struct blkcipher_desc *desc,
7576cb9521SKevin Coffman 			   struct scatterlist *dst,
7676cb9521SKevin Coffman 			   struct scatterlist *src,
7776cb9521SKevin Coffman 			   unsigned int offset,
7876cb9521SKevin Coffman 			   unsigned int nbytes)
7976cb9521SKevin Coffman {
8076cb9521SKevin Coffman 	int bsize = crypto_blkcipher_blocksize(desc->tfm);
8176cb9521SKevin Coffman 	u8 tmp[bsize], tmp2[bsize];
8276cb9521SKevin Coffman 	struct blkcipher_desc lcldesc;
8376cb9521SKevin Coffman 	struct scatterlist sgsrc[1], sgdst[1];
8476cb9521SKevin Coffman 	int lastn = nbytes - bsize;
8576cb9521SKevin Coffman 	u8 iv[bsize];
8676cb9521SKevin Coffman 	u8 s[bsize * 2], d[bsize * 2];
8776cb9521SKevin Coffman 	int err;
8876cb9521SKevin Coffman 
8976cb9521SKevin Coffman 	if (lastn < 0)
9076cb9521SKevin Coffman 		return -EINVAL;
9176cb9521SKevin Coffman 
92c4913c7bSAlexey Dobriyan 	sg_init_table(sgsrc, 1);
93c4913c7bSAlexey Dobriyan 	sg_init_table(sgdst, 1);
94c4913c7bSAlexey Dobriyan 
9576cb9521SKevin Coffman 	memset(s, 0, sizeof(s));
9676cb9521SKevin Coffman 	scatterwalk_map_and_copy(s, src, offset, nbytes, 0);
9776cb9521SKevin Coffman 
9876cb9521SKevin Coffman 	memcpy(iv, desc->info, bsize);
9976cb9521SKevin Coffman 
10076cb9521SKevin Coffman 	lcldesc.tfm = ctx->child;
10176cb9521SKevin Coffman 	lcldesc.info = iv;
10276cb9521SKevin Coffman 	lcldesc.flags = desc->flags;
10376cb9521SKevin Coffman 
10476cb9521SKevin Coffman 	sg_set_buf(&sgsrc[0], s, bsize);
10576cb9521SKevin Coffman 	sg_set_buf(&sgdst[0], tmp, bsize);
10676cb9521SKevin Coffman 	err = crypto_blkcipher_encrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
10776cb9521SKevin Coffman 
10876cb9521SKevin Coffman 	memcpy(d + bsize, tmp, lastn);
10976cb9521SKevin Coffman 
11076cb9521SKevin Coffman 	lcldesc.info = tmp;
11176cb9521SKevin Coffman 
11276cb9521SKevin Coffman 	sg_set_buf(&sgsrc[0], s + bsize, bsize);
11376cb9521SKevin Coffman 	sg_set_buf(&sgdst[0], tmp2, bsize);
11476cb9521SKevin Coffman 	err = crypto_blkcipher_encrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
11576cb9521SKevin Coffman 
11676cb9521SKevin Coffman 	memcpy(d, tmp2, bsize);
11776cb9521SKevin Coffman 
11876cb9521SKevin Coffman 	scatterwalk_map_and_copy(d, dst, offset, nbytes, 1);
11976cb9521SKevin Coffman 
12076cb9521SKevin Coffman 	memcpy(desc->info, tmp2, bsize);
12176cb9521SKevin Coffman 
12276cb9521SKevin Coffman 	return err;
12376cb9521SKevin Coffman }
12476cb9521SKevin Coffman 
12576cb9521SKevin Coffman static int crypto_cts_encrypt(struct blkcipher_desc *desc,
12676cb9521SKevin Coffman 			      struct scatterlist *dst, struct scatterlist *src,
12776cb9521SKevin Coffman 			      unsigned int nbytes)
12876cb9521SKevin Coffman {
12976cb9521SKevin Coffman 	struct crypto_cts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
13076cb9521SKevin Coffman 	int bsize = crypto_blkcipher_blocksize(desc->tfm);
13176cb9521SKevin Coffman 	int tot_blocks = (nbytes + bsize - 1) / bsize;
13276cb9521SKevin Coffman 	int cbc_blocks = tot_blocks > 2 ? tot_blocks - 2 : 0;
13376cb9521SKevin Coffman 	struct blkcipher_desc lcldesc;
13476cb9521SKevin Coffman 	int err;
13576cb9521SKevin Coffman 
13676cb9521SKevin Coffman 	lcldesc.tfm = ctx->child;
13776cb9521SKevin Coffman 	lcldesc.info = desc->info;
13876cb9521SKevin Coffman 	lcldesc.flags = desc->flags;
13976cb9521SKevin Coffman 
14076cb9521SKevin Coffman 	if (tot_blocks == 1) {
14176cb9521SKevin Coffman 		err = crypto_blkcipher_encrypt_iv(&lcldesc, dst, src, bsize);
14276cb9521SKevin Coffman 	} else if (nbytes <= bsize * 2) {
14376cb9521SKevin Coffman 		err = cts_cbc_encrypt(ctx, desc, dst, src, 0, nbytes);
14476cb9521SKevin Coffman 	} else {
14576cb9521SKevin Coffman 		/* do normal function for tot_blocks - 2 */
14676cb9521SKevin Coffman 		err = crypto_blkcipher_encrypt_iv(&lcldesc, dst, src,
14776cb9521SKevin Coffman 							cbc_blocks * bsize);
14876cb9521SKevin Coffman 		if (err == 0) {
14976cb9521SKevin Coffman 			/* do cts for final two blocks */
15076cb9521SKevin Coffman 			err = cts_cbc_encrypt(ctx, desc, dst, src,
15176cb9521SKevin Coffman 						cbc_blocks * bsize,
15276cb9521SKevin Coffman 						nbytes - (cbc_blocks * bsize));
15376cb9521SKevin Coffman 		}
15476cb9521SKevin Coffman 	}
15576cb9521SKevin Coffman 
15676cb9521SKevin Coffman 	return err;
15776cb9521SKevin Coffman }
15876cb9521SKevin Coffman 
15976cb9521SKevin Coffman static int cts_cbc_decrypt(struct crypto_cts_ctx *ctx,
16076cb9521SKevin Coffman 			   struct blkcipher_desc *desc,
16176cb9521SKevin Coffman 			   struct scatterlist *dst,
16276cb9521SKevin Coffman 			   struct scatterlist *src,
16376cb9521SKevin Coffman 			   unsigned int offset,
16476cb9521SKevin Coffman 			   unsigned int nbytes)
16576cb9521SKevin Coffman {
16676cb9521SKevin Coffman 	int bsize = crypto_blkcipher_blocksize(desc->tfm);
16776cb9521SKevin Coffman 	u8 tmp[bsize];
16876cb9521SKevin Coffman 	struct blkcipher_desc lcldesc;
16976cb9521SKevin Coffman 	struct scatterlist sgsrc[1], sgdst[1];
17076cb9521SKevin Coffman 	int lastn = nbytes - bsize;
17176cb9521SKevin Coffman 	u8 iv[bsize];
17276cb9521SKevin Coffman 	u8 s[bsize * 2], d[bsize * 2];
17376cb9521SKevin Coffman 	int err;
17476cb9521SKevin Coffman 
17576cb9521SKevin Coffman 	if (lastn < 0)
17676cb9521SKevin Coffman 		return -EINVAL;
17776cb9521SKevin Coffman 
178c4913c7bSAlexey Dobriyan 	sg_init_table(sgsrc, 1);
179c4913c7bSAlexey Dobriyan 	sg_init_table(sgdst, 1);
180c4913c7bSAlexey Dobriyan 
18176cb9521SKevin Coffman 	scatterwalk_map_and_copy(s, src, offset, nbytes, 0);
18276cb9521SKevin Coffman 
18376cb9521SKevin Coffman 	lcldesc.tfm = ctx->child;
18476cb9521SKevin Coffman 	lcldesc.info = iv;
18576cb9521SKevin Coffman 	lcldesc.flags = desc->flags;
18676cb9521SKevin Coffman 
18776cb9521SKevin Coffman 	/* 1. Decrypt Cn-1 (s) to create Dn (tmp)*/
18876cb9521SKevin Coffman 	memset(iv, 0, sizeof(iv));
18976cb9521SKevin Coffman 	sg_set_buf(&sgsrc[0], s, bsize);
19076cb9521SKevin Coffman 	sg_set_buf(&sgdst[0], tmp, bsize);
19176cb9521SKevin Coffman 	err = crypto_blkcipher_decrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
19276cb9521SKevin Coffman 	if (err)
19376cb9521SKevin Coffman 		return err;
19476cb9521SKevin Coffman 	/* 2. Pad Cn with zeros at the end to create C of length BB */
19576cb9521SKevin Coffman 	memset(iv, 0, sizeof(iv));
19676cb9521SKevin Coffman 	memcpy(iv, s + bsize, lastn);
19776cb9521SKevin Coffman 	/* 3. Exclusive-or Dn (tmp) with C (iv) to create Xn (tmp) */
19876cb9521SKevin Coffman 	crypto_xor(tmp, iv, bsize);
19976cb9521SKevin Coffman 	/* 4. Select the first Ln bytes of Xn (tmp) to create Pn */
20076cb9521SKevin Coffman 	memcpy(d + bsize, tmp, lastn);
20176cb9521SKevin Coffman 
20276cb9521SKevin Coffman 	/* 5. Append the tail (BB - Ln) bytes of Xn (tmp) to Cn to create En */
20376cb9521SKevin Coffman 	memcpy(s + bsize + lastn, tmp + lastn, bsize - lastn);
20476cb9521SKevin Coffman 	/* 6. Decrypt En to create Pn-1 */
2057185ad26SDaniel Borkmann 	memzero_explicit(iv, sizeof(iv));
2067185ad26SDaniel Borkmann 
20776cb9521SKevin Coffman 	sg_set_buf(&sgsrc[0], s + bsize, bsize);
20876cb9521SKevin Coffman 	sg_set_buf(&sgdst[0], d, bsize);
20976cb9521SKevin Coffman 	err = crypto_blkcipher_decrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
21076cb9521SKevin Coffman 
21176cb9521SKevin Coffman 	/* XOR with previous block */
21276cb9521SKevin Coffman 	crypto_xor(d, desc->info, bsize);
21376cb9521SKevin Coffman 
21476cb9521SKevin Coffman 	scatterwalk_map_and_copy(d, dst, offset, nbytes, 1);
21576cb9521SKevin Coffman 
21676cb9521SKevin Coffman 	memcpy(desc->info, s, bsize);
21776cb9521SKevin Coffman 	return err;
21876cb9521SKevin Coffman }
21976cb9521SKevin Coffman 
22076cb9521SKevin Coffman static int crypto_cts_decrypt(struct blkcipher_desc *desc,
22176cb9521SKevin Coffman 			      struct scatterlist *dst, struct scatterlist *src,
22276cb9521SKevin Coffman 			      unsigned int nbytes)
22376cb9521SKevin Coffman {
22476cb9521SKevin Coffman 	struct crypto_cts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
22576cb9521SKevin Coffman 	int bsize = crypto_blkcipher_blocksize(desc->tfm);
22676cb9521SKevin Coffman 	int tot_blocks = (nbytes + bsize - 1) / bsize;
22776cb9521SKevin Coffman 	int cbc_blocks = tot_blocks > 2 ? tot_blocks - 2 : 0;
22876cb9521SKevin Coffman 	struct blkcipher_desc lcldesc;
22976cb9521SKevin Coffman 	int err;
23076cb9521SKevin Coffman 
23176cb9521SKevin Coffman 	lcldesc.tfm = ctx->child;
23276cb9521SKevin Coffman 	lcldesc.info = desc->info;
23376cb9521SKevin Coffman 	lcldesc.flags = desc->flags;
23476cb9521SKevin Coffman 
23576cb9521SKevin Coffman 	if (tot_blocks == 1) {
23676cb9521SKevin Coffman 		err = crypto_blkcipher_decrypt_iv(&lcldesc, dst, src, bsize);
23776cb9521SKevin Coffman 	} else if (nbytes <= bsize * 2) {
23876cb9521SKevin Coffman 		err = cts_cbc_decrypt(ctx, desc, dst, src, 0, nbytes);
23976cb9521SKevin Coffman 	} else {
24076cb9521SKevin Coffman 		/* do normal function for tot_blocks - 2 */
24176cb9521SKevin Coffman 		err = crypto_blkcipher_decrypt_iv(&lcldesc, dst, src,
24276cb9521SKevin Coffman 							cbc_blocks * bsize);
24376cb9521SKevin Coffman 		if (err == 0) {
24476cb9521SKevin Coffman 			/* do cts for final two blocks */
24576cb9521SKevin Coffman 			err = cts_cbc_decrypt(ctx, desc, dst, src,
24676cb9521SKevin Coffman 						cbc_blocks * bsize,
24776cb9521SKevin Coffman 						nbytes - (cbc_blocks * bsize));
24876cb9521SKevin Coffman 		}
24976cb9521SKevin Coffman 	}
25076cb9521SKevin Coffman 	return err;
25176cb9521SKevin Coffman }
25276cb9521SKevin Coffman 
25376cb9521SKevin Coffman static int crypto_cts_init_tfm(struct crypto_tfm *tfm)
25476cb9521SKevin Coffman {
25576cb9521SKevin Coffman 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
25676cb9521SKevin Coffman 	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
25776cb9521SKevin Coffman 	struct crypto_cts_ctx *ctx = crypto_tfm_ctx(tfm);
25876cb9521SKevin Coffman 	struct crypto_blkcipher *cipher;
25976cb9521SKevin Coffman 
26076cb9521SKevin Coffman 	cipher = crypto_spawn_blkcipher(spawn);
26176cb9521SKevin Coffman 	if (IS_ERR(cipher))
26276cb9521SKevin Coffman 		return PTR_ERR(cipher);
26376cb9521SKevin Coffman 
26476cb9521SKevin Coffman 	ctx->child = cipher;
26576cb9521SKevin Coffman 	return 0;
26676cb9521SKevin Coffman }
26776cb9521SKevin Coffman 
26876cb9521SKevin Coffman static void crypto_cts_exit_tfm(struct crypto_tfm *tfm)
26976cb9521SKevin Coffman {
27076cb9521SKevin Coffman 	struct crypto_cts_ctx *ctx = crypto_tfm_ctx(tfm);
27176cb9521SKevin Coffman 	crypto_free_blkcipher(ctx->child);
27276cb9521SKevin Coffman }
27376cb9521SKevin Coffman 
27476cb9521SKevin Coffman static struct crypto_instance *crypto_cts_alloc(struct rtattr **tb)
27576cb9521SKevin Coffman {
27676cb9521SKevin Coffman 	struct crypto_instance *inst;
27776cb9521SKevin Coffman 	struct crypto_alg *alg;
27876cb9521SKevin Coffman 	int err;
27976cb9521SKevin Coffman 
28076cb9521SKevin Coffman 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
28176cb9521SKevin Coffman 	if (err)
28276cb9521SKevin Coffman 		return ERR_PTR(err);
28376cb9521SKevin Coffman 
28476cb9521SKevin Coffman 	alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_BLKCIPHER,
28576cb9521SKevin Coffman 				  CRYPTO_ALG_TYPE_MASK);
28676cb9521SKevin Coffman 	if (IS_ERR(alg))
2873e8afe35SJulia Lawall 		return ERR_CAST(alg);
28876cb9521SKevin Coffman 
28976cb9521SKevin Coffman 	inst = ERR_PTR(-EINVAL);
29076cb9521SKevin Coffman 	if (!is_power_of_2(alg->cra_blocksize))
29176cb9521SKevin Coffman 		goto out_put_alg;
29276cb9521SKevin Coffman 
29376cb9521SKevin Coffman 	inst = crypto_alloc_instance("cts", alg);
29476cb9521SKevin Coffman 	if (IS_ERR(inst))
29576cb9521SKevin Coffman 		goto out_put_alg;
29676cb9521SKevin Coffman 
29776cb9521SKevin Coffman 	inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
29876cb9521SKevin Coffman 	inst->alg.cra_priority = alg->cra_priority;
29976cb9521SKevin Coffman 	inst->alg.cra_blocksize = alg->cra_blocksize;
30076cb9521SKevin Coffman 	inst->alg.cra_alignmask = alg->cra_alignmask;
30176cb9521SKevin Coffman 	inst->alg.cra_type = &crypto_blkcipher_type;
30276cb9521SKevin Coffman 
30376cb9521SKevin Coffman 	/* We access the data as u32s when xoring. */
30476cb9521SKevin Coffman 	inst->alg.cra_alignmask |= __alignof__(u32) - 1;
30576cb9521SKevin Coffman 
30676cb9521SKevin Coffman 	inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
30776cb9521SKevin Coffman 	inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
30876cb9521SKevin Coffman 	inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
30976cb9521SKevin Coffman 
31076cb9521SKevin Coffman 	inst->alg.cra_blkcipher.geniv = "seqiv";
31176cb9521SKevin Coffman 
31276cb9521SKevin Coffman 	inst->alg.cra_ctxsize = sizeof(struct crypto_cts_ctx);
31376cb9521SKevin Coffman 
31476cb9521SKevin Coffman 	inst->alg.cra_init = crypto_cts_init_tfm;
31576cb9521SKevin Coffman 	inst->alg.cra_exit = crypto_cts_exit_tfm;
31676cb9521SKevin Coffman 
31776cb9521SKevin Coffman 	inst->alg.cra_blkcipher.setkey = crypto_cts_setkey;
31876cb9521SKevin Coffman 	inst->alg.cra_blkcipher.encrypt = crypto_cts_encrypt;
31976cb9521SKevin Coffman 	inst->alg.cra_blkcipher.decrypt = crypto_cts_decrypt;
32076cb9521SKevin Coffman 
32176cb9521SKevin Coffman out_put_alg:
32276cb9521SKevin Coffman 	crypto_mod_put(alg);
32376cb9521SKevin Coffman 	return inst;
32476cb9521SKevin Coffman }
32576cb9521SKevin Coffman 
32676cb9521SKevin Coffman static void crypto_cts_free(struct crypto_instance *inst)
32776cb9521SKevin Coffman {
32876cb9521SKevin Coffman 	crypto_drop_spawn(crypto_instance_ctx(inst));
32976cb9521SKevin Coffman 	kfree(inst);
33076cb9521SKevin Coffman }
33176cb9521SKevin Coffman 
33276cb9521SKevin Coffman static struct crypto_template crypto_cts_tmpl = {
33376cb9521SKevin Coffman 	.name = "cts",
33476cb9521SKevin Coffman 	.alloc = crypto_cts_alloc,
33576cb9521SKevin Coffman 	.free = crypto_cts_free,
33676cb9521SKevin Coffman 	.module = THIS_MODULE,
33776cb9521SKevin Coffman };
33876cb9521SKevin Coffman 
33976cb9521SKevin Coffman static int __init crypto_cts_module_init(void)
34076cb9521SKevin Coffman {
34176cb9521SKevin Coffman 	return crypto_register_template(&crypto_cts_tmpl);
34276cb9521SKevin Coffman }
34376cb9521SKevin Coffman 
34476cb9521SKevin Coffman static void __exit crypto_cts_module_exit(void)
34576cb9521SKevin Coffman {
34676cb9521SKevin Coffman 	crypto_unregister_template(&crypto_cts_tmpl);
34776cb9521SKevin Coffman }
34876cb9521SKevin Coffman 
34976cb9521SKevin Coffman module_init(crypto_cts_module_init);
35076cb9521SKevin Coffman module_exit(crypto_cts_module_exit);
35176cb9521SKevin Coffman 
35276cb9521SKevin Coffman MODULE_LICENSE("Dual BSD/GPL");
35376cb9521SKevin Coffman MODULE_DESCRIPTION("CTS-CBC CipherText Stealing for CBC");
354