12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
271ebc4d1SMartin Willi /*
371ebc4d1SMartin Willi * ChaCha20-Poly1305 AEAD, RFC7539
471ebc4d1SMartin Willi *
571ebc4d1SMartin Willi * Copyright (C) 2015 Martin Willi
671ebc4d1SMartin Willi */
771ebc4d1SMartin Willi
871ebc4d1SMartin Willi #include <crypto/internal/aead.h>
971ebc4d1SMartin Willi #include <crypto/internal/hash.h>
1071ebc4d1SMartin Willi #include <crypto/internal/skcipher.h>
1171ebc4d1SMartin Willi #include <crypto/scatterwalk.h>
121ca1b917SEric Biggers #include <crypto/chacha.h>
132546f811SMartin Willi #include <crypto/poly1305.h>
1471ebc4d1SMartin Willi #include <linux/err.h>
1571ebc4d1SMartin Willi #include <linux/kernel.h>
16a298765eSHerbert Xu #include <linux/mm.h>
1771ebc4d1SMartin Willi #include <linux/module.h>
18a298765eSHerbert Xu #include <linux/string.h>
1971ebc4d1SMartin Willi
2071ebc4d1SMartin Willi struct chachapoly_instance_ctx {
2171ebc4d1SMartin Willi struct crypto_skcipher_spawn chacha;
2271ebc4d1SMartin Willi unsigned int saltlen;
2371ebc4d1SMartin Willi };
2471ebc4d1SMartin Willi
2571ebc4d1SMartin Willi struct chachapoly_ctx {
261e1f0061SHerbert Xu struct crypto_skcipher *chacha;
2771ebc4d1SMartin Willi /* key bytes we use for the ChaCha20 IV */
2871ebc4d1SMartin Willi unsigned int saltlen;
2918e2188cSThorsten Blum u8 salt[] __counted_by(saltlen);
3071ebc4d1SMartin Willi };
3171ebc4d1SMartin Willi
3271ebc4d1SMartin Willi struct chacha_req {
331ca1b917SEric Biggers u8 iv[CHACHA_IV_SIZE];
3471ebc4d1SMartin Willi struct scatterlist src[1];
351e1f0061SHerbert Xu struct skcipher_request req; /* must be last member */
3671ebc4d1SMartin Willi };
3771ebc4d1SMartin Willi
3871ebc4d1SMartin Willi struct chachapoly_req_ctx {
3974790922SHerbert Xu struct scatterlist src[2];
4074790922SHerbert Xu struct scatterlist dst[2];
41c2b7b20aSMartin Willi /* the key we generate for Poly1305 using Chacha20 */
42c2b7b20aSMartin Willi u8 key[POLY1305_KEY_SIZE];
4371ebc4d1SMartin Willi /* calculated Poly1305 tag */
4471ebc4d1SMartin Willi u8 tag[POLY1305_DIGEST_SIZE];
4571ebc4d1SMartin Willi /* length of data to en/decrypt, without ICV */
4671ebc4d1SMartin Willi unsigned int cryptlen;
4774790922SHerbert Xu /* Actual AD, excluding IV */
4874790922SHerbert Xu unsigned int assoclen;
497545b6c2SEric Biggers /* request flags, with MAY_SLEEP cleared if needed */
507545b6c2SEric Biggers u32 flags;
5171ebc4d1SMartin Willi union {
5271ebc4d1SMartin Willi struct chacha_req chacha;
5371ebc4d1SMartin Willi } u;
5471ebc4d1SMartin Willi };
5571ebc4d1SMartin Willi
async_done_continue(struct aead_request * req,int err,int (* cont)(struct aead_request *))5671ebc4d1SMartin Willi static inline void async_done_continue(struct aead_request *req, int err,
5771ebc4d1SMartin Willi int (*cont)(struct aead_request *))
5871ebc4d1SMartin Willi {
597545b6c2SEric Biggers if (!err) {
607545b6c2SEric Biggers struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
617545b6c2SEric Biggers
627545b6c2SEric Biggers rctx->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
6371ebc4d1SMartin Willi err = cont(req);
647545b6c2SEric Biggers }
6571ebc4d1SMartin Willi
6671ebc4d1SMartin Willi if (err != -EINPROGRESS && err != -EBUSY)
6771ebc4d1SMartin Willi aead_request_complete(req, err);
6871ebc4d1SMartin Willi }
6971ebc4d1SMartin Willi
chacha_iv(u8 * iv,struct aead_request * req,u32 icb)7071ebc4d1SMartin Willi static void chacha_iv(u8 *iv, struct aead_request *req, u32 icb)
7171ebc4d1SMartin Willi {
7271ebc4d1SMartin Willi struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
7371ebc4d1SMartin Willi __le32 leicb = cpu_to_le32(icb);
7471ebc4d1SMartin Willi
7571ebc4d1SMartin Willi memcpy(iv, &leicb, sizeof(leicb));
7671ebc4d1SMartin Willi memcpy(iv + sizeof(leicb), ctx->salt, ctx->saltlen);
7771ebc4d1SMartin Willi memcpy(iv + sizeof(leicb) + ctx->saltlen, req->iv,
781ca1b917SEric Biggers CHACHA_IV_SIZE - sizeof(leicb) - ctx->saltlen);
7971ebc4d1SMartin Willi }
8071ebc4d1SMartin Willi
poly_verify_tag(struct aead_request * req)8171ebc4d1SMartin Willi static int poly_verify_tag(struct aead_request *req)
8271ebc4d1SMartin Willi {
8371ebc4d1SMartin Willi struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
8471ebc4d1SMartin Willi u8 tag[sizeof(rctx->tag)];
8571ebc4d1SMartin Willi
8674790922SHerbert Xu scatterwalk_map_and_copy(tag, req->src,
8774790922SHerbert Xu req->assoclen + rctx->cryptlen,
8874790922SHerbert Xu sizeof(tag), 0);
8971ebc4d1SMartin Willi if (crypto_memneq(tag, rctx->tag, sizeof(tag)))
9071ebc4d1SMartin Willi return -EBADMSG;
9171ebc4d1SMartin Willi return 0;
9271ebc4d1SMartin Willi }
9371ebc4d1SMartin Willi
chacha_decrypt_done(void * data,int err)94255e48ebSHerbert Xu static void chacha_decrypt_done(void *data, int err)
9571ebc4d1SMartin Willi {
96255e48ebSHerbert Xu async_done_continue(data, err, poly_verify_tag);
9771ebc4d1SMartin Willi }
9871ebc4d1SMartin Willi
chacha_decrypt(struct aead_request * req)9971ebc4d1SMartin Willi static int chacha_decrypt(struct aead_request *req)
10071ebc4d1SMartin Willi {
10171ebc4d1SMartin Willi struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
10271ebc4d1SMartin Willi struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
10371ebc4d1SMartin Willi struct chacha_req *creq = &rctx->u.chacha;
10474790922SHerbert Xu struct scatterlist *src, *dst;
10571ebc4d1SMartin Willi int err;
10671ebc4d1SMartin Willi
107161151d7SJason A. Donenfeld if (rctx->cryptlen == 0)
108161151d7SJason A. Donenfeld goto skip;
109161151d7SJason A. Donenfeld
11071ebc4d1SMartin Willi chacha_iv(creq->iv, req, 1);
11171ebc4d1SMartin Willi
11274790922SHerbert Xu src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen);
11374790922SHerbert Xu dst = src;
11476cadf22SEric Biggers if (req->src != req->dst)
11574790922SHerbert Xu dst = scatterwalk_ffwd(rctx->dst, req->dst, req->assoclen);
11674790922SHerbert Xu
1177545b6c2SEric Biggers skcipher_request_set_callback(&creq->req, rctx->flags,
11871ebc4d1SMartin Willi chacha_decrypt_done, req);
1191e1f0061SHerbert Xu skcipher_request_set_tfm(&creq->req, ctx->chacha);
1201e1f0061SHerbert Xu skcipher_request_set_crypt(&creq->req, src, dst,
12171ebc4d1SMartin Willi rctx->cryptlen, creq->iv);
1221e1f0061SHerbert Xu err = crypto_skcipher_decrypt(&creq->req);
12371ebc4d1SMartin Willi if (err)
12471ebc4d1SMartin Willi return err;
12571ebc4d1SMartin Willi
126161151d7SJason A. Donenfeld skip:
12771ebc4d1SMartin Willi return poly_verify_tag(req);
12871ebc4d1SMartin Willi }
12971ebc4d1SMartin Willi
poly_hash(struct aead_request * req)130a298765eSHerbert Xu static int poly_hash(struct aead_request *req)
13171ebc4d1SMartin Willi {
13271ebc4d1SMartin Willi struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
133a298765eSHerbert Xu const void *zp = page_address(ZERO_PAGE(0));
134a298765eSHerbert Xu struct scatterlist *sg = req->src;
135a298765eSHerbert Xu struct poly1305_desc_ctx desc;
136a298765eSHerbert Xu struct scatter_walk walk;
137a298765eSHerbert Xu struct {
138a298765eSHerbert Xu union {
139a298765eSHerbert Xu struct {
140a298765eSHerbert Xu __le64 assoclen;
141a298765eSHerbert Xu __le64 cryptlen;
142a298765eSHerbert Xu };
143a298765eSHerbert Xu u8 u8[16];
144a298765eSHerbert Xu };
145a298765eSHerbert Xu } tail;
146a298765eSHerbert Xu unsigned int padlen;
147a298765eSHerbert Xu unsigned int total;
148a298765eSHerbert Xu
149a298765eSHerbert Xu if (sg != req->dst)
150a298765eSHerbert Xu memcpy_sglist(req->dst, sg, req->assoclen);
15171ebc4d1SMartin Willi
15271ebc4d1SMartin Willi if (rctx->cryptlen == req->cryptlen) /* encrypting */
153a298765eSHerbert Xu sg = req->dst;
15471ebc4d1SMartin Willi
155a298765eSHerbert Xu poly1305_init(&desc, rctx->key);
156a298765eSHerbert Xu scatterwalk_start(&walk, sg);
157a298765eSHerbert Xu
158a298765eSHerbert Xu total = rctx->assoclen;
159a298765eSHerbert Xu while (total) {
160a298765eSHerbert Xu unsigned int n = scatterwalk_next(&walk, total);
161a298765eSHerbert Xu
162a298765eSHerbert Xu poly1305_update(&desc, walk.addr, n);
163a298765eSHerbert Xu scatterwalk_done_src(&walk, n);
164a298765eSHerbert Xu total -= n;
16571ebc4d1SMartin Willi }
16671ebc4d1SMartin Willi
16776cadf22SEric Biggers padlen = -rctx->assoclen % POLY1305_BLOCK_SIZE;
168a298765eSHerbert Xu poly1305_update(&desc, zp, padlen);
16971ebc4d1SMartin Willi
170a298765eSHerbert Xu scatterwalk_skip(&walk, req->assoclen - rctx->assoclen);
17171ebc4d1SMartin Willi
172a298765eSHerbert Xu total = rctx->cryptlen;
173a298765eSHerbert Xu while (total) {
174a298765eSHerbert Xu unsigned int n = scatterwalk_next(&walk, total);
17571ebc4d1SMartin Willi
176a298765eSHerbert Xu poly1305_update(&desc, walk.addr, n);
177a298765eSHerbert Xu scatterwalk_done_src(&walk, n);
178a298765eSHerbert Xu total -= n;
17971ebc4d1SMartin Willi }
18071ebc4d1SMartin Willi
181a298765eSHerbert Xu padlen = -rctx->cryptlen % POLY1305_BLOCK_SIZE;
182a298765eSHerbert Xu poly1305_update(&desc, zp, padlen);
18371ebc4d1SMartin Willi
184a298765eSHerbert Xu tail.assoclen = cpu_to_le64(rctx->assoclen);
185a298765eSHerbert Xu tail.cryptlen = cpu_to_le64(rctx->cryptlen);
186a298765eSHerbert Xu poly1305_update(&desc, tail.u8, sizeof(tail));
187a298765eSHerbert Xu memzero_explicit(&tail, sizeof(tail));
188a298765eSHerbert Xu poly1305_final(&desc, rctx->tag);
18971ebc4d1SMartin Willi
190a298765eSHerbert Xu if (rctx->cryptlen != req->cryptlen)
191a298765eSHerbert Xu return chacha_decrypt(req);
19271ebc4d1SMartin Willi
193a298765eSHerbert Xu memcpy_to_scatterwalk(&walk, rctx->tag, sizeof(rctx->tag));
194a298765eSHerbert Xu return 0;
19571ebc4d1SMartin Willi }
19671ebc4d1SMartin Willi
poly_genkey_done(void * data,int err)197255e48ebSHerbert Xu static void poly_genkey_done(void *data, int err)
19871ebc4d1SMartin Willi {
199a298765eSHerbert Xu async_done_continue(data, err, poly_hash);
20071ebc4d1SMartin Willi }
20171ebc4d1SMartin Willi
poly_genkey(struct aead_request * req)20271ebc4d1SMartin Willi static int poly_genkey(struct aead_request *req)
20371ebc4d1SMartin Willi {
20474790922SHerbert Xu struct crypto_aead *tfm = crypto_aead_reqtfm(req);
20574790922SHerbert Xu struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm);
20671ebc4d1SMartin Willi struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
20771ebc4d1SMartin Willi struct chacha_req *creq = &rctx->u.chacha;
20871ebc4d1SMartin Willi int err;
20971ebc4d1SMartin Willi
21074790922SHerbert Xu rctx->assoclen = req->assoclen;
21174790922SHerbert Xu
21274790922SHerbert Xu if (crypto_aead_ivsize(tfm) == 8) {
21374790922SHerbert Xu if (rctx->assoclen < 8)
21474790922SHerbert Xu return -EINVAL;
21574790922SHerbert Xu rctx->assoclen -= 8;
21674790922SHerbert Xu }
21774790922SHerbert Xu
218c2b7b20aSMartin Willi memset(rctx->key, 0, sizeof(rctx->key));
21976cadf22SEric Biggers sg_init_one(creq->src, rctx->key, sizeof(rctx->key));
22071ebc4d1SMartin Willi
22171ebc4d1SMartin Willi chacha_iv(creq->iv, req, 0);
22271ebc4d1SMartin Willi
2237545b6c2SEric Biggers skcipher_request_set_callback(&creq->req, rctx->flags,
22471ebc4d1SMartin Willi poly_genkey_done, req);
2251e1f0061SHerbert Xu skcipher_request_set_tfm(&creq->req, ctx->chacha);
2261e1f0061SHerbert Xu skcipher_request_set_crypt(&creq->req, creq->src, creq->src,
22771ebc4d1SMartin Willi POLY1305_KEY_SIZE, creq->iv);
22871ebc4d1SMartin Willi
2291e1f0061SHerbert Xu err = crypto_skcipher_decrypt(&creq->req);
23071ebc4d1SMartin Willi if (err)
23171ebc4d1SMartin Willi return err;
23271ebc4d1SMartin Willi
233a298765eSHerbert Xu return poly_hash(req);
23471ebc4d1SMartin Willi }
23571ebc4d1SMartin Willi
chacha_encrypt_done(void * data,int err)236255e48ebSHerbert Xu static void chacha_encrypt_done(void *data, int err)
23771ebc4d1SMartin Willi {
238255e48ebSHerbert Xu async_done_continue(data, err, poly_genkey);
23971ebc4d1SMartin Willi }
24071ebc4d1SMartin Willi
chacha_encrypt(struct aead_request * req)24171ebc4d1SMartin Willi static int chacha_encrypt(struct aead_request *req)
24271ebc4d1SMartin Willi {
24371ebc4d1SMartin Willi struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
24471ebc4d1SMartin Willi struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
24571ebc4d1SMartin Willi struct chacha_req *creq = &rctx->u.chacha;
24674790922SHerbert Xu struct scatterlist *src, *dst;
24771ebc4d1SMartin Willi int err;
24871ebc4d1SMartin Willi
249161151d7SJason A. Donenfeld if (req->cryptlen == 0)
250161151d7SJason A. Donenfeld goto skip;
251161151d7SJason A. Donenfeld
25271ebc4d1SMartin Willi chacha_iv(creq->iv, req, 1);
25371ebc4d1SMartin Willi
25474790922SHerbert Xu src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen);
25574790922SHerbert Xu dst = src;
25676cadf22SEric Biggers if (req->src != req->dst)
25774790922SHerbert Xu dst = scatterwalk_ffwd(rctx->dst, req->dst, req->assoclen);
25874790922SHerbert Xu
2597545b6c2SEric Biggers skcipher_request_set_callback(&creq->req, rctx->flags,
26071ebc4d1SMartin Willi chacha_encrypt_done, req);
2611e1f0061SHerbert Xu skcipher_request_set_tfm(&creq->req, ctx->chacha);
2621e1f0061SHerbert Xu skcipher_request_set_crypt(&creq->req, src, dst,
26371ebc4d1SMartin Willi req->cryptlen, creq->iv);
2641e1f0061SHerbert Xu err = crypto_skcipher_encrypt(&creq->req);
26571ebc4d1SMartin Willi if (err)
26671ebc4d1SMartin Willi return err;
26771ebc4d1SMartin Willi
268161151d7SJason A. Donenfeld skip:
26971ebc4d1SMartin Willi return poly_genkey(req);
27071ebc4d1SMartin Willi }
27171ebc4d1SMartin Willi
chachapoly_encrypt(struct aead_request * req)27271ebc4d1SMartin Willi static int chachapoly_encrypt(struct aead_request *req)
27371ebc4d1SMartin Willi {
27471ebc4d1SMartin Willi struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
27571ebc4d1SMartin Willi
27671ebc4d1SMartin Willi rctx->cryptlen = req->cryptlen;
2777545b6c2SEric Biggers rctx->flags = aead_request_flags(req);
27871ebc4d1SMartin Willi
27971ebc4d1SMartin Willi /* encrypt call chain:
28071ebc4d1SMartin Willi * - chacha_encrypt/done()
281c2b7b20aSMartin Willi * - poly_genkey/done()
282a298765eSHerbert Xu * - poly_hash()
28371ebc4d1SMartin Willi */
28471ebc4d1SMartin Willi return chacha_encrypt(req);
28571ebc4d1SMartin Willi }
28671ebc4d1SMartin Willi
chachapoly_decrypt(struct aead_request * req)28771ebc4d1SMartin Willi static int chachapoly_decrypt(struct aead_request *req)
28871ebc4d1SMartin Willi {
28971ebc4d1SMartin Willi struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
29071ebc4d1SMartin Willi
29171ebc4d1SMartin Willi rctx->cryptlen = req->cryptlen - POLY1305_DIGEST_SIZE;
2927545b6c2SEric Biggers rctx->flags = aead_request_flags(req);
29371ebc4d1SMartin Willi
29471ebc4d1SMartin Willi /* decrypt call chain:
295c2b7b20aSMartin Willi * - poly_genkey/done()
296a298765eSHerbert Xu * - poly_hash()
29771ebc4d1SMartin Willi * - chacha_decrypt/done()
29871ebc4d1SMartin Willi * - poly_verify_tag()
29971ebc4d1SMartin Willi */
30071ebc4d1SMartin Willi return poly_genkey(req);
30171ebc4d1SMartin Willi }
30271ebc4d1SMartin Willi
chachapoly_setkey(struct crypto_aead * aead,const u8 * key,unsigned int keylen)30371ebc4d1SMartin Willi static int chachapoly_setkey(struct crypto_aead *aead, const u8 *key,
30471ebc4d1SMartin Willi unsigned int keylen)
30571ebc4d1SMartin Willi {
30671ebc4d1SMartin Willi struct chachapoly_ctx *ctx = crypto_aead_ctx(aead);
30771ebc4d1SMartin Willi
3081ca1b917SEric Biggers if (keylen != ctx->saltlen + CHACHA_KEY_SIZE)
30971ebc4d1SMartin Willi return -EINVAL;
31071ebc4d1SMartin Willi
31171ebc4d1SMartin Willi keylen -= ctx->saltlen;
31271ebc4d1SMartin Willi memcpy(ctx->salt, key + keylen, ctx->saltlen);
31371ebc4d1SMartin Willi
3141e1f0061SHerbert Xu crypto_skcipher_clear_flags(ctx->chacha, CRYPTO_TFM_REQ_MASK);
3151e1f0061SHerbert Xu crypto_skcipher_set_flags(ctx->chacha, crypto_aead_get_flags(aead) &
31671ebc4d1SMartin Willi CRYPTO_TFM_REQ_MASK);
317af5034e8SEric Biggers return crypto_skcipher_setkey(ctx->chacha, key, keylen);
31871ebc4d1SMartin Willi }
31971ebc4d1SMartin Willi
chachapoly_setauthsize(struct crypto_aead * tfm,unsigned int authsize)32071ebc4d1SMartin Willi static int chachapoly_setauthsize(struct crypto_aead *tfm,
32171ebc4d1SMartin Willi unsigned int authsize)
32271ebc4d1SMartin Willi {
32371ebc4d1SMartin Willi if (authsize != POLY1305_DIGEST_SIZE)
32471ebc4d1SMartin Willi return -EINVAL;
32571ebc4d1SMartin Willi
32671ebc4d1SMartin Willi return 0;
32771ebc4d1SMartin Willi }
32871ebc4d1SMartin Willi
chachapoly_init(struct crypto_aead * tfm)32974790922SHerbert Xu static int chachapoly_init(struct crypto_aead *tfm)
33071ebc4d1SMartin Willi {
33174790922SHerbert Xu struct aead_instance *inst = aead_alg_instance(tfm);
33274790922SHerbert Xu struct chachapoly_instance_ctx *ictx = aead_instance_ctx(inst);
33374790922SHerbert Xu struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm);
3341e1f0061SHerbert Xu struct crypto_skcipher *chacha;
33571ebc4d1SMartin Willi unsigned long align;
33671ebc4d1SMartin Willi
33760425a8bSEric Biggers chacha = crypto_spawn_skcipher(&ictx->chacha);
338a298765eSHerbert Xu if (IS_ERR(chacha))
33971ebc4d1SMartin Willi return PTR_ERR(chacha);
34071ebc4d1SMartin Willi
34171ebc4d1SMartin Willi ctx->chacha = chacha;
34271ebc4d1SMartin Willi ctx->saltlen = ictx->saltlen;
34371ebc4d1SMartin Willi
34474790922SHerbert Xu align = crypto_aead_alignmask(tfm);
34571ebc4d1SMartin Willi align &= ~(crypto_tfm_ctx_alignment() - 1);
34674790922SHerbert Xu crypto_aead_set_reqsize(
34774790922SHerbert Xu tfm,
34871ebc4d1SMartin Willi align + offsetof(struct chachapoly_req_ctx, u) +
349a298765eSHerbert Xu offsetof(struct chacha_req, req) +
3501e1f0061SHerbert Xu sizeof(struct skcipher_request) +
351a298765eSHerbert Xu crypto_skcipher_reqsize(chacha));
35271ebc4d1SMartin Willi
35371ebc4d1SMartin Willi return 0;
35471ebc4d1SMartin Willi }
35571ebc4d1SMartin Willi
chachapoly_exit(struct crypto_aead * tfm)35674790922SHerbert Xu static void chachapoly_exit(struct crypto_aead *tfm)
35771ebc4d1SMartin Willi {
35874790922SHerbert Xu struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm);
35971ebc4d1SMartin Willi
3601e1f0061SHerbert Xu crypto_free_skcipher(ctx->chacha);
36171ebc4d1SMartin Willi }
36271ebc4d1SMartin Willi
chachapoly_free(struct aead_instance * inst)36374790922SHerbert Xu static void chachapoly_free(struct aead_instance *inst)
36474790922SHerbert Xu {
36574790922SHerbert Xu struct chachapoly_instance_ctx *ctx = aead_instance_ctx(inst);
36674790922SHerbert Xu
36774790922SHerbert Xu crypto_drop_skcipher(&ctx->chacha);
36874790922SHerbert Xu kfree(inst);
36974790922SHerbert Xu }
37074790922SHerbert Xu
chachapoly_create(struct crypto_template * tmpl,struct rtattr ** tb,const char * name,unsigned int ivsize)37174790922SHerbert Xu static int chachapoly_create(struct crypto_template *tmpl, struct rtattr **tb,
37274790922SHerbert Xu const char *name, unsigned int ivsize)
37371ebc4d1SMartin Willi {
374b9f76dddSEric Biggers u32 mask;
37574790922SHerbert Xu struct aead_instance *inst;
37671ebc4d1SMartin Willi struct chachapoly_instance_ctx *ctx;
377c9e4b76fSHerbert Xu struct skcipher_alg_common *chacha;
37871ebc4d1SMartin Willi int err;
37971ebc4d1SMartin Willi
38071ebc4d1SMartin Willi if (ivsize > CHACHAPOLY_IV_SIZE)
38174790922SHerbert Xu return -EINVAL;
38271ebc4d1SMartin Willi
3837bcb2c99SEric Biggers err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask);
3847bcb2c99SEric Biggers if (err)
3857bcb2c99SEric Biggers return err;
386b9f76dddSEric Biggers
38771ebc4d1SMartin Willi inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
38871ebc4d1SMartin Willi if (!inst)
389c282586fSEric Biggers return -ENOMEM;
39074790922SHerbert Xu ctx = aead_instance_ctx(inst);
39171ebc4d1SMartin Willi ctx->saltlen = CHACHAPOLY_IV_SIZE - ivsize;
39271ebc4d1SMartin Willi
393b9f76dddSEric Biggers err = crypto_grab_skcipher(&ctx->chacha, aead_crypto_instance(inst),
394c282586fSEric Biggers crypto_attr_alg_name(tb[1]), 0, mask);
39571ebc4d1SMartin Willi if (err)
396c282586fSEric Biggers goto err_free_inst;
397c9e4b76fSHerbert Xu chacha = crypto_spawn_skcipher_alg_common(&ctx->chacha);
39871ebc4d1SMartin Willi
39971ebc4d1SMartin Willi err = -EINVAL;
400a298765eSHerbert Xu if (strcmp(crypto_attr_alg_name(tb[2]), "poly1305") &&
401a298765eSHerbert Xu strcmp(crypto_attr_alg_name(tb[2]), "poly1305-generic"))
402c282586fSEric Biggers goto err_free_inst;
40371ebc4d1SMartin Willi /* Need 16-byte IV size, including Initial Block Counter value */
404c9e4b76fSHerbert Xu if (chacha->ivsize != CHACHA_IV_SIZE)
405c282586fSEric Biggers goto err_free_inst;
40671ebc4d1SMartin Willi /* Not a stream cipher? */
4071e1f0061SHerbert Xu if (chacha->base.cra_blocksize != 1)
408c282586fSEric Biggers goto err_free_inst;
40971ebc4d1SMartin Willi
41071ebc4d1SMartin Willi err = -ENAMETOOLONG;
41174790922SHerbert Xu if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
412a298765eSHerbert Xu "%s(%s,poly1305)", name,
413a298765eSHerbert Xu chacha->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
414c282586fSEric Biggers goto err_free_inst;
41574790922SHerbert Xu if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
416a298765eSHerbert Xu "%s(%s,poly1305-generic)", name,
417a298765eSHerbert Xu chacha->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
418c282586fSEric Biggers goto err_free_inst;
41971ebc4d1SMartin Willi
420a298765eSHerbert Xu inst->alg.base.cra_priority = chacha->base.cra_priority;
42174790922SHerbert Xu inst->alg.base.cra_blocksize = 1;
422381a796aSEric Biggers inst->alg.base.cra_alignmask = chacha->base.cra_alignmask;
42374790922SHerbert Xu inst->alg.base.cra_ctxsize = sizeof(struct chachapoly_ctx) +
42474790922SHerbert Xu ctx->saltlen;
42574790922SHerbert Xu inst->alg.ivsize = ivsize;
426c9e4b76fSHerbert Xu inst->alg.chunksize = chacha->chunksize;
42774790922SHerbert Xu inst->alg.maxauthsize = POLY1305_DIGEST_SIZE;
42874790922SHerbert Xu inst->alg.init = chachapoly_init;
42974790922SHerbert Xu inst->alg.exit = chachapoly_exit;
43074790922SHerbert Xu inst->alg.encrypt = chachapoly_encrypt;
43174790922SHerbert Xu inst->alg.decrypt = chachapoly_decrypt;
43274790922SHerbert Xu inst->alg.setkey = chachapoly_setkey;
43374790922SHerbert Xu inst->alg.setauthsize = chachapoly_setauthsize;
43471ebc4d1SMartin Willi
43574790922SHerbert Xu inst->free = chachapoly_free;
43674790922SHerbert Xu
43774790922SHerbert Xu err = aead_register_instance(tmpl, inst);
438c282586fSEric Biggers if (err) {
43971ebc4d1SMartin Willi err_free_inst:
440c282586fSEric Biggers chachapoly_free(inst);
441c282586fSEric Biggers }
442c282586fSEric Biggers return err;
44371ebc4d1SMartin Willi }
44471ebc4d1SMartin Willi
rfc7539_create(struct crypto_template * tmpl,struct rtattr ** tb)44574790922SHerbert Xu static int rfc7539_create(struct crypto_template *tmpl, struct rtattr **tb)
44671ebc4d1SMartin Willi {
44774790922SHerbert Xu return chachapoly_create(tmpl, tb, "rfc7539", 12);
44871ebc4d1SMartin Willi }
44971ebc4d1SMartin Willi
rfc7539esp_create(struct crypto_template * tmpl,struct rtattr ** tb)45074790922SHerbert Xu static int rfc7539esp_create(struct crypto_template *tmpl, struct rtattr **tb)
4514db4ad26SMartin Willi {
45274790922SHerbert Xu return chachapoly_create(tmpl, tb, "rfc7539esp", 8);
45371ebc4d1SMartin Willi }
45471ebc4d1SMartin Willi
4551a5e02b6SXiongfeng Wang static struct crypto_template rfc7539_tmpls[] = {
4561a5e02b6SXiongfeng Wang {
45771ebc4d1SMartin Willi .name = "rfc7539",
45874790922SHerbert Xu .create = rfc7539_create,
45971ebc4d1SMartin Willi .module = THIS_MODULE,
4601a5e02b6SXiongfeng Wang }, {
4614db4ad26SMartin Willi .name = "rfc7539esp",
46274790922SHerbert Xu .create = rfc7539esp_create,
4634db4ad26SMartin Willi .module = THIS_MODULE,
4641a5e02b6SXiongfeng Wang },
4654db4ad26SMartin Willi };
4664db4ad26SMartin Willi
chacha20poly1305_module_init(void)46771ebc4d1SMartin Willi static int __init chacha20poly1305_module_init(void)
46871ebc4d1SMartin Willi {
4691a5e02b6SXiongfeng Wang return crypto_register_templates(rfc7539_tmpls,
4701a5e02b6SXiongfeng Wang ARRAY_SIZE(rfc7539_tmpls));
47171ebc4d1SMartin Willi }
47271ebc4d1SMartin Willi
chacha20poly1305_module_exit(void)47371ebc4d1SMartin Willi static void __exit chacha20poly1305_module_exit(void)
47471ebc4d1SMartin Willi {
4751a5e02b6SXiongfeng Wang crypto_unregister_templates(rfc7539_tmpls,
4761a5e02b6SXiongfeng Wang ARRAY_SIZE(rfc7539_tmpls));
47771ebc4d1SMartin Willi }
47871ebc4d1SMartin Willi
479*ef93f156SHerbert Xu module_init(chacha20poly1305_module_init);
48071ebc4d1SMartin Willi module_exit(chacha20poly1305_module_exit);
48171ebc4d1SMartin Willi
48271ebc4d1SMartin Willi MODULE_LICENSE("GPL");
48371ebc4d1SMartin Willi MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
48471ebc4d1SMartin Willi MODULE_DESCRIPTION("ChaCha20-Poly1305 AEAD");
48571ebc4d1SMartin Willi MODULE_ALIAS_CRYPTO("rfc7539");
4864db4ad26SMartin Willi MODULE_ALIAS_CRYPTO("rfc7539esp");
487