xref: /openbmc/linux/crypto/essiv.c (revision 255e48eb)
1be1eb7f7SArd Biesheuvel // SPDX-License-Identifier: GPL-2.0
2be1eb7f7SArd Biesheuvel /*
3be1eb7f7SArd Biesheuvel  * ESSIV skcipher and aead template for block encryption
4be1eb7f7SArd Biesheuvel  *
5be1eb7f7SArd Biesheuvel  * This template encapsulates the ESSIV IV generation algorithm used by
6be1eb7f7SArd Biesheuvel  * dm-crypt and fscrypt, which converts the initial vector for the skcipher
7be1eb7f7SArd Biesheuvel  * used for block encryption, by encrypting it using the hash of the
8be1eb7f7SArd Biesheuvel  * skcipher key as encryption key. Usually, the input IV is a 64-bit sector
9be1eb7f7SArd Biesheuvel  * number in LE representation zero-padded to the size of the IV, but this
10be1eb7f7SArd Biesheuvel  * is not assumed by this driver.
11be1eb7f7SArd Biesheuvel  *
12be1eb7f7SArd Biesheuvel  * The typical use of this template is to instantiate the skcipher
13be1eb7f7SArd Biesheuvel  * 'essiv(cbc(aes),sha256)', which is the only instantiation used by
14be1eb7f7SArd Biesheuvel  * fscrypt, and the most relevant one for dm-crypt. However, dm-crypt
15be1eb7f7SArd Biesheuvel  * also permits ESSIV to be used in combination with the authenc template,
16be1eb7f7SArd Biesheuvel  * e.g., 'essiv(authenc(hmac(sha256),cbc(aes)),sha256)', in which case
17be1eb7f7SArd Biesheuvel  * we need to instantiate an aead that accepts the same special key format
18be1eb7f7SArd Biesheuvel  * as the authenc template, and deals with the way the encrypted IV is
19be1eb7f7SArd Biesheuvel  * embedded into the AAD area of the aead request. This means the AEAD
20be1eb7f7SArd Biesheuvel  * flavor produced by this template is tightly coupled to the way dm-crypt
21be1eb7f7SArd Biesheuvel  * happens to use it.
22be1eb7f7SArd Biesheuvel  *
23be1eb7f7SArd Biesheuvel  * Copyright (c) 2019 Linaro, Ltd. <ard.biesheuvel@linaro.org>
24be1eb7f7SArd Biesheuvel  *
25be1eb7f7SArd Biesheuvel  * Heavily based on:
26be1eb7f7SArd Biesheuvel  * adiantum length-preserving encryption mode
27be1eb7f7SArd Biesheuvel  *
28be1eb7f7SArd Biesheuvel  * Copyright 2018 Google LLC
29be1eb7f7SArd Biesheuvel  */
30be1eb7f7SArd Biesheuvel 
31be1eb7f7SArd Biesheuvel #include <crypto/authenc.h>
32be1eb7f7SArd Biesheuvel #include <crypto/internal/aead.h>
330eb76ba2SArd Biesheuvel #include <crypto/internal/cipher.h>
34be1eb7f7SArd Biesheuvel #include <crypto/internal/hash.h>
35be1eb7f7SArd Biesheuvel #include <crypto/internal/skcipher.h>
36be1eb7f7SArd Biesheuvel #include <crypto/scatterwalk.h>
37be1eb7f7SArd Biesheuvel #include <linux/module.h>
38be1eb7f7SArd Biesheuvel 
39be1eb7f7SArd Biesheuvel #include "internal.h"
40be1eb7f7SArd Biesheuvel 
41be1eb7f7SArd Biesheuvel struct essiv_instance_ctx {
42be1eb7f7SArd Biesheuvel 	union {
43be1eb7f7SArd Biesheuvel 		struct crypto_skcipher_spawn	skcipher_spawn;
44be1eb7f7SArd Biesheuvel 		struct crypto_aead_spawn	aead_spawn;
45be1eb7f7SArd Biesheuvel 	} u;
46be1eb7f7SArd Biesheuvel 	char	essiv_cipher_name[CRYPTO_MAX_ALG_NAME];
47be1eb7f7SArd Biesheuvel 	char	shash_driver_name[CRYPTO_MAX_ALG_NAME];
48be1eb7f7SArd Biesheuvel };
49be1eb7f7SArd Biesheuvel 
50be1eb7f7SArd Biesheuvel struct essiv_tfm_ctx {
51be1eb7f7SArd Biesheuvel 	union {
52be1eb7f7SArd Biesheuvel 		struct crypto_skcipher	*skcipher;
53be1eb7f7SArd Biesheuvel 		struct crypto_aead	*aead;
54be1eb7f7SArd Biesheuvel 	} u;
55be1eb7f7SArd Biesheuvel 	struct crypto_cipher		*essiv_cipher;
56be1eb7f7SArd Biesheuvel 	struct crypto_shash		*hash;
57be1eb7f7SArd Biesheuvel 	int				ivoffset;
58be1eb7f7SArd Biesheuvel };
59be1eb7f7SArd Biesheuvel 
60be1eb7f7SArd Biesheuvel struct essiv_aead_request_ctx {
61be1eb7f7SArd Biesheuvel 	struct scatterlist		sg[4];
62be1eb7f7SArd Biesheuvel 	u8				*assoc;
63be1eb7f7SArd Biesheuvel 	struct aead_request		aead_req;
64be1eb7f7SArd Biesheuvel };
65be1eb7f7SArd Biesheuvel 
essiv_skcipher_setkey(struct crypto_skcipher * tfm,const u8 * key,unsigned int keylen)66be1eb7f7SArd Biesheuvel static int essiv_skcipher_setkey(struct crypto_skcipher *tfm,
67be1eb7f7SArd Biesheuvel 				 const u8 *key, unsigned int keylen)
68be1eb7f7SArd Biesheuvel {
69be1eb7f7SArd Biesheuvel 	struct essiv_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
70be1eb7f7SArd Biesheuvel 	u8 salt[HASH_MAX_DIGESTSIZE];
71be1eb7f7SArd Biesheuvel 	int err;
72be1eb7f7SArd Biesheuvel 
73be1eb7f7SArd Biesheuvel 	crypto_skcipher_clear_flags(tctx->u.skcipher, CRYPTO_TFM_REQ_MASK);
74be1eb7f7SArd Biesheuvel 	crypto_skcipher_set_flags(tctx->u.skcipher,
75be1eb7f7SArd Biesheuvel 				  crypto_skcipher_get_flags(tfm) &
76be1eb7f7SArd Biesheuvel 				  CRYPTO_TFM_REQ_MASK);
77be1eb7f7SArd Biesheuvel 	err = crypto_skcipher_setkey(tctx->u.skcipher, key, keylen);
78be1eb7f7SArd Biesheuvel 	if (err)
79be1eb7f7SArd Biesheuvel 		return err;
80be1eb7f7SArd Biesheuvel 
811306664fSEric Biggers 	err = crypto_shash_tfm_digest(tctx->hash, key, keylen, salt);
82be1eb7f7SArd Biesheuvel 	if (err)
83be1eb7f7SArd Biesheuvel 		return err;
84be1eb7f7SArd Biesheuvel 
85be1eb7f7SArd Biesheuvel 	crypto_cipher_clear_flags(tctx->essiv_cipher, CRYPTO_TFM_REQ_MASK);
86be1eb7f7SArd Biesheuvel 	crypto_cipher_set_flags(tctx->essiv_cipher,
87be1eb7f7SArd Biesheuvel 				crypto_skcipher_get_flags(tfm) &
88be1eb7f7SArd Biesheuvel 				CRYPTO_TFM_REQ_MASK);
89af5034e8SEric Biggers 	return crypto_cipher_setkey(tctx->essiv_cipher, salt,
90be1eb7f7SArd Biesheuvel 				    crypto_shash_digestsize(tctx->hash));
91be1eb7f7SArd Biesheuvel }
92be1eb7f7SArd Biesheuvel 
essiv_aead_setkey(struct crypto_aead * tfm,const u8 * key,unsigned int keylen)93be1eb7f7SArd Biesheuvel static int essiv_aead_setkey(struct crypto_aead *tfm, const u8 *key,
94be1eb7f7SArd Biesheuvel 			     unsigned int keylen)
95be1eb7f7SArd Biesheuvel {
96be1eb7f7SArd Biesheuvel 	struct essiv_tfm_ctx *tctx = crypto_aead_ctx(tfm);
97be1eb7f7SArd Biesheuvel 	SHASH_DESC_ON_STACK(desc, tctx->hash);
98be1eb7f7SArd Biesheuvel 	struct crypto_authenc_keys keys;
99be1eb7f7SArd Biesheuvel 	u8 salt[HASH_MAX_DIGESTSIZE];
100be1eb7f7SArd Biesheuvel 	int err;
101be1eb7f7SArd Biesheuvel 
102be1eb7f7SArd Biesheuvel 	crypto_aead_clear_flags(tctx->u.aead, CRYPTO_TFM_REQ_MASK);
103be1eb7f7SArd Biesheuvel 	crypto_aead_set_flags(tctx->u.aead, crypto_aead_get_flags(tfm) &
104be1eb7f7SArd Biesheuvel 					    CRYPTO_TFM_REQ_MASK);
105be1eb7f7SArd Biesheuvel 	err = crypto_aead_setkey(tctx->u.aead, key, keylen);
106be1eb7f7SArd Biesheuvel 	if (err)
107be1eb7f7SArd Biesheuvel 		return err;
108be1eb7f7SArd Biesheuvel 
109674f368aSEric Biggers 	if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
110be1eb7f7SArd Biesheuvel 		return -EINVAL;
111be1eb7f7SArd Biesheuvel 
112be1eb7f7SArd Biesheuvel 	desc->tfm = tctx->hash;
113be1eb7f7SArd Biesheuvel 	err = crypto_shash_init(desc) ?:
114be1eb7f7SArd Biesheuvel 	      crypto_shash_update(desc, keys.enckey, keys.enckeylen) ?:
115be1eb7f7SArd Biesheuvel 	      crypto_shash_finup(desc, keys.authkey, keys.authkeylen, salt);
116be1eb7f7SArd Biesheuvel 	if (err)
117be1eb7f7SArd Biesheuvel 		return err;
118be1eb7f7SArd Biesheuvel 
119be1eb7f7SArd Biesheuvel 	crypto_cipher_clear_flags(tctx->essiv_cipher, CRYPTO_TFM_REQ_MASK);
120be1eb7f7SArd Biesheuvel 	crypto_cipher_set_flags(tctx->essiv_cipher, crypto_aead_get_flags(tfm) &
121be1eb7f7SArd Biesheuvel 						    CRYPTO_TFM_REQ_MASK);
122af5034e8SEric Biggers 	return crypto_cipher_setkey(tctx->essiv_cipher, salt,
123be1eb7f7SArd Biesheuvel 				    crypto_shash_digestsize(tctx->hash));
124be1eb7f7SArd Biesheuvel }
125be1eb7f7SArd Biesheuvel 
essiv_aead_setauthsize(struct crypto_aead * tfm,unsigned int authsize)126be1eb7f7SArd Biesheuvel static int essiv_aead_setauthsize(struct crypto_aead *tfm,
127be1eb7f7SArd Biesheuvel 				  unsigned int authsize)
128be1eb7f7SArd Biesheuvel {
129be1eb7f7SArd Biesheuvel 	struct essiv_tfm_ctx *tctx = crypto_aead_ctx(tfm);
130be1eb7f7SArd Biesheuvel 
131be1eb7f7SArd Biesheuvel 	return crypto_aead_setauthsize(tctx->u.aead, authsize);
132be1eb7f7SArd Biesheuvel }
133be1eb7f7SArd Biesheuvel 
essiv_skcipher_done(void * data,int err)134*255e48ebSHerbert Xu static void essiv_skcipher_done(void *data, int err)
135be1eb7f7SArd Biesheuvel {
136*255e48ebSHerbert Xu 	struct skcipher_request *req = data;
137be1eb7f7SArd Biesheuvel 
138be1eb7f7SArd Biesheuvel 	skcipher_request_complete(req, err);
139be1eb7f7SArd Biesheuvel }
140be1eb7f7SArd Biesheuvel 
essiv_skcipher_crypt(struct skcipher_request * req,bool enc)141be1eb7f7SArd Biesheuvel static int essiv_skcipher_crypt(struct skcipher_request *req, bool enc)
142be1eb7f7SArd Biesheuvel {
143be1eb7f7SArd Biesheuvel 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
144be1eb7f7SArd Biesheuvel 	const struct essiv_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
145be1eb7f7SArd Biesheuvel 	struct skcipher_request *subreq = skcipher_request_ctx(req);
146be1eb7f7SArd Biesheuvel 
147be1eb7f7SArd Biesheuvel 	crypto_cipher_encrypt_one(tctx->essiv_cipher, req->iv, req->iv);
148be1eb7f7SArd Biesheuvel 
149be1eb7f7SArd Biesheuvel 	skcipher_request_set_tfm(subreq, tctx->u.skcipher);
150be1eb7f7SArd Biesheuvel 	skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen,
151be1eb7f7SArd Biesheuvel 				   req->iv);
152be1eb7f7SArd Biesheuvel 	skcipher_request_set_callback(subreq, skcipher_request_flags(req),
153be1eb7f7SArd Biesheuvel 				      essiv_skcipher_done, req);
154be1eb7f7SArd Biesheuvel 
155be1eb7f7SArd Biesheuvel 	return enc ? crypto_skcipher_encrypt(subreq) :
156be1eb7f7SArd Biesheuvel 		     crypto_skcipher_decrypt(subreq);
157be1eb7f7SArd Biesheuvel }
158be1eb7f7SArd Biesheuvel 
essiv_skcipher_encrypt(struct skcipher_request * req)159be1eb7f7SArd Biesheuvel static int essiv_skcipher_encrypt(struct skcipher_request *req)
160be1eb7f7SArd Biesheuvel {
161be1eb7f7SArd Biesheuvel 	return essiv_skcipher_crypt(req, true);
162be1eb7f7SArd Biesheuvel }
163be1eb7f7SArd Biesheuvel 
essiv_skcipher_decrypt(struct skcipher_request * req)164be1eb7f7SArd Biesheuvel static int essiv_skcipher_decrypt(struct skcipher_request *req)
165be1eb7f7SArd Biesheuvel {
166be1eb7f7SArd Biesheuvel 	return essiv_skcipher_crypt(req, false);
167be1eb7f7SArd Biesheuvel }
168be1eb7f7SArd Biesheuvel 
essiv_aead_done(void * data,int err)169*255e48ebSHerbert Xu static void essiv_aead_done(void *data, int err)
170be1eb7f7SArd Biesheuvel {
171*255e48ebSHerbert Xu 	struct aead_request *req = data;
172be1eb7f7SArd Biesheuvel 	struct essiv_aead_request_ctx *rctx = aead_request_ctx(req);
173be1eb7f7SArd Biesheuvel 
174b5a772adSHerbert Xu 	if (err == -EINPROGRESS)
175b5a772adSHerbert Xu 		goto out;
176b5a772adSHerbert Xu 
177be1eb7f7SArd Biesheuvel 	kfree(rctx->assoc);
178b5a772adSHerbert Xu 
179b5a772adSHerbert Xu out:
180be1eb7f7SArd Biesheuvel 	aead_request_complete(req, err);
181be1eb7f7SArd Biesheuvel }
182be1eb7f7SArd Biesheuvel 
essiv_aead_crypt(struct aead_request * req,bool enc)183be1eb7f7SArd Biesheuvel static int essiv_aead_crypt(struct aead_request *req, bool enc)
184be1eb7f7SArd Biesheuvel {
185be1eb7f7SArd Biesheuvel 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
186be1eb7f7SArd Biesheuvel 	const struct essiv_tfm_ctx *tctx = crypto_aead_ctx(tfm);
187be1eb7f7SArd Biesheuvel 	struct essiv_aead_request_ctx *rctx = aead_request_ctx(req);
188be1eb7f7SArd Biesheuvel 	struct aead_request *subreq = &rctx->aead_req;
189be1eb7f7SArd Biesheuvel 	struct scatterlist *src = req->src;
190be1eb7f7SArd Biesheuvel 	int err;
191be1eb7f7SArd Biesheuvel 
192be1eb7f7SArd Biesheuvel 	crypto_cipher_encrypt_one(tctx->essiv_cipher, req->iv, req->iv);
193be1eb7f7SArd Biesheuvel 
194be1eb7f7SArd Biesheuvel 	/*
195be1eb7f7SArd Biesheuvel 	 * dm-crypt embeds the sector number and the IV in the AAD region, so
196be1eb7f7SArd Biesheuvel 	 * we have to copy the converted IV into the right scatterlist before
197be1eb7f7SArd Biesheuvel 	 * we pass it on.
198be1eb7f7SArd Biesheuvel 	 */
199be1eb7f7SArd Biesheuvel 	rctx->assoc = NULL;
200be1eb7f7SArd Biesheuvel 	if (req->src == req->dst || !enc) {
201be1eb7f7SArd Biesheuvel 		scatterwalk_map_and_copy(req->iv, req->dst,
202be1eb7f7SArd Biesheuvel 					 req->assoclen - crypto_aead_ivsize(tfm),
203be1eb7f7SArd Biesheuvel 					 crypto_aead_ivsize(tfm), 1);
204be1eb7f7SArd Biesheuvel 	} else {
205be1eb7f7SArd Biesheuvel 		u8 *iv = (u8 *)aead_request_ctx(req) + tctx->ivoffset;
206be1eb7f7SArd Biesheuvel 		int ivsize = crypto_aead_ivsize(tfm);
207be1eb7f7SArd Biesheuvel 		int ssize = req->assoclen - ivsize;
208be1eb7f7SArd Biesheuvel 		struct scatterlist *sg;
209be1eb7f7SArd Biesheuvel 		int nents;
210be1eb7f7SArd Biesheuvel 
211be1eb7f7SArd Biesheuvel 		if (ssize < 0)
212be1eb7f7SArd Biesheuvel 			return -EINVAL;
213be1eb7f7SArd Biesheuvel 
214be1eb7f7SArd Biesheuvel 		nents = sg_nents_for_len(req->src, ssize);
215be1eb7f7SArd Biesheuvel 		if (nents < 0)
216be1eb7f7SArd Biesheuvel 			return -EINVAL;
217be1eb7f7SArd Biesheuvel 
218be1eb7f7SArd Biesheuvel 		memcpy(iv, req->iv, ivsize);
219be1eb7f7SArd Biesheuvel 		sg_init_table(rctx->sg, 4);
220be1eb7f7SArd Biesheuvel 
221be1eb7f7SArd Biesheuvel 		if (unlikely(nents > 1)) {
222be1eb7f7SArd Biesheuvel 			/*
223be1eb7f7SArd Biesheuvel 			 * This is a case that rarely occurs in practice, but
224be1eb7f7SArd Biesheuvel 			 * for correctness, we have to deal with it nonetheless.
225be1eb7f7SArd Biesheuvel 			 */
226be1eb7f7SArd Biesheuvel 			rctx->assoc = kmalloc(ssize, GFP_ATOMIC);
227be1eb7f7SArd Biesheuvel 			if (!rctx->assoc)
228be1eb7f7SArd Biesheuvel 				return -ENOMEM;
229be1eb7f7SArd Biesheuvel 
230be1eb7f7SArd Biesheuvel 			scatterwalk_map_and_copy(rctx->assoc, req->src, 0,
231be1eb7f7SArd Biesheuvel 						 ssize, 0);
232be1eb7f7SArd Biesheuvel 			sg_set_buf(rctx->sg, rctx->assoc, ssize);
233be1eb7f7SArd Biesheuvel 		} else {
234be1eb7f7SArd Biesheuvel 			sg_set_page(rctx->sg, sg_page(req->src), ssize,
235be1eb7f7SArd Biesheuvel 				    req->src->offset);
236be1eb7f7SArd Biesheuvel 		}
237be1eb7f7SArd Biesheuvel 
238be1eb7f7SArd Biesheuvel 		sg_set_buf(rctx->sg + 1, iv, ivsize);
239be1eb7f7SArd Biesheuvel 		sg = scatterwalk_ffwd(rctx->sg + 2, req->src, req->assoclen);
240be1eb7f7SArd Biesheuvel 		if (sg != rctx->sg + 2)
241be1eb7f7SArd Biesheuvel 			sg_chain(rctx->sg, 3, sg);
242be1eb7f7SArd Biesheuvel 
243be1eb7f7SArd Biesheuvel 		src = rctx->sg;
244be1eb7f7SArd Biesheuvel 	}
245be1eb7f7SArd Biesheuvel 
246be1eb7f7SArd Biesheuvel 	aead_request_set_tfm(subreq, tctx->u.aead);
247be1eb7f7SArd Biesheuvel 	aead_request_set_ad(subreq, req->assoclen);
248be1eb7f7SArd Biesheuvel 	aead_request_set_callback(subreq, aead_request_flags(req),
249be1eb7f7SArd Biesheuvel 				  essiv_aead_done, req);
250be1eb7f7SArd Biesheuvel 	aead_request_set_crypt(subreq, src, req->dst, req->cryptlen, req->iv);
251be1eb7f7SArd Biesheuvel 
252be1eb7f7SArd Biesheuvel 	err = enc ? crypto_aead_encrypt(subreq) :
253be1eb7f7SArd Biesheuvel 		    crypto_aead_decrypt(subreq);
254be1eb7f7SArd Biesheuvel 
255b5a772adSHerbert Xu 	if (rctx->assoc && err != -EINPROGRESS && err != -EBUSY)
256be1eb7f7SArd Biesheuvel 		kfree(rctx->assoc);
257be1eb7f7SArd Biesheuvel 	return err;
258be1eb7f7SArd Biesheuvel }
259be1eb7f7SArd Biesheuvel 
essiv_aead_encrypt(struct aead_request * req)260be1eb7f7SArd Biesheuvel static int essiv_aead_encrypt(struct aead_request *req)
261be1eb7f7SArd Biesheuvel {
262be1eb7f7SArd Biesheuvel 	return essiv_aead_crypt(req, true);
263be1eb7f7SArd Biesheuvel }
264be1eb7f7SArd Biesheuvel 
essiv_aead_decrypt(struct aead_request * req)265be1eb7f7SArd Biesheuvel static int essiv_aead_decrypt(struct aead_request *req)
266be1eb7f7SArd Biesheuvel {
267be1eb7f7SArd Biesheuvel 	return essiv_aead_crypt(req, false);
268be1eb7f7SArd Biesheuvel }
269be1eb7f7SArd Biesheuvel 
essiv_init_tfm(struct essiv_instance_ctx * ictx,struct essiv_tfm_ctx * tctx)270be1eb7f7SArd Biesheuvel static int essiv_init_tfm(struct essiv_instance_ctx *ictx,
271be1eb7f7SArd Biesheuvel 			  struct essiv_tfm_ctx *tctx)
272be1eb7f7SArd Biesheuvel {
273be1eb7f7SArd Biesheuvel 	struct crypto_cipher *essiv_cipher;
274be1eb7f7SArd Biesheuvel 	struct crypto_shash *hash;
275be1eb7f7SArd Biesheuvel 	int err;
276be1eb7f7SArd Biesheuvel 
277be1eb7f7SArd Biesheuvel 	essiv_cipher = crypto_alloc_cipher(ictx->essiv_cipher_name, 0, 0);
278be1eb7f7SArd Biesheuvel 	if (IS_ERR(essiv_cipher))
279be1eb7f7SArd Biesheuvel 		return PTR_ERR(essiv_cipher);
280be1eb7f7SArd Biesheuvel 
281be1eb7f7SArd Biesheuvel 	hash = crypto_alloc_shash(ictx->shash_driver_name, 0, 0);
282be1eb7f7SArd Biesheuvel 	if (IS_ERR(hash)) {
283be1eb7f7SArd Biesheuvel 		err = PTR_ERR(hash);
284be1eb7f7SArd Biesheuvel 		goto err_free_essiv_cipher;
285be1eb7f7SArd Biesheuvel 	}
286be1eb7f7SArd Biesheuvel 
287be1eb7f7SArd Biesheuvel 	tctx->essiv_cipher = essiv_cipher;
288be1eb7f7SArd Biesheuvel 	tctx->hash = hash;
289be1eb7f7SArd Biesheuvel 
290be1eb7f7SArd Biesheuvel 	return 0;
291be1eb7f7SArd Biesheuvel 
292be1eb7f7SArd Biesheuvel err_free_essiv_cipher:
293be1eb7f7SArd Biesheuvel 	crypto_free_cipher(essiv_cipher);
294be1eb7f7SArd Biesheuvel 	return err;
295be1eb7f7SArd Biesheuvel }
296be1eb7f7SArd Biesheuvel 
essiv_skcipher_init_tfm(struct crypto_skcipher * tfm)297be1eb7f7SArd Biesheuvel static int essiv_skcipher_init_tfm(struct crypto_skcipher *tfm)
298be1eb7f7SArd Biesheuvel {
299be1eb7f7SArd Biesheuvel 	struct skcipher_instance *inst = skcipher_alg_instance(tfm);
300be1eb7f7SArd Biesheuvel 	struct essiv_instance_ctx *ictx = skcipher_instance_ctx(inst);
301be1eb7f7SArd Biesheuvel 	struct essiv_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
302be1eb7f7SArd Biesheuvel 	struct crypto_skcipher *skcipher;
303be1eb7f7SArd Biesheuvel 	int err;
304be1eb7f7SArd Biesheuvel 
305be1eb7f7SArd Biesheuvel 	skcipher = crypto_spawn_skcipher(&ictx->u.skcipher_spawn);
306be1eb7f7SArd Biesheuvel 	if (IS_ERR(skcipher))
307be1eb7f7SArd Biesheuvel 		return PTR_ERR(skcipher);
308be1eb7f7SArd Biesheuvel 
309be1eb7f7SArd Biesheuvel 	crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) +
310be1eb7f7SArd Biesheuvel 				         crypto_skcipher_reqsize(skcipher));
311be1eb7f7SArd Biesheuvel 
312be1eb7f7SArd Biesheuvel 	err = essiv_init_tfm(ictx, tctx);
313be1eb7f7SArd Biesheuvel 	if (err) {
314be1eb7f7SArd Biesheuvel 		crypto_free_skcipher(skcipher);
315be1eb7f7SArd Biesheuvel 		return err;
316be1eb7f7SArd Biesheuvel 	}
317be1eb7f7SArd Biesheuvel 
318be1eb7f7SArd Biesheuvel 	tctx->u.skcipher = skcipher;
319be1eb7f7SArd Biesheuvel 	return 0;
320be1eb7f7SArd Biesheuvel }
321be1eb7f7SArd Biesheuvel 
essiv_aead_init_tfm(struct crypto_aead * tfm)322be1eb7f7SArd Biesheuvel static int essiv_aead_init_tfm(struct crypto_aead *tfm)
323be1eb7f7SArd Biesheuvel {
324be1eb7f7SArd Biesheuvel 	struct aead_instance *inst = aead_alg_instance(tfm);
325be1eb7f7SArd Biesheuvel 	struct essiv_instance_ctx *ictx = aead_instance_ctx(inst);
326be1eb7f7SArd Biesheuvel 	struct essiv_tfm_ctx *tctx = crypto_aead_ctx(tfm);
327be1eb7f7SArd Biesheuvel 	struct crypto_aead *aead;
328be1eb7f7SArd Biesheuvel 	unsigned int subreq_size;
329be1eb7f7SArd Biesheuvel 	int err;
330be1eb7f7SArd Biesheuvel 
331be1eb7f7SArd Biesheuvel 	BUILD_BUG_ON(offsetofend(struct essiv_aead_request_ctx, aead_req) !=
332be1eb7f7SArd Biesheuvel 		     sizeof(struct essiv_aead_request_ctx));
333be1eb7f7SArd Biesheuvel 
334be1eb7f7SArd Biesheuvel 	aead = crypto_spawn_aead(&ictx->u.aead_spawn);
335be1eb7f7SArd Biesheuvel 	if (IS_ERR(aead))
336be1eb7f7SArd Biesheuvel 		return PTR_ERR(aead);
337be1eb7f7SArd Biesheuvel 
338c593642cSPankaj Bharadiya 	subreq_size = sizeof_field(struct essiv_aead_request_ctx, aead_req) +
339be1eb7f7SArd Biesheuvel 		      crypto_aead_reqsize(aead);
340be1eb7f7SArd Biesheuvel 
341be1eb7f7SArd Biesheuvel 	tctx->ivoffset = offsetof(struct essiv_aead_request_ctx, aead_req) +
342be1eb7f7SArd Biesheuvel 			 subreq_size;
343be1eb7f7SArd Biesheuvel 	crypto_aead_set_reqsize(tfm, tctx->ivoffset + crypto_aead_ivsize(aead));
344be1eb7f7SArd Biesheuvel 
345be1eb7f7SArd Biesheuvel 	err = essiv_init_tfm(ictx, tctx);
346be1eb7f7SArd Biesheuvel 	if (err) {
347be1eb7f7SArd Biesheuvel 		crypto_free_aead(aead);
348be1eb7f7SArd Biesheuvel 		return err;
349be1eb7f7SArd Biesheuvel 	}
350be1eb7f7SArd Biesheuvel 
351be1eb7f7SArd Biesheuvel 	tctx->u.aead = aead;
352be1eb7f7SArd Biesheuvel 	return 0;
353be1eb7f7SArd Biesheuvel }
354be1eb7f7SArd Biesheuvel 
essiv_skcipher_exit_tfm(struct crypto_skcipher * tfm)355be1eb7f7SArd Biesheuvel static void essiv_skcipher_exit_tfm(struct crypto_skcipher *tfm)
356be1eb7f7SArd Biesheuvel {
357be1eb7f7SArd Biesheuvel 	struct essiv_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
358be1eb7f7SArd Biesheuvel 
359be1eb7f7SArd Biesheuvel 	crypto_free_skcipher(tctx->u.skcipher);
360be1eb7f7SArd Biesheuvel 	crypto_free_cipher(tctx->essiv_cipher);
361be1eb7f7SArd Biesheuvel 	crypto_free_shash(tctx->hash);
362be1eb7f7SArd Biesheuvel }
363be1eb7f7SArd Biesheuvel 
essiv_aead_exit_tfm(struct crypto_aead * tfm)364be1eb7f7SArd Biesheuvel static void essiv_aead_exit_tfm(struct crypto_aead *tfm)
365be1eb7f7SArd Biesheuvel {
366be1eb7f7SArd Biesheuvel 	struct essiv_tfm_ctx *tctx = crypto_aead_ctx(tfm);
367be1eb7f7SArd Biesheuvel 
368be1eb7f7SArd Biesheuvel 	crypto_free_aead(tctx->u.aead);
369be1eb7f7SArd Biesheuvel 	crypto_free_cipher(tctx->essiv_cipher);
370be1eb7f7SArd Biesheuvel 	crypto_free_shash(tctx->hash);
371be1eb7f7SArd Biesheuvel }
372be1eb7f7SArd Biesheuvel 
essiv_skcipher_free_instance(struct skcipher_instance * inst)373be1eb7f7SArd Biesheuvel static void essiv_skcipher_free_instance(struct skcipher_instance *inst)
374be1eb7f7SArd Biesheuvel {
375be1eb7f7SArd Biesheuvel 	struct essiv_instance_ctx *ictx = skcipher_instance_ctx(inst);
376be1eb7f7SArd Biesheuvel 
377be1eb7f7SArd Biesheuvel 	crypto_drop_skcipher(&ictx->u.skcipher_spawn);
378be1eb7f7SArd Biesheuvel 	kfree(inst);
379be1eb7f7SArd Biesheuvel }
380be1eb7f7SArd Biesheuvel 
essiv_aead_free_instance(struct aead_instance * inst)381be1eb7f7SArd Biesheuvel static void essiv_aead_free_instance(struct aead_instance *inst)
382be1eb7f7SArd Biesheuvel {
383be1eb7f7SArd Biesheuvel 	struct essiv_instance_ctx *ictx = aead_instance_ctx(inst);
384be1eb7f7SArd Biesheuvel 
385be1eb7f7SArd Biesheuvel 	crypto_drop_aead(&ictx->u.aead_spawn);
386be1eb7f7SArd Biesheuvel 	kfree(inst);
387be1eb7f7SArd Biesheuvel }
388be1eb7f7SArd Biesheuvel 
parse_cipher_name(char * essiv_cipher_name,const char * cra_name)389be1eb7f7SArd Biesheuvel static bool parse_cipher_name(char *essiv_cipher_name, const char *cra_name)
390be1eb7f7SArd Biesheuvel {
391be1eb7f7SArd Biesheuvel 	const char *p, *q;
392be1eb7f7SArd Biesheuvel 	int len;
393be1eb7f7SArd Biesheuvel 
394be1eb7f7SArd Biesheuvel 	/* find the last opening parens */
395be1eb7f7SArd Biesheuvel 	p = strrchr(cra_name, '(');
396be1eb7f7SArd Biesheuvel 	if (!p++)
397be1eb7f7SArd Biesheuvel 		return false;
398be1eb7f7SArd Biesheuvel 
399be1eb7f7SArd Biesheuvel 	/* find the first closing parens in the tail of the string */
400be1eb7f7SArd Biesheuvel 	q = strchr(p, ')');
401be1eb7f7SArd Biesheuvel 	if (!q)
402be1eb7f7SArd Biesheuvel 		return false;
403be1eb7f7SArd Biesheuvel 
404be1eb7f7SArd Biesheuvel 	len = q - p;
405be1eb7f7SArd Biesheuvel 	if (len >= CRYPTO_MAX_ALG_NAME)
406be1eb7f7SArd Biesheuvel 		return false;
407be1eb7f7SArd Biesheuvel 
408be1eb7f7SArd Biesheuvel 	memcpy(essiv_cipher_name, p, len);
409be1eb7f7SArd Biesheuvel 	essiv_cipher_name[len] = '\0';
410be1eb7f7SArd Biesheuvel 	return true;
411be1eb7f7SArd Biesheuvel }
412be1eb7f7SArd Biesheuvel 
essiv_supported_algorithms(const char * essiv_cipher_name,struct shash_alg * hash_alg,int ivsize)413be1eb7f7SArd Biesheuvel static bool essiv_supported_algorithms(const char *essiv_cipher_name,
414be1eb7f7SArd Biesheuvel 				       struct shash_alg *hash_alg,
415be1eb7f7SArd Biesheuvel 				       int ivsize)
416be1eb7f7SArd Biesheuvel {
417be1eb7f7SArd Biesheuvel 	struct crypto_alg *alg;
418be1eb7f7SArd Biesheuvel 	bool ret = false;
419be1eb7f7SArd Biesheuvel 
420be1eb7f7SArd Biesheuvel 	alg = crypto_alg_mod_lookup(essiv_cipher_name,
421be1eb7f7SArd Biesheuvel 				    CRYPTO_ALG_TYPE_CIPHER,
422be1eb7f7SArd Biesheuvel 				    CRYPTO_ALG_TYPE_MASK);
423be1eb7f7SArd Biesheuvel 	if (IS_ERR(alg))
424be1eb7f7SArd Biesheuvel 		return false;
425be1eb7f7SArd Biesheuvel 
426be1eb7f7SArd Biesheuvel 	if (hash_alg->digestsize < alg->cra_cipher.cia_min_keysize ||
427be1eb7f7SArd Biesheuvel 	    hash_alg->digestsize > alg->cra_cipher.cia_max_keysize)
428be1eb7f7SArd Biesheuvel 		goto out;
429be1eb7f7SArd Biesheuvel 
430be1eb7f7SArd Biesheuvel 	if (ivsize != alg->cra_blocksize)
431be1eb7f7SArd Biesheuvel 		goto out;
432be1eb7f7SArd Biesheuvel 
433c2881789SEric Biggers 	if (crypto_shash_alg_needs_key(hash_alg))
434be1eb7f7SArd Biesheuvel 		goto out;
435be1eb7f7SArd Biesheuvel 
436be1eb7f7SArd Biesheuvel 	ret = true;
437be1eb7f7SArd Biesheuvel 
438be1eb7f7SArd Biesheuvel out:
439be1eb7f7SArd Biesheuvel 	crypto_mod_put(alg);
440be1eb7f7SArd Biesheuvel 	return ret;
441be1eb7f7SArd Biesheuvel }
442be1eb7f7SArd Biesheuvel 
essiv_create(struct crypto_template * tmpl,struct rtattr ** tb)443be1eb7f7SArd Biesheuvel static int essiv_create(struct crypto_template *tmpl, struct rtattr **tb)
444be1eb7f7SArd Biesheuvel {
445be1eb7f7SArd Biesheuvel 	struct crypto_attr_type *algt;
446be1eb7f7SArd Biesheuvel 	const char *inner_cipher_name;
447be1eb7f7SArd Biesheuvel 	const char *shash_name;
448be1eb7f7SArd Biesheuvel 	struct skcipher_instance *skcipher_inst = NULL;
449be1eb7f7SArd Biesheuvel 	struct aead_instance *aead_inst = NULL;
450be1eb7f7SArd Biesheuvel 	struct crypto_instance *inst;
451be1eb7f7SArd Biesheuvel 	struct crypto_alg *base, *block_base;
452be1eb7f7SArd Biesheuvel 	struct essiv_instance_ctx *ictx;
453be1eb7f7SArd Biesheuvel 	struct skcipher_alg *skcipher_alg = NULL;
454be1eb7f7SArd Biesheuvel 	struct aead_alg *aead_alg = NULL;
455be1eb7f7SArd Biesheuvel 	struct crypto_alg *_hash_alg;
456be1eb7f7SArd Biesheuvel 	struct shash_alg *hash_alg;
457be1eb7f7SArd Biesheuvel 	int ivsize;
458be1eb7f7SArd Biesheuvel 	u32 type;
459b9f76dddSEric Biggers 	u32 mask;
460be1eb7f7SArd Biesheuvel 	int err;
461be1eb7f7SArd Biesheuvel 
462be1eb7f7SArd Biesheuvel 	algt = crypto_get_attr_type(tb);
463be1eb7f7SArd Biesheuvel 	if (IS_ERR(algt))
464be1eb7f7SArd Biesheuvel 		return PTR_ERR(algt);
465be1eb7f7SArd Biesheuvel 
466be1eb7f7SArd Biesheuvel 	inner_cipher_name = crypto_attr_alg_name(tb[1]);
467be1eb7f7SArd Biesheuvel 	if (IS_ERR(inner_cipher_name))
468be1eb7f7SArd Biesheuvel 		return PTR_ERR(inner_cipher_name);
469be1eb7f7SArd Biesheuvel 
470be1eb7f7SArd Biesheuvel 	shash_name = crypto_attr_alg_name(tb[2]);
471be1eb7f7SArd Biesheuvel 	if (IS_ERR(shash_name))
472be1eb7f7SArd Biesheuvel 		return PTR_ERR(shash_name);
473be1eb7f7SArd Biesheuvel 
474be1eb7f7SArd Biesheuvel 	type = algt->type & algt->mask;
4757bcb2c99SEric Biggers 	mask = crypto_algt_inherited_mask(algt);
476be1eb7f7SArd Biesheuvel 
477be1eb7f7SArd Biesheuvel 	switch (type) {
478c65058b7SEric Biggers 	case CRYPTO_ALG_TYPE_SKCIPHER:
479be1eb7f7SArd Biesheuvel 		skcipher_inst = kzalloc(sizeof(*skcipher_inst) +
480be1eb7f7SArd Biesheuvel 					sizeof(*ictx), GFP_KERNEL);
481be1eb7f7SArd Biesheuvel 		if (!skcipher_inst)
482be1eb7f7SArd Biesheuvel 			return -ENOMEM;
483be1eb7f7SArd Biesheuvel 		inst = skcipher_crypto_instance(skcipher_inst);
484be1eb7f7SArd Biesheuvel 		base = &skcipher_inst->alg.base;
485be1eb7f7SArd Biesheuvel 		ictx = crypto_instance_ctx(inst);
486be1eb7f7SArd Biesheuvel 
487be1eb7f7SArd Biesheuvel 		/* Symmetric cipher, e.g., "cbc(aes)" */
488b9f76dddSEric Biggers 		err = crypto_grab_skcipher(&ictx->u.skcipher_spawn, inst,
489b9f76dddSEric Biggers 					   inner_cipher_name, 0, mask);
490be1eb7f7SArd Biesheuvel 		if (err)
491be1eb7f7SArd Biesheuvel 			goto out_free_inst;
492be1eb7f7SArd Biesheuvel 		skcipher_alg = crypto_spawn_skcipher_alg(&ictx->u.skcipher_spawn);
493be1eb7f7SArd Biesheuvel 		block_base = &skcipher_alg->base;
494be1eb7f7SArd Biesheuvel 		ivsize = crypto_skcipher_alg_ivsize(skcipher_alg);
495be1eb7f7SArd Biesheuvel 		break;
496be1eb7f7SArd Biesheuvel 
497be1eb7f7SArd Biesheuvel 	case CRYPTO_ALG_TYPE_AEAD:
498be1eb7f7SArd Biesheuvel 		aead_inst = kzalloc(sizeof(*aead_inst) +
499be1eb7f7SArd Biesheuvel 				    sizeof(*ictx), GFP_KERNEL);
500be1eb7f7SArd Biesheuvel 		if (!aead_inst)
501be1eb7f7SArd Biesheuvel 			return -ENOMEM;
502be1eb7f7SArd Biesheuvel 		inst = aead_crypto_instance(aead_inst);
503be1eb7f7SArd Biesheuvel 		base = &aead_inst->alg.base;
504be1eb7f7SArd Biesheuvel 		ictx = crypto_instance_ctx(inst);
505be1eb7f7SArd Biesheuvel 
506be1eb7f7SArd Biesheuvel 		/* AEAD cipher, e.g., "authenc(hmac(sha256),cbc(aes))" */
507cd900f0cSEric Biggers 		err = crypto_grab_aead(&ictx->u.aead_spawn, inst,
508b9f76dddSEric Biggers 				       inner_cipher_name, 0, mask);
509be1eb7f7SArd Biesheuvel 		if (err)
510be1eb7f7SArd Biesheuvel 			goto out_free_inst;
511be1eb7f7SArd Biesheuvel 		aead_alg = crypto_spawn_aead_alg(&ictx->u.aead_spawn);
512be1eb7f7SArd Biesheuvel 		block_base = &aead_alg->base;
513be1eb7f7SArd Biesheuvel 		if (!strstarts(block_base->cra_name, "authenc(")) {
514be1eb7f7SArd Biesheuvel 			pr_warn("Only authenc() type AEADs are supported by ESSIV\n");
515be1eb7f7SArd Biesheuvel 			err = -EINVAL;
516be1eb7f7SArd Biesheuvel 			goto out_drop_skcipher;
517be1eb7f7SArd Biesheuvel 		}
518be1eb7f7SArd Biesheuvel 		ivsize = aead_alg->ivsize;
519be1eb7f7SArd Biesheuvel 		break;
520be1eb7f7SArd Biesheuvel 
521be1eb7f7SArd Biesheuvel 	default:
522be1eb7f7SArd Biesheuvel 		return -EINVAL;
523be1eb7f7SArd Biesheuvel 	}
524be1eb7f7SArd Biesheuvel 
525be1eb7f7SArd Biesheuvel 	if (!parse_cipher_name(ictx->essiv_cipher_name, block_base->cra_name)) {
526be1eb7f7SArd Biesheuvel 		pr_warn("Failed to parse ESSIV cipher name from skcipher cra_name\n");
527be1eb7f7SArd Biesheuvel 		err = -EINVAL;
528be1eb7f7SArd Biesheuvel 		goto out_drop_skcipher;
529be1eb7f7SArd Biesheuvel 	}
530be1eb7f7SArd Biesheuvel 
531be1eb7f7SArd Biesheuvel 	/* Synchronous hash, e.g., "sha256" */
532be1eb7f7SArd Biesheuvel 	_hash_alg = crypto_alg_mod_lookup(shash_name,
533be1eb7f7SArd Biesheuvel 					  CRYPTO_ALG_TYPE_SHASH,
5347bcb2c99SEric Biggers 					  CRYPTO_ALG_TYPE_MASK | mask);
535be1eb7f7SArd Biesheuvel 	if (IS_ERR(_hash_alg)) {
536be1eb7f7SArd Biesheuvel 		err = PTR_ERR(_hash_alg);
537be1eb7f7SArd Biesheuvel 		goto out_drop_skcipher;
538be1eb7f7SArd Biesheuvel 	}
539be1eb7f7SArd Biesheuvel 	hash_alg = __crypto_shash_alg(_hash_alg);
540be1eb7f7SArd Biesheuvel 
541be1eb7f7SArd Biesheuvel 	/* Check the set of algorithms */
542be1eb7f7SArd Biesheuvel 	if (!essiv_supported_algorithms(ictx->essiv_cipher_name, hash_alg,
543be1eb7f7SArd Biesheuvel 					ivsize)) {
544be1eb7f7SArd Biesheuvel 		pr_warn("Unsupported essiv instantiation: essiv(%s,%s)\n",
545be1eb7f7SArd Biesheuvel 			block_base->cra_name, hash_alg->base.cra_name);
546be1eb7f7SArd Biesheuvel 		err = -EINVAL;
547be1eb7f7SArd Biesheuvel 		goto out_free_hash;
548be1eb7f7SArd Biesheuvel 	}
549be1eb7f7SArd Biesheuvel 
550be1eb7f7SArd Biesheuvel 	/* record the driver name so we can instantiate this exact algo later */
551dd4f8ee7SWolfram Sang 	strscpy(ictx->shash_driver_name, hash_alg->base.cra_driver_name,
552be1eb7f7SArd Biesheuvel 		CRYPTO_MAX_ALG_NAME);
553be1eb7f7SArd Biesheuvel 
554be1eb7f7SArd Biesheuvel 	/* Instance fields */
555be1eb7f7SArd Biesheuvel 
556be1eb7f7SArd Biesheuvel 	err = -ENAMETOOLONG;
557be1eb7f7SArd Biesheuvel 	if (snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME,
558be1eb7f7SArd Biesheuvel 		     "essiv(%s,%s)", block_base->cra_name,
559be1eb7f7SArd Biesheuvel 		     hash_alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
560be1eb7f7SArd Biesheuvel 		goto out_free_hash;
561be1eb7f7SArd Biesheuvel 	if (snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME,
562be1eb7f7SArd Biesheuvel 		     "essiv(%s,%s)", block_base->cra_driver_name,
563be1eb7f7SArd Biesheuvel 		     hash_alg->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
564be1eb7f7SArd Biesheuvel 		goto out_free_hash;
565be1eb7f7SArd Biesheuvel 
5667bcb2c99SEric Biggers 	/*
5677bcb2c99SEric Biggers 	 * hash_alg wasn't gotten via crypto_grab*(), so we need to inherit its
5687bcb2c99SEric Biggers 	 * flags manually.
5697bcb2c99SEric Biggers 	 */
5707bcb2c99SEric Biggers 	base->cra_flags        |= (hash_alg->base.cra_flags &
5717bcb2c99SEric Biggers 				   CRYPTO_ALG_INHERITED_FLAGS);
572be1eb7f7SArd Biesheuvel 	base->cra_blocksize	= block_base->cra_blocksize;
573be1eb7f7SArd Biesheuvel 	base->cra_ctxsize	= sizeof(struct essiv_tfm_ctx);
574be1eb7f7SArd Biesheuvel 	base->cra_alignmask	= block_base->cra_alignmask;
575be1eb7f7SArd Biesheuvel 	base->cra_priority	= block_base->cra_priority;
576be1eb7f7SArd Biesheuvel 
577c65058b7SEric Biggers 	if (type == CRYPTO_ALG_TYPE_SKCIPHER) {
578be1eb7f7SArd Biesheuvel 		skcipher_inst->alg.setkey	= essiv_skcipher_setkey;
579be1eb7f7SArd Biesheuvel 		skcipher_inst->alg.encrypt	= essiv_skcipher_encrypt;
580be1eb7f7SArd Biesheuvel 		skcipher_inst->alg.decrypt	= essiv_skcipher_decrypt;
581be1eb7f7SArd Biesheuvel 		skcipher_inst->alg.init		= essiv_skcipher_init_tfm;
582be1eb7f7SArd Biesheuvel 		skcipher_inst->alg.exit		= essiv_skcipher_exit_tfm;
583be1eb7f7SArd Biesheuvel 
584be1eb7f7SArd Biesheuvel 		skcipher_inst->alg.min_keysize	= crypto_skcipher_alg_min_keysize(skcipher_alg);
585be1eb7f7SArd Biesheuvel 		skcipher_inst->alg.max_keysize	= crypto_skcipher_alg_max_keysize(skcipher_alg);
586be1eb7f7SArd Biesheuvel 		skcipher_inst->alg.ivsize	= ivsize;
587be1eb7f7SArd Biesheuvel 		skcipher_inst->alg.chunksize	= crypto_skcipher_alg_chunksize(skcipher_alg);
588be1eb7f7SArd Biesheuvel 		skcipher_inst->alg.walksize	= crypto_skcipher_alg_walksize(skcipher_alg);
589be1eb7f7SArd Biesheuvel 
590be1eb7f7SArd Biesheuvel 		skcipher_inst->free		= essiv_skcipher_free_instance;
591be1eb7f7SArd Biesheuvel 
592be1eb7f7SArd Biesheuvel 		err = skcipher_register_instance(tmpl, skcipher_inst);
593be1eb7f7SArd Biesheuvel 	} else {
594be1eb7f7SArd Biesheuvel 		aead_inst->alg.setkey		= essiv_aead_setkey;
595be1eb7f7SArd Biesheuvel 		aead_inst->alg.setauthsize	= essiv_aead_setauthsize;
596be1eb7f7SArd Biesheuvel 		aead_inst->alg.encrypt		= essiv_aead_encrypt;
597be1eb7f7SArd Biesheuvel 		aead_inst->alg.decrypt		= essiv_aead_decrypt;
598be1eb7f7SArd Biesheuvel 		aead_inst->alg.init		= essiv_aead_init_tfm;
599be1eb7f7SArd Biesheuvel 		aead_inst->alg.exit		= essiv_aead_exit_tfm;
600be1eb7f7SArd Biesheuvel 
601be1eb7f7SArd Biesheuvel 		aead_inst->alg.ivsize		= ivsize;
602be1eb7f7SArd Biesheuvel 		aead_inst->alg.maxauthsize	= crypto_aead_alg_maxauthsize(aead_alg);
603be1eb7f7SArd Biesheuvel 		aead_inst->alg.chunksize	= crypto_aead_alg_chunksize(aead_alg);
604be1eb7f7SArd Biesheuvel 
605be1eb7f7SArd Biesheuvel 		aead_inst->free			= essiv_aead_free_instance;
606be1eb7f7SArd Biesheuvel 
607be1eb7f7SArd Biesheuvel 		err = aead_register_instance(tmpl, aead_inst);
608be1eb7f7SArd Biesheuvel 	}
609be1eb7f7SArd Biesheuvel 
610be1eb7f7SArd Biesheuvel 	if (err)
611be1eb7f7SArd Biesheuvel 		goto out_free_hash;
612be1eb7f7SArd Biesheuvel 
613be1eb7f7SArd Biesheuvel 	crypto_mod_put(_hash_alg);
614be1eb7f7SArd Biesheuvel 	return 0;
615be1eb7f7SArd Biesheuvel 
616be1eb7f7SArd Biesheuvel out_free_hash:
617be1eb7f7SArd Biesheuvel 	crypto_mod_put(_hash_alg);
618be1eb7f7SArd Biesheuvel out_drop_skcipher:
619c65058b7SEric Biggers 	if (type == CRYPTO_ALG_TYPE_SKCIPHER)
620be1eb7f7SArd Biesheuvel 		crypto_drop_skcipher(&ictx->u.skcipher_spawn);
621be1eb7f7SArd Biesheuvel 	else
622be1eb7f7SArd Biesheuvel 		crypto_drop_aead(&ictx->u.aead_spawn);
623be1eb7f7SArd Biesheuvel out_free_inst:
624be1eb7f7SArd Biesheuvel 	kfree(skcipher_inst);
625be1eb7f7SArd Biesheuvel 	kfree(aead_inst);
626be1eb7f7SArd Biesheuvel 	return err;
627be1eb7f7SArd Biesheuvel }
628be1eb7f7SArd Biesheuvel 
629be1eb7f7SArd Biesheuvel /* essiv(cipher_name, shash_name) */
630be1eb7f7SArd Biesheuvel static struct crypto_template essiv_tmpl = {
631be1eb7f7SArd Biesheuvel 	.name	= "essiv",
632be1eb7f7SArd Biesheuvel 	.create	= essiv_create,
633be1eb7f7SArd Biesheuvel 	.module	= THIS_MODULE,
634be1eb7f7SArd Biesheuvel };
635be1eb7f7SArd Biesheuvel 
essiv_module_init(void)636be1eb7f7SArd Biesheuvel static int __init essiv_module_init(void)
637be1eb7f7SArd Biesheuvel {
638be1eb7f7SArd Biesheuvel 	return crypto_register_template(&essiv_tmpl);
639be1eb7f7SArd Biesheuvel }
640be1eb7f7SArd Biesheuvel 
essiv_module_exit(void)641be1eb7f7SArd Biesheuvel static void __exit essiv_module_exit(void)
642be1eb7f7SArd Biesheuvel {
643be1eb7f7SArd Biesheuvel 	crypto_unregister_template(&essiv_tmpl);
644be1eb7f7SArd Biesheuvel }
645be1eb7f7SArd Biesheuvel 
646be1eb7f7SArd Biesheuvel subsys_initcall(essiv_module_init);
647be1eb7f7SArd Biesheuvel module_exit(essiv_module_exit);
648be1eb7f7SArd Biesheuvel 
649be1eb7f7SArd Biesheuvel MODULE_DESCRIPTION("ESSIV skcipher/aead wrapper for block encryption");
650be1eb7f7SArd Biesheuvel MODULE_LICENSE("GPL v2");
651be1eb7f7SArd Biesheuvel MODULE_ALIAS_CRYPTO("essiv");
6520eb76ba2SArd Biesheuvel MODULE_IMPORT_NS(CRYPTO_INTERNAL);
653