xref: /openbmc/linux/crypto/ccm.c (revision f15f05b0)
14a49b499SJoy Latten /*
24a49b499SJoy Latten  * CCM: Counter with CBC-MAC
34a49b499SJoy Latten  *
44a49b499SJoy Latten  * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
54a49b499SJoy Latten  *
64a49b499SJoy Latten  * This program is free software; you can redistribute it and/or modify it
74a49b499SJoy Latten  * under the terms of the GNU General Public License as published by the Free
84a49b499SJoy Latten  * Software Foundation; either version 2 of the License, or (at your option)
94a49b499SJoy Latten  * any later version.
104a49b499SJoy Latten  *
114a49b499SJoy Latten  */
124a49b499SJoy Latten 
134a49b499SJoy Latten #include <crypto/internal/aead.h>
14f15f05b0SArd Biesheuvel #include <crypto/internal/hash.h>
154a49b499SJoy Latten #include <crypto/internal/skcipher.h>
164a49b499SJoy Latten #include <crypto/scatterwalk.h>
174a49b499SJoy Latten #include <linux/err.h>
184a49b499SJoy Latten #include <linux/init.h>
194a49b499SJoy Latten #include <linux/kernel.h>
204a49b499SJoy Latten #include <linux/module.h>
214a49b499SJoy Latten #include <linux/slab.h>
224a49b499SJoy Latten 
234a49b499SJoy Latten #include "internal.h"
244a49b499SJoy Latten 
254a49b499SJoy Latten struct ccm_instance_ctx {
264a49b499SJoy Latten 	struct crypto_skcipher_spawn ctr;
27f15f05b0SArd Biesheuvel 	struct crypto_ahash_spawn mac;
284a49b499SJoy Latten };
294a49b499SJoy Latten 
304a49b499SJoy Latten struct crypto_ccm_ctx {
31f15f05b0SArd Biesheuvel 	struct crypto_ahash *mac;
32464b93a3SHerbert Xu 	struct crypto_skcipher *ctr;
334a49b499SJoy Latten };
344a49b499SJoy Latten 
354a49b499SJoy Latten struct crypto_rfc4309_ctx {
364a49b499SJoy Latten 	struct crypto_aead *child;
374a49b499SJoy Latten 	u8 nonce[3];
384a49b499SJoy Latten };
394a49b499SJoy Latten 
4081c4c35eSHerbert Xu struct crypto_rfc4309_req_ctx {
4181c4c35eSHerbert Xu 	struct scatterlist src[3];
4281c4c35eSHerbert Xu 	struct scatterlist dst[3];
4381c4c35eSHerbert Xu 	struct aead_request subreq;
4481c4c35eSHerbert Xu };
4581c4c35eSHerbert Xu 
464a49b499SJoy Latten struct crypto_ccm_req_priv_ctx {
474a49b499SJoy Latten 	u8 odata[16];
484a49b499SJoy Latten 	u8 auth_tag[16];
494a49b499SJoy Latten 	u32 flags;
5081c4c35eSHerbert Xu 	struct scatterlist src[3];
5181c4c35eSHerbert Xu 	struct scatterlist dst[3];
52464b93a3SHerbert Xu 	struct skcipher_request skreq;
534a49b499SJoy Latten };
544a49b499SJoy Latten 
55f15f05b0SArd Biesheuvel struct cbcmac_tfm_ctx {
56f15f05b0SArd Biesheuvel 	struct crypto_cipher *child;
57f15f05b0SArd Biesheuvel };
58f15f05b0SArd Biesheuvel 
59f15f05b0SArd Biesheuvel struct cbcmac_desc_ctx {
60f15f05b0SArd Biesheuvel 	unsigned int len;
61f15f05b0SArd Biesheuvel 	u8 dg[];
62f15f05b0SArd Biesheuvel };
63f15f05b0SArd Biesheuvel 
644a49b499SJoy Latten static inline struct crypto_ccm_req_priv_ctx *crypto_ccm_reqctx(
654a49b499SJoy Latten 	struct aead_request *req)
664a49b499SJoy Latten {
674a49b499SJoy Latten 	unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req));
684a49b499SJoy Latten 
694a49b499SJoy Latten 	return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1);
704a49b499SJoy Latten }
714a49b499SJoy Latten 
724a49b499SJoy Latten static int set_msg_len(u8 *block, unsigned int msglen, int csize)
734a49b499SJoy Latten {
744a49b499SJoy Latten 	__be32 data;
754a49b499SJoy Latten 
764a49b499SJoy Latten 	memset(block, 0, csize);
774a49b499SJoy Latten 	block += csize;
784a49b499SJoy Latten 
794a49b499SJoy Latten 	if (csize >= 4)
804a49b499SJoy Latten 		csize = 4;
814a49b499SJoy Latten 	else if (msglen > (1 << (8 * csize)))
824a49b499SJoy Latten 		return -EOVERFLOW;
834a49b499SJoy Latten 
844a49b499SJoy Latten 	data = cpu_to_be32(msglen);
854a49b499SJoy Latten 	memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
864a49b499SJoy Latten 
874a49b499SJoy Latten 	return 0;
884a49b499SJoy Latten }
894a49b499SJoy Latten 
904a49b499SJoy Latten static int crypto_ccm_setkey(struct crypto_aead *aead, const u8 *key,
914a49b499SJoy Latten 			     unsigned int keylen)
924a49b499SJoy Latten {
934a49b499SJoy Latten 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
94464b93a3SHerbert Xu 	struct crypto_skcipher *ctr = ctx->ctr;
95f15f05b0SArd Biesheuvel 	struct crypto_ahash *mac = ctx->mac;
964a49b499SJoy Latten 	int err = 0;
974a49b499SJoy Latten 
98464b93a3SHerbert Xu 	crypto_skcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
99464b93a3SHerbert Xu 	crypto_skcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
1004a49b499SJoy Latten 				       CRYPTO_TFM_REQ_MASK);
101464b93a3SHerbert Xu 	err = crypto_skcipher_setkey(ctr, key, keylen);
102464b93a3SHerbert Xu 	crypto_aead_set_flags(aead, crypto_skcipher_get_flags(ctr) &
1034a49b499SJoy Latten 			      CRYPTO_TFM_RES_MASK);
1044a49b499SJoy Latten 	if (err)
1054a49b499SJoy Latten 		goto out;
1064a49b499SJoy Latten 
107f15f05b0SArd Biesheuvel 	crypto_ahash_clear_flags(mac, CRYPTO_TFM_REQ_MASK);
108f15f05b0SArd Biesheuvel 	crypto_ahash_set_flags(mac, crypto_aead_get_flags(aead) &
1094a49b499SJoy Latten 				    CRYPTO_TFM_REQ_MASK);
110f15f05b0SArd Biesheuvel 	err = crypto_ahash_setkey(mac, key, keylen);
111f15f05b0SArd Biesheuvel 	crypto_aead_set_flags(aead, crypto_ahash_get_flags(mac) &
1124a49b499SJoy Latten 			      CRYPTO_TFM_RES_MASK);
1134a49b499SJoy Latten 
1144a49b499SJoy Latten out:
1154a49b499SJoy Latten 	return err;
1164a49b499SJoy Latten }
1174a49b499SJoy Latten 
1184a49b499SJoy Latten static int crypto_ccm_setauthsize(struct crypto_aead *tfm,
1194a49b499SJoy Latten 				  unsigned int authsize)
1204a49b499SJoy Latten {
1214a49b499SJoy Latten 	switch (authsize) {
1224a49b499SJoy Latten 	case 4:
1234a49b499SJoy Latten 	case 6:
1244a49b499SJoy Latten 	case 8:
1254a49b499SJoy Latten 	case 10:
1264a49b499SJoy Latten 	case 12:
1274a49b499SJoy Latten 	case 14:
1284a49b499SJoy Latten 	case 16:
1294a49b499SJoy Latten 		break;
1304a49b499SJoy Latten 	default:
1314a49b499SJoy Latten 		return -EINVAL;
1324a49b499SJoy Latten 	}
1334a49b499SJoy Latten 
1344a49b499SJoy Latten 	return 0;
1354a49b499SJoy Latten }
1364a49b499SJoy Latten 
1374a49b499SJoy Latten static int format_input(u8 *info, struct aead_request *req,
1384a49b499SJoy Latten 			unsigned int cryptlen)
1394a49b499SJoy Latten {
1404a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
1414a49b499SJoy Latten 	unsigned int lp = req->iv[0];
1424a49b499SJoy Latten 	unsigned int l = lp + 1;
1434a49b499SJoy Latten 	unsigned int m;
1444a49b499SJoy Latten 
1454a49b499SJoy Latten 	m = crypto_aead_authsize(aead);
1464a49b499SJoy Latten 
1474a49b499SJoy Latten 	memcpy(info, req->iv, 16);
1484a49b499SJoy Latten 
1494a49b499SJoy Latten 	/* format control info per RFC 3610 and
1504a49b499SJoy Latten 	 * NIST Special Publication 800-38C
1514a49b499SJoy Latten 	 */
1524a49b499SJoy Latten 	*info |= (8 * ((m - 2) / 2));
1534a49b499SJoy Latten 	if (req->assoclen)
1544a49b499SJoy Latten 		*info |= 64;
1554a49b499SJoy Latten 
1564a49b499SJoy Latten 	return set_msg_len(info + 16 - l, cryptlen, l);
1574a49b499SJoy Latten }
1584a49b499SJoy Latten 
1594a49b499SJoy Latten static int format_adata(u8 *adata, unsigned int a)
1604a49b499SJoy Latten {
1614a49b499SJoy Latten 	int len = 0;
1624a49b499SJoy Latten 
1634a49b499SJoy Latten 	/* add control info for associated data
1644a49b499SJoy Latten 	 * RFC 3610 and NIST Special Publication 800-38C
1654a49b499SJoy Latten 	 */
1664a49b499SJoy Latten 	if (a < 65280) {
1674a49b499SJoy Latten 		*(__be16 *)adata = cpu_to_be16(a);
1684a49b499SJoy Latten 		len = 2;
1694a49b499SJoy Latten 	} else  {
1704a49b499SJoy Latten 		*(__be16 *)adata = cpu_to_be16(0xfffe);
1714a49b499SJoy Latten 		*(__be32 *)&adata[2] = cpu_to_be32(a);
1724a49b499SJoy Latten 		len = 6;
1734a49b499SJoy Latten 	}
1744a49b499SJoy Latten 
1754a49b499SJoy Latten 	return len;
1764a49b499SJoy Latten }
1774a49b499SJoy Latten 
1784a49b499SJoy Latten static int crypto_ccm_auth(struct aead_request *req, struct scatterlist *plain,
1794a49b499SJoy Latten 			   unsigned int cryptlen)
1804a49b499SJoy Latten {
181f15f05b0SArd Biesheuvel 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
1824a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
1834a49b499SJoy Latten 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
184f15f05b0SArd Biesheuvel 	AHASH_REQUEST_ON_STACK(ahreq, ctx->mac);
1854a49b499SJoy Latten 	unsigned int assoclen = req->assoclen;
186f15f05b0SArd Biesheuvel 	struct scatterlist sg[3];
187f15f05b0SArd Biesheuvel 	u8 odata[16];
188f15f05b0SArd Biesheuvel 	u8 idata[16];
189f15f05b0SArd Biesheuvel 	int ilen, err;
1904a49b499SJoy Latten 
1914a49b499SJoy Latten 	/* format control data for input */
1924a49b499SJoy Latten 	err = format_input(odata, req, cryptlen);
1934a49b499SJoy Latten 	if (err)
1944a49b499SJoy Latten 		goto out;
1954a49b499SJoy Latten 
196f15f05b0SArd Biesheuvel 	sg_init_table(sg, 3);
197f15f05b0SArd Biesheuvel 	sg_set_buf(&sg[0], odata, 16);
1984a49b499SJoy Latten 
1994a49b499SJoy Latten 	/* format associated data and compute into mac */
2004a49b499SJoy Latten 	if (assoclen) {
201f15f05b0SArd Biesheuvel 		ilen = format_adata(idata, assoclen);
202f15f05b0SArd Biesheuvel 		sg_set_buf(&sg[1], idata, ilen);
203f15f05b0SArd Biesheuvel 		sg_chain(sg, 3, req->src);
204516280e7SJarod Wilson 	} else {
205f15f05b0SArd Biesheuvel 		ilen = 0;
206f15f05b0SArd Biesheuvel 		sg_chain(sg, 2, req->src);
2074a49b499SJoy Latten 	}
2084a49b499SJoy Latten 
209f15f05b0SArd Biesheuvel 	ahash_request_set_tfm(ahreq, ctx->mac);
210f15f05b0SArd Biesheuvel 	ahash_request_set_callback(ahreq, pctx->flags, NULL, NULL);
211f15f05b0SArd Biesheuvel 	ahash_request_set_crypt(ahreq, sg, NULL, assoclen + ilen + 16);
212f15f05b0SArd Biesheuvel 	err = crypto_ahash_init(ahreq);
213f15f05b0SArd Biesheuvel 	if (err)
214f15f05b0SArd Biesheuvel 		goto out;
215f15f05b0SArd Biesheuvel 	err = crypto_ahash_update(ahreq);
216f15f05b0SArd Biesheuvel 	if (err)
217f15f05b0SArd Biesheuvel 		goto out;
2184a49b499SJoy Latten 
219f15f05b0SArd Biesheuvel 	/* we need to pad the MAC input to a round multiple of the block size */
220f15f05b0SArd Biesheuvel 	ilen = 16 - (assoclen + ilen) % 16;
221f15f05b0SArd Biesheuvel 	if (ilen < 16) {
222f15f05b0SArd Biesheuvel 		memset(idata, 0, ilen);
223f15f05b0SArd Biesheuvel 		sg_init_table(sg, 2);
224f15f05b0SArd Biesheuvel 		sg_set_buf(&sg[0], idata, ilen);
225f15f05b0SArd Biesheuvel 		if (plain)
226f15f05b0SArd Biesheuvel 			sg_chain(sg, 2, plain);
227f15f05b0SArd Biesheuvel 		plain = sg;
228f15f05b0SArd Biesheuvel 		cryptlen += ilen;
229f15f05b0SArd Biesheuvel 	}
230f15f05b0SArd Biesheuvel 
231f15f05b0SArd Biesheuvel 	ahash_request_set_crypt(ahreq, plain, pctx->odata, cryptlen);
232f15f05b0SArd Biesheuvel 	err = crypto_ahash_finup(ahreq);
2334a49b499SJoy Latten out:
2344a49b499SJoy Latten 	return err;
2354a49b499SJoy Latten }
2364a49b499SJoy Latten 
2374a49b499SJoy Latten static void crypto_ccm_encrypt_done(struct crypto_async_request *areq, int err)
2384a49b499SJoy Latten {
2394a49b499SJoy Latten 	struct aead_request *req = areq->data;
2404a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
2414a49b499SJoy Latten 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
2424a49b499SJoy Latten 	u8 *odata = pctx->odata;
2434a49b499SJoy Latten 
2444a49b499SJoy Latten 	if (!err)
24581c4c35eSHerbert Xu 		scatterwalk_map_and_copy(odata, req->dst,
24681c4c35eSHerbert Xu 					 req->assoclen + req->cryptlen,
2474a49b499SJoy Latten 					 crypto_aead_authsize(aead), 1);
2484a49b499SJoy Latten 	aead_request_complete(req, err);
2494a49b499SJoy Latten }
2504a49b499SJoy Latten 
2514a49b499SJoy Latten static inline int crypto_ccm_check_iv(const u8 *iv)
2524a49b499SJoy Latten {
2534a49b499SJoy Latten 	/* 2 <= L <= 8, so 1 <= L' <= 7. */
2544a49b499SJoy Latten 	if (1 > iv[0] || iv[0] > 7)
2554a49b499SJoy Latten 		return -EINVAL;
2564a49b499SJoy Latten 
2574a49b499SJoy Latten 	return 0;
2584a49b499SJoy Latten }
2594a49b499SJoy Latten 
26081c4c35eSHerbert Xu static int crypto_ccm_init_crypt(struct aead_request *req, u8 *tag)
26181c4c35eSHerbert Xu {
26281c4c35eSHerbert Xu 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
26381c4c35eSHerbert Xu 	struct scatterlist *sg;
26481c4c35eSHerbert Xu 	u8 *iv = req->iv;
26581c4c35eSHerbert Xu 	int err;
26681c4c35eSHerbert Xu 
26781c4c35eSHerbert Xu 	err = crypto_ccm_check_iv(iv);
26881c4c35eSHerbert Xu 	if (err)
26981c4c35eSHerbert Xu 		return err;
27081c4c35eSHerbert Xu 
27181c4c35eSHerbert Xu 	pctx->flags = aead_request_flags(req);
27281c4c35eSHerbert Xu 
27381c4c35eSHerbert Xu 	 /* Note: rfc 3610 and NIST 800-38C require counter of
27481c4c35eSHerbert Xu 	 * zero to encrypt auth tag.
27581c4c35eSHerbert Xu 	 */
27681c4c35eSHerbert Xu 	memset(iv + 15 - iv[0], 0, iv[0] + 1);
27781c4c35eSHerbert Xu 
27881c4c35eSHerbert Xu 	sg_init_table(pctx->src, 3);
27981c4c35eSHerbert Xu 	sg_set_buf(pctx->src, tag, 16);
28081c4c35eSHerbert Xu 	sg = scatterwalk_ffwd(pctx->src + 1, req->src, req->assoclen);
28181c4c35eSHerbert Xu 	if (sg != pctx->src + 1)
28281c4c35eSHerbert Xu 		sg_chain(pctx->src, 2, sg);
28381c4c35eSHerbert Xu 
28481c4c35eSHerbert Xu 	if (req->src != req->dst) {
28581c4c35eSHerbert Xu 		sg_init_table(pctx->dst, 3);
28681c4c35eSHerbert Xu 		sg_set_buf(pctx->dst, tag, 16);
28781c4c35eSHerbert Xu 		sg = scatterwalk_ffwd(pctx->dst + 1, req->dst, req->assoclen);
28881c4c35eSHerbert Xu 		if (sg != pctx->dst + 1)
28981c4c35eSHerbert Xu 			sg_chain(pctx->dst, 2, sg);
29081c4c35eSHerbert Xu 	}
29181c4c35eSHerbert Xu 
29281c4c35eSHerbert Xu 	return 0;
29381c4c35eSHerbert Xu }
29481c4c35eSHerbert Xu 
2954a49b499SJoy Latten static int crypto_ccm_encrypt(struct aead_request *req)
2964a49b499SJoy Latten {
2974a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
2984a49b499SJoy Latten 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
2994a49b499SJoy Latten 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
300464b93a3SHerbert Xu 	struct skcipher_request *skreq = &pctx->skreq;
3014a49b499SJoy Latten 	struct scatterlist *dst;
3024a49b499SJoy Latten 	unsigned int cryptlen = req->cryptlen;
3034a49b499SJoy Latten 	u8 *odata = pctx->odata;
3044a49b499SJoy Latten 	u8 *iv = req->iv;
3054a49b499SJoy Latten 	int err;
3064a49b499SJoy Latten 
30781c4c35eSHerbert Xu 	err = crypto_ccm_init_crypt(req, odata);
3084a49b499SJoy Latten 	if (err)
3094a49b499SJoy Latten 		return err;
3104a49b499SJoy Latten 
31181c4c35eSHerbert Xu 	err = crypto_ccm_auth(req, sg_next(pctx->src), cryptlen);
3124a49b499SJoy Latten 	if (err)
3134a49b499SJoy Latten 		return err;
3144a49b499SJoy Latten 
3154a49b499SJoy Latten 	dst = pctx->src;
31681c4c35eSHerbert Xu 	if (req->src != req->dst)
3174a49b499SJoy Latten 		dst = pctx->dst;
3184a49b499SJoy Latten 
319464b93a3SHerbert Xu 	skcipher_request_set_tfm(skreq, ctx->ctr);
320464b93a3SHerbert Xu 	skcipher_request_set_callback(skreq, pctx->flags,
3214a49b499SJoy Latten 				      crypto_ccm_encrypt_done, req);
322464b93a3SHerbert Xu 	skcipher_request_set_crypt(skreq, pctx->src, dst, cryptlen + 16, iv);
323464b93a3SHerbert Xu 	err = crypto_skcipher_encrypt(skreq);
3244a49b499SJoy Latten 	if (err)
3254a49b499SJoy Latten 		return err;
3264a49b499SJoy Latten 
3274a49b499SJoy Latten 	/* copy authtag to end of dst */
32881c4c35eSHerbert Xu 	scatterwalk_map_and_copy(odata, sg_next(dst), cryptlen,
3294a49b499SJoy Latten 				 crypto_aead_authsize(aead), 1);
3304a49b499SJoy Latten 	return err;
3314a49b499SJoy Latten }
3324a49b499SJoy Latten 
3334a49b499SJoy Latten static void crypto_ccm_decrypt_done(struct crypto_async_request *areq,
3344a49b499SJoy Latten 				   int err)
3354a49b499SJoy Latten {
3364a49b499SJoy Latten 	struct aead_request *req = areq->data;
3374a49b499SJoy Latten 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
3384a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
3394a49b499SJoy Latten 	unsigned int authsize = crypto_aead_authsize(aead);
3404a49b499SJoy Latten 	unsigned int cryptlen = req->cryptlen - authsize;
34181c4c35eSHerbert Xu 	struct scatterlist *dst;
34281c4c35eSHerbert Xu 
34381c4c35eSHerbert Xu 	pctx->flags = 0;
34481c4c35eSHerbert Xu 
34581c4c35eSHerbert Xu 	dst = sg_next(req->src == req->dst ? pctx->src : pctx->dst);
3464a49b499SJoy Latten 
3474a49b499SJoy Latten 	if (!err) {
34881c4c35eSHerbert Xu 		err = crypto_ccm_auth(req, dst, cryptlen);
3496bf37e5aSJames Yonan 		if (!err && crypto_memneq(pctx->auth_tag, pctx->odata, authsize))
3504a49b499SJoy Latten 			err = -EBADMSG;
3514a49b499SJoy Latten 	}
3524a49b499SJoy Latten 	aead_request_complete(req, err);
3534a49b499SJoy Latten }
3544a49b499SJoy Latten 
3554a49b499SJoy Latten static int crypto_ccm_decrypt(struct aead_request *req)
3564a49b499SJoy Latten {
3574a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
3584a49b499SJoy Latten 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
3594a49b499SJoy Latten 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
360464b93a3SHerbert Xu 	struct skcipher_request *skreq = &pctx->skreq;
3614a49b499SJoy Latten 	struct scatterlist *dst;
3624a49b499SJoy Latten 	unsigned int authsize = crypto_aead_authsize(aead);
3634a49b499SJoy Latten 	unsigned int cryptlen = req->cryptlen;
3644a49b499SJoy Latten 	u8 *authtag = pctx->auth_tag;
3654a49b499SJoy Latten 	u8 *odata = pctx->odata;
3664a49b499SJoy Latten 	u8 *iv = req->iv;
3674a49b499SJoy Latten 	int err;
3684a49b499SJoy Latten 
3694a49b499SJoy Latten 	cryptlen -= authsize;
3704a49b499SJoy Latten 
37181c4c35eSHerbert Xu 	err = crypto_ccm_init_crypt(req, authtag);
3724a49b499SJoy Latten 	if (err)
3734a49b499SJoy Latten 		return err;
3744a49b499SJoy Latten 
37581c4c35eSHerbert Xu 	scatterwalk_map_and_copy(authtag, sg_next(pctx->src), cryptlen,
37681c4c35eSHerbert Xu 				 authsize, 0);
3774a49b499SJoy Latten 
3784a49b499SJoy Latten 	dst = pctx->src;
37981c4c35eSHerbert Xu 	if (req->src != req->dst)
3804a49b499SJoy Latten 		dst = pctx->dst;
3814a49b499SJoy Latten 
382464b93a3SHerbert Xu 	skcipher_request_set_tfm(skreq, ctx->ctr);
383464b93a3SHerbert Xu 	skcipher_request_set_callback(skreq, pctx->flags,
3844a49b499SJoy Latten 				      crypto_ccm_decrypt_done, req);
385464b93a3SHerbert Xu 	skcipher_request_set_crypt(skreq, pctx->src, dst, cryptlen + 16, iv);
386464b93a3SHerbert Xu 	err = crypto_skcipher_decrypt(skreq);
3874a49b499SJoy Latten 	if (err)
3884a49b499SJoy Latten 		return err;
3894a49b499SJoy Latten 
39081c4c35eSHerbert Xu 	err = crypto_ccm_auth(req, sg_next(dst), cryptlen);
3914a49b499SJoy Latten 	if (err)
3924a49b499SJoy Latten 		return err;
3934a49b499SJoy Latten 
3944a49b499SJoy Latten 	/* verify */
3956bf37e5aSJames Yonan 	if (crypto_memneq(authtag, odata, authsize))
3964a49b499SJoy Latten 		return -EBADMSG;
3974a49b499SJoy Latten 
3984a49b499SJoy Latten 	return err;
3994a49b499SJoy Latten }
4004a49b499SJoy Latten 
40181c4c35eSHerbert Xu static int crypto_ccm_init_tfm(struct crypto_aead *tfm)
4024a49b499SJoy Latten {
40381c4c35eSHerbert Xu 	struct aead_instance *inst = aead_alg_instance(tfm);
40481c4c35eSHerbert Xu 	struct ccm_instance_ctx *ictx = aead_instance_ctx(inst);
40581c4c35eSHerbert Xu 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(tfm);
406f15f05b0SArd Biesheuvel 	struct crypto_ahash *mac;
407464b93a3SHerbert Xu 	struct crypto_skcipher *ctr;
4084a49b499SJoy Latten 	unsigned long align;
4094a49b499SJoy Latten 	int err;
4104a49b499SJoy Latten 
411f15f05b0SArd Biesheuvel 	mac = crypto_spawn_ahash(&ictx->mac);
412f15f05b0SArd Biesheuvel 	if (IS_ERR(mac))
413f15f05b0SArd Biesheuvel 		return PTR_ERR(mac);
4144a49b499SJoy Latten 
41560425a8bSEric Biggers 	ctr = crypto_spawn_skcipher(&ictx->ctr);
4164a49b499SJoy Latten 	err = PTR_ERR(ctr);
4174a49b499SJoy Latten 	if (IS_ERR(ctr))
418f15f05b0SArd Biesheuvel 		goto err_free_mac;
4194a49b499SJoy Latten 
420f15f05b0SArd Biesheuvel 	ctx->mac = mac;
4214a49b499SJoy Latten 	ctx->ctr = ctr;
4224a49b499SJoy Latten 
42381c4c35eSHerbert Xu 	align = crypto_aead_alignmask(tfm);
4244a49b499SJoy Latten 	align &= ~(crypto_tfm_ctx_alignment() - 1);
42581c4c35eSHerbert Xu 	crypto_aead_set_reqsize(
42681c4c35eSHerbert Xu 		tfm,
4272c221ad3SHerbert Xu 		align + sizeof(struct crypto_ccm_req_priv_ctx) +
428464b93a3SHerbert Xu 		crypto_skcipher_reqsize(ctr));
4294a49b499SJoy Latten 
4304a49b499SJoy Latten 	return 0;
4314a49b499SJoy Latten 
432f15f05b0SArd Biesheuvel err_free_mac:
433f15f05b0SArd Biesheuvel 	crypto_free_ahash(mac);
4344a49b499SJoy Latten 	return err;
4354a49b499SJoy Latten }
4364a49b499SJoy Latten 
43781c4c35eSHerbert Xu static void crypto_ccm_exit_tfm(struct crypto_aead *tfm)
4384a49b499SJoy Latten {
43981c4c35eSHerbert Xu 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(tfm);
4404a49b499SJoy Latten 
441f15f05b0SArd Biesheuvel 	crypto_free_ahash(ctx->mac);
442464b93a3SHerbert Xu 	crypto_free_skcipher(ctx->ctr);
4434a49b499SJoy Latten }
4444a49b499SJoy Latten 
44581c4c35eSHerbert Xu static void crypto_ccm_free(struct aead_instance *inst)
44681c4c35eSHerbert Xu {
44781c4c35eSHerbert Xu 	struct ccm_instance_ctx *ctx = aead_instance_ctx(inst);
44881c4c35eSHerbert Xu 
449f15f05b0SArd Biesheuvel 	crypto_drop_ahash(&ctx->mac);
45081c4c35eSHerbert Xu 	crypto_drop_skcipher(&ctx->ctr);
45181c4c35eSHerbert Xu 	kfree(inst);
45281c4c35eSHerbert Xu }
45381c4c35eSHerbert Xu 
45481c4c35eSHerbert Xu static int crypto_ccm_create_common(struct crypto_template *tmpl,
45581c4c35eSHerbert Xu 				    struct rtattr **tb,
4564a49b499SJoy Latten 				    const char *full_name,
4574a49b499SJoy Latten 				    const char *ctr_name,
458f15f05b0SArd Biesheuvel 				    const char *mac_name)
4594a49b499SJoy Latten {
4604a49b499SJoy Latten 	struct crypto_attr_type *algt;
46181c4c35eSHerbert Xu 	struct aead_instance *inst;
462464b93a3SHerbert Xu 	struct skcipher_alg *ctr;
463f15f05b0SArd Biesheuvel 	struct crypto_alg *mac_alg;
464f15f05b0SArd Biesheuvel 	struct hash_alg_common *mac;
4654a49b499SJoy Latten 	struct ccm_instance_ctx *ictx;
4664a49b499SJoy Latten 	int err;
4674a49b499SJoy Latten 
4684a49b499SJoy Latten 	algt = crypto_get_attr_type(tb);
4694a49b499SJoy Latten 	if (IS_ERR(algt))
47081c4c35eSHerbert Xu 		return PTR_ERR(algt);
4714a49b499SJoy Latten 
4725e4b8c1fSHerbert Xu 	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
47381c4c35eSHerbert Xu 		return -EINVAL;
4744a49b499SJoy Latten 
475f15f05b0SArd Biesheuvel 	mac_alg = crypto_find_alg(mac_name, &crypto_ahash_type,
476f15f05b0SArd Biesheuvel 				  CRYPTO_ALG_TYPE_HASH,
477f15f05b0SArd Biesheuvel 				  CRYPTO_ALG_TYPE_AHASH_MASK |
478f15f05b0SArd Biesheuvel 				  CRYPTO_ALG_ASYNC);
479f15f05b0SArd Biesheuvel 	if (IS_ERR(mac_alg))
480f15f05b0SArd Biesheuvel 		return PTR_ERR(mac_alg);
4814a49b499SJoy Latten 
482f15f05b0SArd Biesheuvel 	mac = __crypto_hash_alg_common(mac_alg);
4834a49b499SJoy Latten 	err = -EINVAL;
484f15f05b0SArd Biesheuvel 	if (mac->digestsize != 16)
485f15f05b0SArd Biesheuvel 		goto out_put_mac;
4864a49b499SJoy Latten 
4874a49b499SJoy Latten 	inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL);
4884a49b499SJoy Latten 	err = -ENOMEM;
4894a49b499SJoy Latten 	if (!inst)
490f15f05b0SArd Biesheuvel 		goto out_put_mac;
4914a49b499SJoy Latten 
49281c4c35eSHerbert Xu 	ictx = aead_instance_ctx(inst);
493f15f05b0SArd Biesheuvel 	err = crypto_init_ahash_spawn(&ictx->mac, mac,
494f15f05b0SArd Biesheuvel 				      aead_crypto_instance(inst));
4954a49b499SJoy Latten 	if (err)
4964a49b499SJoy Latten 		goto err_free_inst;
4974a49b499SJoy Latten 
49881c4c35eSHerbert Xu 	crypto_set_skcipher_spawn(&ictx->ctr, aead_crypto_instance(inst));
499a35528ecSEric Biggers 	err = crypto_grab_skcipher(&ictx->ctr, ctr_name, 0,
5004a49b499SJoy Latten 				   crypto_requires_sync(algt->type,
5014a49b499SJoy Latten 							algt->mask));
5024a49b499SJoy Latten 	if (err)
503f15f05b0SArd Biesheuvel 		goto err_drop_mac;
5044a49b499SJoy Latten 
505464b93a3SHerbert Xu 	ctr = crypto_spawn_skcipher_alg(&ictx->ctr);
5064a49b499SJoy Latten 
5074a49b499SJoy Latten 	/* Not a stream cipher? */
5084a49b499SJoy Latten 	err = -EINVAL;
509464b93a3SHerbert Xu 	if (ctr->base.cra_blocksize != 1)
5104a49b499SJoy Latten 		goto err_drop_ctr;
5114a49b499SJoy Latten 
5124a49b499SJoy Latten 	/* We want the real thing! */
513464b93a3SHerbert Xu 	if (crypto_skcipher_alg_ivsize(ctr) != 16)
5144a49b499SJoy Latten 		goto err_drop_ctr;
5154a49b499SJoy Latten 
5164a49b499SJoy Latten 	err = -ENAMETOOLONG;
51781c4c35eSHerbert Xu 	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
518464b93a3SHerbert Xu 		     "ccm_base(%s,%s)", ctr->base.cra_driver_name,
519f15f05b0SArd Biesheuvel 		     mac->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
5204a49b499SJoy Latten 		goto err_drop_ctr;
5214a49b499SJoy Latten 
52281c4c35eSHerbert Xu 	memcpy(inst->alg.base.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
5234a49b499SJoy Latten 
524464b93a3SHerbert Xu 	inst->alg.base.cra_flags = ctr->base.cra_flags & CRYPTO_ALG_ASYNC;
525f15f05b0SArd Biesheuvel 	inst->alg.base.cra_priority = (mac->base.cra_priority +
526464b93a3SHerbert Xu 				       ctr->base.cra_priority) / 2;
52781c4c35eSHerbert Xu 	inst->alg.base.cra_blocksize = 1;
528f15f05b0SArd Biesheuvel 	inst->alg.base.cra_alignmask = mac->base.cra_alignmask |
529464b93a3SHerbert Xu 				       ctr->base.cra_alignmask |
5304a49b499SJoy Latten 				       (__alignof__(u32) - 1);
53181c4c35eSHerbert Xu 	inst->alg.ivsize = 16;
532464b93a3SHerbert Xu 	inst->alg.chunksize = crypto_skcipher_alg_chunksize(ctr);
53381c4c35eSHerbert Xu 	inst->alg.maxauthsize = 16;
53481c4c35eSHerbert Xu 	inst->alg.base.cra_ctxsize = sizeof(struct crypto_ccm_ctx);
53581c4c35eSHerbert Xu 	inst->alg.init = crypto_ccm_init_tfm;
53681c4c35eSHerbert Xu 	inst->alg.exit = crypto_ccm_exit_tfm;
53781c4c35eSHerbert Xu 	inst->alg.setkey = crypto_ccm_setkey;
53881c4c35eSHerbert Xu 	inst->alg.setauthsize = crypto_ccm_setauthsize;
53981c4c35eSHerbert Xu 	inst->alg.encrypt = crypto_ccm_encrypt;
54081c4c35eSHerbert Xu 	inst->alg.decrypt = crypto_ccm_decrypt;
5414a49b499SJoy Latten 
54281c4c35eSHerbert Xu 	inst->free = crypto_ccm_free;
54381c4c35eSHerbert Xu 
54481c4c35eSHerbert Xu 	err = aead_register_instance(tmpl, inst);
54581c4c35eSHerbert Xu 	if (err)
54681c4c35eSHerbert Xu 		goto err_drop_ctr;
54781c4c35eSHerbert Xu 
548f15f05b0SArd Biesheuvel out_put_mac:
549f15f05b0SArd Biesheuvel 	crypto_mod_put(mac_alg);
55081c4c35eSHerbert Xu 	return err;
5514a49b499SJoy Latten 
5524a49b499SJoy Latten err_drop_ctr:
5534a49b499SJoy Latten 	crypto_drop_skcipher(&ictx->ctr);
554f15f05b0SArd Biesheuvel err_drop_mac:
555f15f05b0SArd Biesheuvel 	crypto_drop_ahash(&ictx->mac);
5564a49b499SJoy Latten err_free_inst:
5574a49b499SJoy Latten 	kfree(inst);
558f15f05b0SArd Biesheuvel 	goto out_put_mac;
5594a49b499SJoy Latten }
5604a49b499SJoy Latten 
56181c4c35eSHerbert Xu static int crypto_ccm_create(struct crypto_template *tmpl, struct rtattr **tb)
5624a49b499SJoy Latten {
5634a49b499SJoy Latten 	const char *cipher_name;
5644a49b499SJoy Latten 	char ctr_name[CRYPTO_MAX_ALG_NAME];
565f15f05b0SArd Biesheuvel 	char mac_name[CRYPTO_MAX_ALG_NAME];
5664a49b499SJoy Latten 	char full_name[CRYPTO_MAX_ALG_NAME];
5674a49b499SJoy Latten 
5684a49b499SJoy Latten 	cipher_name = crypto_attr_alg_name(tb[1]);
5694a49b499SJoy Latten 	if (IS_ERR(cipher_name))
57081c4c35eSHerbert Xu 		return PTR_ERR(cipher_name);
5714a49b499SJoy Latten 
5724a49b499SJoy Latten 	if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)",
5734a49b499SJoy Latten 		     cipher_name) >= CRYPTO_MAX_ALG_NAME)
57481c4c35eSHerbert Xu 		return -ENAMETOOLONG;
5754a49b499SJoy Latten 
576f15f05b0SArd Biesheuvel 	if (snprintf(mac_name, CRYPTO_MAX_ALG_NAME, "cbcmac(%s)",
577f15f05b0SArd Biesheuvel 		     cipher_name) >= CRYPTO_MAX_ALG_NAME)
578f15f05b0SArd Biesheuvel 		return -ENAMETOOLONG;
579f15f05b0SArd Biesheuvel 
5804a49b499SJoy Latten 	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "ccm(%s)", cipher_name) >=
5814a49b499SJoy Latten 	    CRYPTO_MAX_ALG_NAME)
58281c4c35eSHerbert Xu 		return -ENAMETOOLONG;
5834a49b499SJoy Latten 
58481c4c35eSHerbert Xu 	return crypto_ccm_create_common(tmpl, tb, full_name, ctr_name,
585f15f05b0SArd Biesheuvel 					mac_name);
5864a49b499SJoy Latten }
5874a49b499SJoy Latten 
5884a49b499SJoy Latten static struct crypto_template crypto_ccm_tmpl = {
5894a49b499SJoy Latten 	.name = "ccm",
59081c4c35eSHerbert Xu 	.create = crypto_ccm_create,
5914a49b499SJoy Latten 	.module = THIS_MODULE,
5924a49b499SJoy Latten };
5934a49b499SJoy Latten 
59481c4c35eSHerbert Xu static int crypto_ccm_base_create(struct crypto_template *tmpl,
59581c4c35eSHerbert Xu 				  struct rtattr **tb)
5964a49b499SJoy Latten {
5974a49b499SJoy Latten 	const char *ctr_name;
5984a49b499SJoy Latten 	const char *cipher_name;
5994a49b499SJoy Latten 	char full_name[CRYPTO_MAX_ALG_NAME];
6004a49b499SJoy Latten 
6014a49b499SJoy Latten 	ctr_name = crypto_attr_alg_name(tb[1]);
6024a49b499SJoy Latten 	if (IS_ERR(ctr_name))
60381c4c35eSHerbert Xu 		return PTR_ERR(ctr_name);
6044a49b499SJoy Latten 
6054a49b499SJoy Latten 	cipher_name = crypto_attr_alg_name(tb[2]);
6064a49b499SJoy Latten 	if (IS_ERR(cipher_name))
60781c4c35eSHerbert Xu 		return PTR_ERR(cipher_name);
6084a49b499SJoy Latten 
6094a49b499SJoy Latten 	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "ccm_base(%s,%s)",
6104a49b499SJoy Latten 		     ctr_name, cipher_name) >= CRYPTO_MAX_ALG_NAME)
61181c4c35eSHerbert Xu 		return -ENAMETOOLONG;
6124a49b499SJoy Latten 
61381c4c35eSHerbert Xu 	return crypto_ccm_create_common(tmpl, tb, full_name, ctr_name,
61481c4c35eSHerbert Xu 					cipher_name);
6154a49b499SJoy Latten }
6164a49b499SJoy Latten 
6174a49b499SJoy Latten static struct crypto_template crypto_ccm_base_tmpl = {
6184a49b499SJoy Latten 	.name = "ccm_base",
61981c4c35eSHerbert Xu 	.create = crypto_ccm_base_create,
6204a49b499SJoy Latten 	.module = THIS_MODULE,
6214a49b499SJoy Latten };
6224a49b499SJoy Latten 
6234a49b499SJoy Latten static int crypto_rfc4309_setkey(struct crypto_aead *parent, const u8 *key,
6244a49b499SJoy Latten 				 unsigned int keylen)
6254a49b499SJoy Latten {
6264a49b499SJoy Latten 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(parent);
6274a49b499SJoy Latten 	struct crypto_aead *child = ctx->child;
6284a49b499SJoy Latten 	int err;
6294a49b499SJoy Latten 
6304a49b499SJoy Latten 	if (keylen < 3)
6314a49b499SJoy Latten 		return -EINVAL;
6324a49b499SJoy Latten 
6334a49b499SJoy Latten 	keylen -= 3;
6344a49b499SJoy Latten 	memcpy(ctx->nonce, key + keylen, 3);
6354a49b499SJoy Latten 
6364a49b499SJoy Latten 	crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
6374a49b499SJoy Latten 	crypto_aead_set_flags(child, crypto_aead_get_flags(parent) &
6384a49b499SJoy Latten 				     CRYPTO_TFM_REQ_MASK);
6394a49b499SJoy Latten 	err = crypto_aead_setkey(child, key, keylen);
6404a49b499SJoy Latten 	crypto_aead_set_flags(parent, crypto_aead_get_flags(child) &
6414a49b499SJoy Latten 				      CRYPTO_TFM_RES_MASK);
6424a49b499SJoy Latten 
6434a49b499SJoy Latten 	return err;
6444a49b499SJoy Latten }
6454a49b499SJoy Latten 
6464a49b499SJoy Latten static int crypto_rfc4309_setauthsize(struct crypto_aead *parent,
6474a49b499SJoy Latten 				      unsigned int authsize)
6484a49b499SJoy Latten {
6494a49b499SJoy Latten 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(parent);
6504a49b499SJoy Latten 
6514a49b499SJoy Latten 	switch (authsize) {
6524a49b499SJoy Latten 	case 8:
6534a49b499SJoy Latten 	case 12:
6544a49b499SJoy Latten 	case 16:
6554a49b499SJoy Latten 		break;
6564a49b499SJoy Latten 	default:
6574a49b499SJoy Latten 		return -EINVAL;
6584a49b499SJoy Latten 	}
6594a49b499SJoy Latten 
6604a49b499SJoy Latten 	return crypto_aead_setauthsize(ctx->child, authsize);
6614a49b499SJoy Latten }
6624a49b499SJoy Latten 
6634a49b499SJoy Latten static struct aead_request *crypto_rfc4309_crypt(struct aead_request *req)
6644a49b499SJoy Latten {
66581c4c35eSHerbert Xu 	struct crypto_rfc4309_req_ctx *rctx = aead_request_ctx(req);
66681c4c35eSHerbert Xu 	struct aead_request *subreq = &rctx->subreq;
6674a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
6684a49b499SJoy Latten 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(aead);
6694a49b499SJoy Latten 	struct crypto_aead *child = ctx->child;
67081c4c35eSHerbert Xu 	struct scatterlist *sg;
6714a49b499SJoy Latten 	u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child),
6724a49b499SJoy Latten 			   crypto_aead_alignmask(child) + 1);
6734a49b499SJoy Latten 
6744a49b499SJoy Latten 	/* L' */
6754a49b499SJoy Latten 	iv[0] = 3;
6764a49b499SJoy Latten 
6774a49b499SJoy Latten 	memcpy(iv + 1, ctx->nonce, 3);
6784a49b499SJoy Latten 	memcpy(iv + 4, req->iv, 8);
6794a49b499SJoy Latten 
68081c4c35eSHerbert Xu 	scatterwalk_map_and_copy(iv + 16, req->src, 0, req->assoclen - 8, 0);
68181c4c35eSHerbert Xu 
68281c4c35eSHerbert Xu 	sg_init_table(rctx->src, 3);
68381c4c35eSHerbert Xu 	sg_set_buf(rctx->src, iv + 16, req->assoclen - 8);
68481c4c35eSHerbert Xu 	sg = scatterwalk_ffwd(rctx->src + 1, req->src, req->assoclen);
68581c4c35eSHerbert Xu 	if (sg != rctx->src + 1)
68681c4c35eSHerbert Xu 		sg_chain(rctx->src, 2, sg);
68781c4c35eSHerbert Xu 
68881c4c35eSHerbert Xu 	if (req->src != req->dst) {
68981c4c35eSHerbert Xu 		sg_init_table(rctx->dst, 3);
69081c4c35eSHerbert Xu 		sg_set_buf(rctx->dst, iv + 16, req->assoclen - 8);
69181c4c35eSHerbert Xu 		sg = scatterwalk_ffwd(rctx->dst + 1, req->dst, req->assoclen);
69281c4c35eSHerbert Xu 		if (sg != rctx->dst + 1)
69381c4c35eSHerbert Xu 			sg_chain(rctx->dst, 2, sg);
69481c4c35eSHerbert Xu 	}
69581c4c35eSHerbert Xu 
6964a49b499SJoy Latten 	aead_request_set_tfm(subreq, child);
6974a49b499SJoy Latten 	aead_request_set_callback(subreq, req->base.flags, req->base.complete,
6984a49b499SJoy Latten 				  req->base.data);
69981c4c35eSHerbert Xu 	aead_request_set_crypt(subreq, rctx->src,
70081c4c35eSHerbert Xu 			       req->src == req->dst ? rctx->src : rctx->dst,
70181c4c35eSHerbert Xu 			       req->cryptlen, iv);
70281c4c35eSHerbert Xu 	aead_request_set_ad(subreq, req->assoclen - 8);
7034a49b499SJoy Latten 
7044a49b499SJoy Latten 	return subreq;
7054a49b499SJoy Latten }
7064a49b499SJoy Latten 
7074a49b499SJoy Latten static int crypto_rfc4309_encrypt(struct aead_request *req)
7084a49b499SJoy Latten {
70981c4c35eSHerbert Xu 	if (req->assoclen != 16 && req->assoclen != 20)
71081c4c35eSHerbert Xu 		return -EINVAL;
71181c4c35eSHerbert Xu 
7124a49b499SJoy Latten 	req = crypto_rfc4309_crypt(req);
7134a49b499SJoy Latten 
7144a49b499SJoy Latten 	return crypto_aead_encrypt(req);
7154a49b499SJoy Latten }
7164a49b499SJoy Latten 
7174a49b499SJoy Latten static int crypto_rfc4309_decrypt(struct aead_request *req)
7184a49b499SJoy Latten {
71981c4c35eSHerbert Xu 	if (req->assoclen != 16 && req->assoclen != 20)
72081c4c35eSHerbert Xu 		return -EINVAL;
72181c4c35eSHerbert Xu 
7224a49b499SJoy Latten 	req = crypto_rfc4309_crypt(req);
7234a49b499SJoy Latten 
7244a49b499SJoy Latten 	return crypto_aead_decrypt(req);
7254a49b499SJoy Latten }
7264a49b499SJoy Latten 
72781c4c35eSHerbert Xu static int crypto_rfc4309_init_tfm(struct crypto_aead *tfm)
7284a49b499SJoy Latten {
72981c4c35eSHerbert Xu 	struct aead_instance *inst = aead_alg_instance(tfm);
73081c4c35eSHerbert Xu 	struct crypto_aead_spawn *spawn = aead_instance_ctx(inst);
73181c4c35eSHerbert Xu 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(tfm);
7324a49b499SJoy Latten 	struct crypto_aead *aead;
7334a49b499SJoy Latten 	unsigned long align;
7344a49b499SJoy Latten 
7354a49b499SJoy Latten 	aead = crypto_spawn_aead(spawn);
7364a49b499SJoy Latten 	if (IS_ERR(aead))
7374a49b499SJoy Latten 		return PTR_ERR(aead);
7384a49b499SJoy Latten 
7394a49b499SJoy Latten 	ctx->child = aead;
7404a49b499SJoy Latten 
7414a49b499SJoy Latten 	align = crypto_aead_alignmask(aead);
7424a49b499SJoy Latten 	align &= ~(crypto_tfm_ctx_alignment() - 1);
74381c4c35eSHerbert Xu 	crypto_aead_set_reqsize(
74481c4c35eSHerbert Xu 		tfm,
74581c4c35eSHerbert Xu 		sizeof(struct crypto_rfc4309_req_ctx) +
7462c221ad3SHerbert Xu 		ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) +
74781c4c35eSHerbert Xu 		align + 32);
7484a49b499SJoy Latten 
7494a49b499SJoy Latten 	return 0;
7504a49b499SJoy Latten }
7514a49b499SJoy Latten 
75281c4c35eSHerbert Xu static void crypto_rfc4309_exit_tfm(struct crypto_aead *tfm)
7534a49b499SJoy Latten {
75481c4c35eSHerbert Xu 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(tfm);
7554a49b499SJoy Latten 
7564a49b499SJoy Latten 	crypto_free_aead(ctx->child);
7574a49b499SJoy Latten }
7584a49b499SJoy Latten 
75981c4c35eSHerbert Xu static void crypto_rfc4309_free(struct aead_instance *inst)
76081c4c35eSHerbert Xu {
76181c4c35eSHerbert Xu 	crypto_drop_aead(aead_instance_ctx(inst));
76281c4c35eSHerbert Xu 	kfree(inst);
76381c4c35eSHerbert Xu }
76481c4c35eSHerbert Xu 
76581c4c35eSHerbert Xu static int crypto_rfc4309_create(struct crypto_template *tmpl,
76681c4c35eSHerbert Xu 				 struct rtattr **tb)
7674a49b499SJoy Latten {
7684a49b499SJoy Latten 	struct crypto_attr_type *algt;
76981c4c35eSHerbert Xu 	struct aead_instance *inst;
7704a49b499SJoy Latten 	struct crypto_aead_spawn *spawn;
77181c4c35eSHerbert Xu 	struct aead_alg *alg;
7724a49b499SJoy Latten 	const char *ccm_name;
7734a49b499SJoy Latten 	int err;
7744a49b499SJoy Latten 
7754a49b499SJoy Latten 	algt = crypto_get_attr_type(tb);
7764a49b499SJoy Latten 	if (IS_ERR(algt))
77781c4c35eSHerbert Xu 		return PTR_ERR(algt);
7784a49b499SJoy Latten 
7795e4b8c1fSHerbert Xu 	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
78081c4c35eSHerbert Xu 		return -EINVAL;
7814a49b499SJoy Latten 
7824a49b499SJoy Latten 	ccm_name = crypto_attr_alg_name(tb[1]);
7834a49b499SJoy Latten 	if (IS_ERR(ccm_name))
78481c4c35eSHerbert Xu 		return PTR_ERR(ccm_name);
7854a49b499SJoy Latten 
7864a49b499SJoy Latten 	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
7874a49b499SJoy Latten 	if (!inst)
78881c4c35eSHerbert Xu 		return -ENOMEM;
7894a49b499SJoy Latten 
79081c4c35eSHerbert Xu 	spawn = aead_instance_ctx(inst);
79181c4c35eSHerbert Xu 	crypto_set_aead_spawn(spawn, aead_crypto_instance(inst));
7924a49b499SJoy Latten 	err = crypto_grab_aead(spawn, ccm_name, 0,
7934a49b499SJoy Latten 			       crypto_requires_sync(algt->type, algt->mask));
7944a49b499SJoy Latten 	if (err)
7954a49b499SJoy Latten 		goto out_free_inst;
7964a49b499SJoy Latten 
79781c4c35eSHerbert Xu 	alg = crypto_spawn_aead_alg(spawn);
7984a49b499SJoy Latten 
7994a49b499SJoy Latten 	err = -EINVAL;
8004a49b499SJoy Latten 
8014a49b499SJoy Latten 	/* We only support 16-byte blocks. */
80281c4c35eSHerbert Xu 	if (crypto_aead_alg_ivsize(alg) != 16)
8034a49b499SJoy Latten 		goto out_drop_alg;
8044a49b499SJoy Latten 
8054a49b499SJoy Latten 	/* Not a stream cipher? */
80681c4c35eSHerbert Xu 	if (alg->base.cra_blocksize != 1)
8074a49b499SJoy Latten 		goto out_drop_alg;
8084a49b499SJoy Latten 
8094a49b499SJoy Latten 	err = -ENAMETOOLONG;
81081c4c35eSHerbert Xu 	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
81181c4c35eSHerbert Xu 		     "rfc4309(%s)", alg->base.cra_name) >=
81281c4c35eSHerbert Xu 	    CRYPTO_MAX_ALG_NAME ||
81381c4c35eSHerbert Xu 	    snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
81481c4c35eSHerbert Xu 		     "rfc4309(%s)", alg->base.cra_driver_name) >=
8154a49b499SJoy Latten 	    CRYPTO_MAX_ALG_NAME)
8164a49b499SJoy Latten 		goto out_drop_alg;
8174a49b499SJoy Latten 
81881c4c35eSHerbert Xu 	inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC;
81981c4c35eSHerbert Xu 	inst->alg.base.cra_priority = alg->base.cra_priority;
82081c4c35eSHerbert Xu 	inst->alg.base.cra_blocksize = 1;
82181c4c35eSHerbert Xu 	inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
8224a49b499SJoy Latten 
82381c4c35eSHerbert Xu 	inst->alg.ivsize = 8;
824464b93a3SHerbert Xu 	inst->alg.chunksize = crypto_aead_alg_chunksize(alg);
82581c4c35eSHerbert Xu 	inst->alg.maxauthsize = 16;
8264a49b499SJoy Latten 
82781c4c35eSHerbert Xu 	inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4309_ctx);
8284a49b499SJoy Latten 
82981c4c35eSHerbert Xu 	inst->alg.init = crypto_rfc4309_init_tfm;
83081c4c35eSHerbert Xu 	inst->alg.exit = crypto_rfc4309_exit_tfm;
8314a49b499SJoy Latten 
83281c4c35eSHerbert Xu 	inst->alg.setkey = crypto_rfc4309_setkey;
83381c4c35eSHerbert Xu 	inst->alg.setauthsize = crypto_rfc4309_setauthsize;
83481c4c35eSHerbert Xu 	inst->alg.encrypt = crypto_rfc4309_encrypt;
83581c4c35eSHerbert Xu 	inst->alg.decrypt = crypto_rfc4309_decrypt;
8364a49b499SJoy Latten 
83781c4c35eSHerbert Xu 	inst->free = crypto_rfc4309_free;
83881c4c35eSHerbert Xu 
83981c4c35eSHerbert Xu 	err = aead_register_instance(tmpl, inst);
84081c4c35eSHerbert Xu 	if (err)
84181c4c35eSHerbert Xu 		goto out_drop_alg;
8424a49b499SJoy Latten 
8434a49b499SJoy Latten out:
84481c4c35eSHerbert Xu 	return err;
8454a49b499SJoy Latten 
8464a49b499SJoy Latten out_drop_alg:
8474a49b499SJoy Latten 	crypto_drop_aead(spawn);
8484a49b499SJoy Latten out_free_inst:
8494a49b499SJoy Latten 	kfree(inst);
8504a49b499SJoy Latten 	goto out;
8514a49b499SJoy Latten }
8524a49b499SJoy Latten 
8534a49b499SJoy Latten static struct crypto_template crypto_rfc4309_tmpl = {
8544a49b499SJoy Latten 	.name = "rfc4309",
85581c4c35eSHerbert Xu 	.create = crypto_rfc4309_create,
8564a49b499SJoy Latten 	.module = THIS_MODULE,
8574a49b499SJoy Latten };
8584a49b499SJoy Latten 
859f15f05b0SArd Biesheuvel static int crypto_cbcmac_digest_setkey(struct crypto_shash *parent,
860f15f05b0SArd Biesheuvel 				     const u8 *inkey, unsigned int keylen)
861f15f05b0SArd Biesheuvel {
862f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *ctx = crypto_shash_ctx(parent);
863f15f05b0SArd Biesheuvel 
864f15f05b0SArd Biesheuvel 	return crypto_cipher_setkey(ctx->child, inkey, keylen);
865f15f05b0SArd Biesheuvel }
866f15f05b0SArd Biesheuvel 
867f15f05b0SArd Biesheuvel static int crypto_cbcmac_digest_init(struct shash_desc *pdesc)
868f15f05b0SArd Biesheuvel {
869f15f05b0SArd Biesheuvel 	struct cbcmac_desc_ctx *ctx = shash_desc_ctx(pdesc);
870f15f05b0SArd Biesheuvel 	int bs = crypto_shash_digestsize(pdesc->tfm);
871f15f05b0SArd Biesheuvel 
872f15f05b0SArd Biesheuvel 	ctx->len = 0;
873f15f05b0SArd Biesheuvel 	memset(ctx->dg, 0, bs);
874f15f05b0SArd Biesheuvel 
875f15f05b0SArd Biesheuvel 	return 0;
876f15f05b0SArd Biesheuvel }
877f15f05b0SArd Biesheuvel 
878f15f05b0SArd Biesheuvel static int crypto_cbcmac_digest_update(struct shash_desc *pdesc, const u8 *p,
879f15f05b0SArd Biesheuvel 				       unsigned int len)
880f15f05b0SArd Biesheuvel {
881f15f05b0SArd Biesheuvel 	struct crypto_shash *parent = pdesc->tfm;
882f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *tctx = crypto_shash_ctx(parent);
883f15f05b0SArd Biesheuvel 	struct cbcmac_desc_ctx *ctx = shash_desc_ctx(pdesc);
884f15f05b0SArd Biesheuvel 	struct crypto_cipher *tfm = tctx->child;
885f15f05b0SArd Biesheuvel 	int bs = crypto_shash_digestsize(parent);
886f15f05b0SArd Biesheuvel 
887f15f05b0SArd Biesheuvel 	while (len > 0) {
888f15f05b0SArd Biesheuvel 		unsigned int l = min(len, bs - ctx->len);
889f15f05b0SArd Biesheuvel 
890f15f05b0SArd Biesheuvel 		crypto_xor(ctx->dg + ctx->len, p, l);
891f15f05b0SArd Biesheuvel 		ctx->len +=l;
892f15f05b0SArd Biesheuvel 		len -= l;
893f15f05b0SArd Biesheuvel 		p += l;
894f15f05b0SArd Biesheuvel 
895f15f05b0SArd Biesheuvel 		if (ctx->len == bs) {
896f15f05b0SArd Biesheuvel 			crypto_cipher_encrypt_one(tfm, ctx->dg, ctx->dg);
897f15f05b0SArd Biesheuvel 			ctx->len = 0;
898f15f05b0SArd Biesheuvel 		}
899f15f05b0SArd Biesheuvel 	}
900f15f05b0SArd Biesheuvel 
901f15f05b0SArd Biesheuvel 	return 0;
902f15f05b0SArd Biesheuvel }
903f15f05b0SArd Biesheuvel 
904f15f05b0SArd Biesheuvel static int crypto_cbcmac_digest_final(struct shash_desc *pdesc, u8 *out)
905f15f05b0SArd Biesheuvel {
906f15f05b0SArd Biesheuvel 	struct crypto_shash *parent = pdesc->tfm;
907f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *tctx = crypto_shash_ctx(parent);
908f15f05b0SArd Biesheuvel 	struct cbcmac_desc_ctx *ctx = shash_desc_ctx(pdesc);
909f15f05b0SArd Biesheuvel 	struct crypto_cipher *tfm = tctx->child;
910f15f05b0SArd Biesheuvel 	int bs = crypto_shash_digestsize(parent);
911f15f05b0SArd Biesheuvel 
912f15f05b0SArd Biesheuvel 	if (ctx->len)
913f15f05b0SArd Biesheuvel 		crypto_cipher_encrypt_one(tfm, out, ctx->dg);
914f15f05b0SArd Biesheuvel 	else
915f15f05b0SArd Biesheuvel 		memcpy(out, ctx->dg, bs);
916f15f05b0SArd Biesheuvel 
917f15f05b0SArd Biesheuvel 	return 0;
918f15f05b0SArd Biesheuvel }
919f15f05b0SArd Biesheuvel 
920f15f05b0SArd Biesheuvel static int cbcmac_init_tfm(struct crypto_tfm *tfm)
921f15f05b0SArd Biesheuvel {
922f15f05b0SArd Biesheuvel 	struct crypto_cipher *cipher;
923f15f05b0SArd Biesheuvel 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
924f15f05b0SArd Biesheuvel 	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
925f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
926f15f05b0SArd Biesheuvel 
927f15f05b0SArd Biesheuvel 	cipher = crypto_spawn_cipher(spawn);
928f15f05b0SArd Biesheuvel 	if (IS_ERR(cipher))
929f15f05b0SArd Biesheuvel 		return PTR_ERR(cipher);
930f15f05b0SArd Biesheuvel 
931f15f05b0SArd Biesheuvel 	ctx->child = cipher;
932f15f05b0SArd Biesheuvel 
933f15f05b0SArd Biesheuvel 	return 0;
934f15f05b0SArd Biesheuvel };
935f15f05b0SArd Biesheuvel 
936f15f05b0SArd Biesheuvel static void cbcmac_exit_tfm(struct crypto_tfm *tfm)
937f15f05b0SArd Biesheuvel {
938f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
939f15f05b0SArd Biesheuvel 	crypto_free_cipher(ctx->child);
940f15f05b0SArd Biesheuvel }
941f15f05b0SArd Biesheuvel 
942f15f05b0SArd Biesheuvel static int cbcmac_create(struct crypto_template *tmpl, struct rtattr **tb)
943f15f05b0SArd Biesheuvel {
944f15f05b0SArd Biesheuvel 	struct shash_instance *inst;
945f15f05b0SArd Biesheuvel 	struct crypto_alg *alg;
946f15f05b0SArd Biesheuvel 	int err;
947f15f05b0SArd Biesheuvel 
948f15f05b0SArd Biesheuvel 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH);
949f15f05b0SArd Biesheuvel 	if (err)
950f15f05b0SArd Biesheuvel 		return err;
951f15f05b0SArd Biesheuvel 
952f15f05b0SArd Biesheuvel 	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
953f15f05b0SArd Biesheuvel 				  CRYPTO_ALG_TYPE_MASK);
954f15f05b0SArd Biesheuvel 	if (IS_ERR(alg))
955f15f05b0SArd Biesheuvel 		return PTR_ERR(alg);
956f15f05b0SArd Biesheuvel 
957f15f05b0SArd Biesheuvel 	inst = shash_alloc_instance("cbcmac", alg);
958f15f05b0SArd Biesheuvel 	err = PTR_ERR(inst);
959f15f05b0SArd Biesheuvel 	if (IS_ERR(inst))
960f15f05b0SArd Biesheuvel 		goto out_put_alg;
961f15f05b0SArd Biesheuvel 
962f15f05b0SArd Biesheuvel 	err = crypto_init_spawn(shash_instance_ctx(inst), alg,
963f15f05b0SArd Biesheuvel 				shash_crypto_instance(inst),
964f15f05b0SArd Biesheuvel 				CRYPTO_ALG_TYPE_MASK);
965f15f05b0SArd Biesheuvel 	if (err)
966f15f05b0SArd Biesheuvel 		goto out_free_inst;
967f15f05b0SArd Biesheuvel 
968f15f05b0SArd Biesheuvel 	inst->alg.base.cra_priority = alg->cra_priority;
969f15f05b0SArd Biesheuvel 	inst->alg.base.cra_blocksize = 1;
970f15f05b0SArd Biesheuvel 
971f15f05b0SArd Biesheuvel 	inst->alg.digestsize = alg->cra_blocksize;
972f15f05b0SArd Biesheuvel 	inst->alg.descsize = sizeof(struct cbcmac_desc_ctx) +
973f15f05b0SArd Biesheuvel 			     alg->cra_blocksize;
974f15f05b0SArd Biesheuvel 
975f15f05b0SArd Biesheuvel 	inst->alg.base.cra_ctxsize = sizeof(struct cbcmac_tfm_ctx);
976f15f05b0SArd Biesheuvel 	inst->alg.base.cra_init = cbcmac_init_tfm;
977f15f05b0SArd Biesheuvel 	inst->alg.base.cra_exit = cbcmac_exit_tfm;
978f15f05b0SArd Biesheuvel 
979f15f05b0SArd Biesheuvel 	inst->alg.init = crypto_cbcmac_digest_init;
980f15f05b0SArd Biesheuvel 	inst->alg.update = crypto_cbcmac_digest_update;
981f15f05b0SArd Biesheuvel 	inst->alg.final = crypto_cbcmac_digest_final;
982f15f05b0SArd Biesheuvel 	inst->alg.setkey = crypto_cbcmac_digest_setkey;
983f15f05b0SArd Biesheuvel 
984f15f05b0SArd Biesheuvel 	err = shash_register_instance(tmpl, inst);
985f15f05b0SArd Biesheuvel 
986f15f05b0SArd Biesheuvel out_free_inst:
987f15f05b0SArd Biesheuvel 	if (err)
988f15f05b0SArd Biesheuvel 		shash_free_instance(shash_crypto_instance(inst));
989f15f05b0SArd Biesheuvel 
990f15f05b0SArd Biesheuvel out_put_alg:
991f15f05b0SArd Biesheuvel 	crypto_mod_put(alg);
992f15f05b0SArd Biesheuvel 	return err;
993f15f05b0SArd Biesheuvel }
994f15f05b0SArd Biesheuvel 
995f15f05b0SArd Biesheuvel static struct crypto_template crypto_cbcmac_tmpl = {
996f15f05b0SArd Biesheuvel 	.name = "cbcmac",
997f15f05b0SArd Biesheuvel 	.create = cbcmac_create,
998f15f05b0SArd Biesheuvel 	.free = shash_free_instance,
999f15f05b0SArd Biesheuvel 	.module = THIS_MODULE,
1000f15f05b0SArd Biesheuvel };
1001f15f05b0SArd Biesheuvel 
10024a49b499SJoy Latten static int __init crypto_ccm_module_init(void)
10034a49b499SJoy Latten {
10044a49b499SJoy Latten 	int err;
10054a49b499SJoy Latten 
1006f15f05b0SArd Biesheuvel 	err = crypto_register_template(&crypto_cbcmac_tmpl);
10074a49b499SJoy Latten 	if (err)
10084a49b499SJoy Latten 		goto out;
10094a49b499SJoy Latten 
1010f15f05b0SArd Biesheuvel 	err = crypto_register_template(&crypto_ccm_base_tmpl);
1011f15f05b0SArd Biesheuvel 	if (err)
1012f15f05b0SArd Biesheuvel 		goto out_undo_cbcmac;
1013f15f05b0SArd Biesheuvel 
10144a49b499SJoy Latten 	err = crypto_register_template(&crypto_ccm_tmpl);
10154a49b499SJoy Latten 	if (err)
10164a49b499SJoy Latten 		goto out_undo_base;
10174a49b499SJoy Latten 
10184a49b499SJoy Latten 	err = crypto_register_template(&crypto_rfc4309_tmpl);
10194a49b499SJoy Latten 	if (err)
10204a49b499SJoy Latten 		goto out_undo_ccm;
10214a49b499SJoy Latten 
10224a49b499SJoy Latten out:
10234a49b499SJoy Latten 	return err;
10244a49b499SJoy Latten 
10254a49b499SJoy Latten out_undo_ccm:
10264a49b499SJoy Latten 	crypto_unregister_template(&crypto_ccm_tmpl);
10274a49b499SJoy Latten out_undo_base:
10284a49b499SJoy Latten 	crypto_unregister_template(&crypto_ccm_base_tmpl);
1029f15f05b0SArd Biesheuvel out_undo_cbcmac:
1030f15f05b0SArd Biesheuvel 	crypto_register_template(&crypto_cbcmac_tmpl);
10314a49b499SJoy Latten 	goto out;
10324a49b499SJoy Latten }
10334a49b499SJoy Latten 
10344a49b499SJoy Latten static void __exit crypto_ccm_module_exit(void)
10354a49b499SJoy Latten {
10364a49b499SJoy Latten 	crypto_unregister_template(&crypto_rfc4309_tmpl);
10374a49b499SJoy Latten 	crypto_unregister_template(&crypto_ccm_tmpl);
10384a49b499SJoy Latten 	crypto_unregister_template(&crypto_ccm_base_tmpl);
1039f15f05b0SArd Biesheuvel 	crypto_unregister_template(&crypto_cbcmac_tmpl);
10404a49b499SJoy Latten }
10414a49b499SJoy Latten 
10424a49b499SJoy Latten module_init(crypto_ccm_module_init);
10434a49b499SJoy Latten module_exit(crypto_ccm_module_exit);
10444a49b499SJoy Latten 
10454a49b499SJoy Latten MODULE_LICENSE("GPL");
10464a49b499SJoy Latten MODULE_DESCRIPTION("Counter with CBC MAC");
10475d26a105SKees Cook MODULE_ALIAS_CRYPTO("ccm_base");
10485d26a105SKees Cook MODULE_ALIAS_CRYPTO("rfc4309");
10494943ba16SKees Cook MODULE_ALIAS_CRYPTO("ccm");
1050