xref: /openbmc/linux/crypto/ccm.c (revision 0db19035)
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];
483b30460cSArd Biesheuvel 	u8 idata[16];
494a49b499SJoy Latten 	u8 auth_tag[16];
504a49b499SJoy Latten 	u32 flags;
5181c4c35eSHerbert Xu 	struct scatterlist src[3];
5281c4c35eSHerbert Xu 	struct scatterlist dst[3];
53ebf533adSArd Biesheuvel 	union {
54ebf533adSArd Biesheuvel 		struct ahash_request ahreq;
55464b93a3SHerbert Xu 		struct skcipher_request skreq;
564a49b499SJoy Latten 	};
57ebf533adSArd Biesheuvel };
584a49b499SJoy Latten 
59f15f05b0SArd Biesheuvel struct cbcmac_tfm_ctx {
60f15f05b0SArd Biesheuvel 	struct crypto_cipher *child;
61f15f05b0SArd Biesheuvel };
62f15f05b0SArd Biesheuvel 
63f15f05b0SArd Biesheuvel struct cbcmac_desc_ctx {
64f15f05b0SArd Biesheuvel 	unsigned int len;
65f15f05b0SArd Biesheuvel };
66f15f05b0SArd Biesheuvel 
674a49b499SJoy Latten static inline struct crypto_ccm_req_priv_ctx *crypto_ccm_reqctx(
684a49b499SJoy Latten 	struct aead_request *req)
694a49b499SJoy Latten {
704a49b499SJoy Latten 	unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req));
714a49b499SJoy Latten 
724a49b499SJoy Latten 	return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1);
734a49b499SJoy Latten }
744a49b499SJoy Latten 
754a49b499SJoy Latten static int set_msg_len(u8 *block, unsigned int msglen, int csize)
764a49b499SJoy Latten {
774a49b499SJoy Latten 	__be32 data;
784a49b499SJoy Latten 
794a49b499SJoy Latten 	memset(block, 0, csize);
804a49b499SJoy Latten 	block += csize;
814a49b499SJoy Latten 
824a49b499SJoy Latten 	if (csize >= 4)
834a49b499SJoy Latten 		csize = 4;
844a49b499SJoy Latten 	else if (msglen > (1 << (8 * csize)))
854a49b499SJoy Latten 		return -EOVERFLOW;
864a49b499SJoy Latten 
874a49b499SJoy Latten 	data = cpu_to_be32(msglen);
884a49b499SJoy Latten 	memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
894a49b499SJoy Latten 
904a49b499SJoy Latten 	return 0;
914a49b499SJoy Latten }
924a49b499SJoy Latten 
934a49b499SJoy Latten static int crypto_ccm_setkey(struct crypto_aead *aead, const u8 *key,
944a49b499SJoy Latten 			     unsigned int keylen)
954a49b499SJoy Latten {
964a49b499SJoy Latten 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
97464b93a3SHerbert Xu 	struct crypto_skcipher *ctr = ctx->ctr;
98f15f05b0SArd Biesheuvel 	struct crypto_ahash *mac = ctx->mac;
994a49b499SJoy Latten 	int err = 0;
1004a49b499SJoy Latten 
101464b93a3SHerbert Xu 	crypto_skcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
102464b93a3SHerbert Xu 	crypto_skcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
1034a49b499SJoy Latten 				       CRYPTO_TFM_REQ_MASK);
104464b93a3SHerbert Xu 	err = crypto_skcipher_setkey(ctr, key, keylen);
105464b93a3SHerbert Xu 	crypto_aead_set_flags(aead, crypto_skcipher_get_flags(ctr) &
1064a49b499SJoy Latten 			      CRYPTO_TFM_RES_MASK);
1074a49b499SJoy Latten 	if (err)
1084a49b499SJoy Latten 		goto out;
1094a49b499SJoy Latten 
110f15f05b0SArd Biesheuvel 	crypto_ahash_clear_flags(mac, CRYPTO_TFM_REQ_MASK);
111f15f05b0SArd Biesheuvel 	crypto_ahash_set_flags(mac, crypto_aead_get_flags(aead) &
1124a49b499SJoy Latten 				    CRYPTO_TFM_REQ_MASK);
113f15f05b0SArd Biesheuvel 	err = crypto_ahash_setkey(mac, key, keylen);
114f15f05b0SArd Biesheuvel 	crypto_aead_set_flags(aead, crypto_ahash_get_flags(mac) &
1154a49b499SJoy Latten 			      CRYPTO_TFM_RES_MASK);
1164a49b499SJoy Latten 
1174a49b499SJoy Latten out:
1184a49b499SJoy Latten 	return err;
1194a49b499SJoy Latten }
1204a49b499SJoy Latten 
1214a49b499SJoy Latten static int crypto_ccm_setauthsize(struct crypto_aead *tfm,
1224a49b499SJoy Latten 				  unsigned int authsize)
1234a49b499SJoy Latten {
1244a49b499SJoy Latten 	switch (authsize) {
1254a49b499SJoy Latten 	case 4:
1264a49b499SJoy Latten 	case 6:
1274a49b499SJoy Latten 	case 8:
1284a49b499SJoy Latten 	case 10:
1294a49b499SJoy Latten 	case 12:
1304a49b499SJoy Latten 	case 14:
1314a49b499SJoy Latten 	case 16:
1324a49b499SJoy Latten 		break;
1334a49b499SJoy Latten 	default:
1344a49b499SJoy Latten 		return -EINVAL;
1354a49b499SJoy Latten 	}
1364a49b499SJoy Latten 
1374a49b499SJoy Latten 	return 0;
1384a49b499SJoy Latten }
1394a49b499SJoy Latten 
1404a49b499SJoy Latten static int format_input(u8 *info, struct aead_request *req,
1414a49b499SJoy Latten 			unsigned int cryptlen)
1424a49b499SJoy Latten {
1434a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
1444a49b499SJoy Latten 	unsigned int lp = req->iv[0];
1454a49b499SJoy Latten 	unsigned int l = lp + 1;
1464a49b499SJoy Latten 	unsigned int m;
1474a49b499SJoy Latten 
1484a49b499SJoy Latten 	m = crypto_aead_authsize(aead);
1494a49b499SJoy Latten 
1504a49b499SJoy Latten 	memcpy(info, req->iv, 16);
1514a49b499SJoy Latten 
1524a49b499SJoy Latten 	/* format control info per RFC 3610 and
1534a49b499SJoy Latten 	 * NIST Special Publication 800-38C
1544a49b499SJoy Latten 	 */
1554a49b499SJoy Latten 	*info |= (8 * ((m - 2) / 2));
1564a49b499SJoy Latten 	if (req->assoclen)
1574a49b499SJoy Latten 		*info |= 64;
1584a49b499SJoy Latten 
1594a49b499SJoy Latten 	return set_msg_len(info + 16 - l, cryptlen, l);
1604a49b499SJoy Latten }
1614a49b499SJoy Latten 
1624a49b499SJoy Latten static int format_adata(u8 *adata, unsigned int a)
1634a49b499SJoy Latten {
1644a49b499SJoy Latten 	int len = 0;
1654a49b499SJoy Latten 
1664a49b499SJoy Latten 	/* add control info for associated data
1674a49b499SJoy Latten 	 * RFC 3610 and NIST Special Publication 800-38C
1684a49b499SJoy Latten 	 */
1694a49b499SJoy Latten 	if (a < 65280) {
1704a49b499SJoy Latten 		*(__be16 *)adata = cpu_to_be16(a);
1714a49b499SJoy Latten 		len = 2;
1724a49b499SJoy Latten 	} else  {
1734a49b499SJoy Latten 		*(__be16 *)adata = cpu_to_be16(0xfffe);
1744a49b499SJoy Latten 		*(__be32 *)&adata[2] = cpu_to_be32(a);
1754a49b499SJoy Latten 		len = 6;
1764a49b499SJoy Latten 	}
1774a49b499SJoy Latten 
1784a49b499SJoy Latten 	return len;
1794a49b499SJoy Latten }
1804a49b499SJoy Latten 
1814a49b499SJoy Latten static int crypto_ccm_auth(struct aead_request *req, struct scatterlist *plain,
1824a49b499SJoy Latten 			   unsigned int cryptlen)
1834a49b499SJoy Latten {
184f15f05b0SArd Biesheuvel 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
1854a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
1864a49b499SJoy Latten 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
187ebf533adSArd Biesheuvel 	struct ahash_request *ahreq = &pctx->ahreq;
1884a49b499SJoy Latten 	unsigned int assoclen = req->assoclen;
189f15f05b0SArd Biesheuvel 	struct scatterlist sg[3];
1903b30460cSArd Biesheuvel 	u8 *odata = pctx->odata;
1913b30460cSArd Biesheuvel 	u8 *idata = pctx->idata;
192f15f05b0SArd Biesheuvel 	int ilen, err;
1934a49b499SJoy Latten 
1944a49b499SJoy Latten 	/* format control data for input */
1954a49b499SJoy Latten 	err = format_input(odata, req, cryptlen);
1964a49b499SJoy Latten 	if (err)
1974a49b499SJoy Latten 		goto out;
1984a49b499SJoy Latten 
199f15f05b0SArd Biesheuvel 	sg_init_table(sg, 3);
200f15f05b0SArd Biesheuvel 	sg_set_buf(&sg[0], odata, 16);
2014a49b499SJoy Latten 
2024a49b499SJoy Latten 	/* format associated data and compute into mac */
2034a49b499SJoy Latten 	if (assoclen) {
204f15f05b0SArd Biesheuvel 		ilen = format_adata(idata, assoclen);
205f15f05b0SArd Biesheuvel 		sg_set_buf(&sg[1], idata, ilen);
206f15f05b0SArd Biesheuvel 		sg_chain(sg, 3, req->src);
207516280e7SJarod Wilson 	} else {
208f15f05b0SArd Biesheuvel 		ilen = 0;
209f15f05b0SArd Biesheuvel 		sg_chain(sg, 2, req->src);
2104a49b499SJoy Latten 	}
2114a49b499SJoy Latten 
212f15f05b0SArd Biesheuvel 	ahash_request_set_tfm(ahreq, ctx->mac);
213f15f05b0SArd Biesheuvel 	ahash_request_set_callback(ahreq, pctx->flags, NULL, NULL);
214f15f05b0SArd Biesheuvel 	ahash_request_set_crypt(ahreq, sg, NULL, assoclen + ilen + 16);
215f15f05b0SArd Biesheuvel 	err = crypto_ahash_init(ahreq);
216f15f05b0SArd Biesheuvel 	if (err)
217f15f05b0SArd Biesheuvel 		goto out;
218f15f05b0SArd Biesheuvel 	err = crypto_ahash_update(ahreq);
219f15f05b0SArd Biesheuvel 	if (err)
220f15f05b0SArd Biesheuvel 		goto out;
2214a49b499SJoy Latten 
222f15f05b0SArd Biesheuvel 	/* we need to pad the MAC input to a round multiple of the block size */
223f15f05b0SArd Biesheuvel 	ilen = 16 - (assoclen + ilen) % 16;
224f15f05b0SArd Biesheuvel 	if (ilen < 16) {
225f15f05b0SArd Biesheuvel 		memset(idata, 0, ilen);
226f15f05b0SArd Biesheuvel 		sg_init_table(sg, 2);
227f15f05b0SArd Biesheuvel 		sg_set_buf(&sg[0], idata, ilen);
228f15f05b0SArd Biesheuvel 		if (plain)
229f15f05b0SArd Biesheuvel 			sg_chain(sg, 2, plain);
230f15f05b0SArd Biesheuvel 		plain = sg;
231f15f05b0SArd Biesheuvel 		cryptlen += ilen;
232f15f05b0SArd Biesheuvel 	}
233f15f05b0SArd Biesheuvel 
234f15f05b0SArd Biesheuvel 	ahash_request_set_crypt(ahreq, plain, pctx->odata, cryptlen);
235f15f05b0SArd Biesheuvel 	err = crypto_ahash_finup(ahreq);
2364a49b499SJoy Latten out:
2374a49b499SJoy Latten 	return err;
2384a49b499SJoy Latten }
2394a49b499SJoy Latten 
2404a49b499SJoy Latten static void crypto_ccm_encrypt_done(struct crypto_async_request *areq, int err)
2414a49b499SJoy Latten {
2424a49b499SJoy Latten 	struct aead_request *req = areq->data;
2434a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
2444a49b499SJoy Latten 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
2454a49b499SJoy Latten 	u8 *odata = pctx->odata;
2464a49b499SJoy Latten 
2474a49b499SJoy Latten 	if (!err)
24881c4c35eSHerbert Xu 		scatterwalk_map_and_copy(odata, req->dst,
24981c4c35eSHerbert Xu 					 req->assoclen + req->cryptlen,
2504a49b499SJoy Latten 					 crypto_aead_authsize(aead), 1);
2514a49b499SJoy Latten 	aead_request_complete(req, err);
2524a49b499SJoy Latten }
2534a49b499SJoy Latten 
2544a49b499SJoy Latten static inline int crypto_ccm_check_iv(const u8 *iv)
2554a49b499SJoy Latten {
2564a49b499SJoy Latten 	/* 2 <= L <= 8, so 1 <= L' <= 7. */
2574a49b499SJoy Latten 	if (1 > iv[0] || iv[0] > 7)
2584a49b499SJoy Latten 		return -EINVAL;
2594a49b499SJoy Latten 
2604a49b499SJoy Latten 	return 0;
2614a49b499SJoy Latten }
2624a49b499SJoy Latten 
26381c4c35eSHerbert Xu static int crypto_ccm_init_crypt(struct aead_request *req, u8 *tag)
26481c4c35eSHerbert Xu {
26581c4c35eSHerbert Xu 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
26681c4c35eSHerbert Xu 	struct scatterlist *sg;
26781c4c35eSHerbert Xu 	u8 *iv = req->iv;
26881c4c35eSHerbert Xu 	int err;
26981c4c35eSHerbert Xu 
27081c4c35eSHerbert Xu 	err = crypto_ccm_check_iv(iv);
27181c4c35eSHerbert Xu 	if (err)
27281c4c35eSHerbert Xu 		return err;
27381c4c35eSHerbert Xu 
27481c4c35eSHerbert Xu 	pctx->flags = aead_request_flags(req);
27581c4c35eSHerbert Xu 
27681c4c35eSHerbert Xu 	 /* Note: rfc 3610 and NIST 800-38C require counter of
27781c4c35eSHerbert Xu 	 * zero to encrypt auth tag.
27881c4c35eSHerbert Xu 	 */
27981c4c35eSHerbert Xu 	memset(iv + 15 - iv[0], 0, iv[0] + 1);
28081c4c35eSHerbert Xu 
28181c4c35eSHerbert Xu 	sg_init_table(pctx->src, 3);
28281c4c35eSHerbert Xu 	sg_set_buf(pctx->src, tag, 16);
28381c4c35eSHerbert Xu 	sg = scatterwalk_ffwd(pctx->src + 1, req->src, req->assoclen);
28481c4c35eSHerbert Xu 	if (sg != pctx->src + 1)
28581c4c35eSHerbert Xu 		sg_chain(pctx->src, 2, sg);
28681c4c35eSHerbert Xu 
28781c4c35eSHerbert Xu 	if (req->src != req->dst) {
28881c4c35eSHerbert Xu 		sg_init_table(pctx->dst, 3);
28981c4c35eSHerbert Xu 		sg_set_buf(pctx->dst, tag, 16);
29081c4c35eSHerbert Xu 		sg = scatterwalk_ffwd(pctx->dst + 1, req->dst, req->assoclen);
29181c4c35eSHerbert Xu 		if (sg != pctx->dst + 1)
29281c4c35eSHerbert Xu 			sg_chain(pctx->dst, 2, sg);
29381c4c35eSHerbert Xu 	}
29481c4c35eSHerbert Xu 
29581c4c35eSHerbert Xu 	return 0;
29681c4c35eSHerbert Xu }
29781c4c35eSHerbert Xu 
2984a49b499SJoy Latten static int crypto_ccm_encrypt(struct aead_request *req)
2994a49b499SJoy Latten {
3004a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
3014a49b499SJoy Latten 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
3024a49b499SJoy Latten 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
303464b93a3SHerbert Xu 	struct skcipher_request *skreq = &pctx->skreq;
3044a49b499SJoy Latten 	struct scatterlist *dst;
3054a49b499SJoy Latten 	unsigned int cryptlen = req->cryptlen;
3064a49b499SJoy Latten 	u8 *odata = pctx->odata;
3074a49b499SJoy Latten 	u8 *iv = req->iv;
3084a49b499SJoy Latten 	int err;
3094a49b499SJoy Latten 
31081c4c35eSHerbert Xu 	err = crypto_ccm_init_crypt(req, odata);
3114a49b499SJoy Latten 	if (err)
3124a49b499SJoy Latten 		return err;
3134a49b499SJoy Latten 
31481c4c35eSHerbert Xu 	err = crypto_ccm_auth(req, sg_next(pctx->src), cryptlen);
3154a49b499SJoy Latten 	if (err)
3164a49b499SJoy Latten 		return err;
3174a49b499SJoy Latten 
3184a49b499SJoy Latten 	dst = pctx->src;
31981c4c35eSHerbert Xu 	if (req->src != req->dst)
3204a49b499SJoy Latten 		dst = pctx->dst;
3214a49b499SJoy Latten 
322464b93a3SHerbert Xu 	skcipher_request_set_tfm(skreq, ctx->ctr);
323464b93a3SHerbert Xu 	skcipher_request_set_callback(skreq, pctx->flags,
3244a49b499SJoy Latten 				      crypto_ccm_encrypt_done, req);
325464b93a3SHerbert Xu 	skcipher_request_set_crypt(skreq, pctx->src, dst, cryptlen + 16, iv);
326464b93a3SHerbert Xu 	err = crypto_skcipher_encrypt(skreq);
3274a49b499SJoy Latten 	if (err)
3284a49b499SJoy Latten 		return err;
3294a49b499SJoy Latten 
3304a49b499SJoy Latten 	/* copy authtag to end of dst */
33181c4c35eSHerbert Xu 	scatterwalk_map_and_copy(odata, sg_next(dst), cryptlen,
3324a49b499SJoy Latten 				 crypto_aead_authsize(aead), 1);
3334a49b499SJoy Latten 	return err;
3344a49b499SJoy Latten }
3354a49b499SJoy Latten 
3364a49b499SJoy Latten static void crypto_ccm_decrypt_done(struct crypto_async_request *areq,
3374a49b499SJoy Latten 				   int err)
3384a49b499SJoy Latten {
3394a49b499SJoy Latten 	struct aead_request *req = areq->data;
3404a49b499SJoy Latten 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
3414a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
3424a49b499SJoy Latten 	unsigned int authsize = crypto_aead_authsize(aead);
3434a49b499SJoy Latten 	unsigned int cryptlen = req->cryptlen - authsize;
34481c4c35eSHerbert Xu 	struct scatterlist *dst;
34581c4c35eSHerbert Xu 
34681c4c35eSHerbert Xu 	pctx->flags = 0;
34781c4c35eSHerbert Xu 
34881c4c35eSHerbert Xu 	dst = sg_next(req->src == req->dst ? pctx->src : pctx->dst);
3494a49b499SJoy Latten 
3504a49b499SJoy Latten 	if (!err) {
35181c4c35eSHerbert Xu 		err = crypto_ccm_auth(req, dst, cryptlen);
3526bf37e5aSJames Yonan 		if (!err && crypto_memneq(pctx->auth_tag, pctx->odata, authsize))
3534a49b499SJoy Latten 			err = -EBADMSG;
3544a49b499SJoy Latten 	}
3554a49b499SJoy Latten 	aead_request_complete(req, err);
3564a49b499SJoy Latten }
3574a49b499SJoy Latten 
3584a49b499SJoy Latten static int crypto_ccm_decrypt(struct aead_request *req)
3594a49b499SJoy Latten {
3604a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
3614a49b499SJoy Latten 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
3624a49b499SJoy Latten 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
363464b93a3SHerbert Xu 	struct skcipher_request *skreq = &pctx->skreq;
3644a49b499SJoy Latten 	struct scatterlist *dst;
3654a49b499SJoy Latten 	unsigned int authsize = crypto_aead_authsize(aead);
3664a49b499SJoy Latten 	unsigned int cryptlen = req->cryptlen;
3674a49b499SJoy Latten 	u8 *authtag = pctx->auth_tag;
3684a49b499SJoy Latten 	u8 *odata = pctx->odata;
369441f99c9SRomain Izard 	u8 *iv = pctx->idata;
3704a49b499SJoy Latten 	int err;
3714a49b499SJoy Latten 
3724a49b499SJoy Latten 	cryptlen -= authsize;
3734a49b499SJoy Latten 
37481c4c35eSHerbert Xu 	err = crypto_ccm_init_crypt(req, authtag);
3754a49b499SJoy Latten 	if (err)
3764a49b499SJoy Latten 		return err;
3774a49b499SJoy Latten 
37881c4c35eSHerbert Xu 	scatterwalk_map_and_copy(authtag, sg_next(pctx->src), cryptlen,
37981c4c35eSHerbert Xu 				 authsize, 0);
3804a49b499SJoy Latten 
3814a49b499SJoy Latten 	dst = pctx->src;
38281c4c35eSHerbert Xu 	if (req->src != req->dst)
3834a49b499SJoy Latten 		dst = pctx->dst;
3844a49b499SJoy Latten 
385441f99c9SRomain Izard 	memcpy(iv, req->iv, 16);
386441f99c9SRomain Izard 
387464b93a3SHerbert Xu 	skcipher_request_set_tfm(skreq, ctx->ctr);
388464b93a3SHerbert Xu 	skcipher_request_set_callback(skreq, pctx->flags,
3894a49b499SJoy Latten 				      crypto_ccm_decrypt_done, req);
390464b93a3SHerbert Xu 	skcipher_request_set_crypt(skreq, pctx->src, dst, cryptlen + 16, iv);
391464b93a3SHerbert Xu 	err = crypto_skcipher_decrypt(skreq);
3924a49b499SJoy Latten 	if (err)
3934a49b499SJoy Latten 		return err;
3944a49b499SJoy Latten 
39581c4c35eSHerbert Xu 	err = crypto_ccm_auth(req, sg_next(dst), cryptlen);
3964a49b499SJoy Latten 	if (err)
3974a49b499SJoy Latten 		return err;
3984a49b499SJoy Latten 
3994a49b499SJoy Latten 	/* verify */
4006bf37e5aSJames Yonan 	if (crypto_memneq(authtag, odata, authsize))
4014a49b499SJoy Latten 		return -EBADMSG;
4024a49b499SJoy Latten 
4034a49b499SJoy Latten 	return err;
4044a49b499SJoy Latten }
4054a49b499SJoy Latten 
40681c4c35eSHerbert Xu static int crypto_ccm_init_tfm(struct crypto_aead *tfm)
4074a49b499SJoy Latten {
40881c4c35eSHerbert Xu 	struct aead_instance *inst = aead_alg_instance(tfm);
40981c4c35eSHerbert Xu 	struct ccm_instance_ctx *ictx = aead_instance_ctx(inst);
41081c4c35eSHerbert Xu 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(tfm);
411f15f05b0SArd Biesheuvel 	struct crypto_ahash *mac;
412464b93a3SHerbert Xu 	struct crypto_skcipher *ctr;
4134a49b499SJoy Latten 	unsigned long align;
4144a49b499SJoy Latten 	int err;
4154a49b499SJoy Latten 
416f15f05b0SArd Biesheuvel 	mac = crypto_spawn_ahash(&ictx->mac);
417f15f05b0SArd Biesheuvel 	if (IS_ERR(mac))
418f15f05b0SArd Biesheuvel 		return PTR_ERR(mac);
4194a49b499SJoy Latten 
42060425a8bSEric Biggers 	ctr = crypto_spawn_skcipher(&ictx->ctr);
4214a49b499SJoy Latten 	err = PTR_ERR(ctr);
4224a49b499SJoy Latten 	if (IS_ERR(ctr))
423f15f05b0SArd Biesheuvel 		goto err_free_mac;
4244a49b499SJoy Latten 
425f15f05b0SArd Biesheuvel 	ctx->mac = mac;
4264a49b499SJoy Latten 	ctx->ctr = ctr;
4274a49b499SJoy Latten 
42881c4c35eSHerbert Xu 	align = crypto_aead_alignmask(tfm);
4294a49b499SJoy Latten 	align &= ~(crypto_tfm_ctx_alignment() - 1);
43081c4c35eSHerbert Xu 	crypto_aead_set_reqsize(
43181c4c35eSHerbert Xu 		tfm,
4322c221ad3SHerbert Xu 		align + sizeof(struct crypto_ccm_req_priv_ctx) +
433ebf533adSArd Biesheuvel 		max(crypto_ahash_reqsize(mac), crypto_skcipher_reqsize(ctr)));
4344a49b499SJoy Latten 
4354a49b499SJoy Latten 	return 0;
4364a49b499SJoy Latten 
437f15f05b0SArd Biesheuvel err_free_mac:
438f15f05b0SArd Biesheuvel 	crypto_free_ahash(mac);
4394a49b499SJoy Latten 	return err;
4404a49b499SJoy Latten }
4414a49b499SJoy Latten 
44281c4c35eSHerbert Xu static void crypto_ccm_exit_tfm(struct crypto_aead *tfm)
4434a49b499SJoy Latten {
44481c4c35eSHerbert Xu 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(tfm);
4454a49b499SJoy Latten 
446f15f05b0SArd Biesheuvel 	crypto_free_ahash(ctx->mac);
447464b93a3SHerbert Xu 	crypto_free_skcipher(ctx->ctr);
4484a49b499SJoy Latten }
4494a49b499SJoy Latten 
45081c4c35eSHerbert Xu static void crypto_ccm_free(struct aead_instance *inst)
45181c4c35eSHerbert Xu {
45281c4c35eSHerbert Xu 	struct ccm_instance_ctx *ctx = aead_instance_ctx(inst);
45381c4c35eSHerbert Xu 
454f15f05b0SArd Biesheuvel 	crypto_drop_ahash(&ctx->mac);
45581c4c35eSHerbert Xu 	crypto_drop_skcipher(&ctx->ctr);
45681c4c35eSHerbert Xu 	kfree(inst);
45781c4c35eSHerbert Xu }
45881c4c35eSHerbert Xu 
45981c4c35eSHerbert Xu static int crypto_ccm_create_common(struct crypto_template *tmpl,
46081c4c35eSHerbert Xu 				    struct rtattr **tb,
4614a49b499SJoy Latten 				    const char *full_name,
4624a49b499SJoy Latten 				    const char *ctr_name,
463f15f05b0SArd Biesheuvel 				    const char *mac_name)
4644a49b499SJoy Latten {
4654a49b499SJoy Latten 	struct crypto_attr_type *algt;
46681c4c35eSHerbert Xu 	struct aead_instance *inst;
467464b93a3SHerbert Xu 	struct skcipher_alg *ctr;
468f15f05b0SArd Biesheuvel 	struct crypto_alg *mac_alg;
469f15f05b0SArd Biesheuvel 	struct hash_alg_common *mac;
4704a49b499SJoy Latten 	struct ccm_instance_ctx *ictx;
4714a49b499SJoy Latten 	int err;
4724a49b499SJoy Latten 
4734a49b499SJoy Latten 	algt = crypto_get_attr_type(tb);
4744a49b499SJoy Latten 	if (IS_ERR(algt))
47581c4c35eSHerbert Xu 		return PTR_ERR(algt);
4764a49b499SJoy Latten 
4775e4b8c1fSHerbert Xu 	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
47881c4c35eSHerbert Xu 		return -EINVAL;
4794a49b499SJoy Latten 
480f15f05b0SArd Biesheuvel 	mac_alg = crypto_find_alg(mac_name, &crypto_ahash_type,
481f15f05b0SArd Biesheuvel 				  CRYPTO_ALG_TYPE_HASH,
482f15f05b0SArd Biesheuvel 				  CRYPTO_ALG_TYPE_AHASH_MASK |
483f15f05b0SArd Biesheuvel 				  CRYPTO_ALG_ASYNC);
484f15f05b0SArd Biesheuvel 	if (IS_ERR(mac_alg))
485f15f05b0SArd Biesheuvel 		return PTR_ERR(mac_alg);
4864a49b499SJoy Latten 
487f15f05b0SArd Biesheuvel 	mac = __crypto_hash_alg_common(mac_alg);
4884a49b499SJoy Latten 	err = -EINVAL;
489f15f05b0SArd Biesheuvel 	if (mac->digestsize != 16)
490f15f05b0SArd Biesheuvel 		goto out_put_mac;
4914a49b499SJoy Latten 
4924a49b499SJoy Latten 	inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL);
4934a49b499SJoy Latten 	err = -ENOMEM;
4944a49b499SJoy Latten 	if (!inst)
495f15f05b0SArd Biesheuvel 		goto out_put_mac;
4964a49b499SJoy Latten 
49781c4c35eSHerbert Xu 	ictx = aead_instance_ctx(inst);
498f15f05b0SArd Biesheuvel 	err = crypto_init_ahash_spawn(&ictx->mac, mac,
499f15f05b0SArd Biesheuvel 				      aead_crypto_instance(inst));
5004a49b499SJoy Latten 	if (err)
5014a49b499SJoy Latten 		goto err_free_inst;
5024a49b499SJoy Latten 
50381c4c35eSHerbert Xu 	crypto_set_skcipher_spawn(&ictx->ctr, aead_crypto_instance(inst));
504a35528ecSEric Biggers 	err = crypto_grab_skcipher(&ictx->ctr, ctr_name, 0,
5054a49b499SJoy Latten 				   crypto_requires_sync(algt->type,
5064a49b499SJoy Latten 							algt->mask));
5074a49b499SJoy Latten 	if (err)
508f15f05b0SArd Biesheuvel 		goto err_drop_mac;
5094a49b499SJoy Latten 
510464b93a3SHerbert Xu 	ctr = crypto_spawn_skcipher_alg(&ictx->ctr);
5114a49b499SJoy Latten 
5124a49b499SJoy Latten 	/* Not a stream cipher? */
5134a49b499SJoy Latten 	err = -EINVAL;
514464b93a3SHerbert Xu 	if (ctr->base.cra_blocksize != 1)
5154a49b499SJoy Latten 		goto err_drop_ctr;
5164a49b499SJoy Latten 
5174a49b499SJoy Latten 	/* We want the real thing! */
518464b93a3SHerbert Xu 	if (crypto_skcipher_alg_ivsize(ctr) != 16)
5194a49b499SJoy Latten 		goto err_drop_ctr;
5204a49b499SJoy Latten 
5214a49b499SJoy Latten 	err = -ENAMETOOLONG;
52281c4c35eSHerbert Xu 	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
523464b93a3SHerbert Xu 		     "ccm_base(%s,%s)", ctr->base.cra_driver_name,
524f15f05b0SArd Biesheuvel 		     mac->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
5254a49b499SJoy Latten 		goto err_drop_ctr;
5264a49b499SJoy Latten 
52781c4c35eSHerbert Xu 	memcpy(inst->alg.base.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
5284a49b499SJoy Latten 
529464b93a3SHerbert Xu 	inst->alg.base.cra_flags = ctr->base.cra_flags & CRYPTO_ALG_ASYNC;
530f15f05b0SArd Biesheuvel 	inst->alg.base.cra_priority = (mac->base.cra_priority +
531464b93a3SHerbert Xu 				       ctr->base.cra_priority) / 2;
53281c4c35eSHerbert Xu 	inst->alg.base.cra_blocksize = 1;
533f15f05b0SArd Biesheuvel 	inst->alg.base.cra_alignmask = mac->base.cra_alignmask |
5345ba8e2a0SArd Biesheuvel 				       ctr->base.cra_alignmask;
53581c4c35eSHerbert Xu 	inst->alg.ivsize = 16;
536464b93a3SHerbert Xu 	inst->alg.chunksize = crypto_skcipher_alg_chunksize(ctr);
53781c4c35eSHerbert Xu 	inst->alg.maxauthsize = 16;
53881c4c35eSHerbert Xu 	inst->alg.base.cra_ctxsize = sizeof(struct crypto_ccm_ctx);
53981c4c35eSHerbert Xu 	inst->alg.init = crypto_ccm_init_tfm;
54081c4c35eSHerbert Xu 	inst->alg.exit = crypto_ccm_exit_tfm;
54181c4c35eSHerbert Xu 	inst->alg.setkey = crypto_ccm_setkey;
54281c4c35eSHerbert Xu 	inst->alg.setauthsize = crypto_ccm_setauthsize;
54381c4c35eSHerbert Xu 	inst->alg.encrypt = crypto_ccm_encrypt;
54481c4c35eSHerbert Xu 	inst->alg.decrypt = crypto_ccm_decrypt;
5454a49b499SJoy Latten 
54681c4c35eSHerbert Xu 	inst->free = crypto_ccm_free;
54781c4c35eSHerbert Xu 
54881c4c35eSHerbert Xu 	err = aead_register_instance(tmpl, inst);
54981c4c35eSHerbert Xu 	if (err)
55081c4c35eSHerbert Xu 		goto err_drop_ctr;
55181c4c35eSHerbert Xu 
552f15f05b0SArd Biesheuvel out_put_mac:
553f15f05b0SArd Biesheuvel 	crypto_mod_put(mac_alg);
55481c4c35eSHerbert Xu 	return err;
5554a49b499SJoy Latten 
5564a49b499SJoy Latten err_drop_ctr:
5574a49b499SJoy Latten 	crypto_drop_skcipher(&ictx->ctr);
558f15f05b0SArd Biesheuvel err_drop_mac:
559f15f05b0SArd Biesheuvel 	crypto_drop_ahash(&ictx->mac);
5604a49b499SJoy Latten err_free_inst:
5614a49b499SJoy Latten 	kfree(inst);
562f15f05b0SArd Biesheuvel 	goto out_put_mac;
5634a49b499SJoy Latten }
5644a49b499SJoy Latten 
56581c4c35eSHerbert Xu static int crypto_ccm_create(struct crypto_template *tmpl, struct rtattr **tb)
5664a49b499SJoy Latten {
5674a49b499SJoy Latten 	const char *cipher_name;
5684a49b499SJoy Latten 	char ctr_name[CRYPTO_MAX_ALG_NAME];
569f15f05b0SArd Biesheuvel 	char mac_name[CRYPTO_MAX_ALG_NAME];
5704a49b499SJoy Latten 	char full_name[CRYPTO_MAX_ALG_NAME];
5714a49b499SJoy Latten 
5724a49b499SJoy Latten 	cipher_name = crypto_attr_alg_name(tb[1]);
5734a49b499SJoy Latten 	if (IS_ERR(cipher_name))
57481c4c35eSHerbert Xu 		return PTR_ERR(cipher_name);
5754a49b499SJoy Latten 
5764a49b499SJoy Latten 	if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)",
5774a49b499SJoy Latten 		     cipher_name) >= CRYPTO_MAX_ALG_NAME)
57881c4c35eSHerbert Xu 		return -ENAMETOOLONG;
5794a49b499SJoy Latten 
580f15f05b0SArd Biesheuvel 	if (snprintf(mac_name, CRYPTO_MAX_ALG_NAME, "cbcmac(%s)",
581f15f05b0SArd Biesheuvel 		     cipher_name) >= CRYPTO_MAX_ALG_NAME)
582f15f05b0SArd Biesheuvel 		return -ENAMETOOLONG;
583f15f05b0SArd Biesheuvel 
5844a49b499SJoy Latten 	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "ccm(%s)", cipher_name) >=
5854a49b499SJoy Latten 	    CRYPTO_MAX_ALG_NAME)
58681c4c35eSHerbert Xu 		return -ENAMETOOLONG;
5874a49b499SJoy Latten 
58881c4c35eSHerbert Xu 	return crypto_ccm_create_common(tmpl, tb, full_name, ctr_name,
589f15f05b0SArd Biesheuvel 					mac_name);
5904a49b499SJoy Latten }
5914a49b499SJoy Latten 
59281c4c35eSHerbert Xu static int crypto_ccm_base_create(struct crypto_template *tmpl,
59381c4c35eSHerbert Xu 				  struct rtattr **tb)
5944a49b499SJoy Latten {
5954a49b499SJoy Latten 	const char *ctr_name;
5964a49b499SJoy Latten 	const char *cipher_name;
5974a49b499SJoy Latten 	char full_name[CRYPTO_MAX_ALG_NAME];
5984a49b499SJoy Latten 
5994a49b499SJoy Latten 	ctr_name = crypto_attr_alg_name(tb[1]);
6004a49b499SJoy Latten 	if (IS_ERR(ctr_name))
60181c4c35eSHerbert Xu 		return PTR_ERR(ctr_name);
6024a49b499SJoy Latten 
6034a49b499SJoy Latten 	cipher_name = crypto_attr_alg_name(tb[2]);
6044a49b499SJoy Latten 	if (IS_ERR(cipher_name))
60581c4c35eSHerbert Xu 		return PTR_ERR(cipher_name);
6064a49b499SJoy Latten 
6074a49b499SJoy Latten 	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "ccm_base(%s,%s)",
6084a49b499SJoy Latten 		     ctr_name, cipher_name) >= CRYPTO_MAX_ALG_NAME)
60981c4c35eSHerbert Xu 		return -ENAMETOOLONG;
6104a49b499SJoy Latten 
61181c4c35eSHerbert Xu 	return crypto_ccm_create_common(tmpl, tb, full_name, ctr_name,
61281c4c35eSHerbert Xu 					cipher_name);
6134a49b499SJoy Latten }
6144a49b499SJoy Latten 
6154a49b499SJoy Latten static int crypto_rfc4309_setkey(struct crypto_aead *parent, const u8 *key,
6164a49b499SJoy Latten 				 unsigned int keylen)
6174a49b499SJoy Latten {
6184a49b499SJoy Latten 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(parent);
6194a49b499SJoy Latten 	struct crypto_aead *child = ctx->child;
6204a49b499SJoy Latten 	int err;
6214a49b499SJoy Latten 
6224a49b499SJoy Latten 	if (keylen < 3)
6234a49b499SJoy Latten 		return -EINVAL;
6244a49b499SJoy Latten 
6254a49b499SJoy Latten 	keylen -= 3;
6264a49b499SJoy Latten 	memcpy(ctx->nonce, key + keylen, 3);
6274a49b499SJoy Latten 
6284a49b499SJoy Latten 	crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
6294a49b499SJoy Latten 	crypto_aead_set_flags(child, crypto_aead_get_flags(parent) &
6304a49b499SJoy Latten 				     CRYPTO_TFM_REQ_MASK);
6314a49b499SJoy Latten 	err = crypto_aead_setkey(child, key, keylen);
6324a49b499SJoy Latten 	crypto_aead_set_flags(parent, crypto_aead_get_flags(child) &
6334a49b499SJoy Latten 				      CRYPTO_TFM_RES_MASK);
6344a49b499SJoy Latten 
6354a49b499SJoy Latten 	return err;
6364a49b499SJoy Latten }
6374a49b499SJoy Latten 
6384a49b499SJoy Latten static int crypto_rfc4309_setauthsize(struct crypto_aead *parent,
6394a49b499SJoy Latten 				      unsigned int authsize)
6404a49b499SJoy Latten {
6414a49b499SJoy Latten 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(parent);
6424a49b499SJoy Latten 
6434a49b499SJoy Latten 	switch (authsize) {
6444a49b499SJoy Latten 	case 8:
6454a49b499SJoy Latten 	case 12:
6464a49b499SJoy Latten 	case 16:
6474a49b499SJoy Latten 		break;
6484a49b499SJoy Latten 	default:
6494a49b499SJoy Latten 		return -EINVAL;
6504a49b499SJoy Latten 	}
6514a49b499SJoy Latten 
6524a49b499SJoy Latten 	return crypto_aead_setauthsize(ctx->child, authsize);
6534a49b499SJoy Latten }
6544a49b499SJoy Latten 
6554a49b499SJoy Latten static struct aead_request *crypto_rfc4309_crypt(struct aead_request *req)
6564a49b499SJoy Latten {
65781c4c35eSHerbert Xu 	struct crypto_rfc4309_req_ctx *rctx = aead_request_ctx(req);
65881c4c35eSHerbert Xu 	struct aead_request *subreq = &rctx->subreq;
6594a49b499SJoy Latten 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
6604a49b499SJoy Latten 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(aead);
6614a49b499SJoy Latten 	struct crypto_aead *child = ctx->child;
66281c4c35eSHerbert Xu 	struct scatterlist *sg;
6634a49b499SJoy Latten 	u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child),
6644a49b499SJoy Latten 			   crypto_aead_alignmask(child) + 1);
6654a49b499SJoy Latten 
6664a49b499SJoy Latten 	/* L' */
6674a49b499SJoy Latten 	iv[0] = 3;
6684a49b499SJoy Latten 
6694a49b499SJoy Latten 	memcpy(iv + 1, ctx->nonce, 3);
6704a49b499SJoy Latten 	memcpy(iv + 4, req->iv, 8);
6714a49b499SJoy Latten 
67281c4c35eSHerbert Xu 	scatterwalk_map_and_copy(iv + 16, req->src, 0, req->assoclen - 8, 0);
67381c4c35eSHerbert Xu 
67481c4c35eSHerbert Xu 	sg_init_table(rctx->src, 3);
67581c4c35eSHerbert Xu 	sg_set_buf(rctx->src, iv + 16, req->assoclen - 8);
67681c4c35eSHerbert Xu 	sg = scatterwalk_ffwd(rctx->src + 1, req->src, req->assoclen);
67781c4c35eSHerbert Xu 	if (sg != rctx->src + 1)
67881c4c35eSHerbert Xu 		sg_chain(rctx->src, 2, sg);
67981c4c35eSHerbert Xu 
68081c4c35eSHerbert Xu 	if (req->src != req->dst) {
68181c4c35eSHerbert Xu 		sg_init_table(rctx->dst, 3);
68281c4c35eSHerbert Xu 		sg_set_buf(rctx->dst, iv + 16, req->assoclen - 8);
68381c4c35eSHerbert Xu 		sg = scatterwalk_ffwd(rctx->dst + 1, req->dst, req->assoclen);
68481c4c35eSHerbert Xu 		if (sg != rctx->dst + 1)
68581c4c35eSHerbert Xu 			sg_chain(rctx->dst, 2, sg);
68681c4c35eSHerbert Xu 	}
68781c4c35eSHerbert Xu 
6884a49b499SJoy Latten 	aead_request_set_tfm(subreq, child);
6894a49b499SJoy Latten 	aead_request_set_callback(subreq, req->base.flags, req->base.complete,
6904a49b499SJoy Latten 				  req->base.data);
69181c4c35eSHerbert Xu 	aead_request_set_crypt(subreq, rctx->src,
69281c4c35eSHerbert Xu 			       req->src == req->dst ? rctx->src : rctx->dst,
69381c4c35eSHerbert Xu 			       req->cryptlen, iv);
69481c4c35eSHerbert Xu 	aead_request_set_ad(subreq, req->assoclen - 8);
6954a49b499SJoy Latten 
6964a49b499SJoy Latten 	return subreq;
6974a49b499SJoy Latten }
6984a49b499SJoy Latten 
6994a49b499SJoy Latten static int crypto_rfc4309_encrypt(struct aead_request *req)
7004a49b499SJoy Latten {
70181c4c35eSHerbert Xu 	if (req->assoclen != 16 && req->assoclen != 20)
70281c4c35eSHerbert Xu 		return -EINVAL;
70381c4c35eSHerbert Xu 
7044a49b499SJoy Latten 	req = crypto_rfc4309_crypt(req);
7054a49b499SJoy Latten 
7064a49b499SJoy Latten 	return crypto_aead_encrypt(req);
7074a49b499SJoy Latten }
7084a49b499SJoy Latten 
7094a49b499SJoy Latten static int crypto_rfc4309_decrypt(struct aead_request *req)
7104a49b499SJoy Latten {
71181c4c35eSHerbert Xu 	if (req->assoclen != 16 && req->assoclen != 20)
71281c4c35eSHerbert Xu 		return -EINVAL;
71381c4c35eSHerbert Xu 
7144a49b499SJoy Latten 	req = crypto_rfc4309_crypt(req);
7154a49b499SJoy Latten 
7164a49b499SJoy Latten 	return crypto_aead_decrypt(req);
7174a49b499SJoy Latten }
7184a49b499SJoy Latten 
71981c4c35eSHerbert Xu static int crypto_rfc4309_init_tfm(struct crypto_aead *tfm)
7204a49b499SJoy Latten {
72181c4c35eSHerbert Xu 	struct aead_instance *inst = aead_alg_instance(tfm);
72281c4c35eSHerbert Xu 	struct crypto_aead_spawn *spawn = aead_instance_ctx(inst);
72381c4c35eSHerbert Xu 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(tfm);
7244a49b499SJoy Latten 	struct crypto_aead *aead;
7254a49b499SJoy Latten 	unsigned long align;
7264a49b499SJoy Latten 
7274a49b499SJoy Latten 	aead = crypto_spawn_aead(spawn);
7284a49b499SJoy Latten 	if (IS_ERR(aead))
7294a49b499SJoy Latten 		return PTR_ERR(aead);
7304a49b499SJoy Latten 
7314a49b499SJoy Latten 	ctx->child = aead;
7324a49b499SJoy Latten 
7334a49b499SJoy Latten 	align = crypto_aead_alignmask(aead);
7344a49b499SJoy Latten 	align &= ~(crypto_tfm_ctx_alignment() - 1);
73581c4c35eSHerbert Xu 	crypto_aead_set_reqsize(
73681c4c35eSHerbert Xu 		tfm,
73781c4c35eSHerbert Xu 		sizeof(struct crypto_rfc4309_req_ctx) +
7382c221ad3SHerbert Xu 		ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) +
73981c4c35eSHerbert Xu 		align + 32);
7404a49b499SJoy Latten 
7414a49b499SJoy Latten 	return 0;
7424a49b499SJoy Latten }
7434a49b499SJoy Latten 
74481c4c35eSHerbert Xu static void crypto_rfc4309_exit_tfm(struct crypto_aead *tfm)
7454a49b499SJoy Latten {
74681c4c35eSHerbert Xu 	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(tfm);
7474a49b499SJoy Latten 
7484a49b499SJoy Latten 	crypto_free_aead(ctx->child);
7494a49b499SJoy Latten }
7504a49b499SJoy Latten 
75181c4c35eSHerbert Xu static void crypto_rfc4309_free(struct aead_instance *inst)
75281c4c35eSHerbert Xu {
75381c4c35eSHerbert Xu 	crypto_drop_aead(aead_instance_ctx(inst));
75481c4c35eSHerbert Xu 	kfree(inst);
75581c4c35eSHerbert Xu }
75681c4c35eSHerbert Xu 
75781c4c35eSHerbert Xu static int crypto_rfc4309_create(struct crypto_template *tmpl,
75881c4c35eSHerbert Xu 				 struct rtattr **tb)
7594a49b499SJoy Latten {
7604a49b499SJoy Latten 	struct crypto_attr_type *algt;
76181c4c35eSHerbert Xu 	struct aead_instance *inst;
7624a49b499SJoy Latten 	struct crypto_aead_spawn *spawn;
76381c4c35eSHerbert Xu 	struct aead_alg *alg;
7644a49b499SJoy Latten 	const char *ccm_name;
7654a49b499SJoy Latten 	int err;
7664a49b499SJoy Latten 
7674a49b499SJoy Latten 	algt = crypto_get_attr_type(tb);
7684a49b499SJoy Latten 	if (IS_ERR(algt))
76981c4c35eSHerbert Xu 		return PTR_ERR(algt);
7704a49b499SJoy Latten 
7715e4b8c1fSHerbert Xu 	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
77281c4c35eSHerbert Xu 		return -EINVAL;
7734a49b499SJoy Latten 
7744a49b499SJoy Latten 	ccm_name = crypto_attr_alg_name(tb[1]);
7754a49b499SJoy Latten 	if (IS_ERR(ccm_name))
77681c4c35eSHerbert Xu 		return PTR_ERR(ccm_name);
7774a49b499SJoy Latten 
7784a49b499SJoy Latten 	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
7794a49b499SJoy Latten 	if (!inst)
78081c4c35eSHerbert Xu 		return -ENOMEM;
7814a49b499SJoy Latten 
78281c4c35eSHerbert Xu 	spawn = aead_instance_ctx(inst);
78381c4c35eSHerbert Xu 	crypto_set_aead_spawn(spawn, aead_crypto_instance(inst));
7844a49b499SJoy Latten 	err = crypto_grab_aead(spawn, ccm_name, 0,
7854a49b499SJoy Latten 			       crypto_requires_sync(algt->type, algt->mask));
7864a49b499SJoy Latten 	if (err)
7874a49b499SJoy Latten 		goto out_free_inst;
7884a49b499SJoy Latten 
78981c4c35eSHerbert Xu 	alg = crypto_spawn_aead_alg(spawn);
7904a49b499SJoy Latten 
7914a49b499SJoy Latten 	err = -EINVAL;
7924a49b499SJoy Latten 
7934a49b499SJoy Latten 	/* We only support 16-byte blocks. */
79481c4c35eSHerbert Xu 	if (crypto_aead_alg_ivsize(alg) != 16)
7954a49b499SJoy Latten 		goto out_drop_alg;
7964a49b499SJoy Latten 
7974a49b499SJoy Latten 	/* Not a stream cipher? */
79881c4c35eSHerbert Xu 	if (alg->base.cra_blocksize != 1)
7994a49b499SJoy Latten 		goto out_drop_alg;
8004a49b499SJoy Latten 
8014a49b499SJoy Latten 	err = -ENAMETOOLONG;
80281c4c35eSHerbert Xu 	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
80381c4c35eSHerbert Xu 		     "rfc4309(%s)", alg->base.cra_name) >=
80481c4c35eSHerbert Xu 	    CRYPTO_MAX_ALG_NAME ||
80581c4c35eSHerbert Xu 	    snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
80681c4c35eSHerbert Xu 		     "rfc4309(%s)", alg->base.cra_driver_name) >=
8074a49b499SJoy Latten 	    CRYPTO_MAX_ALG_NAME)
8084a49b499SJoy Latten 		goto out_drop_alg;
8094a49b499SJoy Latten 
81081c4c35eSHerbert Xu 	inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC;
81181c4c35eSHerbert Xu 	inst->alg.base.cra_priority = alg->base.cra_priority;
81281c4c35eSHerbert Xu 	inst->alg.base.cra_blocksize = 1;
81381c4c35eSHerbert Xu 	inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
8144a49b499SJoy Latten 
81581c4c35eSHerbert Xu 	inst->alg.ivsize = 8;
816464b93a3SHerbert Xu 	inst->alg.chunksize = crypto_aead_alg_chunksize(alg);
81781c4c35eSHerbert Xu 	inst->alg.maxauthsize = 16;
8184a49b499SJoy Latten 
81981c4c35eSHerbert Xu 	inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4309_ctx);
8204a49b499SJoy Latten 
82181c4c35eSHerbert Xu 	inst->alg.init = crypto_rfc4309_init_tfm;
82281c4c35eSHerbert Xu 	inst->alg.exit = crypto_rfc4309_exit_tfm;
8234a49b499SJoy Latten 
82481c4c35eSHerbert Xu 	inst->alg.setkey = crypto_rfc4309_setkey;
82581c4c35eSHerbert Xu 	inst->alg.setauthsize = crypto_rfc4309_setauthsize;
82681c4c35eSHerbert Xu 	inst->alg.encrypt = crypto_rfc4309_encrypt;
82781c4c35eSHerbert Xu 	inst->alg.decrypt = crypto_rfc4309_decrypt;
8284a49b499SJoy Latten 
82981c4c35eSHerbert Xu 	inst->free = crypto_rfc4309_free;
83081c4c35eSHerbert Xu 
83181c4c35eSHerbert Xu 	err = aead_register_instance(tmpl, inst);
83281c4c35eSHerbert Xu 	if (err)
83381c4c35eSHerbert Xu 		goto out_drop_alg;
8344a49b499SJoy Latten 
8354a49b499SJoy Latten out:
83681c4c35eSHerbert Xu 	return err;
8374a49b499SJoy Latten 
8384a49b499SJoy Latten out_drop_alg:
8394a49b499SJoy Latten 	crypto_drop_aead(spawn);
8404a49b499SJoy Latten out_free_inst:
8414a49b499SJoy Latten 	kfree(inst);
8424a49b499SJoy Latten 	goto out;
8434a49b499SJoy Latten }
8444a49b499SJoy Latten 
845f15f05b0SArd Biesheuvel static int crypto_cbcmac_digest_setkey(struct crypto_shash *parent,
846f15f05b0SArd Biesheuvel 				     const u8 *inkey, unsigned int keylen)
847f15f05b0SArd Biesheuvel {
848f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *ctx = crypto_shash_ctx(parent);
849f15f05b0SArd Biesheuvel 
850f15f05b0SArd Biesheuvel 	return crypto_cipher_setkey(ctx->child, inkey, keylen);
851f15f05b0SArd Biesheuvel }
852f15f05b0SArd Biesheuvel 
853f15f05b0SArd Biesheuvel static int crypto_cbcmac_digest_init(struct shash_desc *pdesc)
854f15f05b0SArd Biesheuvel {
855f15f05b0SArd Biesheuvel 	struct cbcmac_desc_ctx *ctx = shash_desc_ctx(pdesc);
856f15f05b0SArd Biesheuvel 	int bs = crypto_shash_digestsize(pdesc->tfm);
8575338ad70SArd Biesheuvel 	u8 *dg = (u8 *)ctx + crypto_shash_descsize(pdesc->tfm) - bs;
858f15f05b0SArd Biesheuvel 
859f15f05b0SArd Biesheuvel 	ctx->len = 0;
8605338ad70SArd Biesheuvel 	memset(dg, 0, bs);
861f15f05b0SArd Biesheuvel 
862f15f05b0SArd Biesheuvel 	return 0;
863f15f05b0SArd Biesheuvel }
864f15f05b0SArd Biesheuvel 
865f15f05b0SArd Biesheuvel static int crypto_cbcmac_digest_update(struct shash_desc *pdesc, const u8 *p,
866f15f05b0SArd Biesheuvel 				       unsigned int len)
867f15f05b0SArd Biesheuvel {
868f15f05b0SArd Biesheuvel 	struct crypto_shash *parent = pdesc->tfm;
869f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *tctx = crypto_shash_ctx(parent);
870f15f05b0SArd Biesheuvel 	struct cbcmac_desc_ctx *ctx = shash_desc_ctx(pdesc);
871f15f05b0SArd Biesheuvel 	struct crypto_cipher *tfm = tctx->child;
872f15f05b0SArd Biesheuvel 	int bs = crypto_shash_digestsize(parent);
8735338ad70SArd Biesheuvel 	u8 *dg = (u8 *)ctx + crypto_shash_descsize(parent) - bs;
874f15f05b0SArd Biesheuvel 
875f15f05b0SArd Biesheuvel 	while (len > 0) {
876f15f05b0SArd Biesheuvel 		unsigned int l = min(len, bs - ctx->len);
877f15f05b0SArd Biesheuvel 
8785338ad70SArd Biesheuvel 		crypto_xor(dg + ctx->len, p, l);
879f15f05b0SArd Biesheuvel 		ctx->len +=l;
880f15f05b0SArd Biesheuvel 		len -= l;
881f15f05b0SArd Biesheuvel 		p += l;
882f15f05b0SArd Biesheuvel 
883f15f05b0SArd Biesheuvel 		if (ctx->len == bs) {
8845338ad70SArd Biesheuvel 			crypto_cipher_encrypt_one(tfm, dg, dg);
885f15f05b0SArd Biesheuvel 			ctx->len = 0;
886f15f05b0SArd Biesheuvel 		}
887f15f05b0SArd Biesheuvel 	}
888f15f05b0SArd Biesheuvel 
889f15f05b0SArd Biesheuvel 	return 0;
890f15f05b0SArd Biesheuvel }
891f15f05b0SArd Biesheuvel 
892f15f05b0SArd Biesheuvel static int crypto_cbcmac_digest_final(struct shash_desc *pdesc, u8 *out)
893f15f05b0SArd Biesheuvel {
894f15f05b0SArd Biesheuvel 	struct crypto_shash *parent = pdesc->tfm;
895f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *tctx = crypto_shash_ctx(parent);
896f15f05b0SArd Biesheuvel 	struct cbcmac_desc_ctx *ctx = shash_desc_ctx(pdesc);
897f15f05b0SArd Biesheuvel 	struct crypto_cipher *tfm = tctx->child;
898f15f05b0SArd Biesheuvel 	int bs = crypto_shash_digestsize(parent);
8995338ad70SArd Biesheuvel 	u8 *dg = (u8 *)ctx + crypto_shash_descsize(parent) - bs;
900f15f05b0SArd Biesheuvel 
901f15f05b0SArd Biesheuvel 	if (ctx->len)
9025338ad70SArd Biesheuvel 		crypto_cipher_encrypt_one(tfm, dg, dg);
903f15f05b0SArd Biesheuvel 
9045338ad70SArd Biesheuvel 	memcpy(out, dg, bs);
905f15f05b0SArd Biesheuvel 	return 0;
906f15f05b0SArd Biesheuvel }
907f15f05b0SArd Biesheuvel 
908f15f05b0SArd Biesheuvel static int cbcmac_init_tfm(struct crypto_tfm *tfm)
909f15f05b0SArd Biesheuvel {
910f15f05b0SArd Biesheuvel 	struct crypto_cipher *cipher;
911f15f05b0SArd Biesheuvel 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
912f15f05b0SArd Biesheuvel 	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
913f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
914f15f05b0SArd Biesheuvel 
915f15f05b0SArd Biesheuvel 	cipher = crypto_spawn_cipher(spawn);
916f15f05b0SArd Biesheuvel 	if (IS_ERR(cipher))
917f15f05b0SArd Biesheuvel 		return PTR_ERR(cipher);
918f15f05b0SArd Biesheuvel 
919f15f05b0SArd Biesheuvel 	ctx->child = cipher;
920f15f05b0SArd Biesheuvel 
921f15f05b0SArd Biesheuvel 	return 0;
922f15f05b0SArd Biesheuvel };
923f15f05b0SArd Biesheuvel 
924f15f05b0SArd Biesheuvel static void cbcmac_exit_tfm(struct crypto_tfm *tfm)
925f15f05b0SArd Biesheuvel {
926f15f05b0SArd Biesheuvel 	struct cbcmac_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
927f15f05b0SArd Biesheuvel 	crypto_free_cipher(ctx->child);
928f15f05b0SArd Biesheuvel }
929f15f05b0SArd Biesheuvel 
930f15f05b0SArd Biesheuvel static int cbcmac_create(struct crypto_template *tmpl, struct rtattr **tb)
931f15f05b0SArd Biesheuvel {
932f15f05b0SArd Biesheuvel 	struct shash_instance *inst;
933f15f05b0SArd Biesheuvel 	struct crypto_alg *alg;
934f15f05b0SArd Biesheuvel 	int err;
935f15f05b0SArd Biesheuvel 
936f15f05b0SArd Biesheuvel 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH);
937f15f05b0SArd Biesheuvel 	if (err)
938f15f05b0SArd Biesheuvel 		return err;
939f15f05b0SArd Biesheuvel 
940f15f05b0SArd Biesheuvel 	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
941f15f05b0SArd Biesheuvel 				  CRYPTO_ALG_TYPE_MASK);
942f15f05b0SArd Biesheuvel 	if (IS_ERR(alg))
943f15f05b0SArd Biesheuvel 		return PTR_ERR(alg);
944f15f05b0SArd Biesheuvel 
945f15f05b0SArd Biesheuvel 	inst = shash_alloc_instance("cbcmac", alg);
946f15f05b0SArd Biesheuvel 	err = PTR_ERR(inst);
947f15f05b0SArd Biesheuvel 	if (IS_ERR(inst))
948f15f05b0SArd Biesheuvel 		goto out_put_alg;
949f15f05b0SArd Biesheuvel 
950f15f05b0SArd Biesheuvel 	err = crypto_init_spawn(shash_instance_ctx(inst), alg,
951f15f05b0SArd Biesheuvel 				shash_crypto_instance(inst),
952f15f05b0SArd Biesheuvel 				CRYPTO_ALG_TYPE_MASK);
953f15f05b0SArd Biesheuvel 	if (err)
954f15f05b0SArd Biesheuvel 		goto out_free_inst;
955f15f05b0SArd Biesheuvel 
956f15f05b0SArd Biesheuvel 	inst->alg.base.cra_priority = alg->cra_priority;
957f15f05b0SArd Biesheuvel 	inst->alg.base.cra_blocksize = 1;
958f15f05b0SArd Biesheuvel 
959f15f05b0SArd Biesheuvel 	inst->alg.digestsize = alg->cra_blocksize;
9605338ad70SArd Biesheuvel 	inst->alg.descsize = ALIGN(sizeof(struct cbcmac_desc_ctx),
9615338ad70SArd Biesheuvel 				   alg->cra_alignmask + 1) +
962f15f05b0SArd Biesheuvel 			     alg->cra_blocksize;
963f15f05b0SArd Biesheuvel 
964f15f05b0SArd Biesheuvel 	inst->alg.base.cra_ctxsize = sizeof(struct cbcmac_tfm_ctx);
965f15f05b0SArd Biesheuvel 	inst->alg.base.cra_init = cbcmac_init_tfm;
966f15f05b0SArd Biesheuvel 	inst->alg.base.cra_exit = cbcmac_exit_tfm;
967f15f05b0SArd Biesheuvel 
968f15f05b0SArd Biesheuvel 	inst->alg.init = crypto_cbcmac_digest_init;
969f15f05b0SArd Biesheuvel 	inst->alg.update = crypto_cbcmac_digest_update;
970f15f05b0SArd Biesheuvel 	inst->alg.final = crypto_cbcmac_digest_final;
971f15f05b0SArd Biesheuvel 	inst->alg.setkey = crypto_cbcmac_digest_setkey;
972f15f05b0SArd Biesheuvel 
973f15f05b0SArd Biesheuvel 	err = shash_register_instance(tmpl, inst);
974f15f05b0SArd Biesheuvel 
975f15f05b0SArd Biesheuvel out_free_inst:
976f15f05b0SArd Biesheuvel 	if (err)
977f15f05b0SArd Biesheuvel 		shash_free_instance(shash_crypto_instance(inst));
978f15f05b0SArd Biesheuvel 
979f15f05b0SArd Biesheuvel out_put_alg:
980f15f05b0SArd Biesheuvel 	crypto_mod_put(alg);
981f15f05b0SArd Biesheuvel 	return err;
982f15f05b0SArd Biesheuvel }
983f15f05b0SArd Biesheuvel 
9840db19035SXiongfeng Wang static struct crypto_template crypto_ccm_tmpls[] = {
9850db19035SXiongfeng Wang 	{
986f15f05b0SArd Biesheuvel 		.name = "cbcmac",
987f15f05b0SArd Biesheuvel 		.create = cbcmac_create,
988f15f05b0SArd Biesheuvel 		.free = shash_free_instance,
989f15f05b0SArd Biesheuvel 		.module = THIS_MODULE,
9900db19035SXiongfeng Wang 	}, {
9910db19035SXiongfeng Wang 		.name = "ccm_base",
9920db19035SXiongfeng Wang 		.create = crypto_ccm_base_create,
9930db19035SXiongfeng Wang 		.module = THIS_MODULE,
9940db19035SXiongfeng Wang 	}, {
9950db19035SXiongfeng Wang 		.name = "ccm",
9960db19035SXiongfeng Wang 		.create = crypto_ccm_create,
9970db19035SXiongfeng Wang 		.module = THIS_MODULE,
9980db19035SXiongfeng Wang 	}, {
9990db19035SXiongfeng Wang 		.name = "rfc4309",
10000db19035SXiongfeng Wang 		.create = crypto_rfc4309_create,
10010db19035SXiongfeng Wang 		.module = THIS_MODULE,
10020db19035SXiongfeng Wang 	},
1003f15f05b0SArd Biesheuvel };
1004f15f05b0SArd Biesheuvel 
10054a49b499SJoy Latten static int __init crypto_ccm_module_init(void)
10064a49b499SJoy Latten {
10070db19035SXiongfeng Wang 	return crypto_register_templates(crypto_ccm_tmpls,
10080db19035SXiongfeng Wang 					 ARRAY_SIZE(crypto_ccm_tmpls));
10094a49b499SJoy Latten }
10104a49b499SJoy Latten 
10114a49b499SJoy Latten static void __exit crypto_ccm_module_exit(void)
10124a49b499SJoy Latten {
10130db19035SXiongfeng Wang 	crypto_unregister_templates(crypto_ccm_tmpls,
10140db19035SXiongfeng Wang 				    ARRAY_SIZE(crypto_ccm_tmpls));
10154a49b499SJoy Latten }
10164a49b499SJoy Latten 
10174a49b499SJoy Latten module_init(crypto_ccm_module_init);
10184a49b499SJoy Latten module_exit(crypto_ccm_module_exit);
10194a49b499SJoy Latten 
10204a49b499SJoy Latten MODULE_LICENSE("GPL");
10214a49b499SJoy Latten MODULE_DESCRIPTION("Counter with CBC MAC");
10225d26a105SKees Cook MODULE_ALIAS_CRYPTO("ccm_base");
10235d26a105SKees Cook MODULE_ALIAS_CRYPTO("rfc4309");
10244943ba16SKees Cook MODULE_ALIAS_CRYPTO("ccm");
1025