18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/** 38c2ecf20Sopenharmony_ci * AES CCM routines supporting the Power 7+ Nest Accelerators driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 International Business Machines Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Kent Yoder <yoder1@us.ibm.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h> 118c2ecf20Sopenharmony_ci#include <crypto/aes.h> 128c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 138c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/types.h> 168c2ecf20Sopenharmony_ci#include <linux/crypto.h> 178c2ecf20Sopenharmony_ci#include <asm/vio.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "nx_csbcpb.h" 208c2ecf20Sopenharmony_ci#include "nx.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic int ccm_aes_nx_set_key(struct crypto_aead *tfm, 248c2ecf20Sopenharmony_ci const u8 *in_key, 258c2ecf20Sopenharmony_ci unsigned int key_len) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base); 288c2ecf20Sopenharmony_ci struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; 298c2ecf20Sopenharmony_ci struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci nx_ctx_init(nx_ctx, HCOP_FC_AES); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci switch (key_len) { 348c2ecf20Sopenharmony_ci case AES_KEYSIZE_128: 358c2ecf20Sopenharmony_ci NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128); 368c2ecf20Sopenharmony_ci NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128); 378c2ecf20Sopenharmony_ci nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128]; 388c2ecf20Sopenharmony_ci break; 398c2ecf20Sopenharmony_ci default: 408c2ecf20Sopenharmony_ci return -EINVAL; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci csbcpb->cpb.hdr.mode = NX_MODE_AES_CCM; 448c2ecf20Sopenharmony_ci memcpy(csbcpb->cpb.aes_ccm.key, in_key, key_len); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_CCA; 478c2ecf20Sopenharmony_ci memcpy(csbcpb_aead->cpb.aes_cca.key, in_key, key_len); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci return 0; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int ccm4309_aes_nx_set_key(struct crypto_aead *tfm, 548c2ecf20Sopenharmony_ci const u8 *in_key, 558c2ecf20Sopenharmony_ci unsigned int key_len) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (key_len < 3) 608c2ecf20Sopenharmony_ci return -EINVAL; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci key_len -= 3; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci memcpy(nx_ctx->priv.ccm.nonce, in_key + key_len, 3); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return ccm_aes_nx_set_key(tfm, in_key, key_len); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int ccm_aes_nx_setauthsize(struct crypto_aead *tfm, 708c2ecf20Sopenharmony_ci unsigned int authsize) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci switch (authsize) { 738c2ecf20Sopenharmony_ci case 4: 748c2ecf20Sopenharmony_ci case 6: 758c2ecf20Sopenharmony_ci case 8: 768c2ecf20Sopenharmony_ci case 10: 778c2ecf20Sopenharmony_ci case 12: 788c2ecf20Sopenharmony_ci case 14: 798c2ecf20Sopenharmony_ci case 16: 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci default: 828c2ecf20Sopenharmony_ci return -EINVAL; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int ccm4309_aes_nx_setauthsize(struct crypto_aead *tfm, 898c2ecf20Sopenharmony_ci unsigned int authsize) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci switch (authsize) { 928c2ecf20Sopenharmony_ci case 8: 938c2ecf20Sopenharmony_ci case 12: 948c2ecf20Sopenharmony_ci case 16: 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci default: 978c2ecf20Sopenharmony_ci return -EINVAL; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* taken from crypto/ccm.c */ 1048c2ecf20Sopenharmony_cistatic int set_msg_len(u8 *block, unsigned int msglen, int csize) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci __be32 data; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci memset(block, 0, csize); 1098c2ecf20Sopenharmony_ci block += csize; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (csize >= 4) 1128c2ecf20Sopenharmony_ci csize = 4; 1138c2ecf20Sopenharmony_ci else if (msglen > (unsigned int)(1 << (8 * csize))) 1148c2ecf20Sopenharmony_ci return -EOVERFLOW; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci data = cpu_to_be32(msglen); 1178c2ecf20Sopenharmony_ci memcpy(block - csize, (u8 *)&data + 4 - csize, csize); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci return 0; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* taken from crypto/ccm.c */ 1238c2ecf20Sopenharmony_cistatic inline int crypto_ccm_check_iv(const u8 *iv) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci /* 2 <= L <= 8, so 1 <= L' <= 7. */ 1268c2ecf20Sopenharmony_ci if (1 > iv[0] || iv[0] > 7) 1278c2ecf20Sopenharmony_ci return -EINVAL; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* based on code from crypto/ccm.c */ 1338c2ecf20Sopenharmony_cistatic int generate_b0(u8 *iv, unsigned int assoclen, unsigned int authsize, 1348c2ecf20Sopenharmony_ci unsigned int cryptlen, u8 *b0) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci unsigned int l, lp, m = authsize; 1378c2ecf20Sopenharmony_ci int rc; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci memcpy(b0, iv, 16); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci lp = b0[0]; 1428c2ecf20Sopenharmony_ci l = lp + 1; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* set m, bits 3-5 */ 1458c2ecf20Sopenharmony_ci *b0 |= (8 * ((m - 2) / 2)); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* set adata, bit 6, if associated data is used */ 1488c2ecf20Sopenharmony_ci if (assoclen) 1498c2ecf20Sopenharmony_ci *b0 |= 64; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci rc = set_msg_len(b0 + 16 - l, cryptlen, l); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return rc; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic int generate_pat(u8 *iv, 1578c2ecf20Sopenharmony_ci struct aead_request *req, 1588c2ecf20Sopenharmony_ci struct nx_crypto_ctx *nx_ctx, 1598c2ecf20Sopenharmony_ci unsigned int authsize, 1608c2ecf20Sopenharmony_ci unsigned int nbytes, 1618c2ecf20Sopenharmony_ci unsigned int assoclen, 1628c2ecf20Sopenharmony_ci u8 *out) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct nx_sg *nx_insg = nx_ctx->in_sg; 1658c2ecf20Sopenharmony_ci struct nx_sg *nx_outsg = nx_ctx->out_sg; 1668c2ecf20Sopenharmony_ci unsigned int iauth_len = 0; 1678c2ecf20Sopenharmony_ci u8 tmp[16], *b1 = NULL, *b0 = NULL, *result = NULL; 1688c2ecf20Sopenharmony_ci int rc; 1698c2ecf20Sopenharmony_ci unsigned int max_sg_len; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* zero the ctr value */ 1728c2ecf20Sopenharmony_ci memset(iv + 15 - iv[0], 0, iv[0] + 1); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* page 78 of nx_wb.pdf has, 1758c2ecf20Sopenharmony_ci * Note: RFC3610 allows the AAD data to be up to 2^64 -1 bytes 1768c2ecf20Sopenharmony_ci * in length. If a full message is used, the AES CCA implementation 1778c2ecf20Sopenharmony_ci * restricts the maximum AAD length to 2^32 -1 bytes. 1788c2ecf20Sopenharmony_ci * If partial messages are used, the implementation supports 1798c2ecf20Sopenharmony_ci * 2^64 -1 bytes maximum AAD length. 1808c2ecf20Sopenharmony_ci * 1818c2ecf20Sopenharmony_ci * However, in the cryptoapi's aead_request structure, 1828c2ecf20Sopenharmony_ci * assoclen is an unsigned int, thus it cannot hold a length 1838c2ecf20Sopenharmony_ci * value greater than 2^32 - 1. 1848c2ecf20Sopenharmony_ci * Thus the AAD is further constrained by this and is never 1858c2ecf20Sopenharmony_ci * greater than 2^32. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (!assoclen) { 1898c2ecf20Sopenharmony_ci b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0; 1908c2ecf20Sopenharmony_ci } else if (assoclen <= 14) { 1918c2ecf20Sopenharmony_ci /* if associated data is 14 bytes or less, we do 1 GCM 1928c2ecf20Sopenharmony_ci * operation on 2 AES blocks, B0 (stored in the csbcpb) and B1, 1938c2ecf20Sopenharmony_ci * which is fed in through the source buffers here */ 1948c2ecf20Sopenharmony_ci b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0; 1958c2ecf20Sopenharmony_ci b1 = nx_ctx->priv.ccm.iauth_tag; 1968c2ecf20Sopenharmony_ci iauth_len = assoclen; 1978c2ecf20Sopenharmony_ci } else if (assoclen <= 65280) { 1988c2ecf20Sopenharmony_ci /* if associated data is less than (2^16 - 2^8), we construct 1998c2ecf20Sopenharmony_ci * B1 differently and feed in the associated data to a CCA 2008c2ecf20Sopenharmony_ci * operation */ 2018c2ecf20Sopenharmony_ci b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0; 2028c2ecf20Sopenharmony_ci b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1; 2038c2ecf20Sopenharmony_ci iauth_len = 14; 2048c2ecf20Sopenharmony_ci } else { 2058c2ecf20Sopenharmony_ci b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0; 2068c2ecf20Sopenharmony_ci b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1; 2078c2ecf20Sopenharmony_ci iauth_len = 10; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* generate B0 */ 2118c2ecf20Sopenharmony_ci rc = generate_b0(iv, assoclen, authsize, nbytes, b0); 2128c2ecf20Sopenharmony_ci if (rc) 2138c2ecf20Sopenharmony_ci return rc; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* generate B1: 2168c2ecf20Sopenharmony_ci * add control info for associated data 2178c2ecf20Sopenharmony_ci * RFC 3610 and NIST Special Publication 800-38C 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci if (b1) { 2208c2ecf20Sopenharmony_ci memset(b1, 0, 16); 2218c2ecf20Sopenharmony_ci if (assoclen <= 65280) { 2228c2ecf20Sopenharmony_ci *(u16 *)b1 = assoclen; 2238c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(b1 + 2, req->src, 0, 2248c2ecf20Sopenharmony_ci iauth_len, SCATTERWALK_FROM_SG); 2258c2ecf20Sopenharmony_ci } else { 2268c2ecf20Sopenharmony_ci *(u16 *)b1 = (u16)(0xfffe); 2278c2ecf20Sopenharmony_ci *(u32 *)&b1[2] = assoclen; 2288c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(b1 + 6, req->src, 0, 2298c2ecf20Sopenharmony_ci iauth_len, SCATTERWALK_FROM_SG); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* now copy any remaining AAD to scatterlist and call nx... */ 2348c2ecf20Sopenharmony_ci if (!assoclen) { 2358c2ecf20Sopenharmony_ci return rc; 2368c2ecf20Sopenharmony_ci } else if (assoclen <= 14) { 2378c2ecf20Sopenharmony_ci unsigned int len = 16; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci nx_insg = nx_build_sg_list(nx_insg, b1, &len, nx_ctx->ap->sglen); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (len != 16) 2428c2ecf20Sopenharmony_ci return -EINVAL; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci nx_outsg = nx_build_sg_list(nx_outsg, tmp, &len, 2458c2ecf20Sopenharmony_ci nx_ctx->ap->sglen); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (len != 16) 2488c2ecf20Sopenharmony_ci return -EINVAL; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* inlen should be negative, indicating to phyp that its a 2518c2ecf20Sopenharmony_ci * pointer to an sg list */ 2528c2ecf20Sopenharmony_ci nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) * 2538c2ecf20Sopenharmony_ci sizeof(struct nx_sg); 2548c2ecf20Sopenharmony_ci nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) * 2558c2ecf20Sopenharmony_ci sizeof(struct nx_sg); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_ENDE_ENCRYPT; 2588c2ecf20Sopenharmony_ci NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_INTERMEDIATE; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci result = nx_ctx->csbcpb->cpb.aes_ccm.out_pat_or_mac; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci rc = nx_hcall_sync(nx_ctx, &nx_ctx->op, 2638c2ecf20Sopenharmony_ci req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP); 2648c2ecf20Sopenharmony_ci if (rc) 2658c2ecf20Sopenharmony_ci return rc; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci atomic_inc(&(nx_ctx->stats->aes_ops)); 2688c2ecf20Sopenharmony_ci atomic64_add(assoclen, &nx_ctx->stats->aes_bytes); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci } else { 2718c2ecf20Sopenharmony_ci unsigned int processed = 0, to_process; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci processed += iauth_len; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* page_limit: number of sg entries that fit on one page */ 2768c2ecf20Sopenharmony_ci max_sg_len = min_t(u64, nx_ctx->ap->sglen, 2778c2ecf20Sopenharmony_ci nx_driver.of.max_sg_len/sizeof(struct nx_sg)); 2788c2ecf20Sopenharmony_ci max_sg_len = min_t(u64, max_sg_len, 2798c2ecf20Sopenharmony_ci nx_ctx->ap->databytelen/NX_PAGE_SIZE); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci do { 2828c2ecf20Sopenharmony_ci to_process = min_t(u32, assoclen - processed, 2838c2ecf20Sopenharmony_ci nx_ctx->ap->databytelen); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci nx_insg = nx_walk_and_build(nx_ctx->in_sg, 2868c2ecf20Sopenharmony_ci nx_ctx->ap->sglen, 2878c2ecf20Sopenharmony_ci req->src, processed, 2888c2ecf20Sopenharmony_ci &to_process); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if ((to_process + processed) < assoclen) { 2918c2ecf20Sopenharmony_ci NX_CPB_FDM(nx_ctx->csbcpb_aead) |= 2928c2ecf20Sopenharmony_ci NX_FDM_INTERMEDIATE; 2938c2ecf20Sopenharmony_ci } else { 2948c2ecf20Sopenharmony_ci NX_CPB_FDM(nx_ctx->csbcpb_aead) &= 2958c2ecf20Sopenharmony_ci ~NX_FDM_INTERMEDIATE; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) * 3008c2ecf20Sopenharmony_ci sizeof(struct nx_sg); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci rc = nx_hcall_sync(nx_ctx, &nx_ctx->op_aead, 3058c2ecf20Sopenharmony_ci req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP); 3068c2ecf20Sopenharmony_ci if (rc) 3078c2ecf20Sopenharmony_ci return rc; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci memcpy(nx_ctx->csbcpb_aead->cpb.aes_cca.b0, 3108c2ecf20Sopenharmony_ci nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0, 3118c2ecf20Sopenharmony_ci AES_BLOCK_SIZE); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci NX_CPB_FDM(nx_ctx->csbcpb_aead) |= NX_FDM_CONTINUATION; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci atomic_inc(&(nx_ctx->stats->aes_ops)); 3168c2ecf20Sopenharmony_ci atomic64_add(assoclen, &nx_ctx->stats->aes_bytes); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci processed += to_process; 3198c2ecf20Sopenharmony_ci } while (processed < assoclen); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci memcpy(out, result, AES_BLOCK_SIZE); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return rc; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int ccm_nx_decrypt(struct aead_request *req, 3308c2ecf20Sopenharmony_ci u8 *iv, 3318c2ecf20Sopenharmony_ci unsigned int assoclen) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); 3348c2ecf20Sopenharmony_ci struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; 3358c2ecf20Sopenharmony_ci unsigned int nbytes = req->cryptlen; 3368c2ecf20Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req)); 3378c2ecf20Sopenharmony_ci struct nx_ccm_priv *priv = &nx_ctx->priv.ccm; 3388c2ecf20Sopenharmony_ci unsigned long irq_flags; 3398c2ecf20Sopenharmony_ci unsigned int processed = 0, to_process; 3408c2ecf20Sopenharmony_ci int rc = -1; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci spin_lock_irqsave(&nx_ctx->lock, irq_flags); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci nbytes -= authsize; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* copy out the auth tag to compare with later */ 3478c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(priv->oauth_tag, 3488c2ecf20Sopenharmony_ci req->src, nbytes + req->assoclen, authsize, 3498c2ecf20Sopenharmony_ci SCATTERWALK_FROM_SG); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci rc = generate_pat(iv, req, nx_ctx, authsize, nbytes, assoclen, 3528c2ecf20Sopenharmony_ci csbcpb->cpb.aes_ccm.in_pat_or_b0); 3538c2ecf20Sopenharmony_ci if (rc) 3548c2ecf20Sopenharmony_ci goto out; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci do { 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* to_process: the AES_BLOCK_SIZE data chunk to process in this 3598c2ecf20Sopenharmony_ci * update. This value is bound by sg list limits. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci to_process = nbytes - processed; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if ((to_process + processed) < nbytes) 3648c2ecf20Sopenharmony_ci NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE; 3658c2ecf20Sopenharmony_ci else 3668c2ecf20Sopenharmony_ci NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci rc = nx_build_sg_lists(nx_ctx, iv, req->dst, req->src, 3718c2ecf20Sopenharmony_ci &to_process, processed + req->assoclen, 3728c2ecf20Sopenharmony_ci csbcpb->cpb.aes_ccm.iv_or_ctr); 3738c2ecf20Sopenharmony_ci if (rc) 3748c2ecf20Sopenharmony_ci goto out; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci rc = nx_hcall_sync(nx_ctx, &nx_ctx->op, 3778c2ecf20Sopenharmony_ci req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP); 3788c2ecf20Sopenharmony_ci if (rc) 3798c2ecf20Sopenharmony_ci goto out; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* for partial completion, copy following for next 3828c2ecf20Sopenharmony_ci * entry into loop... 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ci memcpy(iv, csbcpb->cpb.aes_ccm.out_ctr, AES_BLOCK_SIZE); 3858c2ecf20Sopenharmony_ci memcpy(csbcpb->cpb.aes_ccm.in_pat_or_b0, 3868c2ecf20Sopenharmony_ci csbcpb->cpb.aes_ccm.out_pat_or_mac, AES_BLOCK_SIZE); 3878c2ecf20Sopenharmony_ci memcpy(csbcpb->cpb.aes_ccm.in_s0, 3888c2ecf20Sopenharmony_ci csbcpb->cpb.aes_ccm.out_s0, AES_BLOCK_SIZE); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* update stats */ 3938c2ecf20Sopenharmony_ci atomic_inc(&(nx_ctx->stats->aes_ops)); 3948c2ecf20Sopenharmony_ci atomic64_add(csbcpb->csb.processed_byte_count, 3958c2ecf20Sopenharmony_ci &(nx_ctx->stats->aes_bytes)); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci processed += to_process; 3988c2ecf20Sopenharmony_ci } while (processed < nbytes); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci rc = crypto_memneq(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag, 4018c2ecf20Sopenharmony_ci authsize) ? -EBADMSG : 0; 4028c2ecf20Sopenharmony_ciout: 4038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nx_ctx->lock, irq_flags); 4048c2ecf20Sopenharmony_ci return rc; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic int ccm_nx_encrypt(struct aead_request *req, 4088c2ecf20Sopenharmony_ci u8 *iv, 4098c2ecf20Sopenharmony_ci unsigned int assoclen) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); 4128c2ecf20Sopenharmony_ci struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; 4138c2ecf20Sopenharmony_ci unsigned int nbytes = req->cryptlen; 4148c2ecf20Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req)); 4158c2ecf20Sopenharmony_ci unsigned long irq_flags; 4168c2ecf20Sopenharmony_ci unsigned int processed = 0, to_process; 4178c2ecf20Sopenharmony_ci int rc = -1; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci spin_lock_irqsave(&nx_ctx->lock, irq_flags); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci rc = generate_pat(iv, req, nx_ctx, authsize, nbytes, assoclen, 4228c2ecf20Sopenharmony_ci csbcpb->cpb.aes_ccm.in_pat_or_b0); 4238c2ecf20Sopenharmony_ci if (rc) 4248c2ecf20Sopenharmony_ci goto out; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci do { 4278c2ecf20Sopenharmony_ci /* to process: the AES_BLOCK_SIZE data chunk to process in this 4288c2ecf20Sopenharmony_ci * update. This value is bound by sg list limits. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_ci to_process = nbytes - processed; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if ((to_process + processed) < nbytes) 4338c2ecf20Sopenharmony_ci NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE; 4348c2ecf20Sopenharmony_ci else 4358c2ecf20Sopenharmony_ci NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci rc = nx_build_sg_lists(nx_ctx, iv, req->dst, req->src, 4408c2ecf20Sopenharmony_ci &to_process, processed + req->assoclen, 4418c2ecf20Sopenharmony_ci csbcpb->cpb.aes_ccm.iv_or_ctr); 4428c2ecf20Sopenharmony_ci if (rc) 4438c2ecf20Sopenharmony_ci goto out; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci rc = nx_hcall_sync(nx_ctx, &nx_ctx->op, 4468c2ecf20Sopenharmony_ci req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP); 4478c2ecf20Sopenharmony_ci if (rc) 4488c2ecf20Sopenharmony_ci goto out; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* for partial completion, copy following for next 4518c2ecf20Sopenharmony_ci * entry into loop... 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci memcpy(iv, csbcpb->cpb.aes_ccm.out_ctr, AES_BLOCK_SIZE); 4548c2ecf20Sopenharmony_ci memcpy(csbcpb->cpb.aes_ccm.in_pat_or_b0, 4558c2ecf20Sopenharmony_ci csbcpb->cpb.aes_ccm.out_pat_or_mac, AES_BLOCK_SIZE); 4568c2ecf20Sopenharmony_ci memcpy(csbcpb->cpb.aes_ccm.in_s0, 4578c2ecf20Sopenharmony_ci csbcpb->cpb.aes_ccm.out_s0, AES_BLOCK_SIZE); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* update stats */ 4628c2ecf20Sopenharmony_ci atomic_inc(&(nx_ctx->stats->aes_ops)); 4638c2ecf20Sopenharmony_ci atomic64_add(csbcpb->csb.processed_byte_count, 4648c2ecf20Sopenharmony_ci &(nx_ctx->stats->aes_bytes)); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci processed += to_process; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci } while (processed < nbytes); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* copy out the auth tag */ 4718c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(csbcpb->cpb.aes_ccm.out_pat_or_mac, 4728c2ecf20Sopenharmony_ci req->dst, nbytes + req->assoclen, authsize, 4738c2ecf20Sopenharmony_ci SCATTERWALK_TO_SG); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ciout: 4768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nx_ctx->lock, irq_flags); 4778c2ecf20Sopenharmony_ci return rc; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic int ccm4309_aes_nx_encrypt(struct aead_request *req) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); 4838c2ecf20Sopenharmony_ci struct nx_gcm_rctx *rctx = aead_request_ctx(req); 4848c2ecf20Sopenharmony_ci u8 *iv = rctx->iv; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci iv[0] = 3; 4878c2ecf20Sopenharmony_ci memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3); 4888c2ecf20Sopenharmony_ci memcpy(iv + 4, req->iv, 8); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return ccm_nx_encrypt(req, iv, req->assoclen - 8); 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic int ccm_aes_nx_encrypt(struct aead_request *req) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci int rc; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci rc = crypto_ccm_check_iv(req->iv); 4988c2ecf20Sopenharmony_ci if (rc) 4998c2ecf20Sopenharmony_ci return rc; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return ccm_nx_encrypt(req, req->iv, req->assoclen); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic int ccm4309_aes_nx_decrypt(struct aead_request *req) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); 5078c2ecf20Sopenharmony_ci struct nx_gcm_rctx *rctx = aead_request_ctx(req); 5088c2ecf20Sopenharmony_ci u8 *iv = rctx->iv; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci iv[0] = 3; 5118c2ecf20Sopenharmony_ci memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3); 5128c2ecf20Sopenharmony_ci memcpy(iv + 4, req->iv, 8); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return ccm_nx_decrypt(req, iv, req->assoclen - 8); 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int ccm_aes_nx_decrypt(struct aead_request *req) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci int rc; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci rc = crypto_ccm_check_iv(req->iv); 5228c2ecf20Sopenharmony_ci if (rc) 5238c2ecf20Sopenharmony_ci return rc; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci return ccm_nx_decrypt(req, req->iv, req->assoclen); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistruct aead_alg nx_ccm_aes_alg = { 5298c2ecf20Sopenharmony_ci .base = { 5308c2ecf20Sopenharmony_ci .cra_name = "ccm(aes)", 5318c2ecf20Sopenharmony_ci .cra_driver_name = "ccm-aes-nx", 5328c2ecf20Sopenharmony_ci .cra_priority = 300, 5338c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_NEED_FALLBACK, 5348c2ecf20Sopenharmony_ci .cra_blocksize = 1, 5358c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct nx_crypto_ctx), 5368c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 5378c2ecf20Sopenharmony_ci }, 5388c2ecf20Sopenharmony_ci .init = nx_crypto_ctx_aes_ccm_init, 5398c2ecf20Sopenharmony_ci .exit = nx_crypto_ctx_aead_exit, 5408c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 5418c2ecf20Sopenharmony_ci .maxauthsize = AES_BLOCK_SIZE, 5428c2ecf20Sopenharmony_ci .setkey = ccm_aes_nx_set_key, 5438c2ecf20Sopenharmony_ci .setauthsize = ccm_aes_nx_setauthsize, 5448c2ecf20Sopenharmony_ci .encrypt = ccm_aes_nx_encrypt, 5458c2ecf20Sopenharmony_ci .decrypt = ccm_aes_nx_decrypt, 5468c2ecf20Sopenharmony_ci}; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistruct aead_alg nx_ccm4309_aes_alg = { 5498c2ecf20Sopenharmony_ci .base = { 5508c2ecf20Sopenharmony_ci .cra_name = "rfc4309(ccm(aes))", 5518c2ecf20Sopenharmony_ci .cra_driver_name = "rfc4309-ccm-aes-nx", 5528c2ecf20Sopenharmony_ci .cra_priority = 300, 5538c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_NEED_FALLBACK, 5548c2ecf20Sopenharmony_ci .cra_blocksize = 1, 5558c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct nx_crypto_ctx), 5568c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 5578c2ecf20Sopenharmony_ci }, 5588c2ecf20Sopenharmony_ci .init = nx_crypto_ctx_aes_ccm_init, 5598c2ecf20Sopenharmony_ci .exit = nx_crypto_ctx_aead_exit, 5608c2ecf20Sopenharmony_ci .ivsize = 8, 5618c2ecf20Sopenharmony_ci .maxauthsize = AES_BLOCK_SIZE, 5628c2ecf20Sopenharmony_ci .setkey = ccm4309_aes_nx_set_key, 5638c2ecf20Sopenharmony_ci .setauthsize = ccm4309_aes_nx_setauthsize, 5648c2ecf20Sopenharmony_ci .encrypt = ccm4309_aes_nx_encrypt, 5658c2ecf20Sopenharmony_ci .decrypt = ccm4309_aes_nx_decrypt, 5668c2ecf20Sopenharmony_ci}; 567