xref: /linux/crypto/xcbc.c (revision ebc610e5bc76df073221e64e86c3f7533a09ea40)
1333b0d7eSKazunori MIYAZAWA /*
2333b0d7eSKazunori MIYAZAWA  * Copyright (C)2006 USAGI/WIDE Project
3333b0d7eSKazunori MIYAZAWA  *
4333b0d7eSKazunori MIYAZAWA  * This program is free software; you can redistribute it and/or modify
5333b0d7eSKazunori MIYAZAWA  * it under the terms of the GNU General Public License as published by
6333b0d7eSKazunori MIYAZAWA  * the Free Software Foundation; either version 2 of the License, or
7333b0d7eSKazunori MIYAZAWA  * (at your option) any later version.
8333b0d7eSKazunori MIYAZAWA  *
9333b0d7eSKazunori MIYAZAWA  * This program is distributed in the hope that it will be useful,
10333b0d7eSKazunori MIYAZAWA  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11333b0d7eSKazunori MIYAZAWA  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12333b0d7eSKazunori MIYAZAWA  * GNU General Public License for more details.
13333b0d7eSKazunori MIYAZAWA  *
14333b0d7eSKazunori MIYAZAWA  * You should have received a copy of the GNU General Public License
15333b0d7eSKazunori MIYAZAWA  * along with this program; if not, write to the Free Software
16333b0d7eSKazunori MIYAZAWA  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17333b0d7eSKazunori MIYAZAWA  *
18333b0d7eSKazunori MIYAZAWA  * Author:
19333b0d7eSKazunori MIYAZAWA  * 	Kazunori Miyazawa <miyazawa@linux-ipv6.org>
20333b0d7eSKazunori MIYAZAWA  */
21333b0d7eSKazunori MIYAZAWA 
22333b0d7eSKazunori MIYAZAWA #include <linux/crypto.h>
23333b0d7eSKazunori MIYAZAWA #include <linux/err.h>
24fb469840SHerbert Xu #include <linux/hardirq.h>
25333b0d7eSKazunori MIYAZAWA #include <linux/kernel.h>
26333b0d7eSKazunori MIYAZAWA #include <linux/mm.h>
27333b0d7eSKazunori MIYAZAWA #include <linux/rtnetlink.h>
28333b0d7eSKazunori MIYAZAWA #include <linux/slab.h>
29333b0d7eSKazunori MIYAZAWA #include <linux/scatterlist.h>
30333b0d7eSKazunori MIYAZAWA #include "internal.h"
31333b0d7eSKazunori MIYAZAWA 
325b37538aSAdrian Bunk static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101,
33333b0d7eSKazunori MIYAZAWA 			   0x02020202, 0x02020202, 0x02020202, 0x02020202,
34333b0d7eSKazunori MIYAZAWA 			   0x03030303, 0x03030303, 0x03030303, 0x03030303};
35333b0d7eSKazunori MIYAZAWA /*
36333b0d7eSKazunori MIYAZAWA  * +------------------------
37333b0d7eSKazunori MIYAZAWA  * | <parent tfm>
38333b0d7eSKazunori MIYAZAWA  * +------------------------
39333b0d7eSKazunori MIYAZAWA  * | crypto_xcbc_ctx
40333b0d7eSKazunori MIYAZAWA  * +------------------------
41333b0d7eSKazunori MIYAZAWA  * | odds (block size)
42333b0d7eSKazunori MIYAZAWA  * +------------------------
43333b0d7eSKazunori MIYAZAWA  * | prev (block size)
44333b0d7eSKazunori MIYAZAWA  * +------------------------
45333b0d7eSKazunori MIYAZAWA  * | key (block size)
46333b0d7eSKazunori MIYAZAWA  * +------------------------
47333b0d7eSKazunori MIYAZAWA  * | consts (block size * 3)
48333b0d7eSKazunori MIYAZAWA  * +------------------------
49333b0d7eSKazunori MIYAZAWA  */
50333b0d7eSKazunori MIYAZAWA struct crypto_xcbc_ctx {
516b701ddeSHerbert Xu 	struct crypto_cipher *child;
52333b0d7eSKazunori MIYAZAWA 	u8 *odds;
53333b0d7eSKazunori MIYAZAWA 	u8 *prev;
54333b0d7eSKazunori MIYAZAWA 	u8 *key;
55333b0d7eSKazunori MIYAZAWA 	u8 *consts;
56333b0d7eSKazunori MIYAZAWA 	void (*xor)(u8 *a, const u8 *b, unsigned int bs);
57333b0d7eSKazunori MIYAZAWA 	unsigned int keylen;
58333b0d7eSKazunori MIYAZAWA 	unsigned int len;
59333b0d7eSKazunori MIYAZAWA };
60333b0d7eSKazunori MIYAZAWA 
61333b0d7eSKazunori MIYAZAWA static void xor_128(u8 *a, const u8 *b, unsigned int bs)
62333b0d7eSKazunori MIYAZAWA {
63333b0d7eSKazunori MIYAZAWA 	((u32 *)a)[0] ^= ((u32 *)b)[0];
64333b0d7eSKazunori MIYAZAWA 	((u32 *)a)[1] ^= ((u32 *)b)[1];
65333b0d7eSKazunori MIYAZAWA 	((u32 *)a)[2] ^= ((u32 *)b)[2];
66333b0d7eSKazunori MIYAZAWA 	((u32 *)a)[3] ^= ((u32 *)b)[3];
67333b0d7eSKazunori MIYAZAWA }
68333b0d7eSKazunori MIYAZAWA 
69333b0d7eSKazunori MIYAZAWA static int _crypto_xcbc_digest_setkey(struct crypto_hash *parent,
70333b0d7eSKazunori MIYAZAWA 				      struct crypto_xcbc_ctx *ctx)
71333b0d7eSKazunori MIYAZAWA {
72333b0d7eSKazunori MIYAZAWA 	int bs = crypto_hash_blocksize(parent);
73333b0d7eSKazunori MIYAZAWA 	int err = 0;
74333b0d7eSKazunori MIYAZAWA 	u8 key1[bs];
75333b0d7eSKazunori MIYAZAWA 
76333b0d7eSKazunori MIYAZAWA 	if ((err = crypto_cipher_setkey(ctx->child, ctx->key, ctx->keylen)))
77333b0d7eSKazunori MIYAZAWA 	    return err;
78333b0d7eSKazunori MIYAZAWA 
796b701ddeSHerbert Xu 	crypto_cipher_encrypt_one(ctx->child, key1, ctx->consts);
80333b0d7eSKazunori MIYAZAWA 
81333b0d7eSKazunori MIYAZAWA 	return crypto_cipher_setkey(ctx->child, key1, bs);
82333b0d7eSKazunori MIYAZAWA }
83333b0d7eSKazunori MIYAZAWA 
84333b0d7eSKazunori MIYAZAWA static int crypto_xcbc_digest_setkey(struct crypto_hash *parent,
85333b0d7eSKazunori MIYAZAWA 				     const u8 *inkey, unsigned int keylen)
86333b0d7eSKazunori MIYAZAWA {
87333b0d7eSKazunori MIYAZAWA 	struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
88333b0d7eSKazunori MIYAZAWA 
896b701ddeSHerbert Xu 	if (keylen != crypto_cipher_blocksize(ctx->child))
90333b0d7eSKazunori MIYAZAWA 		return -EINVAL;
91333b0d7eSKazunori MIYAZAWA 
92333b0d7eSKazunori MIYAZAWA 	ctx->keylen = keylen;
93333b0d7eSKazunori MIYAZAWA 	memcpy(ctx->key, inkey, keylen);
94333b0d7eSKazunori MIYAZAWA 	ctx->consts = (u8*)ks;
95333b0d7eSKazunori MIYAZAWA 
96333b0d7eSKazunori MIYAZAWA 	return _crypto_xcbc_digest_setkey(parent, ctx);
97333b0d7eSKazunori MIYAZAWA }
98333b0d7eSKazunori MIYAZAWA 
995b37538aSAdrian Bunk static int crypto_xcbc_digest_init(struct hash_desc *pdesc)
100333b0d7eSKazunori MIYAZAWA {
101333b0d7eSKazunori MIYAZAWA 	struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(pdesc->tfm);
102333b0d7eSKazunori MIYAZAWA 	int bs = crypto_hash_blocksize(pdesc->tfm);
103333b0d7eSKazunori MIYAZAWA 
104333b0d7eSKazunori MIYAZAWA 	ctx->len = 0;
105333b0d7eSKazunori MIYAZAWA 	memset(ctx->odds, 0, bs);
106333b0d7eSKazunori MIYAZAWA 	memset(ctx->prev, 0, bs);
107333b0d7eSKazunori MIYAZAWA 
108333b0d7eSKazunori MIYAZAWA 	return 0;
109333b0d7eSKazunori MIYAZAWA }
110333b0d7eSKazunori MIYAZAWA 
111fb469840SHerbert Xu static int crypto_xcbc_digest_update2(struct hash_desc *pdesc,
1125b37538aSAdrian Bunk 				      struct scatterlist *sg,
1135b37538aSAdrian Bunk 				      unsigned int nbytes)
114333b0d7eSKazunori MIYAZAWA {
115333b0d7eSKazunori MIYAZAWA 	struct crypto_hash *parent = pdesc->tfm;
116333b0d7eSKazunori MIYAZAWA 	struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
1176b701ddeSHerbert Xu 	struct crypto_cipher *tfm = ctx->child;
118333b0d7eSKazunori MIYAZAWA 	int bs = crypto_hash_blocksize(parent);
119333b0d7eSKazunori MIYAZAWA 	unsigned int i = 0;
120333b0d7eSKazunori MIYAZAWA 
121333b0d7eSKazunori MIYAZAWA 	do {
122333b0d7eSKazunori MIYAZAWA 
123333b0d7eSKazunori MIYAZAWA 		struct page *pg = sg[i].page;
124333b0d7eSKazunori MIYAZAWA 		unsigned int offset = sg[i].offset;
125333b0d7eSKazunori MIYAZAWA 		unsigned int slen = sg[i].length;
126333b0d7eSKazunori MIYAZAWA 
127333b0d7eSKazunori MIYAZAWA 		while (slen > 0) {
128333b0d7eSKazunori MIYAZAWA 			unsigned int len = min(slen, ((unsigned int)(PAGE_SIZE)) - offset);
129333b0d7eSKazunori MIYAZAWA 			char *p = crypto_kmap(pg, 0) + offset;
130333b0d7eSKazunori MIYAZAWA 
131333b0d7eSKazunori MIYAZAWA 			/* checking the data can fill the block */
132333b0d7eSKazunori MIYAZAWA 			if ((ctx->len + len) <= bs) {
133333b0d7eSKazunori MIYAZAWA 				memcpy(ctx->odds + ctx->len, p, len);
134333b0d7eSKazunori MIYAZAWA 				ctx->len += len;
135333b0d7eSKazunori MIYAZAWA 				slen -= len;
136333b0d7eSKazunori MIYAZAWA 
137333b0d7eSKazunori MIYAZAWA 				/* checking the rest of the page */
138333b0d7eSKazunori MIYAZAWA 				if (len + offset >= PAGE_SIZE) {
139333b0d7eSKazunori MIYAZAWA 					offset = 0;
140333b0d7eSKazunori MIYAZAWA 					pg++;
141333b0d7eSKazunori MIYAZAWA 				} else
142333b0d7eSKazunori MIYAZAWA 					offset += len;
143333b0d7eSKazunori MIYAZAWA 
144333b0d7eSKazunori MIYAZAWA 				crypto_kunmap(p, 0);
1456b701ddeSHerbert Xu 				crypto_yield(pdesc->flags);
146333b0d7eSKazunori MIYAZAWA 				continue;
147333b0d7eSKazunori MIYAZAWA 			}
148333b0d7eSKazunori MIYAZAWA 
149333b0d7eSKazunori MIYAZAWA 			/* filling odds with new data and encrypting it */
150333b0d7eSKazunori MIYAZAWA 			memcpy(ctx->odds + ctx->len, p, bs - ctx->len);
151333b0d7eSKazunori MIYAZAWA 			len -= bs - ctx->len;
152333b0d7eSKazunori MIYAZAWA 			p += bs - ctx->len;
153333b0d7eSKazunori MIYAZAWA 
154333b0d7eSKazunori MIYAZAWA 			ctx->xor(ctx->prev, ctx->odds, bs);
1556b701ddeSHerbert Xu 			crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev);
156333b0d7eSKazunori MIYAZAWA 
157333b0d7eSKazunori MIYAZAWA 			/* clearing the length */
158333b0d7eSKazunori MIYAZAWA 			ctx->len = 0;
159333b0d7eSKazunori MIYAZAWA 
160333b0d7eSKazunori MIYAZAWA 			/* encrypting the rest of data */
161333b0d7eSKazunori MIYAZAWA 			while (len > bs) {
162333b0d7eSKazunori MIYAZAWA 				ctx->xor(ctx->prev, p, bs);
1636b701ddeSHerbert Xu 				crypto_cipher_encrypt_one(tfm, ctx->prev,
1646b701ddeSHerbert Xu 							  ctx->prev);
165333b0d7eSKazunori MIYAZAWA 				p += bs;
166333b0d7eSKazunori MIYAZAWA 				len -= bs;
167333b0d7eSKazunori MIYAZAWA 			}
168333b0d7eSKazunori MIYAZAWA 
169333b0d7eSKazunori MIYAZAWA 			/* keeping the surplus of blocksize */
170333b0d7eSKazunori MIYAZAWA 			if (len) {
171333b0d7eSKazunori MIYAZAWA 				memcpy(ctx->odds, p, len);
172333b0d7eSKazunori MIYAZAWA 				ctx->len = len;
173333b0d7eSKazunori MIYAZAWA 			}
174333b0d7eSKazunori MIYAZAWA 			crypto_kunmap(p, 0);
1756b701ddeSHerbert Xu 			crypto_yield(pdesc->flags);
176333b0d7eSKazunori MIYAZAWA 			slen -= min(slen, ((unsigned int)(PAGE_SIZE)) - offset);
177333b0d7eSKazunori MIYAZAWA 			offset = 0;
178333b0d7eSKazunori MIYAZAWA 			pg++;
179333b0d7eSKazunori MIYAZAWA 		}
180333b0d7eSKazunori MIYAZAWA 		nbytes-=sg[i].length;
181333b0d7eSKazunori MIYAZAWA 		i++;
182333b0d7eSKazunori MIYAZAWA 	} while (nbytes>0);
183333b0d7eSKazunori MIYAZAWA 
184333b0d7eSKazunori MIYAZAWA 	return 0;
185333b0d7eSKazunori MIYAZAWA }
186333b0d7eSKazunori MIYAZAWA 
187fb469840SHerbert Xu static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
188fb469840SHerbert Xu 				     struct scatterlist *sg,
189fb469840SHerbert Xu 				     unsigned int nbytes)
190fb469840SHerbert Xu {
191fb469840SHerbert Xu 	if (WARN_ON_ONCE(in_irq()))
192fb469840SHerbert Xu 		return -EDEADLK;
193fb469840SHerbert Xu 	return crypto_xcbc_digest_update2(pdesc, sg, nbytes);
194fb469840SHerbert Xu }
195fb469840SHerbert Xu 
1965b37538aSAdrian Bunk static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out)
197333b0d7eSKazunori MIYAZAWA {
198333b0d7eSKazunori MIYAZAWA 	struct crypto_hash *parent = pdesc->tfm;
199333b0d7eSKazunori MIYAZAWA 	struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
2006b701ddeSHerbert Xu 	struct crypto_cipher *tfm = ctx->child;
201333b0d7eSKazunori MIYAZAWA 	int bs = crypto_hash_blocksize(parent);
202333b0d7eSKazunori MIYAZAWA 	int err = 0;
203333b0d7eSKazunori MIYAZAWA 
204333b0d7eSKazunori MIYAZAWA 	if (ctx->len == bs) {
205333b0d7eSKazunori MIYAZAWA 		u8 key2[bs];
206333b0d7eSKazunori MIYAZAWA 
207333b0d7eSKazunori MIYAZAWA 		if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0)
208333b0d7eSKazunori MIYAZAWA 			return err;
209333b0d7eSKazunori MIYAZAWA 
2106b701ddeSHerbert Xu 		crypto_cipher_encrypt_one(tfm, key2,
2116b701ddeSHerbert Xu 					  (u8 *)(ctx->consts + bs));
212333b0d7eSKazunori MIYAZAWA 
213333b0d7eSKazunori MIYAZAWA 		ctx->xor(ctx->prev, ctx->odds, bs);
214333b0d7eSKazunori MIYAZAWA 		ctx->xor(ctx->prev, key2, bs);
215333b0d7eSKazunori MIYAZAWA 		_crypto_xcbc_digest_setkey(parent, ctx);
216333b0d7eSKazunori MIYAZAWA 
2176b701ddeSHerbert Xu 		crypto_cipher_encrypt_one(tfm, out, ctx->prev);
218333b0d7eSKazunori MIYAZAWA 	} else {
219333b0d7eSKazunori MIYAZAWA 		u8 key3[bs];
220333b0d7eSKazunori MIYAZAWA 		unsigned int rlen;
221333b0d7eSKazunori MIYAZAWA 		u8 *p = ctx->odds + ctx->len;
222333b0d7eSKazunori MIYAZAWA 		*p = 0x80;
223333b0d7eSKazunori MIYAZAWA 		p++;
224333b0d7eSKazunori MIYAZAWA 
225333b0d7eSKazunori MIYAZAWA 		rlen = bs - ctx->len -1;
226333b0d7eSKazunori MIYAZAWA 		if (rlen)
227333b0d7eSKazunori MIYAZAWA 			memset(p, 0, rlen);
228333b0d7eSKazunori MIYAZAWA 
229333b0d7eSKazunori MIYAZAWA 		if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0)
230333b0d7eSKazunori MIYAZAWA 			return err;
231333b0d7eSKazunori MIYAZAWA 
2326b701ddeSHerbert Xu 		crypto_cipher_encrypt_one(tfm, key3,
2336b701ddeSHerbert Xu 					  (u8 *)(ctx->consts + bs * 2));
234333b0d7eSKazunori MIYAZAWA 
235333b0d7eSKazunori MIYAZAWA 		ctx->xor(ctx->prev, ctx->odds, bs);
236333b0d7eSKazunori MIYAZAWA 		ctx->xor(ctx->prev, key3, bs);
237333b0d7eSKazunori MIYAZAWA 
238333b0d7eSKazunori MIYAZAWA 		_crypto_xcbc_digest_setkey(parent, ctx);
239333b0d7eSKazunori MIYAZAWA 
2406b701ddeSHerbert Xu 		crypto_cipher_encrypt_one(tfm, out, ctx->prev);
241333b0d7eSKazunori MIYAZAWA 	}
242333b0d7eSKazunori MIYAZAWA 
243333b0d7eSKazunori MIYAZAWA 	return 0;
244333b0d7eSKazunori MIYAZAWA }
245333b0d7eSKazunori MIYAZAWA 
246333b0d7eSKazunori MIYAZAWA static int crypto_xcbc_digest(struct hash_desc *pdesc,
247333b0d7eSKazunori MIYAZAWA 		  struct scatterlist *sg, unsigned int nbytes, u8 *out)
248333b0d7eSKazunori MIYAZAWA {
249fb469840SHerbert Xu 	if (WARN_ON_ONCE(in_irq()))
250fb469840SHerbert Xu 		return -EDEADLK;
251fb469840SHerbert Xu 
252333b0d7eSKazunori MIYAZAWA 	crypto_xcbc_digest_init(pdesc);
253fb469840SHerbert Xu 	crypto_xcbc_digest_update2(pdesc, sg, nbytes);
254333b0d7eSKazunori MIYAZAWA 	return crypto_xcbc_digest_final(pdesc, out);
255333b0d7eSKazunori MIYAZAWA }
256333b0d7eSKazunori MIYAZAWA 
257333b0d7eSKazunori MIYAZAWA static int xcbc_init_tfm(struct crypto_tfm *tfm)
258333b0d7eSKazunori MIYAZAWA {
2592e306ee0SHerbert Xu 	struct crypto_cipher *cipher;
260333b0d7eSKazunori MIYAZAWA 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
261333b0d7eSKazunori MIYAZAWA 	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
262333b0d7eSKazunori MIYAZAWA 	struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(__crypto_hash_cast(tfm));
263333b0d7eSKazunori MIYAZAWA 	int bs = crypto_hash_blocksize(__crypto_hash_cast(tfm));
264333b0d7eSKazunori MIYAZAWA 
2652e306ee0SHerbert Xu 	cipher = crypto_spawn_cipher(spawn);
2662e306ee0SHerbert Xu 	if (IS_ERR(cipher))
2672e306ee0SHerbert Xu 		return PTR_ERR(cipher);
268333b0d7eSKazunori MIYAZAWA 
269333b0d7eSKazunori MIYAZAWA 	switch(bs) {
270333b0d7eSKazunori MIYAZAWA 	case 16:
271333b0d7eSKazunori MIYAZAWA 		ctx->xor = xor_128;
272333b0d7eSKazunori MIYAZAWA 		break;
273333b0d7eSKazunori MIYAZAWA 	default:
274333b0d7eSKazunori MIYAZAWA 		return -EINVAL;
275333b0d7eSKazunori MIYAZAWA 	}
276333b0d7eSKazunori MIYAZAWA 
2772e306ee0SHerbert Xu 	ctx->child = cipher;
278333b0d7eSKazunori MIYAZAWA 	ctx->odds = (u8*)(ctx+1);
279333b0d7eSKazunori MIYAZAWA 	ctx->prev = ctx->odds + bs;
280333b0d7eSKazunori MIYAZAWA 	ctx->key = ctx->prev + bs;
281333b0d7eSKazunori MIYAZAWA 
282333b0d7eSKazunori MIYAZAWA 	return 0;
283333b0d7eSKazunori MIYAZAWA };
284333b0d7eSKazunori MIYAZAWA 
285333b0d7eSKazunori MIYAZAWA static void xcbc_exit_tfm(struct crypto_tfm *tfm)
286333b0d7eSKazunori MIYAZAWA {
287333b0d7eSKazunori MIYAZAWA 	struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(__crypto_hash_cast(tfm));
288333b0d7eSKazunori MIYAZAWA 	crypto_free_cipher(ctx->child);
289333b0d7eSKazunori MIYAZAWA }
290333b0d7eSKazunori MIYAZAWA 
291*ebc610e5SHerbert Xu static struct crypto_instance *xcbc_alloc(struct rtattr **tb)
292333b0d7eSKazunori MIYAZAWA {
293333b0d7eSKazunori MIYAZAWA 	struct crypto_instance *inst;
294333b0d7eSKazunori MIYAZAWA 	struct crypto_alg *alg;
295*ebc610e5SHerbert Xu 	int err;
296*ebc610e5SHerbert Xu 
297*ebc610e5SHerbert Xu 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH);
298*ebc610e5SHerbert Xu 	if (err)
299*ebc610e5SHerbert Xu 		return ERR_PTR(err);
300*ebc610e5SHerbert Xu 
301*ebc610e5SHerbert Xu 	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
302*ebc610e5SHerbert Xu 				  CRYPTO_ALG_TYPE_MASK);
303333b0d7eSKazunori MIYAZAWA 	if (IS_ERR(alg))
304333b0d7eSKazunori MIYAZAWA 		return ERR_PTR(PTR_ERR(alg));
305333b0d7eSKazunori MIYAZAWA 
306333b0d7eSKazunori MIYAZAWA 	switch(alg->cra_blocksize) {
307333b0d7eSKazunori MIYAZAWA 	case 16:
308333b0d7eSKazunori MIYAZAWA 		break;
309333b0d7eSKazunori MIYAZAWA 	default:
310333b0d7eSKazunori MIYAZAWA 		return ERR_PTR(PTR_ERR(alg));
311333b0d7eSKazunori MIYAZAWA 	}
312333b0d7eSKazunori MIYAZAWA 
313333b0d7eSKazunori MIYAZAWA 	inst = crypto_alloc_instance("xcbc", alg);
314333b0d7eSKazunori MIYAZAWA 	if (IS_ERR(inst))
315333b0d7eSKazunori MIYAZAWA 		goto out_put_alg;
316333b0d7eSKazunori MIYAZAWA 
317333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH;
318333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_priority = alg->cra_priority;
319333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_blocksize = alg->cra_blocksize;
320333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_alignmask = alg->cra_alignmask;
321333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_type = &crypto_hash_type;
322333b0d7eSKazunori MIYAZAWA 
323333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_hash.digestsize =
324333b0d7eSKazunori MIYAZAWA 		(alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
325333b0d7eSKazunori MIYAZAWA 		CRYPTO_ALG_TYPE_HASH ? alg->cra_hash.digestsize :
326333b0d7eSKazunori MIYAZAWA 				       alg->cra_blocksize;
327333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_ctxsize = sizeof(struct crypto_xcbc_ctx) +
328333b0d7eSKazunori MIYAZAWA 				ALIGN(inst->alg.cra_blocksize * 3, sizeof(void *));
329333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_init = xcbc_init_tfm;
330333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_exit = xcbc_exit_tfm;
331333b0d7eSKazunori MIYAZAWA 
332333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_hash.init = crypto_xcbc_digest_init;
333333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_hash.update = crypto_xcbc_digest_update;
334333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_hash.final = crypto_xcbc_digest_final;
335333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_hash.digest = crypto_xcbc_digest;
336333b0d7eSKazunori MIYAZAWA 	inst->alg.cra_hash.setkey = crypto_xcbc_digest_setkey;
337333b0d7eSKazunori MIYAZAWA 
338333b0d7eSKazunori MIYAZAWA out_put_alg:
339333b0d7eSKazunori MIYAZAWA 	crypto_mod_put(alg);
340333b0d7eSKazunori MIYAZAWA 	return inst;
341333b0d7eSKazunori MIYAZAWA }
342333b0d7eSKazunori MIYAZAWA 
343333b0d7eSKazunori MIYAZAWA static void xcbc_free(struct crypto_instance *inst)
344333b0d7eSKazunori MIYAZAWA {
345333b0d7eSKazunori MIYAZAWA 	crypto_drop_spawn(crypto_instance_ctx(inst));
346333b0d7eSKazunori MIYAZAWA 	kfree(inst);
347333b0d7eSKazunori MIYAZAWA }
348333b0d7eSKazunori MIYAZAWA 
349333b0d7eSKazunori MIYAZAWA static struct crypto_template crypto_xcbc_tmpl = {
350333b0d7eSKazunori MIYAZAWA 	.name = "xcbc",
351333b0d7eSKazunori MIYAZAWA 	.alloc = xcbc_alloc,
352333b0d7eSKazunori MIYAZAWA 	.free = xcbc_free,
353333b0d7eSKazunori MIYAZAWA 	.module = THIS_MODULE,
354333b0d7eSKazunori MIYAZAWA };
355333b0d7eSKazunori MIYAZAWA 
356333b0d7eSKazunori MIYAZAWA static int __init crypto_xcbc_module_init(void)
357333b0d7eSKazunori MIYAZAWA {
358333b0d7eSKazunori MIYAZAWA 	return crypto_register_template(&crypto_xcbc_tmpl);
359333b0d7eSKazunori MIYAZAWA }
360333b0d7eSKazunori MIYAZAWA 
361333b0d7eSKazunori MIYAZAWA static void __exit crypto_xcbc_module_exit(void)
362333b0d7eSKazunori MIYAZAWA {
363333b0d7eSKazunori MIYAZAWA 	crypto_unregister_template(&crypto_xcbc_tmpl);
364333b0d7eSKazunori MIYAZAWA }
365333b0d7eSKazunori MIYAZAWA 
366333b0d7eSKazunori MIYAZAWA module_init(crypto_xcbc_module_init);
367333b0d7eSKazunori MIYAZAWA module_exit(crypto_xcbc_module_exit);
368333b0d7eSKazunori MIYAZAWA 
369333b0d7eSKazunori MIYAZAWA MODULE_LICENSE("GPL");
370333b0d7eSKazunori MIYAZAWA MODULE_DESCRIPTION("XCBC keyed hash algorithm");
371