xref: /openbmc/linux/crypto/ccm.c (revision 05b3bbb5)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24a49b499SJoy Latten /*
34a49b499SJoy Latten  * CCM: Counter with CBC-MAC
44a49b499SJoy Latten  *
54a49b499SJoy Latten  * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
64a49b499SJoy Latten  */
74a49b499SJoy Latten 
84a49b499SJoy Latten #include <crypto/internal/aead.h>
9f15f05b0SArd Biesheuvel #include <crypto/internal/hash.h>
104a49b499SJoy Latten #include <crypto/internal/skcipher.h>
114a49b499SJoy Latten #include <crypto/scatterwalk.h>
124a49b499SJoy Latten #include <linux/err.h>
134a49b499SJoy Latten #include <linux/init.h>
144a49b499SJoy Latten #include <linux/kernel.h>
154a49b499SJoy Latten #include <linux/module.h>
164a49b499SJoy Latten #include <linux/slab.h>
174a49b499SJoy Latten 
184a49b499SJoy Latten struct ccm_instance_ctx {
194a49b499SJoy Latten 	struct crypto_skcipher_spawn ctr;
20f15f05b0SArd Biesheuvel 	struct crypto_ahash_spawn mac;
214a49b499SJoy Latten };
224a49b499SJoy Latten 
234a49b499SJoy Latten struct crypto_ccm_ctx {
24f15f05b0SArd Biesheuvel 	struct crypto_ahash *mac;
25464b93a3SHerbert Xu 	struct crypto_skcipher *ctr;
264a49b499SJoy Latten };
274a49b499SJoy Latten 
284a49b499SJoy Latten struct crypto_rfc4309_ctx {
294a49b499SJoy Latten 	struct crypto_aead *child;
304a49b499SJoy Latten 	u8 nonce[3];
314a49b499SJoy Latten };
324a49b499SJoy Latten 
3381c4c35eSHerbert Xu struct crypto_rfc4309_req_ctx {
3481c4c35eSHerbert Xu 	struct scatterlist src[3];
3581c4c35eSHerbert Xu 	struct scatterlist dst[3];
3681c4c35eSHerbert Xu 	struct aead_request subreq;
3781c4c35eSHerbert Xu };
3881c4c35eSHerbert Xu 
394a49b499SJoy Latten struct crypto_ccm_req_priv_ctx {
404a49b499SJoy Latten 	u8 odata[16];
413b30460cSArd Biesheuvel 	u8 idata[16];
424a49b499SJoy Latten 	u8 auth_tag[16];
434a49b499SJoy Latten 	u32 flags;
4481c4c35eSHerbert Xu 	struct scatterlist src[3];
4581c4c35eSHerbert Xu 	struct scatterlist dst[3];
46ebf533adSArd Biesheuvel 	union {
47ebf533adSArd Biesheuvel 		struct ahash_request ahreq;
48464b93a3SHerbert Xu 		struct skcipher_request skreq;
494a49b499SJoy Latten 	};
50ebf533adSArd Biesheuvel };
514a49b499SJoy Latten 
52f15f05b0SArd Biesheuvel struct cbcmac_tfm_ctx {
53f15f05b0SArd Biesheuvel 	struct crypto_cipher *child;
54f15f05b0SArd Biesheuvel };
55f15f05b0SArd Biesheuvel 
56f15f05b0SArd Biesheuvel struct cbcmac_desc_ctx {
57f15f05b0SArd Biesheuvel 	unsigned int len;
58f15f05b0SArd Biesheuvel };
59f15f05b0SArd Biesheuvel 
604a49b499SJoy Latten static inline struct crypto_ccm_req_priv_ctx *crypto_ccm_reqctx(
614a49b499SJoy Latten 	struct aead_request *req)
624a49b499SJoy Latten {
634a49b499SJoy Latten 	unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req));
644a49b499SJoy Latten 
654a49b499SJoy Latten 	return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1);
664a49b499SJoy Latten }
674a49b499SJoy Latten 
684a49b499SJoy Latten static int set_msg_len(u8 *block, unsigned int msglen, int csize)
694a49b499SJoy Latten {
704a49b499SJoy Latten 	__be32 data;
714a49b499SJoy Latten 
724a49b499SJoy Latten 	memset(block, 0, csize);
734a49b499SJoy Latten 	block += csize;
744a49b499SJoy Latten 
754a49b499SJoy Latten 	if (csize >= 4)
764a49b499SJoy Latten 		csize = 4;
774a49b499SJoy Latten 	else if (msglen > (1 << (8 * csize)))
784a49b499SJoy Latten 		return -EOVERFLOW;
794a49b499SJoy Latten 
804a49b499SJoy Latten 	data = cpu_to_be32(msglen);
814a49b499SJoy Latten 	memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
824a49b499SJoy Latten 
834a49b499SJoy Latten 	return 0;
844a49b499SJoy Latten }
854a49b499SJoy Latten 
864a49b499SJoy Latten static int crypto_ccm_setkey(struct crypto_aead *aead, const u8 *key,
874a49b499SJoy Latten 			     unsigned int keylen)
884a49b499SJoy Latten {
894a49b499SJoy Latten 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
90464b93a3SHerbert Xu 	struct crypto_skcipher *ctr = ctx->ctr;
91f15f05b0SArd Biesheuvel 	struct crypto_ahash *mac = ctx->mac;
92af5034e8SEric Biggers 	int err;
934a49b499SJoy Latten 
94464b93a3SHerbert Xu 	crypto_skcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
95464b93a3SHerbert Xu 	crypto_skcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
964a49b499SJoy Latten 				       CRYPTO_TFM_REQ_MASK);
97464b93a3SHerbert Xu 	err = crypto_skcipher_setkey(ctr, key, keylen);
984a49b499SJoy Latten 	if (err)
99af5034e8SEric Biggers 		return err;
1004a49b499SJoy Latten 
101f15f05b0SArd Biesheuvel 	crypto_ahash_clear_flags(mac, CRYPTO_TFM_REQ_MASK);
102f15f05b0SArd Biesheuvel 	crypto_ahash_set_flags(mac, crypto_aead_get_flags(aead) &
1034a49b499SJoy Latten 				    CRYPTO_TFM_REQ_MASK);
104af5034e8SEric Biggers 	return crypto_ahash_setkey(mac, key, keylen);
1054a49b499SJoy Latten }
1064a49b499SJoy Latten 
1074a49b499SJoy Latten static int crypto_ccm_setauthsize(struct crypto_aead *tfm,
1084a49b499SJoy Latten 				  unsigned int authsize)
1094a49b499SJoy Latten {
1104a49b499SJoy Latten 	switch (authsize) {
1114a49b499SJoy Latten 	case 4:
1124a49b499SJoy Latten 	case 6:
1134a49b499SJoy Latten 	case 8:
1144a49b499SJoy Latten 	case 10:
1154a49b499SJoy Latten 	case 12:
1164a49b499SJoy Latten 	case 14:
1174a49b499SJoy Latten 	case 16:
1184a49b499SJoy Latten 		break;
1194a49b499SJoy Latten 	default:
1204a49b499SJoy Latten 		return -EINVAL;
1214a49b499SJoy Latten 	}
1224a49b499SJoy Latten 
1234a49b499SJoy Latten 	return 0;
1244a49b499SJoy Latten }
1254a49b499SJoy Latten 
1264a49b499SJoy Latten static int format_input(u8 *info, struct aead_request *req,
1274a49b499SJoy Latten 			unsigned int cryptlen)
1284a49b499SJoy Latten {
1294a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
1304a49b499SJoy Latten 	unsigned int lp = req->iv[0];
1314a49b499SJoy Latten 	unsigned int l = lp + 1;
1324a49b499SJoy Latten 	unsigned int m;
1334a49b499SJoy Latten 
1344a49b499SJoy Latten 	m = crypto_aead_authsize(aead);
1354a49b499SJoy Latten 
1364a49b499SJoy Latten 	memcpy(info, req->iv, 16);
1374a49b499SJoy Latten 
1384a49b499SJoy Latten 	/* format control info per RFC 3610 and
1394a49b499SJoy Latten 	 * NIST Special Publication 800-38C
1404a49b499SJoy Latten 	 */
1414a49b499SJoy Latten 	*info |= (8 * ((m - 2) / 2));
1424a49b499SJoy Latten 	if (req->assoclen)
1434a49b499SJoy Latten 		*info |= 64;
1444a49b499SJoy Latten 
1454a49b499SJoy Latten 	return set_msg_len(info + 16 - l, cryptlen, l);
1464a49b499SJoy Latten }
1474a49b499SJoy Latten 
1484a49b499SJoy Latten static int format_adata(u8 *adata, unsigned int a)
1494a49b499SJoy Latten {
1504a49b499SJoy Latten 	int len = 0;
1514a49b499SJoy Latten 
1524a49b499SJoy Latten 	/* add control info for associated data
1534a49b499SJoy Latten 	 * RFC 3610 and NIST Special Publication 800-38C
1544a49b499SJoy Latten 	 */
1554a49b499SJoy Latten 	if (a < 65280) {
1564a49b499SJoy Latten 		*(__be16 *)adata = cpu_to_be16(a);
1574a49b499SJoy Latten 		len = 2;
1584a49b499SJoy Latten 	} else  {
1594a49b499SJoy Latten 		*(__be16 *)adata = cpu_to_be16(0xfffe);
1604a49b499SJoy Latten 		*(__be32 *)&adata[2] = cpu_to_be32(a);
1614a49b499SJoy Latten 		len = 6;
1624a49b499SJoy Latten 	}
1634a49b499SJoy Latten 
1644a49b499SJoy Latten 	return len;
1654a49b499SJoy Latten }
1664a49b499SJoy Latten 
1674a49b499SJoy Latten static int crypto_ccm_auth(struct aead_request *req, struct scatterlist *plain,
1684a49b499SJoy Latten 			   unsigned int cryptlen)
1694a49b499SJoy Latten {
170f15f05b0SArd Biesheuvel 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
1714a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
1724a49b499SJoy Latten 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
173ebf533adSArd Biesheuvel 	struct ahash_request *ahreq = &pctx->ahreq;
1744a49b499SJoy Latten 	unsigned int assoclen = req->assoclen;
175f15f05b0SArd Biesheuvel 	struct scatterlist sg[3];
1763b30460cSArd Biesheuvel 	u8 *odata = pctx->odata;
1773b30460cSArd Biesheuvel 	u8 *idata = pctx->idata;
178f15f05b0SArd Biesheuvel 	int ilen, err;
1794a49b499SJoy Latten 
1804a49b499SJoy Latten 	/* format control data for input */
1814a49b499SJoy Latten 	err = format_input(odata, req, cryptlen);
1824a49b499SJoy Latten 	if (err)
1834a49b499SJoy Latten 		goto out;
1844a49b499SJoy Latten 
185f15f05b0SArd Biesheuvel 	sg_init_table(sg, 3);
186f15f05b0SArd Biesheuvel 	sg_set_buf(&sg[0], odata, 16);
1874a49b499SJoy Latten 
1884a49b499SJoy Latten 	/* format associated data and compute into mac */
1894a49b499SJoy Latten 	if (assoclen) {
190f15f05b0SArd Biesheuvel 		ilen = format_adata(idata, assoclen);
191f15f05b0SArd Biesheuvel 		sg_set_buf(&sg[1], idata, ilen);
192f15f05b0SArd Biesheuvel 		sg_chain(sg, 3, req->src);
193516280e7SJarod Wilson 	} else {
194f15f05b0SArd Biesheuvel 		ilen = 0;
195f15f05b0SArd Biesheuvel 		sg_chain(sg, 2, req->src);
1964a49b499SJoy Latten 	}
1974a49b499SJoy Latten 
198f15f05b0SArd Biesheuvel 	ahash_request_set_tfm(ahreq, ctx->mac);
199f15f05b0SArd Biesheuvel 	ahash_request_set_callback(ahreq, pctx->flags, NULL, NULL);
200f15f05b0SArd Biesheuvel 	ahash_request_set_crypt(ahreq, sg, NULL, assoclen + ilen + 16);
201f15f05b0SArd Biesheuvel 	err = crypto_ahash_init(ahreq);
202f15f05b0SArd Biesheuvel 	if (err)
203f15f05b0SArd Biesheuvel 		goto out;
204f15f05b0SArd Biesheuvel 	err = crypto_ahash_update(ahreq);
205f15f05b0SArd Biesheuvel 	if (err)
206f15f05b0SArd Biesheuvel 		goto out;
2074a49b499SJoy Latten 
208f15f05b0SArd Biesheuvel 	/* we need to pad the MAC input to a round multiple of the block size */
209f15f05b0SArd Biesheuvel 	ilen = 16 - (assoclen + ilen) % 16;
210f15f05b0SArd Biesheuvel 	if (ilen < 16) {
211f15f05b0SArd Biesheuvel 		memset(idata, 0, ilen);
212f15f05b0SArd Biesheuvel 		sg_init_table(sg, 2);
213f15f05b0SArd Biesheuvel 		sg_set_buf(&sg[0], idata, ilen);
214f15f05b0SArd Biesheuvel 		if (plain)
215f15f05b0SArd Biesheuvel 			sg_chain(sg, 2, plain);
216f15f05b0SArd Biesheuvel 		plain = sg;
217f15f05b0SArd Biesheuvel 		cryptlen += ilen;
218f15f05b0SArd Biesheuvel 	}
219f15f05b0SArd Biesheuvel 
220f15f05b0SArd Biesheuvel 	ahash_request_set_crypt(ahreq, plain, pctx->odata, cryptlen);
221f15f05b0SArd Biesheuvel 	err = crypto_ahash_finup(ahreq);
2224a49b499SJoy Latten out:
2234a49b499SJoy Latten 	return err;
2244a49b499SJoy Latten }
2254a49b499SJoy Latten 
2264a49b499SJoy Latten static void crypto_ccm_encrypt_done(struct crypto_async_request *areq, int err)
2274a49b499SJoy Latten {
2284a49b499SJoy Latten 	struct aead_request *req = areq->data;
2294a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
2304a49b499SJoy Latten 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
2314a49b499SJoy Latten 	u8 *odata = pctx->odata;
2324a49b499SJoy Latten 
2334a49b499SJoy Latten 	if (!err)
23481c4c35eSHerbert Xu 		scatterwalk_map_and_copy(odata, req->dst,
23581c4c35eSHerbert Xu 					 req->assoclen + req->cryptlen,
2364a49b499SJoy Latten 					 crypto_aead_authsize(aead), 1);
2374a49b499SJoy Latten 	aead_request_complete(req, err);
2384a49b499SJoy Latten }
2394a49b499SJoy Latten 
2404a49b499SJoy Latten static inline int crypto_ccm_check_iv(const u8 *iv)
2414a49b499SJoy Latten {
2424a49b499SJoy Latten 	/* 2 <= L <= 8, so 1 <= L' <= 7. */
2434a49b499SJoy Latten 	if (1 > iv[0] || iv[0] > 7)
2444a49b499SJoy Latten 		return -EINVAL;
2454a49b499SJoy Latten 
2464a49b499SJoy Latten 	return 0;
2474a49b499SJoy Latten }
2484a49b499SJoy Latten 
24981c4c35eSHerbert Xu static int crypto_ccm_init_crypt(struct aead_request *req, u8 *tag)
25081c4c35eSHerbert Xu {
25181c4c35eSHerbert Xu 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
25281c4c35eSHerbert Xu 	struct scatterlist *sg;
25381c4c35eSHerbert Xu 	u8 *iv = req->iv;
25481c4c35eSHerbert Xu 	int err;
25581c4c35eSHerbert Xu 
25681c4c35eSHerbert Xu 	err = crypto_ccm_check_iv(iv);
25781c4c35eSHerbert Xu 	if (err)
25881c4c35eSHerbert Xu 		return err;
25981c4c35eSHerbert Xu 
26081c4c35eSHerbert Xu 	pctx->flags = aead_request_flags(req);
26181c4c35eSHerbert Xu 
26281c4c35eSHerbert Xu 	 /* Note: rfc 3610 and NIST 800-38C require counter of
26381c4c35eSHerbert Xu 	 * zero to encrypt auth tag.
26481c4c35eSHerbert Xu 	 */
26581c4c35eSHerbert Xu 	memset(iv + 15 - iv[0], 0, iv[0] + 1);
26681c4c35eSHerbert Xu 
26781c4c35eSHerbert Xu 	sg_init_table(pctx->src, 3);
26881c4c35eSHerbert Xu 	sg_set_buf(pctx->src, tag, 16);
26981c4c35eSHerbert Xu 	sg = scatterwalk_ffwd(pctx->src + 1, req->src, req->assoclen);
27081c4c35eSHerbert Xu 	if (sg != pctx->src + 1)
27181c4c35eSHerbert Xu 		sg_chain(pctx->src, 2, sg);
27281c4c35eSHerbert Xu 
27381c4c35eSHerbert Xu 	if (req->src != req->dst) {
27481c4c35eSHerbert Xu 		sg_init_table(pctx->dst, 3);
27581c4c35eSHerbert Xu 		sg_set_buf(pctx->dst, tag, 16);
27681c4c35eSHerbert Xu 		sg = scatterwalk_ffwd(pctx->dst + 1, req->dst, req->assoclen);
27781c4c35eSHerbert Xu 		if (sg != pctx->dst + 1)
27881c4c35eSHerbert Xu 			sg_chain(pctx->dst, 2, sg);
27981c4c35eSHerbert Xu 	}
28081c4c35eSHerbert Xu 
28181c4c35eSHerbert Xu 	return 0;
28281c4c35eSHerbert Xu }
28381c4c35eSHerbert Xu 
2844a49b499SJoy Latten static int crypto_ccm_encrypt(struct aead_request *req)
2854a49b499SJoy Latten {
2864a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
2874a49b499SJoy Latten 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
2884a49b499SJoy Latten 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
289464b93a3SHerbert Xu 	struct skcipher_request *skreq = &pctx->skreq;
2904a49b499SJoy Latten 	struct scatterlist *dst;
2914a49b499SJoy Latten 	unsigned int cryptlen = req->cryptlen;
2924a49b499SJoy Latten 	u8 *odata = pctx->odata;
2934a49b499SJoy Latten 	u8 *iv = req->iv;
2944a49b499SJoy Latten 	int err;
2954a49b499SJoy Latten 
29681c4c35eSHerbert Xu 	err = crypto_ccm_init_crypt(req, odata);
2974a49b499SJoy Latten 	if (err)
2984a49b499SJoy Latten 		return err;
2994a49b499SJoy Latten 
30081c4c35eSHerbert Xu 	err = crypto_ccm_auth(req, sg_next(pctx->src), cryptlen);
3014a49b499SJoy Latten 	if (err)
3024a49b499SJoy Latten 		return err;
3034a49b499SJoy Latten 
3044a49b499SJoy Latten 	dst = pctx->src;
30581c4c35eSHerbert Xu 	if (req->src != req->dst)
3064a49b499SJoy Latten 		dst = pctx->dst;
3074a49b499SJoy Latten 
308464b93a3SHerbert Xu 	skcipher_request_set_tfm(skreq, ctx->ctr);
309464b93a3SHerbert Xu 	skcipher_request_set_callback(skreq, pctx->flags,
3104a49b499SJoy Latten 				      crypto_ccm_encrypt_done, req);
311464b93a3SHerbert Xu 	skcipher_request_set_crypt(skreq, pctx->src, dst, cryptlen + 16, iv);
312464b93a3SHerbert Xu 	err = crypto_skcipher_encrypt(skreq);
3134a49b499SJoy Latten 	if (err)
3144a49b499SJoy Latten 		return err;
3154a49b499SJoy Latten 
3164a49b499SJoy Latten 	/* copy authtag to end of dst */
31781c4c35eSHerbert Xu 	scatterwalk_map_and_copy(odata, sg_next(dst), cryptlen,
3184a49b499SJoy Latten 				 crypto_aead_authsize(aead), 1);
3194a49b499SJoy Latten 	return err;
3204a49b499SJoy Latten }
3214a49b499SJoy Latten 
3224a49b499SJoy Latten static void crypto_ccm_decrypt_done(struct crypto_async_request *areq,
3234a49b499SJoy Latten 				   int err)
3244a49b499SJoy Latten {
3254a49b499SJoy Latten 	struct aead_request *req = areq->data;
3264a49b499SJoy Latten 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
3274a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
3284a49b499SJoy Latten 	unsigned int authsize = crypto_aead_authsize(aead);
3294a49b499SJoy Latten 	unsigned int cryptlen = req->cryptlen - authsize;
33081c4c35eSHerbert Xu 	struct scatterlist *dst;
33181c4c35eSHerbert Xu 
33281c4c35eSHerbert Xu 	pctx->flags = 0;
33381c4c35eSHerbert Xu 
33481c4c35eSHerbert Xu 	dst = sg_next(req->src == req->dst ? pctx->src : pctx->dst);
3354a49b499SJoy Latten 
3364a49b499SJoy Latten 	if (!err) {
33781c4c35eSHerbert Xu 		err = crypto_ccm_auth(req, dst, cryptlen);
3386bf37e5aSJames Yonan 		if (!err && crypto_memneq(pctx->auth_tag, pctx->odata, authsize))
3394a49b499SJoy Latten 			err = -EBADMSG;
3404a49b499SJoy Latten 	}
3414a49b499SJoy Latten 	aead_request_complete(req, err);
3424a49b499SJoy Latten }
3434a49b499SJoy Latten 
3444a49b499SJoy Latten static int crypto_ccm_decrypt(struct aead_request *req)
3454a49b499SJoy Latten {
3464a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
3474a49b499SJoy Latten 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
3484a49b499SJoy Latten 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
349464b93a3SHerbert Xu 	struct skcipher_request *skreq = &pctx->skreq;
3504a49b499SJoy Latten 	struct scatterlist *dst;
3514a49b499SJoy Latten 	unsigned int authsize = crypto_aead_authsize(aead);
3524a49b499SJoy Latten 	unsigned int cryptlen = req->cryptlen;
3534a49b499SJoy Latten 	u8 *authtag = pctx->auth_tag;
3544a49b499SJoy Latten 	u8 *odata = pctx->odata;
355441f99c9SRomain Izard 	u8 *iv = pctx->idata;
3564a49b499SJoy Latten 	int err;
3574a49b499SJoy Latten 
3584a49b499SJoy Latten 	cryptlen -= authsize;
3594a49b499SJoy Latten 
36081c4c35eSHerbert Xu 	err = crypto_ccm_init_crypt(req, authtag);
3614a49b499SJoy Latten 	if (err)
3624a49b499SJoy Latten 		return err;
3634a49b499SJoy Latten 
36481c4c35eSHerbert Xu 	scatterwalk_map_and_copy(authtag, sg_next(pctx->src), cryptlen,
36581c4c35eSHerbert Xu 				 authsize, 0);
3664a49b499SJoy Latten 
3674a49b499SJoy Latten 	dst = pctx->src;
36881c4c35eSHerbert Xu 	if (req->src != req->dst)
3694a49b499SJoy Latten 		dst = pctx->dst;
3704a49b499SJoy Latten 
371441f99c9SRomain Izard 	memcpy(iv, req->iv, 16);
372441f99c9SRomain Izard 
373464b93a3SHerbert Xu 	skcipher_request_set_tfm(skreq, ctx->ctr);
374464b93a3SHerbert Xu 	skcipher_request_set_callback(skreq, pctx->flags,
3754a49b499SJoy Latten 				      crypto_ccm_decrypt_done, req);
376464b93a3SHerbert Xu 	skcipher_request_set_crypt(skreq, pctx->src, dst, cryptlen + 16, iv);
377464b93a3SHerbert Xu 	err = crypto_skcipher_decrypt(skreq);
3784a49b499SJoy Latten 	if (err)
3794a49b499SJoy Latten 		return err;
3804a49b499SJoy Latten 
38181c4c35eSHerbert Xu 	err = crypto_ccm_auth(req, sg_next(dst), cryptlen);
3824a49b499SJoy Latten 	if (err)
3834a49b499SJoy Latten 		return err;
3844a49b499SJoy Latten 
3854a49b499SJoy Latten 	/* verify */
3866bf37e5aSJames Yonan 	if (crypto_memneq(authtag, odata, authsize))
3874a49b499SJoy Latten 		return -EBADMSG;
3884a49b499SJoy Latten 
3894a49b499SJoy Latten 	return err;
3904a49b499SJoy Latten }
3914a49b499SJoy Latten 
39281c4c35eSHerbert Xu static int crypto_ccm_init_tfm(struct crypto_aead *tfm)
3934a49b499SJoy Latten {
39481c4c35eSHerbert Xu 	struct aead_instance *inst = aead_alg_instance(tfm);
39581c4c35eSHerbert Xu 	struct ccm_instance_ctx *ictx = aead_instance_ctx(inst);
39681c4c35eSHerbert Xu 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(tfm);
397f15f05b0SArd Biesheuvel 	struct crypto_ahash *mac;
398464b93a3SHerbert Xu 	struct crypto_skcipher *ctr;
3994a49b499SJoy Latten 	unsigned long align;
4004a49b499SJoy Latten 	int err;
4014a49b499SJoy Latten 
402f15f05b0SArd Biesheuvel 	mac = crypto_spawn_ahash(&ictx->mac);
403f15f05b0SArd Biesheuvel 	if (IS_ERR(mac))
404f15f05b0SArd Biesheuvel 		return PTR_ERR(mac);
4054a49b499SJoy Latten 
40660425a8bSEric Biggers 	ctr = crypto_spawn_skcipher(&ictx->ctr);
4074a49b499SJoy Latten 	err = PTR_ERR(ctr);
4084a49b499SJoy Latten 	if (IS_ERR(ctr))
409f15f05b0SArd Biesheuvel 		goto err_free_mac;
4104a49b499SJoy Latten 
411f15f05b0SArd Biesheuvel 	ctx->mac = mac;
4124a49b499SJoy Latten 	ctx->ctr = ctr;
4134a49b499SJoy Latten 
41481c4c35eSHerbert Xu 	align = crypto_aead_alignmask(tfm);
4154a49b499SJoy Latten 	align &= ~(crypto_tfm_ctx_alignment() - 1);
41681c4c35eSHerbert Xu 	crypto_aead_set_reqsize(
41781c4c35eSHerbert Xu 		tfm,
4182c221ad3SHerbert Xu 		align + sizeof(struct crypto_ccm_req_priv_ctx) +
419ebf533adSArd Biesheuvel 		max(crypto_ahash_reqsize(mac), crypto_skcipher_reqsize(ctr)));
4204a49b499SJoy Latten 
4214a49b499SJoy Latten 	return 0;
4224a49b499SJoy Latten 
423f15f05b0SArd Biesheuvel err_free_mac:
424f15f05b0SArd Biesheuvel 	crypto_free_ahash(mac);
4254a49b499SJoy Latten 	return err;
4264a49b499SJoy Latten }
4274a49b499SJoy Latten 
42881c4c35eSHerbert Xu static void crypto_ccm_exit_tfm(struct crypto_aead *tfm)
4294a49b499SJoy Latten {
43081c4c35eSHerbert Xu 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(tfm);
4314a49b499SJoy Latten 
432f15f05b0SArd Biesheuvel 	crypto_free_ahash(ctx->mac);
433464b93a3SHerbert Xu 	crypto_free_skcipher(ctx->ctr);
4344a49b499SJoy Latten }
4354a49b499SJoy Latten 
43681c4c35eSHerbert Xu static void crypto_ccm_free(struct aead_instance *inst)
43781c4c35eSHerbert Xu {
43881c4c35eSHerbert Xu 	struct ccm_instance_ctx *ctx = aead_instance_ctx(inst);
43981c4c35eSHerbert Xu 
440f15f05b0SArd Biesheuvel 	crypto_drop_ahash(&ctx->mac);
44181c4c35eSHerbert Xu 	crypto_drop_skcipher(&ctx->ctr);
44281c4c35eSHerbert Xu 	kfree(inst);
44381c4c35eSHerbert Xu }
44481c4c35eSHerbert Xu 
44581c4c35eSHerbert Xu static int crypto_ccm_create_common(struct crypto_template *tmpl,
44681c4c35eSHerbert Xu 				    struct rtattr **tb,
4474a49b499SJoy Latten 				    const char *ctr_name,
448f15f05b0SArd Biesheuvel 				    const char *mac_name)
4494a49b499SJoy Latten {
4504a49b499SJoy Latten 	struct crypto_attr_type *algt;
451b9f76dddSEric Biggers 	u32 mask;
45281c4c35eSHerbert Xu 	struct aead_instance *inst;
4534a49b499SJoy Latten 	struct ccm_instance_ctx *ictx;
45405b3bbb5SEric Biggers 	struct skcipher_alg *ctr;
45505b3bbb5SEric Biggers 	struct hash_alg_common *mac;
4564a49b499SJoy Latten 	int err;
4574a49b499SJoy Latten 
4584a49b499SJoy Latten 	algt = crypto_get_attr_type(tb);
4594a49b499SJoy Latten 	if (IS_ERR(algt))
46081c4c35eSHerbert Xu 		return PTR_ERR(algt);
4614a49b499SJoy Latten 
4625e4b8c1fSHerbert Xu 	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
46381c4c35eSHerbert Xu 		return -EINVAL;
4644a49b499SJoy Latten 
465b9f76dddSEric Biggers 	mask = crypto_requires_sync(algt->type, algt->mask);
466b9f76dddSEric Biggers 
46705b3bbb5SEric Biggers 	inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL);
46805b3bbb5SEric Biggers 	if (!inst)
46905b3bbb5SEric Biggers 		return -ENOMEM;
47005b3bbb5SEric Biggers 	ictx = aead_instance_ctx(inst);
4714a49b499SJoy Latten 
47205b3bbb5SEric Biggers 	err = crypto_grab_ahash(&ictx->mac, aead_crypto_instance(inst),
47305b3bbb5SEric Biggers 				mac_name, 0, CRYPTO_ALG_ASYNC);
47405b3bbb5SEric Biggers 	if (err)
47505b3bbb5SEric Biggers 		goto err_free_inst;
47605b3bbb5SEric Biggers 	mac = crypto_spawn_ahash_alg(&ictx->mac);
47705b3bbb5SEric Biggers 
4784a49b499SJoy Latten 	err = -EINVAL;
4796a1faa4aSEric Biggers 	if (strncmp(mac->base.cra_name, "cbcmac(", 7) != 0 ||
4806a1faa4aSEric Biggers 	    mac->digestsize != 16)
4814a49b499SJoy Latten 		goto err_free_inst;
4824a49b499SJoy Latten 
483b9f76dddSEric Biggers 	err = crypto_grab_skcipher(&ictx->ctr, aead_crypto_instance(inst),
484b9f76dddSEric Biggers 				   ctr_name, 0, mask);
4854a49b499SJoy Latten 	if (err)
48605b3bbb5SEric Biggers 		goto err_free_inst;
487464b93a3SHerbert Xu 	ctr = crypto_spawn_skcipher_alg(&ictx->ctr);
4884a49b499SJoy Latten 
4896a1faa4aSEric Biggers 	/* The skcipher algorithm must be CTR mode, using 16-byte blocks. */
4904a49b499SJoy Latten 	err = -EINVAL;
4916a1faa4aSEric Biggers 	if (strncmp(ctr->base.cra_name, "ctr(", 4) != 0 ||
4926a1faa4aSEric Biggers 	    crypto_skcipher_alg_ivsize(ctr) != 16 ||
4936a1faa4aSEric Biggers 	    ctr->base.cra_blocksize != 1)
49405b3bbb5SEric Biggers 		goto err_free_inst;
4954a49b499SJoy Latten 
4966a1faa4aSEric Biggers 	/* ctr and cbcmac must use the same underlying block cipher. */
4976a1faa4aSEric Biggers 	if (strcmp(ctr->base.cra_name + 4, mac->base.cra_name + 7) != 0)
49805b3bbb5SEric Biggers 		goto err_free_inst;
4994a49b499SJoy Latten 
5004a49b499SJoy Latten 	err = -ENAMETOOLONG;
5016a1faa4aSEric Biggers 	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
5026a1faa4aSEric Biggers 		     "ccm(%s", ctr->base.cra_name + 4) >= CRYPTO_MAX_ALG_NAME)
50305b3bbb5SEric Biggers 		goto err_free_inst;
5046a1faa4aSEric Biggers 
50581c4c35eSHerbert Xu 	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
506464b93a3SHerbert Xu 		     "ccm_base(%s,%s)", ctr->base.cra_driver_name,
507f15f05b0SArd Biesheuvel 		     mac->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
50805b3bbb5SEric Biggers 		goto err_free_inst;
5094a49b499SJoy Latten 
510464b93a3SHerbert Xu 	inst->alg.base.cra_flags = ctr->base.cra_flags & CRYPTO_ALG_ASYNC;
511f15f05b0SArd Biesheuvel 	inst->alg.base.cra_priority = (mac->base.cra_priority +
512464b93a3SHerbert Xu 				       ctr->base.cra_priority) / 2;
51381c4c35eSHerbert Xu 	inst->alg.base.cra_blocksize = 1;
514f15f05b0SArd Biesheuvel 	inst->alg.base.cra_alignmask = mac->base.cra_alignmask |
5155ba8e2a0SArd Biesheuvel 				       ctr->base.cra_alignmask;
51681c4c35eSHerbert Xu 	inst->alg.ivsize = 16;
517464b93a3SHerbert Xu 	inst->alg.chunksize = crypto_skcipher_alg_chunksize(ctr);
51881c4c35eSHerbert Xu 	inst->alg.maxauthsize = 16;
51981c4c35eSHerbert Xu 	inst->alg.base.cra_ctxsize = sizeof(struct crypto_ccm_ctx);
52081c4c35eSHerbert Xu 	inst->alg.init = crypto_ccm_init_tfm;
52181c4c35eSHerbert Xu 	inst->alg.exit = crypto_ccm_exit_tfm;
52281c4c35eSHerbert Xu 	inst->alg.setkey = crypto_ccm_setkey;
52381c4c35eSHerbert Xu 	inst->alg.setauthsize = crypto_ccm_setauthsize;
52481c4c35eSHerbert Xu 	inst->alg.encrypt = crypto_ccm_encrypt;
52581c4c35eSHerbert Xu 	inst->alg.decrypt = crypto_ccm_decrypt;
5264a49b499SJoy Latten 
52781c4c35eSHerbert Xu 	inst->free = crypto_ccm_free;
52881c4c35eSHerbert Xu 
52981c4c35eSHerbert Xu 	err = aead_register_instance(tmpl, inst);
53005b3bbb5SEric Biggers 	if (err) {
5314a49b499SJoy Latten err_free_inst:
53205b3bbb5SEric Biggers 		crypto_ccm_free(inst);
53305b3bbb5SEric Biggers 	}
53405b3bbb5SEric Biggers 	return err;
5354a49b499SJoy Latten }
5364a49b499SJoy Latten 
53781c4c35eSHerbert Xu static int crypto_ccm_create(struct crypto_template *tmpl, struct rtattr **tb)
5384a49b499SJoy Latten {
5394a49b499SJoy Latten 	const char *cipher_name;
5404a49b499SJoy Latten 	char ctr_name[CRYPTO_MAX_ALG_NAME];
541f15f05b0SArd Biesheuvel 	char mac_name[CRYPTO_MAX_ALG_NAME];
5424a49b499SJoy Latten 
5434a49b499SJoy Latten 	cipher_name = crypto_attr_alg_name(tb[1]);
5444a49b499SJoy Latten 	if (IS_ERR(cipher_name))
54581c4c35eSHerbert Xu 		return PTR_ERR(cipher_name);
5464a49b499SJoy Latten 
5474a49b499SJoy Latten 	if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)",
5484a49b499SJoy Latten 		     cipher_name) >= CRYPTO_MAX_ALG_NAME)
54981c4c35eSHerbert Xu 		return -ENAMETOOLONG;
5504a49b499SJoy Latten 
551f15f05b0SArd Biesheuvel 	if (snprintf(mac_name, CRYPTO_MAX_ALG_NAME, "cbcmac(%s)",
552f15f05b0SArd Biesheuvel 		     cipher_name) >= CRYPTO_MAX_ALG_NAME)
553f15f05b0SArd Biesheuvel 		return -ENAMETOOLONG;
554f15f05b0SArd Biesheuvel 
5556a1faa4aSEric Biggers 	return crypto_ccm_create_common(tmpl, tb, ctr_name, mac_name);
5564a49b499SJoy Latten }
5574a49b499SJoy Latten 
55881c4c35eSHerbert Xu static int crypto_ccm_base_create(struct crypto_template *tmpl,
55981c4c35eSHerbert Xu 				  struct rtattr **tb)
5604a49b499SJoy Latten {
5614a49b499SJoy Latten 	const char *ctr_name;
5626a1faa4aSEric Biggers 	const char *mac_name;
5634a49b499SJoy Latten 
5644a49b499SJoy Latten 	ctr_name = crypto_attr_alg_name(tb[1]);
5654a49b499SJoy Latten 	if (IS_ERR(ctr_name))
56681c4c35eSHerbert Xu 		return PTR_ERR(ctr_name);
5674a49b499SJoy Latten 
5686a1faa4aSEric Biggers 	mac_name = crypto_attr_alg_name(tb[2]);
5696a1faa4aSEric Biggers 	if (IS_ERR(mac_name))
5706a1faa4aSEric Biggers 		return PTR_ERR(mac_name);
5714a49b499SJoy Latten 
5726a1faa4aSEric Biggers 	return crypto_ccm_create_common(tmpl, tb, ctr_name, mac_name);
5734a49b499SJoy Latten }
5744a49b499SJoy Latten 
5754a49b499SJoy Latten static int crypto_rfc4309_setkey(struct crypto_aead *parent, const u8 *key,
5764a49b499SJoy Latten 				 unsigned int keylen)
5774a49b499SJoy Latten {
5784a49b499SJoy Latten 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(parent);
5794a49b499SJoy Latten 	struct crypto_aead *child = ctx->child;
5804a49b499SJoy Latten 
5814a49b499SJoy Latten 	if (keylen < 3)
5824a49b499SJoy Latten 		return -EINVAL;
5834a49b499SJoy Latten 
5844a49b499SJoy Latten 	keylen -= 3;
5854a49b499SJoy Latten 	memcpy(ctx->nonce, key + keylen, 3);
5864a49b499SJoy Latten 
5874a49b499SJoy Latten 	crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
5884a49b499SJoy Latten 	crypto_aead_set_flags(child, crypto_aead_get_flags(parent) &
5894a49b499SJoy Latten 				     CRYPTO_TFM_REQ_MASK);
590af5034e8SEric Biggers 	return crypto_aead_setkey(child, key, keylen);
5914a49b499SJoy Latten }
5924a49b499SJoy Latten 
5934a49b499SJoy Latten static int crypto_rfc4309_setauthsize(struct crypto_aead *parent,
5944a49b499SJoy Latten 				      unsigned int authsize)
5954a49b499SJoy Latten {
5964a49b499SJoy Latten 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(parent);
5974a49b499SJoy Latten 
5984a49b499SJoy Latten 	switch (authsize) {
5994a49b499SJoy Latten 	case 8:
6004a49b499SJoy Latten 	case 12:
6014a49b499SJoy Latten 	case 16:
6024a49b499SJoy Latten 		break;
6034a49b499SJoy Latten 	default:
6044a49b499SJoy Latten 		return -EINVAL;
6054a49b499SJoy Latten 	}
6064a49b499SJoy Latten 
6074a49b499SJoy Latten 	return crypto_aead_setauthsize(ctx->child, authsize);
6084a49b499SJoy Latten }
6094a49b499SJoy Latten 
6104a49b499SJoy Latten static struct aead_request *crypto_rfc4309_crypt(struct aead_request *req)
6114a49b499SJoy Latten {
61281c4c35eSHerbert Xu 	struct crypto_rfc4309_req_ctx *rctx = aead_request_ctx(req);
61381c4c35eSHerbert Xu 	struct aead_request *subreq = &rctx->subreq;
6144a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
6154a49b499SJoy Latten 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(aead);
6164a49b499SJoy Latten 	struct crypto_aead *child = ctx->child;
61781c4c35eSHerbert Xu 	struct scatterlist *sg;
6184a49b499SJoy Latten 	u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child),
6194a49b499SJoy Latten 			   crypto_aead_alignmask(child) + 1);
6204a49b499SJoy Latten 
6214a49b499SJoy Latten 	/* L' */
6224a49b499SJoy Latten 	iv[0] = 3;
6234a49b499SJoy Latten 
6244a49b499SJoy Latten 	memcpy(iv + 1, ctx->nonce, 3);
6254a49b499SJoy Latten 	memcpy(iv + 4, req->iv, 8);
6264a49b499SJoy Latten 
62781c4c35eSHerbert Xu 	scatterwalk_map_and_copy(iv + 16, req->src, 0, req->assoclen - 8, 0);
62881c4c35eSHerbert Xu 
62981c4c35eSHerbert Xu 	sg_init_table(rctx->src, 3);
63081c4c35eSHerbert Xu 	sg_set_buf(rctx->src, iv + 16, req->assoclen - 8);
63181c4c35eSHerbert Xu 	sg = scatterwalk_ffwd(rctx->src + 1, req->src, req->assoclen);
63281c4c35eSHerbert Xu 	if (sg != rctx->src + 1)
63381c4c35eSHerbert Xu 		sg_chain(rctx->src, 2, sg);
63481c4c35eSHerbert Xu 
63581c4c35eSHerbert Xu 	if (req->src != req->dst) {
63681c4c35eSHerbert Xu 		sg_init_table(rctx->dst, 3);
63781c4c35eSHerbert Xu 		sg_set_buf(rctx->dst, iv + 16, req->assoclen - 8);
63881c4c35eSHerbert Xu 		sg = scatterwalk_ffwd(rctx->dst + 1, req->dst, req->assoclen);
63981c4c35eSHerbert Xu 		if (sg != rctx->dst + 1)
64081c4c35eSHerbert Xu 			sg_chain(rctx->dst, 2, sg);
64181c4c35eSHerbert Xu 	}
64281c4c35eSHerbert Xu 
6434a49b499SJoy Latten 	aead_request_set_tfm(subreq, child);
6444a49b499SJoy Latten 	aead_request_set_callback(subreq, req->base.flags, req->base.complete,
6454a49b499SJoy Latten 				  req->base.data);
64681c4c35eSHerbert Xu 	aead_request_set_crypt(subreq, rctx->src,
64781c4c35eSHerbert Xu 			       req->src == req->dst ? rctx->src : rctx->dst,
64881c4c35eSHerbert Xu 			       req->cryptlen, iv);
64981c4c35eSHerbert Xu 	aead_request_set_ad(subreq, req->assoclen - 8);
6504a49b499SJoy Latten 
6514a49b499SJoy Latten 	return subreq;
6524a49b499SJoy Latten }
6534a49b499SJoy Latten 
6544a49b499SJoy Latten static int crypto_rfc4309_encrypt(struct aead_request *req)
6554a49b499SJoy Latten {
65681c4c35eSHerbert Xu 	if (req->assoclen != 16 && req->assoclen != 20)
65781c4c35eSHerbert Xu 		return -EINVAL;
65881c4c35eSHerbert Xu 
6594a49b499SJoy Latten 	req = crypto_rfc4309_crypt(req);
6604a49b499SJoy Latten 
6614a49b499SJoy Latten 	return crypto_aead_encrypt(req);
6624a49b499SJoy Latten }
6634a49b499SJoy Latten 
6644a49b499SJoy Latten static int crypto_rfc4309_decrypt(struct aead_request *req)
6654a49b499SJoy Latten {
66681c4c35eSHerbert Xu 	if (req->assoclen != 16 && req->assoclen != 20)
66781c4c35eSHerbert Xu 		return -EINVAL;
66881c4c35eSHerbert Xu 
6694a49b499SJoy Latten 	req = crypto_rfc4309_crypt(req);
6704a49b499SJoy Latten 
6714a49b499SJoy Latten 	return crypto_aead_decrypt(req);
6724a49b499SJoy Latten }
6734a49b499SJoy Latten 
67481c4c35eSHerbert Xu static int crypto_rfc4309_init_tfm(struct crypto_aead *tfm)
6754a49b499SJoy Latten {
67681c4c35eSHerbert Xu 	struct aead_instance *inst = aead_alg_instance(tfm);
67781c4c35eSHerbert Xu 	struct crypto_aead_spawn *spawn = aead_instance_ctx(inst);
67881c4c35eSHerbert Xu 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(tfm);
6794a49b499SJoy Latten 	struct crypto_aead *aead;
6804a49b499SJoy Latten 	unsigned long align;
6814a49b499SJoy Latten 
6824a49b499SJoy Latten 	aead = crypto_spawn_aead(spawn);
6834a49b499SJoy Latten 	if (IS_ERR(aead))
6844a49b499SJoy Latten 		return PTR_ERR(aead);
6854a49b499SJoy Latten 
6864a49b499SJoy Latten 	ctx->child = aead;
6874a49b499SJoy Latten 
6884a49b499SJoy Latten 	align = crypto_aead_alignmask(aead);
6894a49b499SJoy Latten 	align &= ~(crypto_tfm_ctx_alignment() - 1);
69081c4c35eSHerbert Xu 	crypto_aead_set_reqsize(
69181c4c35eSHerbert Xu 		tfm,
69281c4c35eSHerbert Xu 		sizeof(struct crypto_rfc4309_req_ctx) +
6932c221ad3SHerbert Xu 		ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) +
69481c4c35eSHerbert Xu 		align + 32);
6954a49b499SJoy Latten 
6964a49b499SJoy Latten 	return 0;
6974a49b499SJoy Latten }
6984a49b499SJoy Latten 
69981c4c35eSHerbert Xu static void crypto_rfc4309_exit_tfm(struct crypto_aead *tfm)
7004a49b499SJoy Latten {
70181c4c35eSHerbert Xu 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(tfm);
7024a49b499SJoy Latten 
7034a49b499SJoy Latten 	crypto_free_aead(ctx->child);
7044a49b499SJoy Latten }
7054a49b499SJoy Latten 
70681c4c35eSHerbert Xu static void crypto_rfc4309_free(struct aead_instance *inst)
70781c4c35eSHerbert Xu {
70881c4c35eSHerbert Xu 	crypto_drop_aead(aead_instance_ctx(inst));
70981c4c35eSHerbert Xu 	kfree(inst);
71081c4c35eSHerbert Xu }
71181c4c35eSHerbert Xu 
71281c4c35eSHerbert Xu static int crypto_rfc4309_create(struct crypto_template *tmpl,
71381c4c35eSHerbert Xu 				 struct rtattr **tb)
7144a49b499SJoy Latten {
7154a49b499SJoy Latten 	struct crypto_attr_type *algt;
716cd900f0cSEric Biggers 	u32 mask;
71781c4c35eSHerbert Xu 	struct aead_instance *inst;
7184a49b499SJoy Latten 	struct crypto_aead_spawn *spawn;
71981c4c35eSHerbert Xu 	struct aead_alg *alg;
7204a49b499SJoy Latten 	const char *ccm_name;
7214a49b499SJoy Latten 	int err;
7224a49b499SJoy Latten 
7234a49b499SJoy Latten 	algt = crypto_get_attr_type(tb);
7244a49b499SJoy Latten 	if (IS_ERR(algt))
72581c4c35eSHerbert Xu 		return PTR_ERR(algt);
7264a49b499SJoy Latten 
7275e4b8c1fSHerbert Xu 	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
72881c4c35eSHerbert Xu 		return -EINVAL;
7294a49b499SJoy Latten 
730cd900f0cSEric Biggers 	mask = crypto_requires_sync(algt->type, algt->mask);
731cd900f0cSEric Biggers 
7324a49b499SJoy Latten 	ccm_name = crypto_attr_alg_name(tb[1]);
7334a49b499SJoy Latten 	if (IS_ERR(ccm_name))
73481c4c35eSHerbert Xu 		return PTR_ERR(ccm_name);
7354a49b499SJoy Latten 
7364a49b499SJoy Latten 	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
7374a49b499SJoy Latten 	if (!inst)
73881c4c35eSHerbert Xu 		return -ENOMEM;
7394a49b499SJoy Latten 
74081c4c35eSHerbert Xu 	spawn = aead_instance_ctx(inst);
741cd900f0cSEric Biggers 	err = crypto_grab_aead(spawn, aead_crypto_instance(inst),
742cd900f0cSEric Biggers 			       ccm_name, 0, mask);
7434a49b499SJoy Latten 	if (err)
7444a49b499SJoy Latten 		goto out_free_inst;
7454a49b499SJoy Latten 
74681c4c35eSHerbert Xu 	alg = crypto_spawn_aead_alg(spawn);
7474a49b499SJoy Latten 
7484a49b499SJoy Latten 	err = -EINVAL;
7494a49b499SJoy Latten 
7504a49b499SJoy Latten 	/* We only support 16-byte blocks. */
75181c4c35eSHerbert Xu 	if (crypto_aead_alg_ivsize(alg) != 16)
7524a49b499SJoy Latten 		goto out_drop_alg;
7534a49b499SJoy Latten 
7544a49b499SJoy Latten 	/* Not a stream cipher? */
75581c4c35eSHerbert Xu 	if (alg->base.cra_blocksize != 1)
7564a49b499SJoy Latten 		goto out_drop_alg;
7574a49b499SJoy Latten 
7584a49b499SJoy Latten 	err = -ENAMETOOLONG;
75981c4c35eSHerbert Xu 	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
76081c4c35eSHerbert Xu 		     "rfc4309(%s)", alg->base.cra_name) >=
76181c4c35eSHerbert Xu 	    CRYPTO_MAX_ALG_NAME ||
76281c4c35eSHerbert Xu 	    snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
76381c4c35eSHerbert Xu 		     "rfc4309(%s)", alg->base.cra_driver_name) >=
7644a49b499SJoy Latten 	    CRYPTO_MAX_ALG_NAME)
7654a49b499SJoy Latten 		goto out_drop_alg;
7664a49b499SJoy Latten 
76781c4c35eSHerbert Xu 	inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC;
76881c4c35eSHerbert Xu 	inst->alg.base.cra_priority = alg->base.cra_priority;
76981c4c35eSHerbert Xu 	inst->alg.base.cra_blocksize = 1;
77081c4c35eSHerbert Xu 	inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
7714a49b499SJoy Latten 
77281c4c35eSHerbert Xu 	inst->alg.ivsize = 8;
773464b93a3SHerbert Xu 	inst->alg.chunksize = crypto_aead_alg_chunksize(alg);
77481c4c35eSHerbert Xu 	inst->alg.maxauthsize = 16;
7754a49b499SJoy Latten 
77681c4c35eSHerbert Xu 	inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4309_ctx);
7774a49b499SJoy Latten 
77881c4c35eSHerbert Xu 	inst->alg.init = crypto_rfc4309_init_tfm;
77981c4c35eSHerbert Xu 	inst->alg.exit = crypto_rfc4309_exit_tfm;
7804a49b499SJoy Latten 
78181c4c35eSHerbert Xu 	inst->alg.setkey = crypto_rfc4309_setkey;
78281c4c35eSHerbert Xu 	inst->alg.setauthsize = crypto_rfc4309_setauthsize;
78381c4c35eSHerbert Xu 	inst->alg.encrypt = crypto_rfc4309_encrypt;
78481c4c35eSHerbert Xu 	inst->alg.decrypt = crypto_rfc4309_decrypt;
7854a49b499SJoy Latten 
78681c4c35eSHerbert Xu 	inst->free = crypto_rfc4309_free;
78781c4c35eSHerbert Xu 
78881c4c35eSHerbert Xu 	err = aead_register_instance(tmpl, inst);
78981c4c35eSHerbert Xu 	if (err)
79081c4c35eSHerbert Xu 		goto out_drop_alg;
7914a49b499SJoy Latten 
7924a49b499SJoy Latten out:
79381c4c35eSHerbert Xu 	return err;
7944a49b499SJoy Latten 
7954a49b499SJoy Latten out_drop_alg:
7964a49b499SJoy Latten 	crypto_drop_aead(spawn);
7974a49b499SJoy Latten out_free_inst:
7984a49b499SJoy Latten 	kfree(inst);
7994a49b499SJoy Latten 	goto out;
8004a49b499SJoy Latten }
8014a49b499SJoy Latten 
802f15f05b0SArd Biesheuvel static int crypto_cbcmac_digest_setkey(struct crypto_shash *parent,
803f15f05b0SArd Biesheuvel 				     const u8 *inkey, unsigned int keylen)
804f15f05b0SArd Biesheuvel {
805f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *ctx = crypto_shash_ctx(parent);
806f15f05b0SArd Biesheuvel 
807f15f05b0SArd Biesheuvel 	return crypto_cipher_setkey(ctx->child, inkey, keylen);
808f15f05b0SArd Biesheuvel }
809f15f05b0SArd Biesheuvel 
810f15f05b0SArd Biesheuvel static int crypto_cbcmac_digest_init(struct shash_desc *pdesc)
811f15f05b0SArd Biesheuvel {
812f15f05b0SArd Biesheuvel 	struct cbcmac_desc_ctx *ctx = shash_desc_ctx(pdesc);
813f15f05b0SArd Biesheuvel 	int bs = crypto_shash_digestsize(pdesc->tfm);
8145338ad70SArd Biesheuvel 	u8 *dg = (u8 *)ctx + crypto_shash_descsize(pdesc->tfm) - bs;
815f15f05b0SArd Biesheuvel 
816f15f05b0SArd Biesheuvel 	ctx->len = 0;
8175338ad70SArd Biesheuvel 	memset(dg, 0, bs);
818f15f05b0SArd Biesheuvel 
819f15f05b0SArd Biesheuvel 	return 0;
820f15f05b0SArd Biesheuvel }
821f15f05b0SArd Biesheuvel 
822f15f05b0SArd Biesheuvel static int crypto_cbcmac_digest_update(struct shash_desc *pdesc, const u8 *p,
823f15f05b0SArd Biesheuvel 				       unsigned int len)
824f15f05b0SArd Biesheuvel {
825f15f05b0SArd Biesheuvel 	struct crypto_shash *parent = pdesc->tfm;
826f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *tctx = crypto_shash_ctx(parent);
827f15f05b0SArd Biesheuvel 	struct cbcmac_desc_ctx *ctx = shash_desc_ctx(pdesc);
828f15f05b0SArd Biesheuvel 	struct crypto_cipher *tfm = tctx->child;
829f15f05b0SArd Biesheuvel 	int bs = crypto_shash_digestsize(parent);
8305338ad70SArd Biesheuvel 	u8 *dg = (u8 *)ctx + crypto_shash_descsize(parent) - bs;
831f15f05b0SArd Biesheuvel 
832f15f05b0SArd Biesheuvel 	while (len > 0) {
833f15f05b0SArd Biesheuvel 		unsigned int l = min(len, bs - ctx->len);
834f15f05b0SArd Biesheuvel 
8355338ad70SArd Biesheuvel 		crypto_xor(dg + ctx->len, p, l);
836f15f05b0SArd Biesheuvel 		ctx->len +=l;
837f15f05b0SArd Biesheuvel 		len -= l;
838f15f05b0SArd Biesheuvel 		p += l;
839f15f05b0SArd Biesheuvel 
840f15f05b0SArd Biesheuvel 		if (ctx->len == bs) {
8415338ad70SArd Biesheuvel 			crypto_cipher_encrypt_one(tfm, dg, dg);
842f15f05b0SArd Biesheuvel 			ctx->len = 0;
843f15f05b0SArd Biesheuvel 		}
844f15f05b0SArd Biesheuvel 	}
845f15f05b0SArd Biesheuvel 
846f15f05b0SArd Biesheuvel 	return 0;
847f15f05b0SArd Biesheuvel }
848f15f05b0SArd Biesheuvel 
849f15f05b0SArd Biesheuvel static int crypto_cbcmac_digest_final(struct shash_desc *pdesc, u8 *out)
850f15f05b0SArd Biesheuvel {
851f15f05b0SArd Biesheuvel 	struct crypto_shash *parent = pdesc->tfm;
852f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *tctx = crypto_shash_ctx(parent);
853f15f05b0SArd Biesheuvel 	struct cbcmac_desc_ctx *ctx = shash_desc_ctx(pdesc);
854f15f05b0SArd Biesheuvel 	struct crypto_cipher *tfm = tctx->child;
855f15f05b0SArd Biesheuvel 	int bs = crypto_shash_digestsize(parent);
8565338ad70SArd Biesheuvel 	u8 *dg = (u8 *)ctx + crypto_shash_descsize(parent) - bs;
857f15f05b0SArd Biesheuvel 
858f15f05b0SArd Biesheuvel 	if (ctx->len)
8595338ad70SArd Biesheuvel 		crypto_cipher_encrypt_one(tfm, dg, dg);
860f15f05b0SArd Biesheuvel 
8615338ad70SArd Biesheuvel 	memcpy(out, dg, bs);
862f15f05b0SArd Biesheuvel 	return 0;
863f15f05b0SArd Biesheuvel }
864f15f05b0SArd Biesheuvel 
865f15f05b0SArd Biesheuvel static int cbcmac_init_tfm(struct crypto_tfm *tfm)
866f15f05b0SArd Biesheuvel {
867f15f05b0SArd Biesheuvel 	struct crypto_cipher *cipher;
868f15f05b0SArd Biesheuvel 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
869f15f05b0SArd Biesheuvel 	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
870f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
871f15f05b0SArd Biesheuvel 
872f15f05b0SArd Biesheuvel 	cipher = crypto_spawn_cipher(spawn);
873f15f05b0SArd Biesheuvel 	if (IS_ERR(cipher))
874f15f05b0SArd Biesheuvel 		return PTR_ERR(cipher);
875f15f05b0SArd Biesheuvel 
876f15f05b0SArd Biesheuvel 	ctx->child = cipher;
877f15f05b0SArd Biesheuvel 
878f15f05b0SArd Biesheuvel 	return 0;
879f15f05b0SArd Biesheuvel };
880f15f05b0SArd Biesheuvel 
881f15f05b0SArd Biesheuvel static void cbcmac_exit_tfm(struct crypto_tfm *tfm)
882f15f05b0SArd Biesheuvel {
883f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
884f15f05b0SArd Biesheuvel 	crypto_free_cipher(ctx->child);
885f15f05b0SArd Biesheuvel }
886f15f05b0SArd Biesheuvel 
887f15f05b0SArd Biesheuvel static int cbcmac_create(struct crypto_template *tmpl, struct rtattr **tb)
888f15f05b0SArd Biesheuvel {
889f15f05b0SArd Biesheuvel 	struct shash_instance *inst;
890f15f05b0SArd Biesheuvel 	struct crypto_alg *alg;
891f15f05b0SArd Biesheuvel 	int err;
892f15f05b0SArd Biesheuvel 
893f15f05b0SArd Biesheuvel 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH);
894f15f05b0SArd Biesheuvel 	if (err)
895f15f05b0SArd Biesheuvel 		return err;
896f15f05b0SArd Biesheuvel 
897f15f05b0SArd Biesheuvel 	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
898f15f05b0SArd Biesheuvel 				  CRYPTO_ALG_TYPE_MASK);
899f15f05b0SArd Biesheuvel 	if (IS_ERR(alg))
900f15f05b0SArd Biesheuvel 		return PTR_ERR(alg);
901f15f05b0SArd Biesheuvel 
902f15f05b0SArd Biesheuvel 	inst = shash_alloc_instance("cbcmac", alg);
903f15f05b0SArd Biesheuvel 	err = PTR_ERR(inst);
904f15f05b0SArd Biesheuvel 	if (IS_ERR(inst))
905f15f05b0SArd Biesheuvel 		goto out_put_alg;
906f15f05b0SArd Biesheuvel 
907f15f05b0SArd Biesheuvel 	err = crypto_init_spawn(shash_instance_ctx(inst), alg,
908f15f05b0SArd Biesheuvel 				shash_crypto_instance(inst),
909f15f05b0SArd Biesheuvel 				CRYPTO_ALG_TYPE_MASK);
910f15f05b0SArd Biesheuvel 	if (err)
911f15f05b0SArd Biesheuvel 		goto out_free_inst;
912f15f05b0SArd Biesheuvel 
913f15f05b0SArd Biesheuvel 	inst->alg.base.cra_priority = alg->cra_priority;
914f15f05b0SArd Biesheuvel 	inst->alg.base.cra_blocksize = 1;
915f15f05b0SArd Biesheuvel 
916f15f05b0SArd Biesheuvel 	inst->alg.digestsize = alg->cra_blocksize;
9175338ad70SArd Biesheuvel 	inst->alg.descsize = ALIGN(sizeof(struct cbcmac_desc_ctx),
9185338ad70SArd Biesheuvel 				   alg->cra_alignmask + 1) +
919f15f05b0SArd Biesheuvel 			     alg->cra_blocksize;
920f15f05b0SArd Biesheuvel 
921f15f05b0SArd Biesheuvel 	inst->alg.base.cra_ctxsize = sizeof(struct cbcmac_tfm_ctx);
922f15f05b0SArd Biesheuvel 	inst->alg.base.cra_init = cbcmac_init_tfm;
923f15f05b0SArd Biesheuvel 	inst->alg.base.cra_exit = cbcmac_exit_tfm;
924f15f05b0SArd Biesheuvel 
925f15f05b0SArd Biesheuvel 	inst->alg.init = crypto_cbcmac_digest_init;
926f15f05b0SArd Biesheuvel 	inst->alg.update = crypto_cbcmac_digest_update;
927f15f05b0SArd Biesheuvel 	inst->alg.final = crypto_cbcmac_digest_final;
928f15f05b0SArd Biesheuvel 	inst->alg.setkey = crypto_cbcmac_digest_setkey;
929f15f05b0SArd Biesheuvel 
930f15f05b0SArd Biesheuvel 	err = shash_register_instance(tmpl, inst);
931f15f05b0SArd Biesheuvel 
932f15f05b0SArd Biesheuvel out_free_inst:
933f15f05b0SArd Biesheuvel 	if (err)
934f15f05b0SArd Biesheuvel 		shash_free_instance(shash_crypto_instance(inst));
935f15f05b0SArd Biesheuvel 
936f15f05b0SArd Biesheuvel out_put_alg:
937f15f05b0SArd Biesheuvel 	crypto_mod_put(alg);
938f15f05b0SArd Biesheuvel 	return err;
939f15f05b0SArd Biesheuvel }
940f15f05b0SArd Biesheuvel 
9410db19035SXiongfeng Wang static struct crypto_template crypto_ccm_tmpls[] = {
9420db19035SXiongfeng Wang 	{
943f15f05b0SArd Biesheuvel 		.name = "cbcmac",
944f15f05b0SArd Biesheuvel 		.create = cbcmac_create,
945f15f05b0SArd Biesheuvel 		.free = shash_free_instance,
946f15f05b0SArd Biesheuvel 		.module = THIS_MODULE,
9470db19035SXiongfeng Wang 	}, {
9480db19035SXiongfeng Wang 		.name = "ccm_base",
9490db19035SXiongfeng Wang 		.create = crypto_ccm_base_create,
9500db19035SXiongfeng Wang 		.module = THIS_MODULE,
9510db19035SXiongfeng Wang 	}, {
9520db19035SXiongfeng Wang 		.name = "ccm",
9530db19035SXiongfeng Wang 		.create = crypto_ccm_create,
9540db19035SXiongfeng Wang 		.module = THIS_MODULE,
9550db19035SXiongfeng Wang 	}, {
9560db19035SXiongfeng Wang 		.name = "rfc4309",
9570db19035SXiongfeng Wang 		.create = crypto_rfc4309_create,
9580db19035SXiongfeng Wang 		.module = THIS_MODULE,
9590db19035SXiongfeng Wang 	},
960f15f05b0SArd Biesheuvel };
961f15f05b0SArd Biesheuvel 
9624a49b499SJoy Latten static int __init crypto_ccm_module_init(void)
9634a49b499SJoy Latten {
9640db19035SXiongfeng Wang 	return crypto_register_templates(crypto_ccm_tmpls,
9650db19035SXiongfeng Wang 					 ARRAY_SIZE(crypto_ccm_tmpls));
9664a49b499SJoy Latten }
9674a49b499SJoy Latten 
9684a49b499SJoy Latten static void __exit crypto_ccm_module_exit(void)
9694a49b499SJoy Latten {
9700db19035SXiongfeng Wang 	crypto_unregister_templates(crypto_ccm_tmpls,
9710db19035SXiongfeng Wang 				    ARRAY_SIZE(crypto_ccm_tmpls));
9724a49b499SJoy Latten }
9734a49b499SJoy Latten 
974c4741b23SEric Biggers subsys_initcall(crypto_ccm_module_init);
9754a49b499SJoy Latten module_exit(crypto_ccm_module_exit);
9764a49b499SJoy Latten 
9774a49b499SJoy Latten MODULE_LICENSE("GPL");
9784a49b499SJoy Latten MODULE_DESCRIPTION("Counter with CBC MAC");
9795d26a105SKees Cook MODULE_ALIAS_CRYPTO("ccm_base");
9805d26a105SKees Cook MODULE_ALIAS_CRYPTO("rfc4309");
9814943ba16SKees Cook MODULE_ALIAS_CRYPTO("ccm");
982ae748b9cSArd Biesheuvel MODULE_ALIAS_CRYPTO("cbcmac");
983