18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2003-2004, Instant802 Networks, Inc. 48c2ecf20Sopenharmony_ci * Copyright 2005-2006, Devicescape Software, Inc. 58c2ecf20Sopenharmony_ci * Copyright 2014-2015, Qualcomm Atheros, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Rewrite: Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 148c2ecf20Sopenharmony_ci#include <crypto/aead.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "aead_api.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ciint aead_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len, 198c2ecf20Sopenharmony_ci u8 *data, size_t data_len, u8 *mic) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci size_t mic_len = crypto_aead_authsize(tfm); 228c2ecf20Sopenharmony_ci struct scatterlist sg[3]; 238c2ecf20Sopenharmony_ci struct aead_request *aead_req; 248c2ecf20Sopenharmony_ci int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); 258c2ecf20Sopenharmony_ci u8 *__aad; 268c2ecf20Sopenharmony_ci int ret; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci aead_req = kzalloc(reqsize + aad_len, GFP_ATOMIC); 298c2ecf20Sopenharmony_ci if (!aead_req) 308c2ecf20Sopenharmony_ci return -ENOMEM; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci __aad = (u8 *)aead_req + reqsize; 338c2ecf20Sopenharmony_ci memcpy(__aad, aad, aad_len); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci sg_init_table(sg, 3); 368c2ecf20Sopenharmony_ci sg_set_buf(&sg[0], __aad, aad_len); 378c2ecf20Sopenharmony_ci sg_set_buf(&sg[1], data, data_len); 388c2ecf20Sopenharmony_ci sg_set_buf(&sg[2], mic, mic_len); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci aead_request_set_tfm(aead_req, tfm); 418c2ecf20Sopenharmony_ci aead_request_set_crypt(aead_req, sg, sg, data_len, b_0); 428c2ecf20Sopenharmony_ci aead_request_set_ad(aead_req, sg[0].length); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci ret = crypto_aead_encrypt(aead_req); 458c2ecf20Sopenharmony_ci kfree_sensitive(aead_req); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return ret; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciint aead_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len, 518c2ecf20Sopenharmony_ci u8 *data, size_t data_len, u8 *mic) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci size_t mic_len = crypto_aead_authsize(tfm); 548c2ecf20Sopenharmony_ci struct scatterlist sg[3]; 558c2ecf20Sopenharmony_ci struct aead_request *aead_req; 568c2ecf20Sopenharmony_ci int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); 578c2ecf20Sopenharmony_ci u8 *__aad; 588c2ecf20Sopenharmony_ci int err; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (data_len == 0) 618c2ecf20Sopenharmony_ci return -EINVAL; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci aead_req = kzalloc(reqsize + aad_len, GFP_ATOMIC); 648c2ecf20Sopenharmony_ci if (!aead_req) 658c2ecf20Sopenharmony_ci return -ENOMEM; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci __aad = (u8 *)aead_req + reqsize; 688c2ecf20Sopenharmony_ci memcpy(__aad, aad, aad_len); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci sg_init_table(sg, 3); 718c2ecf20Sopenharmony_ci sg_set_buf(&sg[0], __aad, aad_len); 728c2ecf20Sopenharmony_ci sg_set_buf(&sg[1], data, data_len); 738c2ecf20Sopenharmony_ci sg_set_buf(&sg[2], mic, mic_len); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci aead_request_set_tfm(aead_req, tfm); 768c2ecf20Sopenharmony_ci aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0); 778c2ecf20Sopenharmony_ci aead_request_set_ad(aead_req, sg[0].length); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci err = crypto_aead_decrypt(aead_req); 808c2ecf20Sopenharmony_ci kfree_sensitive(aead_req); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return err; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistruct crypto_aead * 868c2ecf20Sopenharmony_ciaead_key_setup_encrypt(const char *alg, const u8 key[], 878c2ecf20Sopenharmony_ci size_t key_len, size_t mic_len) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct crypto_aead *tfm; 908c2ecf20Sopenharmony_ci int err; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci tfm = crypto_alloc_aead(alg, 0, CRYPTO_ALG_ASYNC); 938c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 948c2ecf20Sopenharmony_ci return tfm; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci err = crypto_aead_setkey(tfm, key, key_len); 978c2ecf20Sopenharmony_ci if (err) 988c2ecf20Sopenharmony_ci goto free_aead; 998c2ecf20Sopenharmony_ci err = crypto_aead_setauthsize(tfm, mic_len); 1008c2ecf20Sopenharmony_ci if (err) 1018c2ecf20Sopenharmony_ci goto free_aead; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return tfm; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cifree_aead: 1068c2ecf20Sopenharmony_ci crypto_free_aead(tfm); 1078c2ecf20Sopenharmony_ci return ERR_PTR(err); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_civoid aead_key_free(struct crypto_aead *tfm) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci crypto_free_aead(tfm); 1138c2ecf20Sopenharmony_ci} 114