xref: /openbmc/linux/crypto/chacha20poly1305.c (revision 74790922)
171ebc4d1SMartin Willi /*
271ebc4d1SMartin Willi  * ChaCha20-Poly1305 AEAD, RFC7539
371ebc4d1SMartin Willi  *
471ebc4d1SMartin Willi  * Copyright (C) 2015 Martin Willi
571ebc4d1SMartin Willi  *
671ebc4d1SMartin Willi  * This program is free software; you can redistribute it and/or modify
771ebc4d1SMartin Willi  * it under the terms of the GNU General Public License as published by
871ebc4d1SMartin Willi  * the Free Software Foundation; either version 2 of the License, or
971ebc4d1SMartin Willi  * (at your option) any later version.
1071ebc4d1SMartin Willi  */
1171ebc4d1SMartin Willi 
1271ebc4d1SMartin Willi #include <crypto/internal/aead.h>
1371ebc4d1SMartin Willi #include <crypto/internal/hash.h>
1471ebc4d1SMartin Willi #include <crypto/internal/skcipher.h>
1571ebc4d1SMartin Willi #include <crypto/scatterwalk.h>
1671ebc4d1SMartin Willi #include <linux/err.h>
1771ebc4d1SMartin Willi #include <linux/init.h>
1871ebc4d1SMartin Willi #include <linux/kernel.h>
1971ebc4d1SMartin Willi #include <linux/module.h>
2071ebc4d1SMartin Willi 
2171ebc4d1SMartin Willi #include "internal.h"
2271ebc4d1SMartin Willi 
2371ebc4d1SMartin Willi #define POLY1305_BLOCK_SIZE	16
2471ebc4d1SMartin Willi #define POLY1305_DIGEST_SIZE	16
2571ebc4d1SMartin Willi #define POLY1305_KEY_SIZE	32
2671ebc4d1SMartin Willi #define CHACHA20_KEY_SIZE	32
2771ebc4d1SMartin Willi #define CHACHA20_IV_SIZE	16
2871ebc4d1SMartin Willi #define CHACHAPOLY_IV_SIZE	12
2971ebc4d1SMartin Willi 
3071ebc4d1SMartin Willi struct chachapoly_instance_ctx {
3171ebc4d1SMartin Willi 	struct crypto_skcipher_spawn chacha;
3271ebc4d1SMartin Willi 	struct crypto_ahash_spawn poly;
3371ebc4d1SMartin Willi 	unsigned int saltlen;
3471ebc4d1SMartin Willi };
3571ebc4d1SMartin Willi 
3671ebc4d1SMartin Willi struct chachapoly_ctx {
3771ebc4d1SMartin Willi 	struct crypto_ablkcipher *chacha;
3871ebc4d1SMartin Willi 	struct crypto_ahash *poly;
3971ebc4d1SMartin Willi 	/* key bytes we use for the ChaCha20 IV */
4071ebc4d1SMartin Willi 	unsigned int saltlen;
4171ebc4d1SMartin Willi 	u8 salt[];
4271ebc4d1SMartin Willi };
4371ebc4d1SMartin Willi 
4471ebc4d1SMartin Willi struct poly_req {
4571ebc4d1SMartin Willi 	/* zero byte padding for AD/ciphertext, as needed */
4671ebc4d1SMartin Willi 	u8 pad[POLY1305_BLOCK_SIZE];
4771ebc4d1SMartin Willi 	/* tail data with AD/ciphertext lengths */
4871ebc4d1SMartin Willi 	struct {
4971ebc4d1SMartin Willi 		__le64 assoclen;
5071ebc4d1SMartin Willi 		__le64 cryptlen;
5171ebc4d1SMartin Willi 	} tail;
5271ebc4d1SMartin Willi 	struct scatterlist src[1];
5371ebc4d1SMartin Willi 	struct ahash_request req; /* must be last member */
5471ebc4d1SMartin Willi };
5571ebc4d1SMartin Willi 
5671ebc4d1SMartin Willi struct chacha_req {
5771ebc4d1SMartin Willi 	u8 iv[CHACHA20_IV_SIZE];
5871ebc4d1SMartin Willi 	struct scatterlist src[1];
5971ebc4d1SMartin Willi 	struct ablkcipher_request req; /* must be last member */
6071ebc4d1SMartin Willi };
6171ebc4d1SMartin Willi 
6271ebc4d1SMartin Willi struct chachapoly_req_ctx {
6374790922SHerbert Xu 	struct scatterlist src[2];
6474790922SHerbert Xu 	struct scatterlist dst[2];
65c2b7b20aSMartin Willi 	/* the key we generate for Poly1305 using Chacha20 */
66c2b7b20aSMartin Willi 	u8 key[POLY1305_KEY_SIZE];
6771ebc4d1SMartin Willi 	/* calculated Poly1305 tag */
6871ebc4d1SMartin Willi 	u8 tag[POLY1305_DIGEST_SIZE];
6971ebc4d1SMartin Willi 	/* length of data to en/decrypt, without ICV */
7071ebc4d1SMartin Willi 	unsigned int cryptlen;
7174790922SHerbert Xu 	/* Actual AD, excluding IV */
7274790922SHerbert Xu 	unsigned int assoclen;
7371ebc4d1SMartin Willi 	union {
7471ebc4d1SMartin Willi 		struct poly_req poly;
7571ebc4d1SMartin Willi 		struct chacha_req chacha;
7671ebc4d1SMartin Willi 	} u;
7771ebc4d1SMartin Willi };
7871ebc4d1SMartin Willi 
7971ebc4d1SMartin Willi static inline void async_done_continue(struct aead_request *req, int err,
8071ebc4d1SMartin Willi 				       int (*cont)(struct aead_request *))
8171ebc4d1SMartin Willi {
8271ebc4d1SMartin Willi 	if (!err)
8371ebc4d1SMartin Willi 		err = cont(req);
8471ebc4d1SMartin Willi 
8571ebc4d1SMartin Willi 	if (err != -EINPROGRESS && err != -EBUSY)
8671ebc4d1SMartin Willi 		aead_request_complete(req, err);
8771ebc4d1SMartin Willi }
8871ebc4d1SMartin Willi 
8971ebc4d1SMartin Willi static void chacha_iv(u8 *iv, struct aead_request *req, u32 icb)
9071ebc4d1SMartin Willi {
9171ebc4d1SMartin Willi 	struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
9271ebc4d1SMartin Willi 	__le32 leicb = cpu_to_le32(icb);
9371ebc4d1SMartin Willi 
9471ebc4d1SMartin Willi 	memcpy(iv, &leicb, sizeof(leicb));
9571ebc4d1SMartin Willi 	memcpy(iv + sizeof(leicb), ctx->salt, ctx->saltlen);
9671ebc4d1SMartin Willi 	memcpy(iv + sizeof(leicb) + ctx->saltlen, req->iv,
9771ebc4d1SMartin Willi 	       CHACHA20_IV_SIZE - sizeof(leicb) - ctx->saltlen);
9871ebc4d1SMartin Willi }
9971ebc4d1SMartin Willi 
10071ebc4d1SMartin Willi static int poly_verify_tag(struct aead_request *req)
10171ebc4d1SMartin Willi {
10271ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
10371ebc4d1SMartin Willi 	u8 tag[sizeof(rctx->tag)];
10471ebc4d1SMartin Willi 
10574790922SHerbert Xu 	scatterwalk_map_and_copy(tag, req->src,
10674790922SHerbert Xu 				 req->assoclen + rctx->cryptlen,
10774790922SHerbert Xu 				 sizeof(tag), 0);
10871ebc4d1SMartin Willi 	if (crypto_memneq(tag, rctx->tag, sizeof(tag)))
10971ebc4d1SMartin Willi 		return -EBADMSG;
11071ebc4d1SMartin Willi 	return 0;
11171ebc4d1SMartin Willi }
11271ebc4d1SMartin Willi 
11371ebc4d1SMartin Willi static int poly_copy_tag(struct aead_request *req)
11471ebc4d1SMartin Willi {
11571ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
11671ebc4d1SMartin Willi 
11774790922SHerbert Xu 	scatterwalk_map_and_copy(rctx->tag, req->dst,
11874790922SHerbert Xu 				 req->assoclen + rctx->cryptlen,
11971ebc4d1SMartin Willi 				 sizeof(rctx->tag), 1);
12071ebc4d1SMartin Willi 	return 0;
12171ebc4d1SMartin Willi }
12271ebc4d1SMartin Willi 
12371ebc4d1SMartin Willi static void chacha_decrypt_done(struct crypto_async_request *areq, int err)
12471ebc4d1SMartin Willi {
12571ebc4d1SMartin Willi 	async_done_continue(areq->data, err, poly_verify_tag);
12671ebc4d1SMartin Willi }
12771ebc4d1SMartin Willi 
12871ebc4d1SMartin Willi static int chacha_decrypt(struct aead_request *req)
12971ebc4d1SMartin Willi {
13071ebc4d1SMartin Willi 	struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
13171ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
13271ebc4d1SMartin Willi 	struct chacha_req *creq = &rctx->u.chacha;
13374790922SHerbert Xu 	struct scatterlist *src, *dst;
13471ebc4d1SMartin Willi 	int err;
13571ebc4d1SMartin Willi 
13671ebc4d1SMartin Willi 	chacha_iv(creq->iv, req, 1);
13771ebc4d1SMartin Willi 
13874790922SHerbert Xu 	sg_init_table(rctx->src, 2);
13974790922SHerbert Xu 	src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen);
14074790922SHerbert Xu 	dst = src;
14174790922SHerbert Xu 
14274790922SHerbert Xu 	if (req->src != req->dst) {
14374790922SHerbert Xu 		sg_init_table(rctx->dst, 2);
14474790922SHerbert Xu 		dst = scatterwalk_ffwd(rctx->dst, req->dst, req->assoclen);
14574790922SHerbert Xu 	}
14674790922SHerbert Xu 
14771ebc4d1SMartin Willi 	ablkcipher_request_set_callback(&creq->req, aead_request_flags(req),
14871ebc4d1SMartin Willi 					chacha_decrypt_done, req);
14971ebc4d1SMartin Willi 	ablkcipher_request_set_tfm(&creq->req, ctx->chacha);
15074790922SHerbert Xu 	ablkcipher_request_set_crypt(&creq->req, src, dst,
15171ebc4d1SMartin Willi 				     rctx->cryptlen, creq->iv);
15271ebc4d1SMartin Willi 	err = crypto_ablkcipher_decrypt(&creq->req);
15371ebc4d1SMartin Willi 	if (err)
15471ebc4d1SMartin Willi 		return err;
15571ebc4d1SMartin Willi 
15671ebc4d1SMartin Willi 	return poly_verify_tag(req);
15771ebc4d1SMartin Willi }
15871ebc4d1SMartin Willi 
15971ebc4d1SMartin Willi static int poly_tail_continue(struct aead_request *req)
16071ebc4d1SMartin Willi {
16171ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
16271ebc4d1SMartin Willi 
16371ebc4d1SMartin Willi 	if (rctx->cryptlen == req->cryptlen) /* encrypting */
16471ebc4d1SMartin Willi 		return poly_copy_tag(req);
16571ebc4d1SMartin Willi 
16671ebc4d1SMartin Willi 	return chacha_decrypt(req);
16771ebc4d1SMartin Willi }
16871ebc4d1SMartin Willi 
16971ebc4d1SMartin Willi static void poly_tail_done(struct crypto_async_request *areq, int err)
17071ebc4d1SMartin Willi {
17171ebc4d1SMartin Willi 	async_done_continue(areq->data, err, poly_tail_continue);
17271ebc4d1SMartin Willi }
17371ebc4d1SMartin Willi 
17471ebc4d1SMartin Willi static int poly_tail(struct aead_request *req)
17571ebc4d1SMartin Willi {
17674790922SHerbert Xu 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
17774790922SHerbert Xu 	struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm);
17871ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
17971ebc4d1SMartin Willi 	struct poly_req *preq = &rctx->u.poly;
18071ebc4d1SMartin Willi 	__le64 len;
18171ebc4d1SMartin Willi 	int err;
18271ebc4d1SMartin Willi 
18371ebc4d1SMartin Willi 	sg_init_table(preq->src, 1);
18474790922SHerbert Xu 	len = cpu_to_le64(rctx->assoclen);
18571ebc4d1SMartin Willi 	memcpy(&preq->tail.assoclen, &len, sizeof(len));
18671ebc4d1SMartin Willi 	len = cpu_to_le64(rctx->cryptlen);
18771ebc4d1SMartin Willi 	memcpy(&preq->tail.cryptlen, &len, sizeof(len));
18871ebc4d1SMartin Willi 	sg_set_buf(preq->src, &preq->tail, sizeof(preq->tail));
18971ebc4d1SMartin Willi 
19071ebc4d1SMartin Willi 	ahash_request_set_callback(&preq->req, aead_request_flags(req),
19171ebc4d1SMartin Willi 				   poly_tail_done, req);
19271ebc4d1SMartin Willi 	ahash_request_set_tfm(&preq->req, ctx->poly);
19371ebc4d1SMartin Willi 	ahash_request_set_crypt(&preq->req, preq->src,
19471ebc4d1SMartin Willi 				rctx->tag, sizeof(preq->tail));
19571ebc4d1SMartin Willi 
19671ebc4d1SMartin Willi 	err = crypto_ahash_finup(&preq->req);
19771ebc4d1SMartin Willi 	if (err)
19871ebc4d1SMartin Willi 		return err;
19971ebc4d1SMartin Willi 
20071ebc4d1SMartin Willi 	return poly_tail_continue(req);
20171ebc4d1SMartin Willi }
20271ebc4d1SMartin Willi 
20371ebc4d1SMartin Willi static void poly_cipherpad_done(struct crypto_async_request *areq, int err)
20471ebc4d1SMartin Willi {
20571ebc4d1SMartin Willi 	async_done_continue(areq->data, err, poly_tail);
20671ebc4d1SMartin Willi }
20771ebc4d1SMartin Willi 
20871ebc4d1SMartin Willi static int poly_cipherpad(struct aead_request *req)
20971ebc4d1SMartin Willi {
21071ebc4d1SMartin Willi 	struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
21171ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
21271ebc4d1SMartin Willi 	struct poly_req *preq = &rctx->u.poly;
21371ebc4d1SMartin Willi 	unsigned int padlen, bs = POLY1305_BLOCK_SIZE;
21471ebc4d1SMartin Willi 	int err;
21571ebc4d1SMartin Willi 
21671ebc4d1SMartin Willi 	padlen = (bs - (rctx->cryptlen % bs)) % bs;
21771ebc4d1SMartin Willi 	memset(preq->pad, 0, sizeof(preq->pad));
21871ebc4d1SMartin Willi 	sg_init_table(preq->src, 1);
21971ebc4d1SMartin Willi 	sg_set_buf(preq->src, &preq->pad, padlen);
22071ebc4d1SMartin Willi 
22171ebc4d1SMartin Willi 	ahash_request_set_callback(&preq->req, aead_request_flags(req),
22271ebc4d1SMartin Willi 				   poly_cipherpad_done, req);
22371ebc4d1SMartin Willi 	ahash_request_set_tfm(&preq->req, ctx->poly);
22471ebc4d1SMartin Willi 	ahash_request_set_crypt(&preq->req, preq->src, NULL, padlen);
22571ebc4d1SMartin Willi 
22671ebc4d1SMartin Willi 	err = crypto_ahash_update(&preq->req);
22771ebc4d1SMartin Willi 	if (err)
22871ebc4d1SMartin Willi 		return err;
22971ebc4d1SMartin Willi 
23071ebc4d1SMartin Willi 	return poly_tail(req);
23171ebc4d1SMartin Willi }
23271ebc4d1SMartin Willi 
23371ebc4d1SMartin Willi static void poly_cipher_done(struct crypto_async_request *areq, int err)
23471ebc4d1SMartin Willi {
23571ebc4d1SMartin Willi 	async_done_continue(areq->data, err, poly_cipherpad);
23671ebc4d1SMartin Willi }
23771ebc4d1SMartin Willi 
23871ebc4d1SMartin Willi static int poly_cipher(struct aead_request *req)
23971ebc4d1SMartin Willi {
24071ebc4d1SMartin Willi 	struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
24171ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
24271ebc4d1SMartin Willi 	struct poly_req *preq = &rctx->u.poly;
24371ebc4d1SMartin Willi 	struct scatterlist *crypt = req->src;
24471ebc4d1SMartin Willi 	int err;
24571ebc4d1SMartin Willi 
24671ebc4d1SMartin Willi 	if (rctx->cryptlen == req->cryptlen) /* encrypting */
24771ebc4d1SMartin Willi 		crypt = req->dst;
24871ebc4d1SMartin Willi 
24974790922SHerbert Xu 	sg_init_table(rctx->src, 2);
25074790922SHerbert Xu 	crypt = scatterwalk_ffwd(rctx->src, crypt, req->assoclen);
25174790922SHerbert Xu 
25271ebc4d1SMartin Willi 	ahash_request_set_callback(&preq->req, aead_request_flags(req),
25371ebc4d1SMartin Willi 				   poly_cipher_done, req);
25471ebc4d1SMartin Willi 	ahash_request_set_tfm(&preq->req, ctx->poly);
25571ebc4d1SMartin Willi 	ahash_request_set_crypt(&preq->req, crypt, NULL, rctx->cryptlen);
25671ebc4d1SMartin Willi 
25771ebc4d1SMartin Willi 	err = crypto_ahash_update(&preq->req);
25871ebc4d1SMartin Willi 	if (err)
25971ebc4d1SMartin Willi 		return err;
26071ebc4d1SMartin Willi 
26171ebc4d1SMartin Willi 	return poly_cipherpad(req);
26271ebc4d1SMartin Willi }
26371ebc4d1SMartin Willi 
26471ebc4d1SMartin Willi static void poly_adpad_done(struct crypto_async_request *areq, int err)
26571ebc4d1SMartin Willi {
26671ebc4d1SMartin Willi 	async_done_continue(areq->data, err, poly_cipher);
26771ebc4d1SMartin Willi }
26871ebc4d1SMartin Willi 
26971ebc4d1SMartin Willi static int poly_adpad(struct aead_request *req)
27071ebc4d1SMartin Willi {
27171ebc4d1SMartin Willi 	struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
27271ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
27371ebc4d1SMartin Willi 	struct poly_req *preq = &rctx->u.poly;
27471ebc4d1SMartin Willi 	unsigned int padlen, bs = POLY1305_BLOCK_SIZE;
27571ebc4d1SMartin Willi 	int err;
27671ebc4d1SMartin Willi 
27774790922SHerbert Xu 	padlen = (bs - (rctx->assoclen % bs)) % bs;
27871ebc4d1SMartin Willi 	memset(preq->pad, 0, sizeof(preq->pad));
27971ebc4d1SMartin Willi 	sg_init_table(preq->src, 1);
28071ebc4d1SMartin Willi 	sg_set_buf(preq->src, preq->pad, padlen);
28171ebc4d1SMartin Willi 
28271ebc4d1SMartin Willi 	ahash_request_set_callback(&preq->req, aead_request_flags(req),
28371ebc4d1SMartin Willi 				   poly_adpad_done, req);
28471ebc4d1SMartin Willi 	ahash_request_set_tfm(&preq->req, ctx->poly);
28571ebc4d1SMartin Willi 	ahash_request_set_crypt(&preq->req, preq->src, NULL, padlen);
28671ebc4d1SMartin Willi 
28771ebc4d1SMartin Willi 	err = crypto_ahash_update(&preq->req);
28871ebc4d1SMartin Willi 	if (err)
28971ebc4d1SMartin Willi 		return err;
29071ebc4d1SMartin Willi 
29171ebc4d1SMartin Willi 	return poly_cipher(req);
29271ebc4d1SMartin Willi }
29371ebc4d1SMartin Willi 
29471ebc4d1SMartin Willi static void poly_ad_done(struct crypto_async_request *areq, int err)
29571ebc4d1SMartin Willi {
29671ebc4d1SMartin Willi 	async_done_continue(areq->data, err, poly_adpad);
29771ebc4d1SMartin Willi }
29871ebc4d1SMartin Willi 
29971ebc4d1SMartin Willi static int poly_ad(struct aead_request *req)
30071ebc4d1SMartin Willi {
30171ebc4d1SMartin Willi 	struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
30271ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
30371ebc4d1SMartin Willi 	struct poly_req *preq = &rctx->u.poly;
30471ebc4d1SMartin Willi 	int err;
30571ebc4d1SMartin Willi 
30671ebc4d1SMartin Willi 	ahash_request_set_callback(&preq->req, aead_request_flags(req),
30771ebc4d1SMartin Willi 				   poly_ad_done, req);
30871ebc4d1SMartin Willi 	ahash_request_set_tfm(&preq->req, ctx->poly);
30974790922SHerbert Xu 	ahash_request_set_crypt(&preq->req, req->src, NULL, rctx->assoclen);
31071ebc4d1SMartin Willi 
31171ebc4d1SMartin Willi 	err = crypto_ahash_update(&preq->req);
31271ebc4d1SMartin Willi 	if (err)
31371ebc4d1SMartin Willi 		return err;
31471ebc4d1SMartin Willi 
31571ebc4d1SMartin Willi 	return poly_adpad(req);
31671ebc4d1SMartin Willi }
31771ebc4d1SMartin Willi 
318c2b7b20aSMartin Willi static void poly_setkey_done(struct crypto_async_request *areq, int err)
31971ebc4d1SMartin Willi {
32071ebc4d1SMartin Willi 	async_done_continue(areq->data, err, poly_ad);
32171ebc4d1SMartin Willi }
32271ebc4d1SMartin Willi 
323c2b7b20aSMartin Willi static int poly_setkey(struct aead_request *req)
324c2b7b20aSMartin Willi {
325c2b7b20aSMartin Willi 	struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
326c2b7b20aSMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
327c2b7b20aSMartin Willi 	struct poly_req *preq = &rctx->u.poly;
328c2b7b20aSMartin Willi 	int err;
329c2b7b20aSMartin Willi 
330c2b7b20aSMartin Willi 	sg_init_table(preq->src, 1);
331c2b7b20aSMartin Willi 	sg_set_buf(preq->src, rctx->key, sizeof(rctx->key));
332c2b7b20aSMartin Willi 
333c2b7b20aSMartin Willi 	ahash_request_set_callback(&preq->req, aead_request_flags(req),
334c2b7b20aSMartin Willi 				   poly_setkey_done, req);
335c2b7b20aSMartin Willi 	ahash_request_set_tfm(&preq->req, ctx->poly);
336c2b7b20aSMartin Willi 	ahash_request_set_crypt(&preq->req, preq->src, NULL, sizeof(rctx->key));
337c2b7b20aSMartin Willi 
338c2b7b20aSMartin Willi 	err = crypto_ahash_update(&preq->req);
339c2b7b20aSMartin Willi 	if (err)
340c2b7b20aSMartin Willi 		return err;
341c2b7b20aSMartin Willi 
342c2b7b20aSMartin Willi 	return poly_ad(req);
343c2b7b20aSMartin Willi }
344c2b7b20aSMartin Willi 
345c2b7b20aSMartin Willi static void poly_init_done(struct crypto_async_request *areq, int err)
346c2b7b20aSMartin Willi {
347c2b7b20aSMartin Willi 	async_done_continue(areq->data, err, poly_setkey);
348c2b7b20aSMartin Willi }
349c2b7b20aSMartin Willi 
35071ebc4d1SMartin Willi static int poly_init(struct aead_request *req)
35171ebc4d1SMartin Willi {
35271ebc4d1SMartin Willi 	struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
35371ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
35471ebc4d1SMartin Willi 	struct poly_req *preq = &rctx->u.poly;
35571ebc4d1SMartin Willi 	int err;
35671ebc4d1SMartin Willi 
35771ebc4d1SMartin Willi 	ahash_request_set_callback(&preq->req, aead_request_flags(req),
35871ebc4d1SMartin Willi 				   poly_init_done, req);
35971ebc4d1SMartin Willi 	ahash_request_set_tfm(&preq->req, ctx->poly);
36071ebc4d1SMartin Willi 
36171ebc4d1SMartin Willi 	err = crypto_ahash_init(&preq->req);
36271ebc4d1SMartin Willi 	if (err)
36371ebc4d1SMartin Willi 		return err;
36471ebc4d1SMartin Willi 
365c2b7b20aSMartin Willi 	return poly_setkey(req);
36671ebc4d1SMartin Willi }
36771ebc4d1SMartin Willi 
36871ebc4d1SMartin Willi static void poly_genkey_done(struct crypto_async_request *areq, int err)
36971ebc4d1SMartin Willi {
370c2b7b20aSMartin Willi 	async_done_continue(areq->data, err, poly_init);
37171ebc4d1SMartin Willi }
37271ebc4d1SMartin Willi 
37371ebc4d1SMartin Willi static int poly_genkey(struct aead_request *req)
37471ebc4d1SMartin Willi {
37574790922SHerbert Xu 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
37674790922SHerbert Xu 	struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm);
37771ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
37871ebc4d1SMartin Willi 	struct chacha_req *creq = &rctx->u.chacha;
37971ebc4d1SMartin Willi 	int err;
38071ebc4d1SMartin Willi 
38174790922SHerbert Xu 	rctx->assoclen = req->assoclen;
38274790922SHerbert Xu 
38374790922SHerbert Xu 	if (crypto_aead_ivsize(tfm) == 8) {
38474790922SHerbert Xu 		if (rctx->assoclen < 8)
38574790922SHerbert Xu 			return -EINVAL;
38674790922SHerbert Xu 		rctx->assoclen -= 8;
38774790922SHerbert Xu 	}
38874790922SHerbert Xu 
38971ebc4d1SMartin Willi 	sg_init_table(creq->src, 1);
390c2b7b20aSMartin Willi 	memset(rctx->key, 0, sizeof(rctx->key));
391c2b7b20aSMartin Willi 	sg_set_buf(creq->src, rctx->key, sizeof(rctx->key));
39271ebc4d1SMartin Willi 
39371ebc4d1SMartin Willi 	chacha_iv(creq->iv, req, 0);
39471ebc4d1SMartin Willi 
39571ebc4d1SMartin Willi 	ablkcipher_request_set_callback(&creq->req, aead_request_flags(req),
39671ebc4d1SMartin Willi 					poly_genkey_done, req);
39771ebc4d1SMartin Willi 	ablkcipher_request_set_tfm(&creq->req, ctx->chacha);
39871ebc4d1SMartin Willi 	ablkcipher_request_set_crypt(&creq->req, creq->src, creq->src,
39971ebc4d1SMartin Willi 				     POLY1305_KEY_SIZE, creq->iv);
40071ebc4d1SMartin Willi 
40171ebc4d1SMartin Willi 	err = crypto_ablkcipher_decrypt(&creq->req);
40271ebc4d1SMartin Willi 	if (err)
40371ebc4d1SMartin Willi 		return err;
40471ebc4d1SMartin Willi 
405c2b7b20aSMartin Willi 	return poly_init(req);
40671ebc4d1SMartin Willi }
40771ebc4d1SMartin Willi 
40871ebc4d1SMartin Willi static void chacha_encrypt_done(struct crypto_async_request *areq, int err)
40971ebc4d1SMartin Willi {
41071ebc4d1SMartin Willi 	async_done_continue(areq->data, err, poly_genkey);
41171ebc4d1SMartin Willi }
41271ebc4d1SMartin Willi 
41371ebc4d1SMartin Willi static int chacha_encrypt(struct aead_request *req)
41471ebc4d1SMartin Willi {
41571ebc4d1SMartin Willi 	struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
41671ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
41771ebc4d1SMartin Willi 	struct chacha_req *creq = &rctx->u.chacha;
41874790922SHerbert Xu 	struct scatterlist *src, *dst;
41971ebc4d1SMartin Willi 	int err;
42071ebc4d1SMartin Willi 
42171ebc4d1SMartin Willi 	chacha_iv(creq->iv, req, 1);
42271ebc4d1SMartin Willi 
42374790922SHerbert Xu 	sg_init_table(rctx->src, 2);
42474790922SHerbert Xu 	src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen);
42574790922SHerbert Xu 	dst = src;
42674790922SHerbert Xu 
42774790922SHerbert Xu 	if (req->src != req->dst) {
42874790922SHerbert Xu 		sg_init_table(rctx->dst, 2);
42974790922SHerbert Xu 		dst = scatterwalk_ffwd(rctx->dst, req->dst, req->assoclen);
43074790922SHerbert Xu 	}
43174790922SHerbert Xu 
43271ebc4d1SMartin Willi 	ablkcipher_request_set_callback(&creq->req, aead_request_flags(req),
43371ebc4d1SMartin Willi 					chacha_encrypt_done, req);
43471ebc4d1SMartin Willi 	ablkcipher_request_set_tfm(&creq->req, ctx->chacha);
43574790922SHerbert Xu 	ablkcipher_request_set_crypt(&creq->req, src, dst,
43671ebc4d1SMartin Willi 				     req->cryptlen, creq->iv);
43771ebc4d1SMartin Willi 	err = crypto_ablkcipher_encrypt(&creq->req);
43871ebc4d1SMartin Willi 	if (err)
43971ebc4d1SMartin Willi 		return err;
44071ebc4d1SMartin Willi 
44171ebc4d1SMartin Willi 	return poly_genkey(req);
44271ebc4d1SMartin Willi }
44371ebc4d1SMartin Willi 
44471ebc4d1SMartin Willi static int chachapoly_encrypt(struct aead_request *req)
44571ebc4d1SMartin Willi {
44671ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
44771ebc4d1SMartin Willi 
44871ebc4d1SMartin Willi 	rctx->cryptlen = req->cryptlen;
44971ebc4d1SMartin Willi 
45071ebc4d1SMartin Willi 	/* encrypt call chain:
45171ebc4d1SMartin Willi 	 * - chacha_encrypt/done()
452c2b7b20aSMartin Willi 	 * - poly_genkey/done()
45371ebc4d1SMartin Willi 	 * - poly_init/done()
454c2b7b20aSMartin Willi 	 * - poly_setkey/done()
45571ebc4d1SMartin Willi 	 * - poly_ad/done()
45671ebc4d1SMartin Willi 	 * - poly_adpad/done()
45771ebc4d1SMartin Willi 	 * - poly_cipher/done()
45871ebc4d1SMartin Willi 	 * - poly_cipherpad/done()
45971ebc4d1SMartin Willi 	 * - poly_tail/done/continue()
46071ebc4d1SMartin Willi 	 * - poly_copy_tag()
46171ebc4d1SMartin Willi 	 */
46271ebc4d1SMartin Willi 	return chacha_encrypt(req);
46371ebc4d1SMartin Willi }
46471ebc4d1SMartin Willi 
46571ebc4d1SMartin Willi static int chachapoly_decrypt(struct aead_request *req)
46671ebc4d1SMartin Willi {
46771ebc4d1SMartin Willi 	struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
46871ebc4d1SMartin Willi 
46971ebc4d1SMartin Willi 	rctx->cryptlen = req->cryptlen - POLY1305_DIGEST_SIZE;
47071ebc4d1SMartin Willi 
47171ebc4d1SMartin Willi 	/* decrypt call chain:
472c2b7b20aSMartin Willi 	 * - poly_genkey/done()
47371ebc4d1SMartin Willi 	 * - poly_init/done()
474c2b7b20aSMartin Willi 	 * - poly_setkey/done()
47571ebc4d1SMartin Willi 	 * - poly_ad/done()
47671ebc4d1SMartin Willi 	 * - poly_adpad/done()
47771ebc4d1SMartin Willi 	 * - poly_cipher/done()
47871ebc4d1SMartin Willi 	 * - poly_cipherpad/done()
47971ebc4d1SMartin Willi 	 * - poly_tail/done/continue()
48071ebc4d1SMartin Willi 	 * - chacha_decrypt/done()
48171ebc4d1SMartin Willi 	 * - poly_verify_tag()
48271ebc4d1SMartin Willi 	 */
48371ebc4d1SMartin Willi 	return poly_genkey(req);
48471ebc4d1SMartin Willi }
48571ebc4d1SMartin Willi 
48671ebc4d1SMartin Willi static int chachapoly_setkey(struct crypto_aead *aead, const u8 *key,
48771ebc4d1SMartin Willi 			     unsigned int keylen)
48871ebc4d1SMartin Willi {
48971ebc4d1SMartin Willi 	struct chachapoly_ctx *ctx = crypto_aead_ctx(aead);
49071ebc4d1SMartin Willi 	int err;
49171ebc4d1SMartin Willi 
49271ebc4d1SMartin Willi 	if (keylen != ctx->saltlen + CHACHA20_KEY_SIZE)
49371ebc4d1SMartin Willi 		return -EINVAL;
49471ebc4d1SMartin Willi 
49571ebc4d1SMartin Willi 	keylen -= ctx->saltlen;
49671ebc4d1SMartin Willi 	memcpy(ctx->salt, key + keylen, ctx->saltlen);
49771ebc4d1SMartin Willi 
49871ebc4d1SMartin Willi 	crypto_ablkcipher_clear_flags(ctx->chacha, CRYPTO_TFM_REQ_MASK);
49971ebc4d1SMartin Willi 	crypto_ablkcipher_set_flags(ctx->chacha, crypto_aead_get_flags(aead) &
50071ebc4d1SMartin Willi 				    CRYPTO_TFM_REQ_MASK);
50171ebc4d1SMartin Willi 
50271ebc4d1SMartin Willi 	err = crypto_ablkcipher_setkey(ctx->chacha, key, keylen);
50371ebc4d1SMartin Willi 	crypto_aead_set_flags(aead, crypto_ablkcipher_get_flags(ctx->chacha) &
50471ebc4d1SMartin Willi 			      CRYPTO_TFM_RES_MASK);
50571ebc4d1SMartin Willi 	return err;
50671ebc4d1SMartin Willi }
50771ebc4d1SMartin Willi 
50871ebc4d1SMartin Willi static int chachapoly_setauthsize(struct crypto_aead *tfm,
50971ebc4d1SMartin Willi 				  unsigned int authsize)
51071ebc4d1SMartin Willi {
51171ebc4d1SMartin Willi 	if (authsize != POLY1305_DIGEST_SIZE)
51271ebc4d1SMartin Willi 		return -EINVAL;
51371ebc4d1SMartin Willi 
51471ebc4d1SMartin Willi 	return 0;
51571ebc4d1SMartin Willi }
51671ebc4d1SMartin Willi 
51774790922SHerbert Xu static int chachapoly_init(struct crypto_aead *tfm)
51871ebc4d1SMartin Willi {
51974790922SHerbert Xu 	struct aead_instance *inst = aead_alg_instance(tfm);
52074790922SHerbert Xu 	struct chachapoly_instance_ctx *ictx = aead_instance_ctx(inst);
52174790922SHerbert Xu 	struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm);
52271ebc4d1SMartin Willi 	struct crypto_ablkcipher *chacha;
52371ebc4d1SMartin Willi 	struct crypto_ahash *poly;
52471ebc4d1SMartin Willi 	unsigned long align;
52571ebc4d1SMartin Willi 
52671ebc4d1SMartin Willi 	poly = crypto_spawn_ahash(&ictx->poly);
52771ebc4d1SMartin Willi 	if (IS_ERR(poly))
52871ebc4d1SMartin Willi 		return PTR_ERR(poly);
52971ebc4d1SMartin Willi 
53071ebc4d1SMartin Willi 	chacha = crypto_spawn_skcipher(&ictx->chacha);
53171ebc4d1SMartin Willi 	if (IS_ERR(chacha)) {
53271ebc4d1SMartin Willi 		crypto_free_ahash(poly);
53371ebc4d1SMartin Willi 		return PTR_ERR(chacha);
53471ebc4d1SMartin Willi 	}
53571ebc4d1SMartin Willi 
53671ebc4d1SMartin Willi 	ctx->chacha = chacha;
53771ebc4d1SMartin Willi 	ctx->poly = poly;
53871ebc4d1SMartin Willi 	ctx->saltlen = ictx->saltlen;
53971ebc4d1SMartin Willi 
54074790922SHerbert Xu 	align = crypto_aead_alignmask(tfm);
54171ebc4d1SMartin Willi 	align &= ~(crypto_tfm_ctx_alignment() - 1);
54274790922SHerbert Xu 	crypto_aead_set_reqsize(
54374790922SHerbert Xu 		tfm,
54471ebc4d1SMartin Willi 		align + offsetof(struct chachapoly_req_ctx, u) +
54571ebc4d1SMartin Willi 		max(offsetof(struct chacha_req, req) +
54671ebc4d1SMartin Willi 		    sizeof(struct ablkcipher_request) +
54771ebc4d1SMartin Willi 		    crypto_ablkcipher_reqsize(chacha),
54871ebc4d1SMartin Willi 		    offsetof(struct poly_req, req) +
54971ebc4d1SMartin Willi 		    sizeof(struct ahash_request) +
55071ebc4d1SMartin Willi 		    crypto_ahash_reqsize(poly)));
55171ebc4d1SMartin Willi 
55271ebc4d1SMartin Willi 	return 0;
55371ebc4d1SMartin Willi }
55471ebc4d1SMartin Willi 
55574790922SHerbert Xu static void chachapoly_exit(struct crypto_aead *tfm)
55671ebc4d1SMartin Willi {
55774790922SHerbert Xu 	struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm);
55871ebc4d1SMartin Willi 
55971ebc4d1SMartin Willi 	crypto_free_ahash(ctx->poly);
56071ebc4d1SMartin Willi 	crypto_free_ablkcipher(ctx->chacha);
56171ebc4d1SMartin Willi }
56271ebc4d1SMartin Willi 
56374790922SHerbert Xu static void chachapoly_free(struct aead_instance *inst)
56474790922SHerbert Xu {
56574790922SHerbert Xu 	struct chachapoly_instance_ctx *ctx = aead_instance_ctx(inst);
56674790922SHerbert Xu 
56774790922SHerbert Xu 	crypto_drop_skcipher(&ctx->chacha);
56874790922SHerbert Xu 	crypto_drop_ahash(&ctx->poly);
56974790922SHerbert Xu 	kfree(inst);
57074790922SHerbert Xu }
57174790922SHerbert Xu 
57274790922SHerbert Xu static int chachapoly_create(struct crypto_template *tmpl, struct rtattr **tb,
57374790922SHerbert Xu 			     const char *name, unsigned int ivsize)
57471ebc4d1SMartin Willi {
57571ebc4d1SMartin Willi 	struct crypto_attr_type *algt;
57674790922SHerbert Xu 	struct aead_instance *inst;
57771ebc4d1SMartin Willi 	struct crypto_alg *chacha;
57871ebc4d1SMartin Willi 	struct crypto_alg *poly;
57974790922SHerbert Xu 	struct hash_alg_common *poly_hash;
58071ebc4d1SMartin Willi 	struct chachapoly_instance_ctx *ctx;
58171ebc4d1SMartin Willi 	const char *chacha_name, *poly_name;
58271ebc4d1SMartin Willi 	int err;
58371ebc4d1SMartin Willi 
58471ebc4d1SMartin Willi 	if (ivsize > CHACHAPOLY_IV_SIZE)
58574790922SHerbert Xu 		return -EINVAL;
58671ebc4d1SMartin Willi 
58771ebc4d1SMartin Willi 	algt = crypto_get_attr_type(tb);
58871ebc4d1SMartin Willi 	if (IS_ERR(algt))
58974790922SHerbert Xu 		return PTR_ERR(algt);
59071ebc4d1SMartin Willi 
59174790922SHerbert Xu 	if ((algt->type ^ (CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_AEAD_NEW)) &
59274790922SHerbert Xu 	    algt->mask)
59374790922SHerbert Xu 		return -EINVAL;
59471ebc4d1SMartin Willi 
59571ebc4d1SMartin Willi 	chacha_name = crypto_attr_alg_name(tb[1]);
59671ebc4d1SMartin Willi 	if (IS_ERR(chacha_name))
59774790922SHerbert Xu 		return PTR_ERR(chacha_name);
59871ebc4d1SMartin Willi 	poly_name = crypto_attr_alg_name(tb[2]);
59971ebc4d1SMartin Willi 	if (IS_ERR(poly_name))
60074790922SHerbert Xu 		return PTR_ERR(poly_name);
60171ebc4d1SMartin Willi 
60271ebc4d1SMartin Willi 	poly = crypto_find_alg(poly_name, &crypto_ahash_type,
60371ebc4d1SMartin Willi 			       CRYPTO_ALG_TYPE_HASH,
60471ebc4d1SMartin Willi 			       CRYPTO_ALG_TYPE_AHASH_MASK);
60571ebc4d1SMartin Willi 	if (IS_ERR(poly))
60674790922SHerbert Xu 		return PTR_ERR(poly);
60771ebc4d1SMartin Willi 
60871ebc4d1SMartin Willi 	err = -ENOMEM;
60971ebc4d1SMartin Willi 	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
61071ebc4d1SMartin Willi 	if (!inst)
61171ebc4d1SMartin Willi 		goto out_put_poly;
61271ebc4d1SMartin Willi 
61374790922SHerbert Xu 	ctx = aead_instance_ctx(inst);
61471ebc4d1SMartin Willi 	ctx->saltlen = CHACHAPOLY_IV_SIZE - ivsize;
61574790922SHerbert Xu 	poly_hash = __crypto_hash_alg_common(poly);
61674790922SHerbert Xu 	err = crypto_init_ahash_spawn(&ctx->poly, poly_hash,
61774790922SHerbert Xu 				      aead_crypto_instance(inst));
61871ebc4d1SMartin Willi 	if (err)
61971ebc4d1SMartin Willi 		goto err_free_inst;
62071ebc4d1SMartin Willi 
62174790922SHerbert Xu 	crypto_set_skcipher_spawn(&ctx->chacha, aead_crypto_instance(inst));
62271ebc4d1SMartin Willi 	err = crypto_grab_skcipher(&ctx->chacha, chacha_name, 0,
62371ebc4d1SMartin Willi 				   crypto_requires_sync(algt->type,
62471ebc4d1SMartin Willi 							algt->mask));
62571ebc4d1SMartin Willi 	if (err)
62671ebc4d1SMartin Willi 		goto err_drop_poly;
62771ebc4d1SMartin Willi 
62871ebc4d1SMartin Willi 	chacha = crypto_skcipher_spawn_alg(&ctx->chacha);
62971ebc4d1SMartin Willi 
63071ebc4d1SMartin Willi 	err = -EINVAL;
63171ebc4d1SMartin Willi 	/* Need 16-byte IV size, including Initial Block Counter value */
63271ebc4d1SMartin Willi 	if (chacha->cra_ablkcipher.ivsize != CHACHA20_IV_SIZE)
63371ebc4d1SMartin Willi 		goto out_drop_chacha;
63471ebc4d1SMartin Willi 	/* Not a stream cipher? */
63571ebc4d1SMartin Willi 	if (chacha->cra_blocksize != 1)
63671ebc4d1SMartin Willi 		goto out_drop_chacha;
63771ebc4d1SMartin Willi 
63871ebc4d1SMartin Willi 	err = -ENAMETOOLONG;
63974790922SHerbert Xu 	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
64071ebc4d1SMartin Willi 		     "%s(%s,%s)", name, chacha_name,
64171ebc4d1SMartin Willi 		     poly_name) >= CRYPTO_MAX_ALG_NAME)
64271ebc4d1SMartin Willi 		goto out_drop_chacha;
64374790922SHerbert Xu 	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
64471ebc4d1SMartin Willi 		     "%s(%s,%s)", name, chacha->cra_driver_name,
64571ebc4d1SMartin Willi 		     poly->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
64671ebc4d1SMartin Willi 		goto out_drop_chacha;
64771ebc4d1SMartin Willi 
64874790922SHerbert Xu 	inst->alg.base.cra_flags = (chacha->cra_flags | poly->cra_flags) &
64974790922SHerbert Xu 				   CRYPTO_ALG_ASYNC;
65074790922SHerbert Xu 	inst->alg.base.cra_flags |= CRYPTO_ALG_AEAD_NEW;
65174790922SHerbert Xu 	inst->alg.base.cra_priority = (chacha->cra_priority +
65271ebc4d1SMartin Willi 				       poly->cra_priority) / 2;
65374790922SHerbert Xu 	inst->alg.base.cra_blocksize = 1;
65474790922SHerbert Xu 	inst->alg.base.cra_alignmask = chacha->cra_alignmask |
65574790922SHerbert Xu 				       poly->cra_alignmask;
65674790922SHerbert Xu 	inst->alg.base.cra_ctxsize = sizeof(struct chachapoly_ctx) +
65774790922SHerbert Xu 				     ctx->saltlen;
65874790922SHerbert Xu 	inst->alg.ivsize = ivsize;
65974790922SHerbert Xu 	inst->alg.maxauthsize = POLY1305_DIGEST_SIZE;
66074790922SHerbert Xu 	inst->alg.init = chachapoly_init;
66174790922SHerbert Xu 	inst->alg.exit = chachapoly_exit;
66274790922SHerbert Xu 	inst->alg.encrypt = chachapoly_encrypt;
66374790922SHerbert Xu 	inst->alg.decrypt = chachapoly_decrypt;
66474790922SHerbert Xu 	inst->alg.setkey = chachapoly_setkey;
66574790922SHerbert Xu 	inst->alg.setauthsize = chachapoly_setauthsize;
66671ebc4d1SMartin Willi 
66774790922SHerbert Xu 	inst->free = chachapoly_free;
66874790922SHerbert Xu 
66974790922SHerbert Xu 	err = aead_register_instance(tmpl, inst);
67074790922SHerbert Xu 	if (err)
67174790922SHerbert Xu 		goto out_drop_chacha;
67274790922SHerbert Xu 
67374790922SHerbert Xu out_put_poly:
67471ebc4d1SMartin Willi 	crypto_mod_put(poly);
67574790922SHerbert Xu 	return err;
67671ebc4d1SMartin Willi 
67771ebc4d1SMartin Willi out_drop_chacha:
67871ebc4d1SMartin Willi 	crypto_drop_skcipher(&ctx->chacha);
67971ebc4d1SMartin Willi err_drop_poly:
68071ebc4d1SMartin Willi 	crypto_drop_ahash(&ctx->poly);
68171ebc4d1SMartin Willi err_free_inst:
68271ebc4d1SMartin Willi 	kfree(inst);
68374790922SHerbert Xu 	goto out_put_poly;
68471ebc4d1SMartin Willi }
68571ebc4d1SMartin Willi 
68674790922SHerbert Xu static int rfc7539_create(struct crypto_template *tmpl, struct rtattr **tb)
68771ebc4d1SMartin Willi {
68874790922SHerbert Xu 	return chachapoly_create(tmpl, tb, "rfc7539", 12);
68971ebc4d1SMartin Willi }
69071ebc4d1SMartin Willi 
69174790922SHerbert Xu static int rfc7539esp_create(struct crypto_template *tmpl, struct rtattr **tb)
6924db4ad26SMartin Willi {
69374790922SHerbert Xu 	return chachapoly_create(tmpl, tb, "rfc7539esp", 8);
69471ebc4d1SMartin Willi }
69571ebc4d1SMartin Willi 
69671ebc4d1SMartin Willi static struct crypto_template rfc7539_tmpl = {
69771ebc4d1SMartin Willi 	.name = "rfc7539",
69874790922SHerbert Xu 	.create = rfc7539_create,
69971ebc4d1SMartin Willi 	.module = THIS_MODULE,
70071ebc4d1SMartin Willi };
70171ebc4d1SMartin Willi 
7024db4ad26SMartin Willi static struct crypto_template rfc7539esp_tmpl = {
7034db4ad26SMartin Willi 	.name = "rfc7539esp",
70474790922SHerbert Xu 	.create = rfc7539esp_create,
7054db4ad26SMartin Willi 	.module = THIS_MODULE,
7064db4ad26SMartin Willi };
7074db4ad26SMartin Willi 
70871ebc4d1SMartin Willi static int __init chacha20poly1305_module_init(void)
70971ebc4d1SMartin Willi {
7104db4ad26SMartin Willi 	int err;
7114db4ad26SMartin Willi 
7124db4ad26SMartin Willi 	err = crypto_register_template(&rfc7539_tmpl);
7134db4ad26SMartin Willi 	if (err)
7144db4ad26SMartin Willi 		return err;
7154db4ad26SMartin Willi 
7164db4ad26SMartin Willi 	err = crypto_register_template(&rfc7539esp_tmpl);
7174db4ad26SMartin Willi 	if (err)
7184db4ad26SMartin Willi 		crypto_unregister_template(&rfc7539_tmpl);
7194db4ad26SMartin Willi 
7204db4ad26SMartin Willi 	return err;
72171ebc4d1SMartin Willi }
72271ebc4d1SMartin Willi 
72371ebc4d1SMartin Willi static void __exit chacha20poly1305_module_exit(void)
72471ebc4d1SMartin Willi {
7254db4ad26SMartin Willi 	crypto_unregister_template(&rfc7539esp_tmpl);
72671ebc4d1SMartin Willi 	crypto_unregister_template(&rfc7539_tmpl);
72771ebc4d1SMartin Willi }
72871ebc4d1SMartin Willi 
72971ebc4d1SMartin Willi module_init(chacha20poly1305_module_init);
73071ebc4d1SMartin Willi module_exit(chacha20poly1305_module_exit);
73171ebc4d1SMartin Willi 
73271ebc4d1SMartin Willi MODULE_LICENSE("GPL");
73371ebc4d1SMartin Willi MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
73471ebc4d1SMartin Willi MODULE_DESCRIPTION("ChaCha20-Poly1305 AEAD");
73571ebc4d1SMartin Willi MODULE_ALIAS_CRYPTO("rfc7539");
7364db4ad26SMartin Willi MODULE_ALIAS_CRYPTO("rfc7539esp");
737