162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ChaCha20-Poly1305 AEAD, RFC7539 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015 Martin Willi 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <crypto/internal/aead.h> 962306a36Sopenharmony_ci#include <crypto/internal/hash.h> 1062306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 1162306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 1262306a36Sopenharmony_ci#include <crypto/chacha.h> 1362306a36Sopenharmony_ci#include <crypto/poly1305.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct chachapoly_instance_ctx { 2062306a36Sopenharmony_ci struct crypto_skcipher_spawn chacha; 2162306a36Sopenharmony_ci struct crypto_ahash_spawn poly; 2262306a36Sopenharmony_ci unsigned int saltlen; 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct chachapoly_ctx { 2662306a36Sopenharmony_ci struct crypto_skcipher *chacha; 2762306a36Sopenharmony_ci struct crypto_ahash *poly; 2862306a36Sopenharmony_ci /* key bytes we use for the ChaCha20 IV */ 2962306a36Sopenharmony_ci unsigned int saltlen; 3062306a36Sopenharmony_ci u8 salt[]; 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistruct poly_req { 3462306a36Sopenharmony_ci /* zero byte padding for AD/ciphertext, as needed */ 3562306a36Sopenharmony_ci u8 pad[POLY1305_BLOCK_SIZE]; 3662306a36Sopenharmony_ci /* tail data with AD/ciphertext lengths */ 3762306a36Sopenharmony_ci struct { 3862306a36Sopenharmony_ci __le64 assoclen; 3962306a36Sopenharmony_ci __le64 cryptlen; 4062306a36Sopenharmony_ci } tail; 4162306a36Sopenharmony_ci struct scatterlist src[1]; 4262306a36Sopenharmony_ci struct ahash_request req; /* must be last member */ 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistruct chacha_req { 4662306a36Sopenharmony_ci u8 iv[CHACHA_IV_SIZE]; 4762306a36Sopenharmony_ci struct scatterlist src[1]; 4862306a36Sopenharmony_ci struct skcipher_request req; /* must be last member */ 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct chachapoly_req_ctx { 5262306a36Sopenharmony_ci struct scatterlist src[2]; 5362306a36Sopenharmony_ci struct scatterlist dst[2]; 5462306a36Sopenharmony_ci /* the key we generate for Poly1305 using Chacha20 */ 5562306a36Sopenharmony_ci u8 key[POLY1305_KEY_SIZE]; 5662306a36Sopenharmony_ci /* calculated Poly1305 tag */ 5762306a36Sopenharmony_ci u8 tag[POLY1305_DIGEST_SIZE]; 5862306a36Sopenharmony_ci /* length of data to en/decrypt, without ICV */ 5962306a36Sopenharmony_ci unsigned int cryptlen; 6062306a36Sopenharmony_ci /* Actual AD, excluding IV */ 6162306a36Sopenharmony_ci unsigned int assoclen; 6262306a36Sopenharmony_ci /* request flags, with MAY_SLEEP cleared if needed */ 6362306a36Sopenharmony_ci u32 flags; 6462306a36Sopenharmony_ci union { 6562306a36Sopenharmony_ci struct poly_req poly; 6662306a36Sopenharmony_ci struct chacha_req chacha; 6762306a36Sopenharmony_ci } u; 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic inline void async_done_continue(struct aead_request *req, int err, 7162306a36Sopenharmony_ci int (*cont)(struct aead_request *)) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci if (!err) { 7462306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci rctx->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 7762306a36Sopenharmony_ci err = cont(req); 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (err != -EINPROGRESS && err != -EBUSY) 8162306a36Sopenharmony_ci aead_request_complete(req, err); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void chacha_iv(u8 *iv, struct aead_request *req, u32 icb) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); 8762306a36Sopenharmony_ci __le32 leicb = cpu_to_le32(icb); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci memcpy(iv, &leicb, sizeof(leicb)); 9062306a36Sopenharmony_ci memcpy(iv + sizeof(leicb), ctx->salt, ctx->saltlen); 9162306a36Sopenharmony_ci memcpy(iv + sizeof(leicb) + ctx->saltlen, req->iv, 9262306a36Sopenharmony_ci CHACHA_IV_SIZE - sizeof(leicb) - ctx->saltlen); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int poly_verify_tag(struct aead_request *req) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 9862306a36Sopenharmony_ci u8 tag[sizeof(rctx->tag)]; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci scatterwalk_map_and_copy(tag, req->src, 10162306a36Sopenharmony_ci req->assoclen + rctx->cryptlen, 10262306a36Sopenharmony_ci sizeof(tag), 0); 10362306a36Sopenharmony_ci if (crypto_memneq(tag, rctx->tag, sizeof(tag))) 10462306a36Sopenharmony_ci return -EBADMSG; 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int poly_copy_tag(struct aead_request *req) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci scatterwalk_map_and_copy(rctx->tag, req->dst, 11362306a36Sopenharmony_ci req->assoclen + rctx->cryptlen, 11462306a36Sopenharmony_ci sizeof(rctx->tag), 1); 11562306a36Sopenharmony_ci return 0; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic void chacha_decrypt_done(void *data, int err) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci async_done_continue(data, err, poly_verify_tag); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int chacha_decrypt(struct aead_request *req) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); 12662306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 12762306a36Sopenharmony_ci struct chacha_req *creq = &rctx->u.chacha; 12862306a36Sopenharmony_ci struct scatterlist *src, *dst; 12962306a36Sopenharmony_ci int err; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (rctx->cryptlen == 0) 13262306a36Sopenharmony_ci goto skip; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci chacha_iv(creq->iv, req, 1); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen); 13762306a36Sopenharmony_ci dst = src; 13862306a36Sopenharmony_ci if (req->src != req->dst) 13962306a36Sopenharmony_ci dst = scatterwalk_ffwd(rctx->dst, req->dst, req->assoclen); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci skcipher_request_set_callback(&creq->req, rctx->flags, 14262306a36Sopenharmony_ci chacha_decrypt_done, req); 14362306a36Sopenharmony_ci skcipher_request_set_tfm(&creq->req, ctx->chacha); 14462306a36Sopenharmony_ci skcipher_request_set_crypt(&creq->req, src, dst, 14562306a36Sopenharmony_ci rctx->cryptlen, creq->iv); 14662306a36Sopenharmony_ci err = crypto_skcipher_decrypt(&creq->req); 14762306a36Sopenharmony_ci if (err) 14862306a36Sopenharmony_ci return err; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ciskip: 15162306a36Sopenharmony_ci return poly_verify_tag(req); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic int poly_tail_continue(struct aead_request *req) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (rctx->cryptlen == req->cryptlen) /* encrypting */ 15962306a36Sopenharmony_ci return poly_copy_tag(req); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return chacha_decrypt(req); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic void poly_tail_done(void *data, int err) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci async_done_continue(data, err, poly_tail_continue); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int poly_tail(struct aead_request *req) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 17262306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm); 17362306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 17462306a36Sopenharmony_ci struct poly_req *preq = &rctx->u.poly; 17562306a36Sopenharmony_ci int err; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci preq->tail.assoclen = cpu_to_le64(rctx->assoclen); 17862306a36Sopenharmony_ci preq->tail.cryptlen = cpu_to_le64(rctx->cryptlen); 17962306a36Sopenharmony_ci sg_init_one(preq->src, &preq->tail, sizeof(preq->tail)); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci ahash_request_set_callback(&preq->req, rctx->flags, 18262306a36Sopenharmony_ci poly_tail_done, req); 18362306a36Sopenharmony_ci ahash_request_set_tfm(&preq->req, ctx->poly); 18462306a36Sopenharmony_ci ahash_request_set_crypt(&preq->req, preq->src, 18562306a36Sopenharmony_ci rctx->tag, sizeof(preq->tail)); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci err = crypto_ahash_finup(&preq->req); 18862306a36Sopenharmony_ci if (err) 18962306a36Sopenharmony_ci return err; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return poly_tail_continue(req); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic void poly_cipherpad_done(void *data, int err) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci async_done_continue(data, err, poly_tail); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic int poly_cipherpad(struct aead_request *req) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); 20262306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 20362306a36Sopenharmony_ci struct poly_req *preq = &rctx->u.poly; 20462306a36Sopenharmony_ci unsigned int padlen; 20562306a36Sopenharmony_ci int err; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci padlen = -rctx->cryptlen % POLY1305_BLOCK_SIZE; 20862306a36Sopenharmony_ci memset(preq->pad, 0, sizeof(preq->pad)); 20962306a36Sopenharmony_ci sg_init_one(preq->src, preq->pad, padlen); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci ahash_request_set_callback(&preq->req, rctx->flags, 21262306a36Sopenharmony_ci poly_cipherpad_done, req); 21362306a36Sopenharmony_ci ahash_request_set_tfm(&preq->req, ctx->poly); 21462306a36Sopenharmony_ci ahash_request_set_crypt(&preq->req, preq->src, NULL, padlen); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci err = crypto_ahash_update(&preq->req); 21762306a36Sopenharmony_ci if (err) 21862306a36Sopenharmony_ci return err; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return poly_tail(req); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void poly_cipher_done(void *data, int err) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci async_done_continue(data, err, poly_cipherpad); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic int poly_cipher(struct aead_request *req) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); 23162306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 23262306a36Sopenharmony_ci struct poly_req *preq = &rctx->u.poly; 23362306a36Sopenharmony_ci struct scatterlist *crypt = req->src; 23462306a36Sopenharmony_ci int err; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (rctx->cryptlen == req->cryptlen) /* encrypting */ 23762306a36Sopenharmony_ci crypt = req->dst; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci crypt = scatterwalk_ffwd(rctx->src, crypt, req->assoclen); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci ahash_request_set_callback(&preq->req, rctx->flags, 24262306a36Sopenharmony_ci poly_cipher_done, req); 24362306a36Sopenharmony_ci ahash_request_set_tfm(&preq->req, ctx->poly); 24462306a36Sopenharmony_ci ahash_request_set_crypt(&preq->req, crypt, NULL, rctx->cryptlen); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci err = crypto_ahash_update(&preq->req); 24762306a36Sopenharmony_ci if (err) 24862306a36Sopenharmony_ci return err; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return poly_cipherpad(req); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic void poly_adpad_done(void *data, int err) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci async_done_continue(data, err, poly_cipher); 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic int poly_adpad(struct aead_request *req) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); 26162306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 26262306a36Sopenharmony_ci struct poly_req *preq = &rctx->u.poly; 26362306a36Sopenharmony_ci unsigned int padlen; 26462306a36Sopenharmony_ci int err; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci padlen = -rctx->assoclen % POLY1305_BLOCK_SIZE; 26762306a36Sopenharmony_ci memset(preq->pad, 0, sizeof(preq->pad)); 26862306a36Sopenharmony_ci sg_init_one(preq->src, preq->pad, padlen); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci ahash_request_set_callback(&preq->req, rctx->flags, 27162306a36Sopenharmony_ci poly_adpad_done, req); 27262306a36Sopenharmony_ci ahash_request_set_tfm(&preq->req, ctx->poly); 27362306a36Sopenharmony_ci ahash_request_set_crypt(&preq->req, preq->src, NULL, padlen); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci err = crypto_ahash_update(&preq->req); 27662306a36Sopenharmony_ci if (err) 27762306a36Sopenharmony_ci return err; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return poly_cipher(req); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic void poly_ad_done(void *data, int err) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci async_done_continue(data, err, poly_adpad); 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic int poly_ad(struct aead_request *req) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); 29062306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 29162306a36Sopenharmony_ci struct poly_req *preq = &rctx->u.poly; 29262306a36Sopenharmony_ci int err; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci ahash_request_set_callback(&preq->req, rctx->flags, 29562306a36Sopenharmony_ci poly_ad_done, req); 29662306a36Sopenharmony_ci ahash_request_set_tfm(&preq->req, ctx->poly); 29762306a36Sopenharmony_ci ahash_request_set_crypt(&preq->req, req->src, NULL, rctx->assoclen); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci err = crypto_ahash_update(&preq->req); 30062306a36Sopenharmony_ci if (err) 30162306a36Sopenharmony_ci return err; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci return poly_adpad(req); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic void poly_setkey_done(void *data, int err) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci async_done_continue(data, err, poly_ad); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int poly_setkey(struct aead_request *req) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); 31462306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 31562306a36Sopenharmony_ci struct poly_req *preq = &rctx->u.poly; 31662306a36Sopenharmony_ci int err; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci sg_init_one(preq->src, rctx->key, sizeof(rctx->key)); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci ahash_request_set_callback(&preq->req, rctx->flags, 32162306a36Sopenharmony_ci poly_setkey_done, req); 32262306a36Sopenharmony_ci ahash_request_set_tfm(&preq->req, ctx->poly); 32362306a36Sopenharmony_ci ahash_request_set_crypt(&preq->req, preq->src, NULL, sizeof(rctx->key)); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci err = crypto_ahash_update(&preq->req); 32662306a36Sopenharmony_ci if (err) 32762306a36Sopenharmony_ci return err; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return poly_ad(req); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic void poly_init_done(void *data, int err) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci async_done_continue(data, err, poly_setkey); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic int poly_init(struct aead_request *req) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); 34062306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 34162306a36Sopenharmony_ci struct poly_req *preq = &rctx->u.poly; 34262306a36Sopenharmony_ci int err; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci ahash_request_set_callback(&preq->req, rctx->flags, 34562306a36Sopenharmony_ci poly_init_done, req); 34662306a36Sopenharmony_ci ahash_request_set_tfm(&preq->req, ctx->poly); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci err = crypto_ahash_init(&preq->req); 34962306a36Sopenharmony_ci if (err) 35062306a36Sopenharmony_ci return err; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return poly_setkey(req); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic void poly_genkey_done(void *data, int err) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci async_done_continue(data, err, poly_init); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic int poly_genkey(struct aead_request *req) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 36362306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm); 36462306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 36562306a36Sopenharmony_ci struct chacha_req *creq = &rctx->u.chacha; 36662306a36Sopenharmony_ci int err; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci rctx->assoclen = req->assoclen; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (crypto_aead_ivsize(tfm) == 8) { 37162306a36Sopenharmony_ci if (rctx->assoclen < 8) 37262306a36Sopenharmony_ci return -EINVAL; 37362306a36Sopenharmony_ci rctx->assoclen -= 8; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci memset(rctx->key, 0, sizeof(rctx->key)); 37762306a36Sopenharmony_ci sg_init_one(creq->src, rctx->key, sizeof(rctx->key)); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci chacha_iv(creq->iv, req, 0); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci skcipher_request_set_callback(&creq->req, rctx->flags, 38262306a36Sopenharmony_ci poly_genkey_done, req); 38362306a36Sopenharmony_ci skcipher_request_set_tfm(&creq->req, ctx->chacha); 38462306a36Sopenharmony_ci skcipher_request_set_crypt(&creq->req, creq->src, creq->src, 38562306a36Sopenharmony_ci POLY1305_KEY_SIZE, creq->iv); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci err = crypto_skcipher_decrypt(&creq->req); 38862306a36Sopenharmony_ci if (err) 38962306a36Sopenharmony_ci return err; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return poly_init(req); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic void chacha_encrypt_done(void *data, int err) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci async_done_continue(data, err, poly_genkey); 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic int chacha_encrypt(struct aead_request *req) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); 40262306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 40362306a36Sopenharmony_ci struct chacha_req *creq = &rctx->u.chacha; 40462306a36Sopenharmony_ci struct scatterlist *src, *dst; 40562306a36Sopenharmony_ci int err; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (req->cryptlen == 0) 40862306a36Sopenharmony_ci goto skip; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci chacha_iv(creq->iv, req, 1); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen); 41362306a36Sopenharmony_ci dst = src; 41462306a36Sopenharmony_ci if (req->src != req->dst) 41562306a36Sopenharmony_ci dst = scatterwalk_ffwd(rctx->dst, req->dst, req->assoclen); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci skcipher_request_set_callback(&creq->req, rctx->flags, 41862306a36Sopenharmony_ci chacha_encrypt_done, req); 41962306a36Sopenharmony_ci skcipher_request_set_tfm(&creq->req, ctx->chacha); 42062306a36Sopenharmony_ci skcipher_request_set_crypt(&creq->req, src, dst, 42162306a36Sopenharmony_ci req->cryptlen, creq->iv); 42262306a36Sopenharmony_ci err = crypto_skcipher_encrypt(&creq->req); 42362306a36Sopenharmony_ci if (err) 42462306a36Sopenharmony_ci return err; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ciskip: 42762306a36Sopenharmony_ci return poly_genkey(req); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic int chachapoly_encrypt(struct aead_request *req) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci rctx->cryptlen = req->cryptlen; 43562306a36Sopenharmony_ci rctx->flags = aead_request_flags(req); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* encrypt call chain: 43862306a36Sopenharmony_ci * - chacha_encrypt/done() 43962306a36Sopenharmony_ci * - poly_genkey/done() 44062306a36Sopenharmony_ci * - poly_init/done() 44162306a36Sopenharmony_ci * - poly_setkey/done() 44262306a36Sopenharmony_ci * - poly_ad/done() 44362306a36Sopenharmony_ci * - poly_adpad/done() 44462306a36Sopenharmony_ci * - poly_cipher/done() 44562306a36Sopenharmony_ci * - poly_cipherpad/done() 44662306a36Sopenharmony_ci * - poly_tail/done/continue() 44762306a36Sopenharmony_ci * - poly_copy_tag() 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci return chacha_encrypt(req); 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int chachapoly_decrypt(struct aead_request *req) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct chachapoly_req_ctx *rctx = aead_request_ctx(req); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci rctx->cryptlen = req->cryptlen - POLY1305_DIGEST_SIZE; 45762306a36Sopenharmony_ci rctx->flags = aead_request_flags(req); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* decrypt call chain: 46062306a36Sopenharmony_ci * - poly_genkey/done() 46162306a36Sopenharmony_ci * - poly_init/done() 46262306a36Sopenharmony_ci * - poly_setkey/done() 46362306a36Sopenharmony_ci * - poly_ad/done() 46462306a36Sopenharmony_ci * - poly_adpad/done() 46562306a36Sopenharmony_ci * - poly_cipher/done() 46662306a36Sopenharmony_ci * - poly_cipherpad/done() 46762306a36Sopenharmony_ci * - poly_tail/done/continue() 46862306a36Sopenharmony_ci * - chacha_decrypt/done() 46962306a36Sopenharmony_ci * - poly_verify_tag() 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_ci return poly_genkey(req); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic int chachapoly_setkey(struct crypto_aead *aead, const u8 *key, 47562306a36Sopenharmony_ci unsigned int keylen) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(aead); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (keylen != ctx->saltlen + CHACHA_KEY_SIZE) 48062306a36Sopenharmony_ci return -EINVAL; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci keylen -= ctx->saltlen; 48362306a36Sopenharmony_ci memcpy(ctx->salt, key + keylen, ctx->saltlen); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci crypto_skcipher_clear_flags(ctx->chacha, CRYPTO_TFM_REQ_MASK); 48662306a36Sopenharmony_ci crypto_skcipher_set_flags(ctx->chacha, crypto_aead_get_flags(aead) & 48762306a36Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 48862306a36Sopenharmony_ci return crypto_skcipher_setkey(ctx->chacha, key, keylen); 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic int chachapoly_setauthsize(struct crypto_aead *tfm, 49262306a36Sopenharmony_ci unsigned int authsize) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci if (authsize != POLY1305_DIGEST_SIZE) 49562306a36Sopenharmony_ci return -EINVAL; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return 0; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int chachapoly_init(struct crypto_aead *tfm) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct aead_instance *inst = aead_alg_instance(tfm); 50362306a36Sopenharmony_ci struct chachapoly_instance_ctx *ictx = aead_instance_ctx(inst); 50462306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm); 50562306a36Sopenharmony_ci struct crypto_skcipher *chacha; 50662306a36Sopenharmony_ci struct crypto_ahash *poly; 50762306a36Sopenharmony_ci unsigned long align; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci poly = crypto_spawn_ahash(&ictx->poly); 51062306a36Sopenharmony_ci if (IS_ERR(poly)) 51162306a36Sopenharmony_ci return PTR_ERR(poly); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci chacha = crypto_spawn_skcipher(&ictx->chacha); 51462306a36Sopenharmony_ci if (IS_ERR(chacha)) { 51562306a36Sopenharmony_ci crypto_free_ahash(poly); 51662306a36Sopenharmony_ci return PTR_ERR(chacha); 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci ctx->chacha = chacha; 52062306a36Sopenharmony_ci ctx->poly = poly; 52162306a36Sopenharmony_ci ctx->saltlen = ictx->saltlen; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci align = crypto_aead_alignmask(tfm); 52462306a36Sopenharmony_ci align &= ~(crypto_tfm_ctx_alignment() - 1); 52562306a36Sopenharmony_ci crypto_aead_set_reqsize( 52662306a36Sopenharmony_ci tfm, 52762306a36Sopenharmony_ci align + offsetof(struct chachapoly_req_ctx, u) + 52862306a36Sopenharmony_ci max(offsetof(struct chacha_req, req) + 52962306a36Sopenharmony_ci sizeof(struct skcipher_request) + 53062306a36Sopenharmony_ci crypto_skcipher_reqsize(chacha), 53162306a36Sopenharmony_ci offsetof(struct poly_req, req) + 53262306a36Sopenharmony_ci sizeof(struct ahash_request) + 53362306a36Sopenharmony_ci crypto_ahash_reqsize(poly))); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci return 0; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic void chachapoly_exit(struct crypto_aead *tfm) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci crypto_free_ahash(ctx->poly); 54362306a36Sopenharmony_ci crypto_free_skcipher(ctx->chacha); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic void chachapoly_free(struct aead_instance *inst) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct chachapoly_instance_ctx *ctx = aead_instance_ctx(inst); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci crypto_drop_skcipher(&ctx->chacha); 55162306a36Sopenharmony_ci crypto_drop_ahash(&ctx->poly); 55262306a36Sopenharmony_ci kfree(inst); 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic int chachapoly_create(struct crypto_template *tmpl, struct rtattr **tb, 55662306a36Sopenharmony_ci const char *name, unsigned int ivsize) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci u32 mask; 55962306a36Sopenharmony_ci struct aead_instance *inst; 56062306a36Sopenharmony_ci struct chachapoly_instance_ctx *ctx; 56162306a36Sopenharmony_ci struct skcipher_alg *chacha; 56262306a36Sopenharmony_ci struct hash_alg_common *poly; 56362306a36Sopenharmony_ci int err; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (ivsize > CHACHAPOLY_IV_SIZE) 56662306a36Sopenharmony_ci return -EINVAL; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask); 56962306a36Sopenharmony_ci if (err) 57062306a36Sopenharmony_ci return err; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); 57362306a36Sopenharmony_ci if (!inst) 57462306a36Sopenharmony_ci return -ENOMEM; 57562306a36Sopenharmony_ci ctx = aead_instance_ctx(inst); 57662306a36Sopenharmony_ci ctx->saltlen = CHACHAPOLY_IV_SIZE - ivsize; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci err = crypto_grab_skcipher(&ctx->chacha, aead_crypto_instance(inst), 57962306a36Sopenharmony_ci crypto_attr_alg_name(tb[1]), 0, mask); 58062306a36Sopenharmony_ci if (err) 58162306a36Sopenharmony_ci goto err_free_inst; 58262306a36Sopenharmony_ci chacha = crypto_spawn_skcipher_alg(&ctx->chacha); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci err = crypto_grab_ahash(&ctx->poly, aead_crypto_instance(inst), 58562306a36Sopenharmony_ci crypto_attr_alg_name(tb[2]), 0, mask); 58662306a36Sopenharmony_ci if (err) 58762306a36Sopenharmony_ci goto err_free_inst; 58862306a36Sopenharmony_ci poly = crypto_spawn_ahash_alg(&ctx->poly); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci err = -EINVAL; 59162306a36Sopenharmony_ci if (poly->digestsize != POLY1305_DIGEST_SIZE) 59262306a36Sopenharmony_ci goto err_free_inst; 59362306a36Sopenharmony_ci /* Need 16-byte IV size, including Initial Block Counter value */ 59462306a36Sopenharmony_ci if (crypto_skcipher_alg_ivsize(chacha) != CHACHA_IV_SIZE) 59562306a36Sopenharmony_ci goto err_free_inst; 59662306a36Sopenharmony_ci /* Not a stream cipher? */ 59762306a36Sopenharmony_ci if (chacha->base.cra_blocksize != 1) 59862306a36Sopenharmony_ci goto err_free_inst; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci err = -ENAMETOOLONG; 60162306a36Sopenharmony_ci if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, 60262306a36Sopenharmony_ci "%s(%s,%s)", name, chacha->base.cra_name, 60362306a36Sopenharmony_ci poly->base.cra_name) >= CRYPTO_MAX_ALG_NAME) 60462306a36Sopenharmony_ci goto err_free_inst; 60562306a36Sopenharmony_ci if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 60662306a36Sopenharmony_ci "%s(%s,%s)", name, chacha->base.cra_driver_name, 60762306a36Sopenharmony_ci poly->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME) 60862306a36Sopenharmony_ci goto err_free_inst; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci inst->alg.base.cra_priority = (chacha->base.cra_priority + 61162306a36Sopenharmony_ci poly->base.cra_priority) / 2; 61262306a36Sopenharmony_ci inst->alg.base.cra_blocksize = 1; 61362306a36Sopenharmony_ci inst->alg.base.cra_alignmask = chacha->base.cra_alignmask | 61462306a36Sopenharmony_ci poly->base.cra_alignmask; 61562306a36Sopenharmony_ci inst->alg.base.cra_ctxsize = sizeof(struct chachapoly_ctx) + 61662306a36Sopenharmony_ci ctx->saltlen; 61762306a36Sopenharmony_ci inst->alg.ivsize = ivsize; 61862306a36Sopenharmony_ci inst->alg.chunksize = crypto_skcipher_alg_chunksize(chacha); 61962306a36Sopenharmony_ci inst->alg.maxauthsize = POLY1305_DIGEST_SIZE; 62062306a36Sopenharmony_ci inst->alg.init = chachapoly_init; 62162306a36Sopenharmony_ci inst->alg.exit = chachapoly_exit; 62262306a36Sopenharmony_ci inst->alg.encrypt = chachapoly_encrypt; 62362306a36Sopenharmony_ci inst->alg.decrypt = chachapoly_decrypt; 62462306a36Sopenharmony_ci inst->alg.setkey = chachapoly_setkey; 62562306a36Sopenharmony_ci inst->alg.setauthsize = chachapoly_setauthsize; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci inst->free = chachapoly_free; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci err = aead_register_instance(tmpl, inst); 63062306a36Sopenharmony_ci if (err) { 63162306a36Sopenharmony_cierr_free_inst: 63262306a36Sopenharmony_ci chachapoly_free(inst); 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci return err; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic int rfc7539_create(struct crypto_template *tmpl, struct rtattr **tb) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci return chachapoly_create(tmpl, tb, "rfc7539", 12); 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic int rfc7539esp_create(struct crypto_template *tmpl, struct rtattr **tb) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci return chachapoly_create(tmpl, tb, "rfc7539esp", 8); 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic struct crypto_template rfc7539_tmpls[] = { 64862306a36Sopenharmony_ci { 64962306a36Sopenharmony_ci .name = "rfc7539", 65062306a36Sopenharmony_ci .create = rfc7539_create, 65162306a36Sopenharmony_ci .module = THIS_MODULE, 65262306a36Sopenharmony_ci }, { 65362306a36Sopenharmony_ci .name = "rfc7539esp", 65462306a36Sopenharmony_ci .create = rfc7539esp_create, 65562306a36Sopenharmony_ci .module = THIS_MODULE, 65662306a36Sopenharmony_ci }, 65762306a36Sopenharmony_ci}; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic int __init chacha20poly1305_module_init(void) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci return crypto_register_templates(rfc7539_tmpls, 66262306a36Sopenharmony_ci ARRAY_SIZE(rfc7539_tmpls)); 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic void __exit chacha20poly1305_module_exit(void) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci crypto_unregister_templates(rfc7539_tmpls, 66862306a36Sopenharmony_ci ARRAY_SIZE(rfc7539_tmpls)); 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cisubsys_initcall(chacha20poly1305_module_init); 67262306a36Sopenharmony_cimodule_exit(chacha20poly1305_module_exit); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 67562306a36Sopenharmony_ciMODULE_AUTHOR("Martin Willi <martin@strongswan.org>"); 67662306a36Sopenharmony_ciMODULE_DESCRIPTION("ChaCha20-Poly1305 AEAD"); 67762306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("rfc7539"); 67862306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("rfc7539esp"); 679