18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * GCM: Galois/Counter Mode. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <crypto/gf128mul.h> 98c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h> 108c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 118c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 128c2ecf20Sopenharmony_ci#include <crypto/null.h> 138c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 148c2ecf20Sopenharmony_ci#include <crypto/gcm.h> 158c2ecf20Sopenharmony_ci#include <crypto/hash.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistruct gcm_instance_ctx { 238c2ecf20Sopenharmony_ci struct crypto_skcipher_spawn ctr; 248c2ecf20Sopenharmony_ci struct crypto_ahash_spawn ghash; 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct crypto_gcm_ctx { 288c2ecf20Sopenharmony_ci struct crypto_skcipher *ctr; 298c2ecf20Sopenharmony_ci struct crypto_ahash *ghash; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct crypto_rfc4106_ctx { 338c2ecf20Sopenharmony_ci struct crypto_aead *child; 348c2ecf20Sopenharmony_ci u8 nonce[4]; 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistruct crypto_rfc4106_req_ctx { 388c2ecf20Sopenharmony_ci struct scatterlist src[3]; 398c2ecf20Sopenharmony_ci struct scatterlist dst[3]; 408c2ecf20Sopenharmony_ci struct aead_request subreq; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct crypto_rfc4543_instance_ctx { 448c2ecf20Sopenharmony_ci struct crypto_aead_spawn aead; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct crypto_rfc4543_ctx { 488c2ecf20Sopenharmony_ci struct crypto_aead *child; 498c2ecf20Sopenharmony_ci struct crypto_sync_skcipher *null; 508c2ecf20Sopenharmony_ci u8 nonce[4]; 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct crypto_rfc4543_req_ctx { 548c2ecf20Sopenharmony_ci struct aead_request subreq; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct crypto_gcm_ghash_ctx { 588c2ecf20Sopenharmony_ci unsigned int cryptlen; 598c2ecf20Sopenharmony_ci struct scatterlist *src; 608c2ecf20Sopenharmony_ci int (*complete)(struct aead_request *req, u32 flags); 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistruct crypto_gcm_req_priv_ctx { 648c2ecf20Sopenharmony_ci u8 iv[16]; 658c2ecf20Sopenharmony_ci u8 auth_tag[16]; 668c2ecf20Sopenharmony_ci u8 iauth_tag[16]; 678c2ecf20Sopenharmony_ci struct scatterlist src[3]; 688c2ecf20Sopenharmony_ci struct scatterlist dst[3]; 698c2ecf20Sopenharmony_ci struct scatterlist sg; 708c2ecf20Sopenharmony_ci struct crypto_gcm_ghash_ctx ghash_ctx; 718c2ecf20Sopenharmony_ci union { 728c2ecf20Sopenharmony_ci struct ahash_request ahreq; 738c2ecf20Sopenharmony_ci struct skcipher_request skreq; 748c2ecf20Sopenharmony_ci } u; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic struct { 788c2ecf20Sopenharmony_ci u8 buf[16]; 798c2ecf20Sopenharmony_ci struct scatterlist sg; 808c2ecf20Sopenharmony_ci} *gcm_zeroes; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic inline struct crypto_gcm_req_priv_ctx *crypto_gcm_reqctx( 858c2ecf20Sopenharmony_ci struct aead_request *req) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req)); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key, 938c2ecf20Sopenharmony_ci unsigned int keylen) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead); 968c2ecf20Sopenharmony_ci struct crypto_ahash *ghash = ctx->ghash; 978c2ecf20Sopenharmony_ci struct crypto_skcipher *ctr = ctx->ctr; 988c2ecf20Sopenharmony_ci struct { 998c2ecf20Sopenharmony_ci be128 hash; 1008c2ecf20Sopenharmony_ci u8 iv[16]; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci struct crypto_wait wait; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci struct scatterlist sg[1]; 1058c2ecf20Sopenharmony_ci struct skcipher_request req; 1068c2ecf20Sopenharmony_ci } *data; 1078c2ecf20Sopenharmony_ci int err; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci crypto_skcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK); 1108c2ecf20Sopenharmony_ci crypto_skcipher_set_flags(ctr, crypto_aead_get_flags(aead) & 1118c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 1128c2ecf20Sopenharmony_ci err = crypto_skcipher_setkey(ctr, key, keylen); 1138c2ecf20Sopenharmony_ci if (err) 1148c2ecf20Sopenharmony_ci return err; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci data = kzalloc(sizeof(*data) + crypto_skcipher_reqsize(ctr), 1178c2ecf20Sopenharmony_ci GFP_KERNEL); 1188c2ecf20Sopenharmony_ci if (!data) 1198c2ecf20Sopenharmony_ci return -ENOMEM; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci crypto_init_wait(&data->wait); 1228c2ecf20Sopenharmony_ci sg_init_one(data->sg, &data->hash, sizeof(data->hash)); 1238c2ecf20Sopenharmony_ci skcipher_request_set_tfm(&data->req, ctr); 1248c2ecf20Sopenharmony_ci skcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP | 1258c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MAY_BACKLOG, 1268c2ecf20Sopenharmony_ci crypto_req_done, 1278c2ecf20Sopenharmony_ci &data->wait); 1288c2ecf20Sopenharmony_ci skcipher_request_set_crypt(&data->req, data->sg, data->sg, 1298c2ecf20Sopenharmony_ci sizeof(data->hash), data->iv); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci err = crypto_wait_req(crypto_skcipher_encrypt(&data->req), 1328c2ecf20Sopenharmony_ci &data->wait); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (err) 1358c2ecf20Sopenharmony_ci goto out; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci crypto_ahash_clear_flags(ghash, CRYPTO_TFM_REQ_MASK); 1388c2ecf20Sopenharmony_ci crypto_ahash_set_flags(ghash, crypto_aead_get_flags(aead) & 1398c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 1408c2ecf20Sopenharmony_ci err = crypto_ahash_setkey(ghash, (u8 *)&data->hash, sizeof(be128)); 1418c2ecf20Sopenharmony_ciout: 1428c2ecf20Sopenharmony_ci kfree_sensitive(data); 1438c2ecf20Sopenharmony_ci return err; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int crypto_gcm_setauthsize(struct crypto_aead *tfm, 1478c2ecf20Sopenharmony_ci unsigned int authsize) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci return crypto_gcm_check_authsize(authsize); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic void crypto_gcm_init_common(struct aead_request *req) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 1558c2ecf20Sopenharmony_ci __be32 counter = cpu_to_be32(1); 1568c2ecf20Sopenharmony_ci struct scatterlist *sg; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci memset(pctx->auth_tag, 0, sizeof(pctx->auth_tag)); 1598c2ecf20Sopenharmony_ci memcpy(pctx->iv, req->iv, GCM_AES_IV_SIZE); 1608c2ecf20Sopenharmony_ci memcpy(pctx->iv + GCM_AES_IV_SIZE, &counter, 4); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci sg_init_table(pctx->src, 3); 1638c2ecf20Sopenharmony_ci sg_set_buf(pctx->src, pctx->auth_tag, sizeof(pctx->auth_tag)); 1648c2ecf20Sopenharmony_ci sg = scatterwalk_ffwd(pctx->src + 1, req->src, req->assoclen); 1658c2ecf20Sopenharmony_ci if (sg != pctx->src + 1) 1668c2ecf20Sopenharmony_ci sg_chain(pctx->src, 2, sg); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (req->src != req->dst) { 1698c2ecf20Sopenharmony_ci sg_init_table(pctx->dst, 3); 1708c2ecf20Sopenharmony_ci sg_set_buf(pctx->dst, pctx->auth_tag, sizeof(pctx->auth_tag)); 1718c2ecf20Sopenharmony_ci sg = scatterwalk_ffwd(pctx->dst + 1, req->dst, req->assoclen); 1728c2ecf20Sopenharmony_ci if (sg != pctx->dst + 1) 1738c2ecf20Sopenharmony_ci sg_chain(pctx->dst, 2, sg); 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic void crypto_gcm_init_crypt(struct aead_request *req, 1788c2ecf20Sopenharmony_ci unsigned int cryptlen) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 1818c2ecf20Sopenharmony_ci struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead); 1828c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 1838c2ecf20Sopenharmony_ci struct skcipher_request *skreq = &pctx->u.skreq; 1848c2ecf20Sopenharmony_ci struct scatterlist *dst; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci dst = req->src == req->dst ? pctx->src : pctx->dst; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci skcipher_request_set_tfm(skreq, ctx->ctr); 1898c2ecf20Sopenharmony_ci skcipher_request_set_crypt(skreq, pctx->src, dst, 1908c2ecf20Sopenharmony_ci cryptlen + sizeof(pctx->auth_tag), 1918c2ecf20Sopenharmony_ci pctx->iv); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic inline unsigned int gcm_remain(unsigned int len) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci len &= 0xfU; 1978c2ecf20Sopenharmony_ci return len ? 16 - len : 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic void gcm_hash_len_done(struct crypto_async_request *areq, int err); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int gcm_hash_update(struct aead_request *req, 2038c2ecf20Sopenharmony_ci crypto_completion_t compl, 2048c2ecf20Sopenharmony_ci struct scatterlist *src, 2058c2ecf20Sopenharmony_ci unsigned int len, u32 flags) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 2088c2ecf20Sopenharmony_ci struct ahash_request *ahreq = &pctx->u.ahreq; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci ahash_request_set_callback(ahreq, flags, compl, req); 2118c2ecf20Sopenharmony_ci ahash_request_set_crypt(ahreq, src, NULL, len); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return crypto_ahash_update(ahreq); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int gcm_hash_remain(struct aead_request *req, 2178c2ecf20Sopenharmony_ci unsigned int remain, 2188c2ecf20Sopenharmony_ci crypto_completion_t compl, u32 flags) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci return gcm_hash_update(req, compl, &gcm_zeroes->sg, remain, flags); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int gcm_hash_len(struct aead_request *req, u32 flags) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 2268c2ecf20Sopenharmony_ci struct ahash_request *ahreq = &pctx->u.ahreq; 2278c2ecf20Sopenharmony_ci struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; 2288c2ecf20Sopenharmony_ci be128 lengths; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci lengths.a = cpu_to_be64(req->assoclen * 8); 2318c2ecf20Sopenharmony_ci lengths.b = cpu_to_be64(gctx->cryptlen * 8); 2328c2ecf20Sopenharmony_ci memcpy(pctx->iauth_tag, &lengths, 16); 2338c2ecf20Sopenharmony_ci sg_init_one(&pctx->sg, pctx->iauth_tag, 16); 2348c2ecf20Sopenharmony_ci ahash_request_set_callback(ahreq, flags, gcm_hash_len_done, req); 2358c2ecf20Sopenharmony_ci ahash_request_set_crypt(ahreq, &pctx->sg, 2368c2ecf20Sopenharmony_ci pctx->iauth_tag, sizeof(lengths)); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return crypto_ahash_finup(ahreq); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int gcm_hash_len_continue(struct aead_request *req, u32 flags) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 2448c2ecf20Sopenharmony_ci struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return gctx->complete(req, flags); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic void gcm_hash_len_done(struct crypto_async_request *areq, int err) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct aead_request *req = areq->data; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (err) 2548c2ecf20Sopenharmony_ci goto out; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci err = gcm_hash_len_continue(req, 0); 2578c2ecf20Sopenharmony_ci if (err == -EINPROGRESS) 2588c2ecf20Sopenharmony_ci return; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ciout: 2618c2ecf20Sopenharmony_ci aead_request_complete(req, err); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int gcm_hash_crypt_remain_continue(struct aead_request *req, u32 flags) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci return gcm_hash_len(req, flags) ?: 2678c2ecf20Sopenharmony_ci gcm_hash_len_continue(req, flags); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void gcm_hash_crypt_remain_done(struct crypto_async_request *areq, 2718c2ecf20Sopenharmony_ci int err) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct aead_request *req = areq->data; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (err) 2768c2ecf20Sopenharmony_ci goto out; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci err = gcm_hash_crypt_remain_continue(req, 0); 2798c2ecf20Sopenharmony_ci if (err == -EINPROGRESS) 2808c2ecf20Sopenharmony_ci return; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ciout: 2838c2ecf20Sopenharmony_ci aead_request_complete(req, err); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic int gcm_hash_crypt_continue(struct aead_request *req, u32 flags) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 2898c2ecf20Sopenharmony_ci struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; 2908c2ecf20Sopenharmony_ci unsigned int remain; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci remain = gcm_remain(gctx->cryptlen); 2938c2ecf20Sopenharmony_ci if (remain) 2948c2ecf20Sopenharmony_ci return gcm_hash_remain(req, remain, 2958c2ecf20Sopenharmony_ci gcm_hash_crypt_remain_done, flags) ?: 2968c2ecf20Sopenharmony_ci gcm_hash_crypt_remain_continue(req, flags); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci return gcm_hash_crypt_remain_continue(req, flags); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void gcm_hash_crypt_done(struct crypto_async_request *areq, int err) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct aead_request *req = areq->data; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (err) 3068c2ecf20Sopenharmony_ci goto out; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci err = gcm_hash_crypt_continue(req, 0); 3098c2ecf20Sopenharmony_ci if (err == -EINPROGRESS) 3108c2ecf20Sopenharmony_ci return; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ciout: 3138c2ecf20Sopenharmony_ci aead_request_complete(req, err); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int gcm_hash_assoc_remain_continue(struct aead_request *req, u32 flags) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 3198c2ecf20Sopenharmony_ci struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (gctx->cryptlen) 3228c2ecf20Sopenharmony_ci return gcm_hash_update(req, gcm_hash_crypt_done, 3238c2ecf20Sopenharmony_ci gctx->src, gctx->cryptlen, flags) ?: 3248c2ecf20Sopenharmony_ci gcm_hash_crypt_continue(req, flags); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return gcm_hash_crypt_remain_continue(req, flags); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic void gcm_hash_assoc_remain_done(struct crypto_async_request *areq, 3308c2ecf20Sopenharmony_ci int err) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci struct aead_request *req = areq->data; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (err) 3358c2ecf20Sopenharmony_ci goto out; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci err = gcm_hash_assoc_remain_continue(req, 0); 3388c2ecf20Sopenharmony_ci if (err == -EINPROGRESS) 3398c2ecf20Sopenharmony_ci return; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ciout: 3428c2ecf20Sopenharmony_ci aead_request_complete(req, err); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic int gcm_hash_assoc_continue(struct aead_request *req, u32 flags) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci unsigned int remain; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci remain = gcm_remain(req->assoclen); 3508c2ecf20Sopenharmony_ci if (remain) 3518c2ecf20Sopenharmony_ci return gcm_hash_remain(req, remain, 3528c2ecf20Sopenharmony_ci gcm_hash_assoc_remain_done, flags) ?: 3538c2ecf20Sopenharmony_ci gcm_hash_assoc_remain_continue(req, flags); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return gcm_hash_assoc_remain_continue(req, flags); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic void gcm_hash_assoc_done(struct crypto_async_request *areq, int err) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct aead_request *req = areq->data; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (err) 3638c2ecf20Sopenharmony_ci goto out; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci err = gcm_hash_assoc_continue(req, 0); 3668c2ecf20Sopenharmony_ci if (err == -EINPROGRESS) 3678c2ecf20Sopenharmony_ci return; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ciout: 3708c2ecf20Sopenharmony_ci aead_request_complete(req, err); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic int gcm_hash_init_continue(struct aead_request *req, u32 flags) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci if (req->assoclen) 3768c2ecf20Sopenharmony_ci return gcm_hash_update(req, gcm_hash_assoc_done, 3778c2ecf20Sopenharmony_ci req->src, req->assoclen, flags) ?: 3788c2ecf20Sopenharmony_ci gcm_hash_assoc_continue(req, flags); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return gcm_hash_assoc_remain_continue(req, flags); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic void gcm_hash_init_done(struct crypto_async_request *areq, int err) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct aead_request *req = areq->data; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (err) 3888c2ecf20Sopenharmony_ci goto out; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci err = gcm_hash_init_continue(req, 0); 3918c2ecf20Sopenharmony_ci if (err == -EINPROGRESS) 3928c2ecf20Sopenharmony_ci return; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ciout: 3958c2ecf20Sopenharmony_ci aead_request_complete(req, err); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic int gcm_hash(struct aead_request *req, u32 flags) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 4018c2ecf20Sopenharmony_ci struct ahash_request *ahreq = &pctx->u.ahreq; 4028c2ecf20Sopenharmony_ci struct crypto_gcm_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci ahash_request_set_tfm(ahreq, ctx->ghash); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci ahash_request_set_callback(ahreq, flags, gcm_hash_init_done, req); 4078c2ecf20Sopenharmony_ci return crypto_ahash_init(ahreq) ?: 4088c2ecf20Sopenharmony_ci gcm_hash_init_continue(req, flags); 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic int gcm_enc_copy_hash(struct aead_request *req, u32 flags) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 4148c2ecf20Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 4158c2ecf20Sopenharmony_ci u8 *auth_tag = pctx->auth_tag; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci crypto_xor(auth_tag, pctx->iauth_tag, 16); 4188c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(auth_tag, req->dst, 4198c2ecf20Sopenharmony_ci req->assoclen + req->cryptlen, 4208c2ecf20Sopenharmony_ci crypto_aead_authsize(aead), 1); 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic int gcm_encrypt_continue(struct aead_request *req, u32 flags) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 4278c2ecf20Sopenharmony_ci struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci gctx->src = sg_next(req->src == req->dst ? pctx->src : pctx->dst); 4308c2ecf20Sopenharmony_ci gctx->cryptlen = req->cryptlen; 4318c2ecf20Sopenharmony_ci gctx->complete = gcm_enc_copy_hash; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return gcm_hash(req, flags); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic void gcm_encrypt_done(struct crypto_async_request *areq, int err) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct aead_request *req = areq->data; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (err) 4418c2ecf20Sopenharmony_ci goto out; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci err = gcm_encrypt_continue(req, 0); 4448c2ecf20Sopenharmony_ci if (err == -EINPROGRESS) 4458c2ecf20Sopenharmony_ci return; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ciout: 4488c2ecf20Sopenharmony_ci aead_request_complete(req, err); 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int crypto_gcm_encrypt(struct aead_request *req) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 4548c2ecf20Sopenharmony_ci struct skcipher_request *skreq = &pctx->u.skreq; 4558c2ecf20Sopenharmony_ci u32 flags = aead_request_flags(req); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci crypto_gcm_init_common(req); 4588c2ecf20Sopenharmony_ci crypto_gcm_init_crypt(req, req->cryptlen); 4598c2ecf20Sopenharmony_ci skcipher_request_set_callback(skreq, flags, gcm_encrypt_done, req); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return crypto_skcipher_encrypt(skreq) ?: 4628c2ecf20Sopenharmony_ci gcm_encrypt_continue(req, flags); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int crypto_gcm_verify(struct aead_request *req) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 4688c2ecf20Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 4698c2ecf20Sopenharmony_ci u8 *auth_tag = pctx->auth_tag; 4708c2ecf20Sopenharmony_ci u8 *iauth_tag = pctx->iauth_tag; 4718c2ecf20Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(aead); 4728c2ecf20Sopenharmony_ci unsigned int cryptlen = req->cryptlen - authsize; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci crypto_xor(auth_tag, iauth_tag, 16); 4758c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(iauth_tag, req->src, 4768c2ecf20Sopenharmony_ci req->assoclen + cryptlen, authsize, 0); 4778c2ecf20Sopenharmony_ci return crypto_memneq(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic void gcm_decrypt_done(struct crypto_async_request *areq, int err) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct aead_request *req = areq->data; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (!err) 4858c2ecf20Sopenharmony_ci err = crypto_gcm_verify(req); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci aead_request_complete(req, err); 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic int gcm_dec_hash_continue(struct aead_request *req, u32 flags) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 4938c2ecf20Sopenharmony_ci struct skcipher_request *skreq = &pctx->u.skreq; 4948c2ecf20Sopenharmony_ci struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci crypto_gcm_init_crypt(req, gctx->cryptlen); 4978c2ecf20Sopenharmony_ci skcipher_request_set_callback(skreq, flags, gcm_decrypt_done, req); 4988c2ecf20Sopenharmony_ci return crypto_skcipher_decrypt(skreq) ?: crypto_gcm_verify(req); 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic int crypto_gcm_decrypt(struct aead_request *req) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 5048c2ecf20Sopenharmony_ci struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); 5058c2ecf20Sopenharmony_ci struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; 5068c2ecf20Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(aead); 5078c2ecf20Sopenharmony_ci unsigned int cryptlen = req->cryptlen; 5088c2ecf20Sopenharmony_ci u32 flags = aead_request_flags(req); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci cryptlen -= authsize; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci crypto_gcm_init_common(req); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci gctx->src = sg_next(pctx->src); 5158c2ecf20Sopenharmony_ci gctx->cryptlen = cryptlen; 5168c2ecf20Sopenharmony_ci gctx->complete = gcm_dec_hash_continue; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci return gcm_hash(req, flags); 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic int crypto_gcm_init_tfm(struct crypto_aead *tfm) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct aead_instance *inst = aead_alg_instance(tfm); 5248c2ecf20Sopenharmony_ci struct gcm_instance_ctx *ictx = aead_instance_ctx(inst); 5258c2ecf20Sopenharmony_ci struct crypto_gcm_ctx *ctx = crypto_aead_ctx(tfm); 5268c2ecf20Sopenharmony_ci struct crypto_skcipher *ctr; 5278c2ecf20Sopenharmony_ci struct crypto_ahash *ghash; 5288c2ecf20Sopenharmony_ci unsigned long align; 5298c2ecf20Sopenharmony_ci int err; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci ghash = crypto_spawn_ahash(&ictx->ghash); 5328c2ecf20Sopenharmony_ci if (IS_ERR(ghash)) 5338c2ecf20Sopenharmony_ci return PTR_ERR(ghash); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci ctr = crypto_spawn_skcipher(&ictx->ctr); 5368c2ecf20Sopenharmony_ci err = PTR_ERR(ctr); 5378c2ecf20Sopenharmony_ci if (IS_ERR(ctr)) 5388c2ecf20Sopenharmony_ci goto err_free_hash; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci ctx->ctr = ctr; 5418c2ecf20Sopenharmony_ci ctx->ghash = ghash; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci align = crypto_aead_alignmask(tfm); 5448c2ecf20Sopenharmony_ci align &= ~(crypto_tfm_ctx_alignment() - 1); 5458c2ecf20Sopenharmony_ci crypto_aead_set_reqsize(tfm, 5468c2ecf20Sopenharmony_ci align + offsetof(struct crypto_gcm_req_priv_ctx, u) + 5478c2ecf20Sopenharmony_ci max(sizeof(struct skcipher_request) + 5488c2ecf20Sopenharmony_ci crypto_skcipher_reqsize(ctr), 5498c2ecf20Sopenharmony_ci sizeof(struct ahash_request) + 5508c2ecf20Sopenharmony_ci crypto_ahash_reqsize(ghash))); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cierr_free_hash: 5558c2ecf20Sopenharmony_ci crypto_free_ahash(ghash); 5568c2ecf20Sopenharmony_ci return err; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic void crypto_gcm_exit_tfm(struct crypto_aead *tfm) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci struct crypto_gcm_ctx *ctx = crypto_aead_ctx(tfm); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci crypto_free_ahash(ctx->ghash); 5648c2ecf20Sopenharmony_ci crypto_free_skcipher(ctx->ctr); 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic void crypto_gcm_free(struct aead_instance *inst) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci struct gcm_instance_ctx *ctx = aead_instance_ctx(inst); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci crypto_drop_skcipher(&ctx->ctr); 5728c2ecf20Sopenharmony_ci crypto_drop_ahash(&ctx->ghash); 5738c2ecf20Sopenharmony_ci kfree(inst); 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic int crypto_gcm_create_common(struct crypto_template *tmpl, 5778c2ecf20Sopenharmony_ci struct rtattr **tb, 5788c2ecf20Sopenharmony_ci const char *ctr_name, 5798c2ecf20Sopenharmony_ci const char *ghash_name) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci u32 mask; 5828c2ecf20Sopenharmony_ci struct aead_instance *inst; 5838c2ecf20Sopenharmony_ci struct gcm_instance_ctx *ctx; 5848c2ecf20Sopenharmony_ci struct skcipher_alg *ctr; 5858c2ecf20Sopenharmony_ci struct hash_alg_common *ghash; 5868c2ecf20Sopenharmony_ci int err; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask); 5898c2ecf20Sopenharmony_ci if (err) 5908c2ecf20Sopenharmony_ci return err; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); 5938c2ecf20Sopenharmony_ci if (!inst) 5948c2ecf20Sopenharmony_ci return -ENOMEM; 5958c2ecf20Sopenharmony_ci ctx = aead_instance_ctx(inst); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci err = crypto_grab_ahash(&ctx->ghash, aead_crypto_instance(inst), 5988c2ecf20Sopenharmony_ci ghash_name, 0, mask); 5998c2ecf20Sopenharmony_ci if (err) 6008c2ecf20Sopenharmony_ci goto err_free_inst; 6018c2ecf20Sopenharmony_ci ghash = crypto_spawn_ahash_alg(&ctx->ghash); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci err = -EINVAL; 6048c2ecf20Sopenharmony_ci if (strcmp(ghash->base.cra_name, "ghash") != 0 || 6058c2ecf20Sopenharmony_ci ghash->digestsize != 16) 6068c2ecf20Sopenharmony_ci goto err_free_inst; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci err = crypto_grab_skcipher(&ctx->ctr, aead_crypto_instance(inst), 6098c2ecf20Sopenharmony_ci ctr_name, 0, mask); 6108c2ecf20Sopenharmony_ci if (err) 6118c2ecf20Sopenharmony_ci goto err_free_inst; 6128c2ecf20Sopenharmony_ci ctr = crypto_spawn_skcipher_alg(&ctx->ctr); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* The skcipher algorithm must be CTR mode, using 16-byte blocks. */ 6158c2ecf20Sopenharmony_ci err = -EINVAL; 6168c2ecf20Sopenharmony_ci if (strncmp(ctr->base.cra_name, "ctr(", 4) != 0 || 6178c2ecf20Sopenharmony_ci crypto_skcipher_alg_ivsize(ctr) != 16 || 6188c2ecf20Sopenharmony_ci ctr->base.cra_blocksize != 1) 6198c2ecf20Sopenharmony_ci goto err_free_inst; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci err = -ENAMETOOLONG; 6228c2ecf20Sopenharmony_ci if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, 6238c2ecf20Sopenharmony_ci "gcm(%s", ctr->base.cra_name + 4) >= CRYPTO_MAX_ALG_NAME) 6248c2ecf20Sopenharmony_ci goto err_free_inst; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 6278c2ecf20Sopenharmony_ci "gcm_base(%s,%s)", ctr->base.cra_driver_name, 6288c2ecf20Sopenharmony_ci ghash->base.cra_driver_name) >= 6298c2ecf20Sopenharmony_ci CRYPTO_MAX_ALG_NAME) 6308c2ecf20Sopenharmony_ci goto err_free_inst; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci inst->alg.base.cra_priority = (ghash->base.cra_priority + 6338c2ecf20Sopenharmony_ci ctr->base.cra_priority) / 2; 6348c2ecf20Sopenharmony_ci inst->alg.base.cra_blocksize = 1; 6358c2ecf20Sopenharmony_ci inst->alg.base.cra_alignmask = ghash->base.cra_alignmask | 6368c2ecf20Sopenharmony_ci ctr->base.cra_alignmask; 6378c2ecf20Sopenharmony_ci inst->alg.base.cra_ctxsize = sizeof(struct crypto_gcm_ctx); 6388c2ecf20Sopenharmony_ci inst->alg.ivsize = GCM_AES_IV_SIZE; 6398c2ecf20Sopenharmony_ci inst->alg.chunksize = crypto_skcipher_alg_chunksize(ctr); 6408c2ecf20Sopenharmony_ci inst->alg.maxauthsize = 16; 6418c2ecf20Sopenharmony_ci inst->alg.init = crypto_gcm_init_tfm; 6428c2ecf20Sopenharmony_ci inst->alg.exit = crypto_gcm_exit_tfm; 6438c2ecf20Sopenharmony_ci inst->alg.setkey = crypto_gcm_setkey; 6448c2ecf20Sopenharmony_ci inst->alg.setauthsize = crypto_gcm_setauthsize; 6458c2ecf20Sopenharmony_ci inst->alg.encrypt = crypto_gcm_encrypt; 6468c2ecf20Sopenharmony_ci inst->alg.decrypt = crypto_gcm_decrypt; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci inst->free = crypto_gcm_free; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci err = aead_register_instance(tmpl, inst); 6518c2ecf20Sopenharmony_ci if (err) { 6528c2ecf20Sopenharmony_cierr_free_inst: 6538c2ecf20Sopenharmony_ci crypto_gcm_free(inst); 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci return err; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int crypto_gcm_create(struct crypto_template *tmpl, struct rtattr **tb) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci const char *cipher_name; 6618c2ecf20Sopenharmony_ci char ctr_name[CRYPTO_MAX_ALG_NAME]; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci cipher_name = crypto_attr_alg_name(tb[1]); 6648c2ecf20Sopenharmony_ci if (IS_ERR(cipher_name)) 6658c2ecf20Sopenharmony_ci return PTR_ERR(cipher_name); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >= 6688c2ecf20Sopenharmony_ci CRYPTO_MAX_ALG_NAME) 6698c2ecf20Sopenharmony_ci return -ENAMETOOLONG; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci return crypto_gcm_create_common(tmpl, tb, ctr_name, "ghash"); 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic int crypto_gcm_base_create(struct crypto_template *tmpl, 6758c2ecf20Sopenharmony_ci struct rtattr **tb) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci const char *ctr_name; 6788c2ecf20Sopenharmony_ci const char *ghash_name; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci ctr_name = crypto_attr_alg_name(tb[1]); 6818c2ecf20Sopenharmony_ci if (IS_ERR(ctr_name)) 6828c2ecf20Sopenharmony_ci return PTR_ERR(ctr_name); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci ghash_name = crypto_attr_alg_name(tb[2]); 6858c2ecf20Sopenharmony_ci if (IS_ERR(ghash_name)) 6868c2ecf20Sopenharmony_ci return PTR_ERR(ghash_name); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci return crypto_gcm_create_common(tmpl, tb, ctr_name, ghash_name); 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic int crypto_rfc4106_setkey(struct crypto_aead *parent, const u8 *key, 6928c2ecf20Sopenharmony_ci unsigned int keylen) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent); 6958c2ecf20Sopenharmony_ci struct crypto_aead *child = ctx->child; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (keylen < 4) 6988c2ecf20Sopenharmony_ci return -EINVAL; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci keylen -= 4; 7018c2ecf20Sopenharmony_ci memcpy(ctx->nonce, key + keylen, 4); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK); 7048c2ecf20Sopenharmony_ci crypto_aead_set_flags(child, crypto_aead_get_flags(parent) & 7058c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 7068c2ecf20Sopenharmony_ci return crypto_aead_setkey(child, key, keylen); 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic int crypto_rfc4106_setauthsize(struct crypto_aead *parent, 7108c2ecf20Sopenharmony_ci unsigned int authsize) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent); 7138c2ecf20Sopenharmony_ci int err; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci err = crypto_rfc4106_check_authsize(authsize); 7168c2ecf20Sopenharmony_ci if (err) 7178c2ecf20Sopenharmony_ci return err; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return crypto_aead_setauthsize(ctx->child, authsize); 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic struct aead_request *crypto_rfc4106_crypt(struct aead_request *req) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct crypto_rfc4106_req_ctx *rctx = aead_request_ctx(req); 7258c2ecf20Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 7268c2ecf20Sopenharmony_ci struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(aead); 7278c2ecf20Sopenharmony_ci struct aead_request *subreq = &rctx->subreq; 7288c2ecf20Sopenharmony_ci struct crypto_aead *child = ctx->child; 7298c2ecf20Sopenharmony_ci struct scatterlist *sg; 7308c2ecf20Sopenharmony_ci u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child), 7318c2ecf20Sopenharmony_ci crypto_aead_alignmask(child) + 1); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(iv + GCM_AES_IV_SIZE, req->src, 0, req->assoclen - 8, 0); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci memcpy(iv, ctx->nonce, 4); 7368c2ecf20Sopenharmony_ci memcpy(iv + 4, req->iv, 8); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci sg_init_table(rctx->src, 3); 7398c2ecf20Sopenharmony_ci sg_set_buf(rctx->src, iv + GCM_AES_IV_SIZE, req->assoclen - 8); 7408c2ecf20Sopenharmony_ci sg = scatterwalk_ffwd(rctx->src + 1, req->src, req->assoclen); 7418c2ecf20Sopenharmony_ci if (sg != rctx->src + 1) 7428c2ecf20Sopenharmony_ci sg_chain(rctx->src, 2, sg); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (req->src != req->dst) { 7458c2ecf20Sopenharmony_ci sg_init_table(rctx->dst, 3); 7468c2ecf20Sopenharmony_ci sg_set_buf(rctx->dst, iv + GCM_AES_IV_SIZE, req->assoclen - 8); 7478c2ecf20Sopenharmony_ci sg = scatterwalk_ffwd(rctx->dst + 1, req->dst, req->assoclen); 7488c2ecf20Sopenharmony_ci if (sg != rctx->dst + 1) 7498c2ecf20Sopenharmony_ci sg_chain(rctx->dst, 2, sg); 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci aead_request_set_tfm(subreq, child); 7538c2ecf20Sopenharmony_ci aead_request_set_callback(subreq, req->base.flags, req->base.complete, 7548c2ecf20Sopenharmony_ci req->base.data); 7558c2ecf20Sopenharmony_ci aead_request_set_crypt(subreq, rctx->src, 7568c2ecf20Sopenharmony_ci req->src == req->dst ? rctx->src : rctx->dst, 7578c2ecf20Sopenharmony_ci req->cryptlen, iv); 7588c2ecf20Sopenharmony_ci aead_request_set_ad(subreq, req->assoclen - 8); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci return subreq; 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic int crypto_rfc4106_encrypt(struct aead_request *req) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci int err; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci err = crypto_ipsec_check_assoclen(req->assoclen); 7688c2ecf20Sopenharmony_ci if (err) 7698c2ecf20Sopenharmony_ci return err; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci req = crypto_rfc4106_crypt(req); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci return crypto_aead_encrypt(req); 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic int crypto_rfc4106_decrypt(struct aead_request *req) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci int err; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci err = crypto_ipsec_check_assoclen(req->assoclen); 7818c2ecf20Sopenharmony_ci if (err) 7828c2ecf20Sopenharmony_ci return err; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci req = crypto_rfc4106_crypt(req); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci return crypto_aead_decrypt(req); 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic int crypto_rfc4106_init_tfm(struct crypto_aead *tfm) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci struct aead_instance *inst = aead_alg_instance(tfm); 7928c2ecf20Sopenharmony_ci struct crypto_aead_spawn *spawn = aead_instance_ctx(inst); 7938c2ecf20Sopenharmony_ci struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(tfm); 7948c2ecf20Sopenharmony_ci struct crypto_aead *aead; 7958c2ecf20Sopenharmony_ci unsigned long align; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci aead = crypto_spawn_aead(spawn); 7988c2ecf20Sopenharmony_ci if (IS_ERR(aead)) 7998c2ecf20Sopenharmony_ci return PTR_ERR(aead); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci ctx->child = aead; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci align = crypto_aead_alignmask(aead); 8048c2ecf20Sopenharmony_ci align &= ~(crypto_tfm_ctx_alignment() - 1); 8058c2ecf20Sopenharmony_ci crypto_aead_set_reqsize( 8068c2ecf20Sopenharmony_ci tfm, 8078c2ecf20Sopenharmony_ci sizeof(struct crypto_rfc4106_req_ctx) + 8088c2ecf20Sopenharmony_ci ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) + 8098c2ecf20Sopenharmony_ci align + 24); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci return 0; 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic void crypto_rfc4106_exit_tfm(struct crypto_aead *tfm) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(tfm); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci crypto_free_aead(ctx->child); 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic void crypto_rfc4106_free(struct aead_instance *inst) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci crypto_drop_aead(aead_instance_ctx(inst)); 8248c2ecf20Sopenharmony_ci kfree(inst); 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cistatic int crypto_rfc4106_create(struct crypto_template *tmpl, 8288c2ecf20Sopenharmony_ci struct rtattr **tb) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci u32 mask; 8318c2ecf20Sopenharmony_ci struct aead_instance *inst; 8328c2ecf20Sopenharmony_ci struct crypto_aead_spawn *spawn; 8338c2ecf20Sopenharmony_ci struct aead_alg *alg; 8348c2ecf20Sopenharmony_ci int err; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask); 8378c2ecf20Sopenharmony_ci if (err) 8388c2ecf20Sopenharmony_ci return err; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); 8418c2ecf20Sopenharmony_ci if (!inst) 8428c2ecf20Sopenharmony_ci return -ENOMEM; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci spawn = aead_instance_ctx(inst); 8458c2ecf20Sopenharmony_ci err = crypto_grab_aead(spawn, aead_crypto_instance(inst), 8468c2ecf20Sopenharmony_ci crypto_attr_alg_name(tb[1]), 0, mask); 8478c2ecf20Sopenharmony_ci if (err) 8488c2ecf20Sopenharmony_ci goto err_free_inst; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci alg = crypto_spawn_aead_alg(spawn); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci err = -EINVAL; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* Underlying IV size must be 12. */ 8558c2ecf20Sopenharmony_ci if (crypto_aead_alg_ivsize(alg) != GCM_AES_IV_SIZE) 8568c2ecf20Sopenharmony_ci goto err_free_inst; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci /* Not a stream cipher? */ 8598c2ecf20Sopenharmony_ci if (alg->base.cra_blocksize != 1) 8608c2ecf20Sopenharmony_ci goto err_free_inst; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci err = -ENAMETOOLONG; 8638c2ecf20Sopenharmony_ci if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, 8648c2ecf20Sopenharmony_ci "rfc4106(%s)", alg->base.cra_name) >= 8658c2ecf20Sopenharmony_ci CRYPTO_MAX_ALG_NAME || 8668c2ecf20Sopenharmony_ci snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 8678c2ecf20Sopenharmony_ci "rfc4106(%s)", alg->base.cra_driver_name) >= 8688c2ecf20Sopenharmony_ci CRYPTO_MAX_ALG_NAME) 8698c2ecf20Sopenharmony_ci goto err_free_inst; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci inst->alg.base.cra_priority = alg->base.cra_priority; 8728c2ecf20Sopenharmony_ci inst->alg.base.cra_blocksize = 1; 8738c2ecf20Sopenharmony_ci inst->alg.base.cra_alignmask = alg->base.cra_alignmask; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4106_ctx); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci inst->alg.ivsize = GCM_RFC4106_IV_SIZE; 8788c2ecf20Sopenharmony_ci inst->alg.chunksize = crypto_aead_alg_chunksize(alg); 8798c2ecf20Sopenharmony_ci inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci inst->alg.init = crypto_rfc4106_init_tfm; 8828c2ecf20Sopenharmony_ci inst->alg.exit = crypto_rfc4106_exit_tfm; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci inst->alg.setkey = crypto_rfc4106_setkey; 8858c2ecf20Sopenharmony_ci inst->alg.setauthsize = crypto_rfc4106_setauthsize; 8868c2ecf20Sopenharmony_ci inst->alg.encrypt = crypto_rfc4106_encrypt; 8878c2ecf20Sopenharmony_ci inst->alg.decrypt = crypto_rfc4106_decrypt; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci inst->free = crypto_rfc4106_free; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci err = aead_register_instance(tmpl, inst); 8928c2ecf20Sopenharmony_ci if (err) { 8938c2ecf20Sopenharmony_cierr_free_inst: 8948c2ecf20Sopenharmony_ci crypto_rfc4106_free(inst); 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci return err; 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cistatic int crypto_rfc4543_setkey(struct crypto_aead *parent, const u8 *key, 9008c2ecf20Sopenharmony_ci unsigned int keylen) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent); 9038c2ecf20Sopenharmony_ci struct crypto_aead *child = ctx->child; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (keylen < 4) 9068c2ecf20Sopenharmony_ci return -EINVAL; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci keylen -= 4; 9098c2ecf20Sopenharmony_ci memcpy(ctx->nonce, key + keylen, 4); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK); 9128c2ecf20Sopenharmony_ci crypto_aead_set_flags(child, crypto_aead_get_flags(parent) & 9138c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 9148c2ecf20Sopenharmony_ci return crypto_aead_setkey(child, key, keylen); 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cistatic int crypto_rfc4543_setauthsize(struct crypto_aead *parent, 9188c2ecf20Sopenharmony_ci unsigned int authsize) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (authsize != 16) 9238c2ecf20Sopenharmony_ci return -EINVAL; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci return crypto_aead_setauthsize(ctx->child, authsize); 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic int crypto_rfc4543_crypt(struct aead_request *req, bool enc) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 9318c2ecf20Sopenharmony_ci struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead); 9328c2ecf20Sopenharmony_ci struct crypto_rfc4543_req_ctx *rctx = aead_request_ctx(req); 9338c2ecf20Sopenharmony_ci struct aead_request *subreq = &rctx->subreq; 9348c2ecf20Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(aead); 9358c2ecf20Sopenharmony_ci u8 *iv = PTR_ALIGN((u8 *)(rctx + 1) + crypto_aead_reqsize(ctx->child), 9368c2ecf20Sopenharmony_ci crypto_aead_alignmask(ctx->child) + 1); 9378c2ecf20Sopenharmony_ci int err; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (req->src != req->dst) { 9408c2ecf20Sopenharmony_ci err = crypto_rfc4543_copy_src_to_dst(req, enc); 9418c2ecf20Sopenharmony_ci if (err) 9428c2ecf20Sopenharmony_ci return err; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci memcpy(iv, ctx->nonce, 4); 9468c2ecf20Sopenharmony_ci memcpy(iv + 4, req->iv, 8); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci aead_request_set_tfm(subreq, ctx->child); 9498c2ecf20Sopenharmony_ci aead_request_set_callback(subreq, req->base.flags, 9508c2ecf20Sopenharmony_ci req->base.complete, req->base.data); 9518c2ecf20Sopenharmony_ci aead_request_set_crypt(subreq, req->src, req->dst, 9528c2ecf20Sopenharmony_ci enc ? 0 : authsize, iv); 9538c2ecf20Sopenharmony_ci aead_request_set_ad(subreq, req->assoclen + req->cryptlen - 9548c2ecf20Sopenharmony_ci subreq->cryptlen); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci return enc ? crypto_aead_encrypt(subreq) : crypto_aead_decrypt(subreq); 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 9628c2ecf20Sopenharmony_ci struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead); 9638c2ecf20Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(aead); 9648c2ecf20Sopenharmony_ci unsigned int nbytes = req->assoclen + req->cryptlen - 9658c2ecf20Sopenharmony_ci (enc ? 0 : authsize); 9668c2ecf20Sopenharmony_ci SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->null); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci skcipher_request_set_sync_tfm(nreq, ctx->null); 9698c2ecf20Sopenharmony_ci skcipher_request_set_callback(nreq, req->base.flags, NULL, NULL); 9708c2ecf20Sopenharmony_ci skcipher_request_set_crypt(nreq, req->src, req->dst, nbytes, NULL); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci return crypto_skcipher_encrypt(nreq); 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic int crypto_rfc4543_encrypt(struct aead_request *req) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci return crypto_ipsec_check_assoclen(req->assoclen) ?: 9788c2ecf20Sopenharmony_ci crypto_rfc4543_crypt(req, true); 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_cistatic int crypto_rfc4543_decrypt(struct aead_request *req) 9828c2ecf20Sopenharmony_ci{ 9838c2ecf20Sopenharmony_ci return crypto_ipsec_check_assoclen(req->assoclen) ?: 9848c2ecf20Sopenharmony_ci crypto_rfc4543_crypt(req, false); 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cistatic int crypto_rfc4543_init_tfm(struct crypto_aead *tfm) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci struct aead_instance *inst = aead_alg_instance(tfm); 9908c2ecf20Sopenharmony_ci struct crypto_rfc4543_instance_ctx *ictx = aead_instance_ctx(inst); 9918c2ecf20Sopenharmony_ci struct crypto_aead_spawn *spawn = &ictx->aead; 9928c2ecf20Sopenharmony_ci struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm); 9938c2ecf20Sopenharmony_ci struct crypto_aead *aead; 9948c2ecf20Sopenharmony_ci struct crypto_sync_skcipher *null; 9958c2ecf20Sopenharmony_ci unsigned long align; 9968c2ecf20Sopenharmony_ci int err = 0; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci aead = crypto_spawn_aead(spawn); 9998c2ecf20Sopenharmony_ci if (IS_ERR(aead)) 10008c2ecf20Sopenharmony_ci return PTR_ERR(aead); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci null = crypto_get_default_null_skcipher(); 10038c2ecf20Sopenharmony_ci err = PTR_ERR(null); 10048c2ecf20Sopenharmony_ci if (IS_ERR(null)) 10058c2ecf20Sopenharmony_ci goto err_free_aead; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci ctx->child = aead; 10088c2ecf20Sopenharmony_ci ctx->null = null; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci align = crypto_aead_alignmask(aead); 10118c2ecf20Sopenharmony_ci align &= ~(crypto_tfm_ctx_alignment() - 1); 10128c2ecf20Sopenharmony_ci crypto_aead_set_reqsize( 10138c2ecf20Sopenharmony_ci tfm, 10148c2ecf20Sopenharmony_ci sizeof(struct crypto_rfc4543_req_ctx) + 10158c2ecf20Sopenharmony_ci ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) + 10168c2ecf20Sopenharmony_ci align + GCM_AES_IV_SIZE); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci return 0; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_cierr_free_aead: 10218c2ecf20Sopenharmony_ci crypto_free_aead(aead); 10228c2ecf20Sopenharmony_ci return err; 10238c2ecf20Sopenharmony_ci} 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_cistatic void crypto_rfc4543_exit_tfm(struct crypto_aead *tfm) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci crypto_free_aead(ctx->child); 10308c2ecf20Sopenharmony_ci crypto_put_default_null_skcipher(); 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cistatic void crypto_rfc4543_free(struct aead_instance *inst) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci struct crypto_rfc4543_instance_ctx *ctx = aead_instance_ctx(inst); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci crypto_drop_aead(&ctx->aead); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci kfree(inst); 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cistatic int crypto_rfc4543_create(struct crypto_template *tmpl, 10438c2ecf20Sopenharmony_ci struct rtattr **tb) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci u32 mask; 10468c2ecf20Sopenharmony_ci struct aead_instance *inst; 10478c2ecf20Sopenharmony_ci struct aead_alg *alg; 10488c2ecf20Sopenharmony_ci struct crypto_rfc4543_instance_ctx *ctx; 10498c2ecf20Sopenharmony_ci int err; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask); 10528c2ecf20Sopenharmony_ci if (err) 10538c2ecf20Sopenharmony_ci return err; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); 10568c2ecf20Sopenharmony_ci if (!inst) 10578c2ecf20Sopenharmony_ci return -ENOMEM; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci ctx = aead_instance_ctx(inst); 10608c2ecf20Sopenharmony_ci err = crypto_grab_aead(&ctx->aead, aead_crypto_instance(inst), 10618c2ecf20Sopenharmony_ci crypto_attr_alg_name(tb[1]), 0, mask); 10628c2ecf20Sopenharmony_ci if (err) 10638c2ecf20Sopenharmony_ci goto err_free_inst; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci alg = crypto_spawn_aead_alg(&ctx->aead); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci err = -EINVAL; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* Underlying IV size must be 12. */ 10708c2ecf20Sopenharmony_ci if (crypto_aead_alg_ivsize(alg) != GCM_AES_IV_SIZE) 10718c2ecf20Sopenharmony_ci goto err_free_inst; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Not a stream cipher? */ 10748c2ecf20Sopenharmony_ci if (alg->base.cra_blocksize != 1) 10758c2ecf20Sopenharmony_ci goto err_free_inst; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci err = -ENAMETOOLONG; 10788c2ecf20Sopenharmony_ci if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, 10798c2ecf20Sopenharmony_ci "rfc4543(%s)", alg->base.cra_name) >= 10808c2ecf20Sopenharmony_ci CRYPTO_MAX_ALG_NAME || 10818c2ecf20Sopenharmony_ci snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 10828c2ecf20Sopenharmony_ci "rfc4543(%s)", alg->base.cra_driver_name) >= 10838c2ecf20Sopenharmony_ci CRYPTO_MAX_ALG_NAME) 10848c2ecf20Sopenharmony_ci goto err_free_inst; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci inst->alg.base.cra_priority = alg->base.cra_priority; 10878c2ecf20Sopenharmony_ci inst->alg.base.cra_blocksize = 1; 10888c2ecf20Sopenharmony_ci inst->alg.base.cra_alignmask = alg->base.cra_alignmask; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4543_ctx); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci inst->alg.ivsize = GCM_RFC4543_IV_SIZE; 10938c2ecf20Sopenharmony_ci inst->alg.chunksize = crypto_aead_alg_chunksize(alg); 10948c2ecf20Sopenharmony_ci inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci inst->alg.init = crypto_rfc4543_init_tfm; 10978c2ecf20Sopenharmony_ci inst->alg.exit = crypto_rfc4543_exit_tfm; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci inst->alg.setkey = crypto_rfc4543_setkey; 11008c2ecf20Sopenharmony_ci inst->alg.setauthsize = crypto_rfc4543_setauthsize; 11018c2ecf20Sopenharmony_ci inst->alg.encrypt = crypto_rfc4543_encrypt; 11028c2ecf20Sopenharmony_ci inst->alg.decrypt = crypto_rfc4543_decrypt; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci inst->free = crypto_rfc4543_free; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci err = aead_register_instance(tmpl, inst); 11078c2ecf20Sopenharmony_ci if (err) { 11088c2ecf20Sopenharmony_cierr_free_inst: 11098c2ecf20Sopenharmony_ci crypto_rfc4543_free(inst); 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci return err; 11128c2ecf20Sopenharmony_ci} 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cistatic struct crypto_template crypto_gcm_tmpls[] = { 11158c2ecf20Sopenharmony_ci { 11168c2ecf20Sopenharmony_ci .name = "gcm_base", 11178c2ecf20Sopenharmony_ci .create = crypto_gcm_base_create, 11188c2ecf20Sopenharmony_ci .module = THIS_MODULE, 11198c2ecf20Sopenharmony_ci }, { 11208c2ecf20Sopenharmony_ci .name = "gcm", 11218c2ecf20Sopenharmony_ci .create = crypto_gcm_create, 11228c2ecf20Sopenharmony_ci .module = THIS_MODULE, 11238c2ecf20Sopenharmony_ci }, { 11248c2ecf20Sopenharmony_ci .name = "rfc4106", 11258c2ecf20Sopenharmony_ci .create = crypto_rfc4106_create, 11268c2ecf20Sopenharmony_ci .module = THIS_MODULE, 11278c2ecf20Sopenharmony_ci }, { 11288c2ecf20Sopenharmony_ci .name = "rfc4543", 11298c2ecf20Sopenharmony_ci .create = crypto_rfc4543_create, 11308c2ecf20Sopenharmony_ci .module = THIS_MODULE, 11318c2ecf20Sopenharmony_ci }, 11328c2ecf20Sopenharmony_ci}; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cistatic int __init crypto_gcm_module_init(void) 11358c2ecf20Sopenharmony_ci{ 11368c2ecf20Sopenharmony_ci int err; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci gcm_zeroes = kzalloc(sizeof(*gcm_zeroes), GFP_KERNEL); 11398c2ecf20Sopenharmony_ci if (!gcm_zeroes) 11408c2ecf20Sopenharmony_ci return -ENOMEM; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci sg_init_one(&gcm_zeroes->sg, gcm_zeroes->buf, sizeof(gcm_zeroes->buf)); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci err = crypto_register_templates(crypto_gcm_tmpls, 11458c2ecf20Sopenharmony_ci ARRAY_SIZE(crypto_gcm_tmpls)); 11468c2ecf20Sopenharmony_ci if (err) 11478c2ecf20Sopenharmony_ci kfree(gcm_zeroes); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci return err; 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistatic void __exit crypto_gcm_module_exit(void) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci kfree(gcm_zeroes); 11558c2ecf20Sopenharmony_ci crypto_unregister_templates(crypto_gcm_tmpls, 11568c2ecf20Sopenharmony_ci ARRAY_SIZE(crypto_gcm_tmpls)); 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_cisubsys_initcall(crypto_gcm_module_init); 11608c2ecf20Sopenharmony_cimodule_exit(crypto_gcm_module_exit); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 11638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Galois/Counter Mode"); 11648c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>"); 11658c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("gcm_base"); 11668c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("rfc4106"); 11678c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("rfc4543"); 11688c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("gcm"); 1169