18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Cryptographic API. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * s390 implementation of the AES Cipher Algorithm. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * s390 Version: 88c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2005, 2017 98c2ecf20Sopenharmony_ci * Author(s): Jan Glauber (jang@de.ibm.com) 108c2ecf20Sopenharmony_ci * Sebastian Siewior (sebastian@breakpoint.cc> SW-Fallback 118c2ecf20Sopenharmony_ci * Patrick Steuer <patrick.steuer@de.ibm.com> 128c2ecf20Sopenharmony_ci * Harald Freudenberger <freude@de.ibm.com> 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Derived from "crypto/aes_generic.c" 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "aes_s390" 188c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <crypto/aes.h> 218c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 228c2ecf20Sopenharmony_ci#include <crypto/ghash.h> 238c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h> 248c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 258c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 268c2ecf20Sopenharmony_ci#include <linux/err.h> 278c2ecf20Sopenharmony_ci#include <linux/module.h> 288c2ecf20Sopenharmony_ci#include <linux/cpufeature.h> 298c2ecf20Sopenharmony_ci#include <linux/init.h> 308c2ecf20Sopenharmony_ci#include <linux/mutex.h> 318c2ecf20Sopenharmony_ci#include <linux/fips.h> 328c2ecf20Sopenharmony_ci#include <linux/string.h> 338c2ecf20Sopenharmony_ci#include <crypto/xts.h> 348c2ecf20Sopenharmony_ci#include <asm/cpacf.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic u8 *ctrblk; 378c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(ctrblk_lock); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic cpacf_mask_t km_functions, kmc_functions, kmctr_functions, 408c2ecf20Sopenharmony_ci kma_functions; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct s390_aes_ctx { 438c2ecf20Sopenharmony_ci u8 key[AES_MAX_KEY_SIZE]; 448c2ecf20Sopenharmony_ci int key_len; 458c2ecf20Sopenharmony_ci unsigned long fc; 468c2ecf20Sopenharmony_ci union { 478c2ecf20Sopenharmony_ci struct crypto_skcipher *skcipher; 488c2ecf20Sopenharmony_ci struct crypto_cipher *cip; 498c2ecf20Sopenharmony_ci } fallback; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistruct s390_xts_ctx { 538c2ecf20Sopenharmony_ci u8 key[32]; 548c2ecf20Sopenharmony_ci u8 pcc_key[32]; 558c2ecf20Sopenharmony_ci int key_len; 568c2ecf20Sopenharmony_ci unsigned long fc; 578c2ecf20Sopenharmony_ci struct crypto_skcipher *fallback; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct gcm_sg_walk { 618c2ecf20Sopenharmony_ci struct scatter_walk walk; 628c2ecf20Sopenharmony_ci unsigned int walk_bytes; 638c2ecf20Sopenharmony_ci u8 *walk_ptr; 648c2ecf20Sopenharmony_ci unsigned int walk_bytes_remain; 658c2ecf20Sopenharmony_ci u8 buf[AES_BLOCK_SIZE]; 668c2ecf20Sopenharmony_ci unsigned int buf_bytes; 678c2ecf20Sopenharmony_ci u8 *ptr; 688c2ecf20Sopenharmony_ci unsigned int nbytes; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int setkey_fallback_cip(struct crypto_tfm *tfm, const u8 *in_key, 728c2ecf20Sopenharmony_ci unsigned int key_len) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci sctx->fallback.cip->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; 778c2ecf20Sopenharmony_ci sctx->fallback.cip->base.crt_flags |= (tfm->crt_flags & 788c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return crypto_cipher_setkey(sctx->fallback.cip, in_key, key_len); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, 848c2ecf20Sopenharmony_ci unsigned int key_len) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); 878c2ecf20Sopenharmony_ci unsigned long fc; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* Pick the correct function code based on the key length */ 908c2ecf20Sopenharmony_ci fc = (key_len == 16) ? CPACF_KM_AES_128 : 918c2ecf20Sopenharmony_ci (key_len == 24) ? CPACF_KM_AES_192 : 928c2ecf20Sopenharmony_ci (key_len == 32) ? CPACF_KM_AES_256 : 0; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* Check if the function code is available */ 958c2ecf20Sopenharmony_ci sctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0; 968c2ecf20Sopenharmony_ci if (!sctx->fc) 978c2ecf20Sopenharmony_ci return setkey_fallback_cip(tfm, in_key, key_len); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci sctx->key_len = key_len; 1008c2ecf20Sopenharmony_ci memcpy(sctx->key, in_key, key_len); 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void crypto_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (unlikely(!sctx->fc)) { 1098c2ecf20Sopenharmony_ci crypto_cipher_encrypt_one(sctx->fallback.cip, out, in); 1108c2ecf20Sopenharmony_ci return; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci cpacf_km(sctx->fc, &sctx->key, out, in, AES_BLOCK_SIZE); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void crypto_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (unlikely(!sctx->fc)) { 1208c2ecf20Sopenharmony_ci crypto_cipher_decrypt_one(sctx->fallback.cip, out, in); 1218c2ecf20Sopenharmony_ci return; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci cpacf_km(sctx->fc | CPACF_DECRYPT, 1248c2ecf20Sopenharmony_ci &sctx->key, out, in, AES_BLOCK_SIZE); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int fallback_init_cip(struct crypto_tfm *tfm) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci const char *name = tfm->__crt_alg->cra_name; 1308c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci sctx->fallback.cip = crypto_alloc_cipher(name, 0, 1338c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (IS_ERR(sctx->fallback.cip)) { 1368c2ecf20Sopenharmony_ci pr_err("Allocating AES fallback algorithm %s failed\n", 1378c2ecf20Sopenharmony_ci name); 1388c2ecf20Sopenharmony_ci return PTR_ERR(sctx->fallback.cip); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void fallback_exit_cip(struct crypto_tfm *tfm) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci crypto_free_cipher(sctx->fallback.cip); 1498c2ecf20Sopenharmony_ci sctx->fallback.cip = NULL; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic struct crypto_alg aes_alg = { 1538c2ecf20Sopenharmony_ci .cra_name = "aes", 1548c2ecf20Sopenharmony_ci .cra_driver_name = "aes-s390", 1558c2ecf20Sopenharmony_ci .cra_priority = 300, 1568c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_TYPE_CIPHER | 1578c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 1588c2ecf20Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 1598c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct s390_aes_ctx), 1608c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 1618c2ecf20Sopenharmony_ci .cra_init = fallback_init_cip, 1628c2ecf20Sopenharmony_ci .cra_exit = fallback_exit_cip, 1638c2ecf20Sopenharmony_ci .cra_u = { 1648c2ecf20Sopenharmony_ci .cipher = { 1658c2ecf20Sopenharmony_ci .cia_min_keysize = AES_MIN_KEY_SIZE, 1668c2ecf20Sopenharmony_ci .cia_max_keysize = AES_MAX_KEY_SIZE, 1678c2ecf20Sopenharmony_ci .cia_setkey = aes_set_key, 1688c2ecf20Sopenharmony_ci .cia_encrypt = crypto_aes_encrypt, 1698c2ecf20Sopenharmony_ci .cia_decrypt = crypto_aes_decrypt, 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic int setkey_fallback_skcipher(struct crypto_skcipher *tfm, const u8 *key, 1758c2ecf20Sopenharmony_ci unsigned int len) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci crypto_skcipher_clear_flags(sctx->fallback.skcipher, 1808c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 1818c2ecf20Sopenharmony_ci crypto_skcipher_set_flags(sctx->fallback.skcipher, 1828c2ecf20Sopenharmony_ci crypto_skcipher_get_flags(tfm) & 1838c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 1848c2ecf20Sopenharmony_ci return crypto_skcipher_setkey(sctx->fallback.skcipher, key, len); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic int fallback_skcipher_crypt(struct s390_aes_ctx *sctx, 1888c2ecf20Sopenharmony_ci struct skcipher_request *req, 1898c2ecf20Sopenharmony_ci unsigned long modifier) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct skcipher_request *subreq = skcipher_request_ctx(req); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci *subreq = *req; 1948c2ecf20Sopenharmony_ci skcipher_request_set_tfm(subreq, sctx->fallback.skcipher); 1958c2ecf20Sopenharmony_ci return (modifier & CPACF_DECRYPT) ? 1968c2ecf20Sopenharmony_ci crypto_skcipher_decrypt(subreq) : 1978c2ecf20Sopenharmony_ci crypto_skcipher_encrypt(subreq); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int ecb_aes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, 2018c2ecf20Sopenharmony_ci unsigned int key_len) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm); 2048c2ecf20Sopenharmony_ci unsigned long fc; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* Pick the correct function code based on the key length */ 2078c2ecf20Sopenharmony_ci fc = (key_len == 16) ? CPACF_KM_AES_128 : 2088c2ecf20Sopenharmony_ci (key_len == 24) ? CPACF_KM_AES_192 : 2098c2ecf20Sopenharmony_ci (key_len == 32) ? CPACF_KM_AES_256 : 0; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* Check if the function code is available */ 2128c2ecf20Sopenharmony_ci sctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0; 2138c2ecf20Sopenharmony_ci if (!sctx->fc) 2148c2ecf20Sopenharmony_ci return setkey_fallback_skcipher(tfm, in_key, key_len); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci sctx->key_len = key_len; 2178c2ecf20Sopenharmony_ci memcpy(sctx->key, in_key, key_len); 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int ecb_aes_crypt(struct skcipher_request *req, unsigned long modifier) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 2248c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm); 2258c2ecf20Sopenharmony_ci struct skcipher_walk walk; 2268c2ecf20Sopenharmony_ci unsigned int nbytes, n; 2278c2ecf20Sopenharmony_ci int ret; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (unlikely(!sctx->fc)) 2308c2ecf20Sopenharmony_ci return fallback_skcipher_crypt(sctx, req, modifier); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 2338c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 2348c2ecf20Sopenharmony_ci /* only use complete blocks */ 2358c2ecf20Sopenharmony_ci n = nbytes & ~(AES_BLOCK_SIZE - 1); 2368c2ecf20Sopenharmony_ci cpacf_km(sctx->fc | modifier, sctx->key, 2378c2ecf20Sopenharmony_ci walk.dst.virt.addr, walk.src.virt.addr, n); 2388c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - n); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci return ret; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic int ecb_aes_encrypt(struct skcipher_request *req) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci return ecb_aes_crypt(req, 0); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic int ecb_aes_decrypt(struct skcipher_request *req) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci return ecb_aes_crypt(req, CPACF_DECRYPT); 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic int fallback_init_skcipher(struct crypto_skcipher *tfm) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci const char *name = crypto_tfm_alg_name(&tfm->base); 2568c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci sctx->fallback.skcipher = crypto_alloc_skcipher(name, 0, 2598c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_ASYNC); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (IS_ERR(sctx->fallback.skcipher)) { 2628c2ecf20Sopenharmony_ci pr_err("Allocating AES fallback algorithm %s failed\n", 2638c2ecf20Sopenharmony_ci name); 2648c2ecf20Sopenharmony_ci return PTR_ERR(sctx->fallback.skcipher); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) + 2688c2ecf20Sopenharmony_ci crypto_skcipher_reqsize(sctx->fallback.skcipher)); 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic void fallback_exit_skcipher(struct crypto_skcipher *tfm) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci crypto_free_skcipher(sctx->fallback.skcipher); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic struct skcipher_alg ecb_aes_alg = { 2808c2ecf20Sopenharmony_ci .base.cra_name = "ecb(aes)", 2818c2ecf20Sopenharmony_ci .base.cra_driver_name = "ecb-aes-s390", 2828c2ecf20Sopenharmony_ci .base.cra_priority = 401, /* combo: aes + ecb + 1 */ 2838c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK, 2848c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 2858c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_aes_ctx), 2868c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 2878c2ecf20Sopenharmony_ci .init = fallback_init_skcipher, 2888c2ecf20Sopenharmony_ci .exit = fallback_exit_skcipher, 2898c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 2908c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 2918c2ecf20Sopenharmony_ci .setkey = ecb_aes_set_key, 2928c2ecf20Sopenharmony_ci .encrypt = ecb_aes_encrypt, 2938c2ecf20Sopenharmony_ci .decrypt = ecb_aes_decrypt, 2948c2ecf20Sopenharmony_ci}; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic int cbc_aes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, 2978c2ecf20Sopenharmony_ci unsigned int key_len) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm); 3008c2ecf20Sopenharmony_ci unsigned long fc; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* Pick the correct function code based on the key length */ 3038c2ecf20Sopenharmony_ci fc = (key_len == 16) ? CPACF_KMC_AES_128 : 3048c2ecf20Sopenharmony_ci (key_len == 24) ? CPACF_KMC_AES_192 : 3058c2ecf20Sopenharmony_ci (key_len == 32) ? CPACF_KMC_AES_256 : 0; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* Check if the function code is available */ 3088c2ecf20Sopenharmony_ci sctx->fc = (fc && cpacf_test_func(&kmc_functions, fc)) ? fc : 0; 3098c2ecf20Sopenharmony_ci if (!sctx->fc) 3108c2ecf20Sopenharmony_ci return setkey_fallback_skcipher(tfm, in_key, key_len); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci sctx->key_len = key_len; 3138c2ecf20Sopenharmony_ci memcpy(sctx->key, in_key, key_len); 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int cbc_aes_crypt(struct skcipher_request *req, unsigned long modifier) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 3208c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm); 3218c2ecf20Sopenharmony_ci struct skcipher_walk walk; 3228c2ecf20Sopenharmony_ci unsigned int nbytes, n; 3238c2ecf20Sopenharmony_ci int ret; 3248c2ecf20Sopenharmony_ci struct { 3258c2ecf20Sopenharmony_ci u8 iv[AES_BLOCK_SIZE]; 3268c2ecf20Sopenharmony_ci u8 key[AES_MAX_KEY_SIZE]; 3278c2ecf20Sopenharmony_ci } param; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (unlikely(!sctx->fc)) 3308c2ecf20Sopenharmony_ci return fallback_skcipher_crypt(sctx, req, modifier); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 3338c2ecf20Sopenharmony_ci if (ret) 3348c2ecf20Sopenharmony_ci return ret; 3358c2ecf20Sopenharmony_ci memcpy(param.iv, walk.iv, AES_BLOCK_SIZE); 3368c2ecf20Sopenharmony_ci memcpy(param.key, sctx->key, sctx->key_len); 3378c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 3388c2ecf20Sopenharmony_ci /* only use complete blocks */ 3398c2ecf20Sopenharmony_ci n = nbytes & ~(AES_BLOCK_SIZE - 1); 3408c2ecf20Sopenharmony_ci cpacf_kmc(sctx->fc | modifier, ¶m, 3418c2ecf20Sopenharmony_ci walk.dst.virt.addr, walk.src.virt.addr, n); 3428c2ecf20Sopenharmony_ci memcpy(walk.iv, param.iv, AES_BLOCK_SIZE); 3438c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - n); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci memzero_explicit(¶m, sizeof(param)); 3468c2ecf20Sopenharmony_ci return ret; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int cbc_aes_encrypt(struct skcipher_request *req) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci return cbc_aes_crypt(req, 0); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int cbc_aes_decrypt(struct skcipher_request *req) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci return cbc_aes_crypt(req, CPACF_DECRYPT); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic struct skcipher_alg cbc_aes_alg = { 3608c2ecf20Sopenharmony_ci .base.cra_name = "cbc(aes)", 3618c2ecf20Sopenharmony_ci .base.cra_driver_name = "cbc-aes-s390", 3628c2ecf20Sopenharmony_ci .base.cra_priority = 402, /* ecb-aes-s390 + 1 */ 3638c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK, 3648c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 3658c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_aes_ctx), 3668c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 3678c2ecf20Sopenharmony_ci .init = fallback_init_skcipher, 3688c2ecf20Sopenharmony_ci .exit = fallback_exit_skcipher, 3698c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 3708c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 3718c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 3728c2ecf20Sopenharmony_ci .setkey = cbc_aes_set_key, 3738c2ecf20Sopenharmony_ci .encrypt = cbc_aes_encrypt, 3748c2ecf20Sopenharmony_ci .decrypt = cbc_aes_decrypt, 3758c2ecf20Sopenharmony_ci}; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int xts_fallback_setkey(struct crypto_skcipher *tfm, const u8 *key, 3788c2ecf20Sopenharmony_ci unsigned int len) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct s390_xts_ctx *xts_ctx = crypto_skcipher_ctx(tfm); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci crypto_skcipher_clear_flags(xts_ctx->fallback, CRYPTO_TFM_REQ_MASK); 3838c2ecf20Sopenharmony_ci crypto_skcipher_set_flags(xts_ctx->fallback, 3848c2ecf20Sopenharmony_ci crypto_skcipher_get_flags(tfm) & 3858c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 3868c2ecf20Sopenharmony_ci return crypto_skcipher_setkey(xts_ctx->fallback, key, len); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int xts_aes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, 3908c2ecf20Sopenharmony_ci unsigned int key_len) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct s390_xts_ctx *xts_ctx = crypto_skcipher_ctx(tfm); 3938c2ecf20Sopenharmony_ci unsigned long fc; 3948c2ecf20Sopenharmony_ci int err; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci err = xts_fallback_setkey(tfm, in_key, key_len); 3978c2ecf20Sopenharmony_ci if (err) 3988c2ecf20Sopenharmony_ci return err; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* In fips mode only 128 bit or 256 bit keys are valid */ 4018c2ecf20Sopenharmony_ci if (fips_enabled && key_len != 32 && key_len != 64) 4028c2ecf20Sopenharmony_ci return -EINVAL; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* Pick the correct function code based on the key length */ 4058c2ecf20Sopenharmony_ci fc = (key_len == 32) ? CPACF_KM_XTS_128 : 4068c2ecf20Sopenharmony_ci (key_len == 64) ? CPACF_KM_XTS_256 : 0; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* Check if the function code is available */ 4098c2ecf20Sopenharmony_ci xts_ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0; 4108c2ecf20Sopenharmony_ci if (!xts_ctx->fc) 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* Split the XTS key into the two subkeys */ 4148c2ecf20Sopenharmony_ci key_len = key_len / 2; 4158c2ecf20Sopenharmony_ci xts_ctx->key_len = key_len; 4168c2ecf20Sopenharmony_ci memcpy(xts_ctx->key, in_key, key_len); 4178c2ecf20Sopenharmony_ci memcpy(xts_ctx->pcc_key, in_key + key_len, key_len); 4188c2ecf20Sopenharmony_ci return 0; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int xts_aes_crypt(struct skcipher_request *req, unsigned long modifier) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 4248c2ecf20Sopenharmony_ci struct s390_xts_ctx *xts_ctx = crypto_skcipher_ctx(tfm); 4258c2ecf20Sopenharmony_ci struct skcipher_walk walk; 4268c2ecf20Sopenharmony_ci unsigned int offset, nbytes, n; 4278c2ecf20Sopenharmony_ci int ret; 4288c2ecf20Sopenharmony_ci struct { 4298c2ecf20Sopenharmony_ci u8 key[32]; 4308c2ecf20Sopenharmony_ci u8 tweak[16]; 4318c2ecf20Sopenharmony_ci u8 block[16]; 4328c2ecf20Sopenharmony_ci u8 bit[16]; 4338c2ecf20Sopenharmony_ci u8 xts[16]; 4348c2ecf20Sopenharmony_ci } pcc_param; 4358c2ecf20Sopenharmony_ci struct { 4368c2ecf20Sopenharmony_ci u8 key[32]; 4378c2ecf20Sopenharmony_ci u8 init[16]; 4388c2ecf20Sopenharmony_ci } xts_param; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (req->cryptlen < AES_BLOCK_SIZE) 4418c2ecf20Sopenharmony_ci return -EINVAL; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (unlikely(!xts_ctx->fc || (req->cryptlen % AES_BLOCK_SIZE) != 0)) { 4448c2ecf20Sopenharmony_ci struct skcipher_request *subreq = skcipher_request_ctx(req); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci *subreq = *req; 4478c2ecf20Sopenharmony_ci skcipher_request_set_tfm(subreq, xts_ctx->fallback); 4488c2ecf20Sopenharmony_ci return (modifier & CPACF_DECRYPT) ? 4498c2ecf20Sopenharmony_ci crypto_skcipher_decrypt(subreq) : 4508c2ecf20Sopenharmony_ci crypto_skcipher_encrypt(subreq); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 4548c2ecf20Sopenharmony_ci if (ret) 4558c2ecf20Sopenharmony_ci return ret; 4568c2ecf20Sopenharmony_ci offset = xts_ctx->key_len & 0x10; 4578c2ecf20Sopenharmony_ci memset(pcc_param.block, 0, sizeof(pcc_param.block)); 4588c2ecf20Sopenharmony_ci memset(pcc_param.bit, 0, sizeof(pcc_param.bit)); 4598c2ecf20Sopenharmony_ci memset(pcc_param.xts, 0, sizeof(pcc_param.xts)); 4608c2ecf20Sopenharmony_ci memcpy(pcc_param.tweak, walk.iv, sizeof(pcc_param.tweak)); 4618c2ecf20Sopenharmony_ci memcpy(pcc_param.key + offset, xts_ctx->pcc_key, xts_ctx->key_len); 4628c2ecf20Sopenharmony_ci cpacf_pcc(xts_ctx->fc, pcc_param.key + offset); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci memcpy(xts_param.key + offset, xts_ctx->key, xts_ctx->key_len); 4658c2ecf20Sopenharmony_ci memcpy(xts_param.init, pcc_param.xts, 16); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 4688c2ecf20Sopenharmony_ci /* only use complete blocks */ 4698c2ecf20Sopenharmony_ci n = nbytes & ~(AES_BLOCK_SIZE - 1); 4708c2ecf20Sopenharmony_ci cpacf_km(xts_ctx->fc | modifier, xts_param.key + offset, 4718c2ecf20Sopenharmony_ci walk.dst.virt.addr, walk.src.virt.addr, n); 4728c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - n); 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci memzero_explicit(&pcc_param, sizeof(pcc_param)); 4758c2ecf20Sopenharmony_ci memzero_explicit(&xts_param, sizeof(xts_param)); 4768c2ecf20Sopenharmony_ci return ret; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic int xts_aes_encrypt(struct skcipher_request *req) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci return xts_aes_crypt(req, 0); 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cistatic int xts_aes_decrypt(struct skcipher_request *req) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci return xts_aes_crypt(req, CPACF_DECRYPT); 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic int xts_fallback_init(struct crypto_skcipher *tfm) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci const char *name = crypto_tfm_alg_name(&tfm->base); 4928c2ecf20Sopenharmony_ci struct s390_xts_ctx *xts_ctx = crypto_skcipher_ctx(tfm); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci xts_ctx->fallback = crypto_alloc_skcipher(name, 0, 4958c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_ASYNC); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (IS_ERR(xts_ctx->fallback)) { 4988c2ecf20Sopenharmony_ci pr_err("Allocating XTS fallback algorithm %s failed\n", 4998c2ecf20Sopenharmony_ci name); 5008c2ecf20Sopenharmony_ci return PTR_ERR(xts_ctx->fallback); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) + 5038c2ecf20Sopenharmony_ci crypto_skcipher_reqsize(xts_ctx->fallback)); 5048c2ecf20Sopenharmony_ci return 0; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic void xts_fallback_exit(struct crypto_skcipher *tfm) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci struct s390_xts_ctx *xts_ctx = crypto_skcipher_ctx(tfm); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci crypto_free_skcipher(xts_ctx->fallback); 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic struct skcipher_alg xts_aes_alg = { 5158c2ecf20Sopenharmony_ci .base.cra_name = "xts(aes)", 5168c2ecf20Sopenharmony_ci .base.cra_driver_name = "xts-aes-s390", 5178c2ecf20Sopenharmony_ci .base.cra_priority = 402, /* ecb-aes-s390 + 1 */ 5188c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK, 5198c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 5208c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_xts_ctx), 5218c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 5228c2ecf20Sopenharmony_ci .init = xts_fallback_init, 5238c2ecf20Sopenharmony_ci .exit = xts_fallback_exit, 5248c2ecf20Sopenharmony_ci .min_keysize = 2 * AES_MIN_KEY_SIZE, 5258c2ecf20Sopenharmony_ci .max_keysize = 2 * AES_MAX_KEY_SIZE, 5268c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 5278c2ecf20Sopenharmony_ci .setkey = xts_aes_set_key, 5288c2ecf20Sopenharmony_ci .encrypt = xts_aes_encrypt, 5298c2ecf20Sopenharmony_ci .decrypt = xts_aes_decrypt, 5308c2ecf20Sopenharmony_ci}; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic int ctr_aes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, 5338c2ecf20Sopenharmony_ci unsigned int key_len) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm); 5368c2ecf20Sopenharmony_ci unsigned long fc; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* Pick the correct function code based on the key length */ 5398c2ecf20Sopenharmony_ci fc = (key_len == 16) ? CPACF_KMCTR_AES_128 : 5408c2ecf20Sopenharmony_ci (key_len == 24) ? CPACF_KMCTR_AES_192 : 5418c2ecf20Sopenharmony_ci (key_len == 32) ? CPACF_KMCTR_AES_256 : 0; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* Check if the function code is available */ 5448c2ecf20Sopenharmony_ci sctx->fc = (fc && cpacf_test_func(&kmctr_functions, fc)) ? fc : 0; 5458c2ecf20Sopenharmony_ci if (!sctx->fc) 5468c2ecf20Sopenharmony_ci return setkey_fallback_skcipher(tfm, in_key, key_len); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci sctx->key_len = key_len; 5498c2ecf20Sopenharmony_ci memcpy(sctx->key, in_key, key_len); 5508c2ecf20Sopenharmony_ci return 0; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci unsigned int i, n; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* only use complete blocks, max. PAGE_SIZE */ 5588c2ecf20Sopenharmony_ci memcpy(ctrptr, iv, AES_BLOCK_SIZE); 5598c2ecf20Sopenharmony_ci n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(AES_BLOCK_SIZE - 1); 5608c2ecf20Sopenharmony_ci for (i = (n / AES_BLOCK_SIZE) - 1; i > 0; i--) { 5618c2ecf20Sopenharmony_ci memcpy(ctrptr + AES_BLOCK_SIZE, ctrptr, AES_BLOCK_SIZE); 5628c2ecf20Sopenharmony_ci crypto_inc(ctrptr + AES_BLOCK_SIZE, AES_BLOCK_SIZE); 5638c2ecf20Sopenharmony_ci ctrptr += AES_BLOCK_SIZE; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci return n; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int ctr_aes_crypt(struct skcipher_request *req) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 5718c2ecf20Sopenharmony_ci struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm); 5728c2ecf20Sopenharmony_ci u8 buf[AES_BLOCK_SIZE], *ctrptr; 5738c2ecf20Sopenharmony_ci struct skcipher_walk walk; 5748c2ecf20Sopenharmony_ci unsigned int n, nbytes; 5758c2ecf20Sopenharmony_ci int ret, locked; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (unlikely(!sctx->fc)) 5788c2ecf20Sopenharmony_ci return fallback_skcipher_crypt(sctx, req, 0); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci locked = mutex_trylock(&ctrblk_lock); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 5838c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) { 5848c2ecf20Sopenharmony_ci n = AES_BLOCK_SIZE; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (nbytes >= 2*AES_BLOCK_SIZE && locked) 5878c2ecf20Sopenharmony_ci n = __ctrblk_init(ctrblk, walk.iv, nbytes); 5888c2ecf20Sopenharmony_ci ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk.iv; 5898c2ecf20Sopenharmony_ci cpacf_kmctr(sctx->fc, sctx->key, walk.dst.virt.addr, 5908c2ecf20Sopenharmony_ci walk.src.virt.addr, n, ctrptr); 5918c2ecf20Sopenharmony_ci if (ctrptr == ctrblk) 5928c2ecf20Sopenharmony_ci memcpy(walk.iv, ctrptr + n - AES_BLOCK_SIZE, 5938c2ecf20Sopenharmony_ci AES_BLOCK_SIZE); 5948c2ecf20Sopenharmony_ci crypto_inc(walk.iv, AES_BLOCK_SIZE); 5958c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - n); 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci if (locked) 5988c2ecf20Sopenharmony_ci mutex_unlock(&ctrblk_lock); 5998c2ecf20Sopenharmony_ci /* 6008c2ecf20Sopenharmony_ci * final block may be < AES_BLOCK_SIZE, copy only nbytes 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci if (nbytes) { 6038c2ecf20Sopenharmony_ci memset(buf, 0, AES_BLOCK_SIZE); 6048c2ecf20Sopenharmony_ci memcpy(buf, walk.src.virt.addr, nbytes); 6058c2ecf20Sopenharmony_ci cpacf_kmctr(sctx->fc, sctx->key, buf, buf, 6068c2ecf20Sopenharmony_ci AES_BLOCK_SIZE, walk.iv); 6078c2ecf20Sopenharmony_ci memcpy(walk.dst.virt.addr, buf, nbytes); 6088c2ecf20Sopenharmony_ci crypto_inc(walk.iv, AES_BLOCK_SIZE); 6098c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, 0); 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci return ret; 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic struct skcipher_alg ctr_aes_alg = { 6168c2ecf20Sopenharmony_ci .base.cra_name = "ctr(aes)", 6178c2ecf20Sopenharmony_ci .base.cra_driver_name = "ctr-aes-s390", 6188c2ecf20Sopenharmony_ci .base.cra_priority = 402, /* ecb-aes-s390 + 1 */ 6198c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK, 6208c2ecf20Sopenharmony_ci .base.cra_blocksize = 1, 6218c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_aes_ctx), 6228c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 6238c2ecf20Sopenharmony_ci .init = fallback_init_skcipher, 6248c2ecf20Sopenharmony_ci .exit = fallback_exit_skcipher, 6258c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 6268c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 6278c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 6288c2ecf20Sopenharmony_ci .setkey = ctr_aes_set_key, 6298c2ecf20Sopenharmony_ci .encrypt = ctr_aes_crypt, 6308c2ecf20Sopenharmony_ci .decrypt = ctr_aes_crypt, 6318c2ecf20Sopenharmony_ci .chunksize = AES_BLOCK_SIZE, 6328c2ecf20Sopenharmony_ci}; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic int gcm_aes_setkey(struct crypto_aead *tfm, const u8 *key, 6358c2ecf20Sopenharmony_ci unsigned int keylen) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci struct s390_aes_ctx *ctx = crypto_aead_ctx(tfm); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci switch (keylen) { 6408c2ecf20Sopenharmony_ci case AES_KEYSIZE_128: 6418c2ecf20Sopenharmony_ci ctx->fc = CPACF_KMA_GCM_AES_128; 6428c2ecf20Sopenharmony_ci break; 6438c2ecf20Sopenharmony_ci case AES_KEYSIZE_192: 6448c2ecf20Sopenharmony_ci ctx->fc = CPACF_KMA_GCM_AES_192; 6458c2ecf20Sopenharmony_ci break; 6468c2ecf20Sopenharmony_ci case AES_KEYSIZE_256: 6478c2ecf20Sopenharmony_ci ctx->fc = CPACF_KMA_GCM_AES_256; 6488c2ecf20Sopenharmony_ci break; 6498c2ecf20Sopenharmony_ci default: 6508c2ecf20Sopenharmony_ci return -EINVAL; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci memcpy(ctx->key, key, keylen); 6548c2ecf20Sopenharmony_ci ctx->key_len = keylen; 6558c2ecf20Sopenharmony_ci return 0; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int gcm_aes_setauthsize(struct crypto_aead *tfm, unsigned int authsize) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci switch (authsize) { 6618c2ecf20Sopenharmony_ci case 4: 6628c2ecf20Sopenharmony_ci case 8: 6638c2ecf20Sopenharmony_ci case 12: 6648c2ecf20Sopenharmony_ci case 13: 6658c2ecf20Sopenharmony_ci case 14: 6668c2ecf20Sopenharmony_ci case 15: 6678c2ecf20Sopenharmony_ci case 16: 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci default: 6708c2ecf20Sopenharmony_ci return -EINVAL; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci return 0; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic void gcm_walk_start(struct gcm_sg_walk *gw, struct scatterlist *sg, 6778c2ecf20Sopenharmony_ci unsigned int len) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci memset(gw, 0, sizeof(*gw)); 6808c2ecf20Sopenharmony_ci gw->walk_bytes_remain = len; 6818c2ecf20Sopenharmony_ci scatterwalk_start(&gw->walk, sg); 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic inline unsigned int _gcm_sg_clamp_and_map(struct gcm_sg_walk *gw) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct scatterlist *nextsg; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci gw->walk_bytes = scatterwalk_clamp(&gw->walk, gw->walk_bytes_remain); 6898c2ecf20Sopenharmony_ci while (!gw->walk_bytes) { 6908c2ecf20Sopenharmony_ci nextsg = sg_next(gw->walk.sg); 6918c2ecf20Sopenharmony_ci if (!nextsg) 6928c2ecf20Sopenharmony_ci return 0; 6938c2ecf20Sopenharmony_ci scatterwalk_start(&gw->walk, nextsg); 6948c2ecf20Sopenharmony_ci gw->walk_bytes = scatterwalk_clamp(&gw->walk, 6958c2ecf20Sopenharmony_ci gw->walk_bytes_remain); 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci gw->walk_ptr = scatterwalk_map(&gw->walk); 6988c2ecf20Sopenharmony_ci return gw->walk_bytes; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic inline void _gcm_sg_unmap_and_advance(struct gcm_sg_walk *gw, 7028c2ecf20Sopenharmony_ci unsigned int nbytes) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci gw->walk_bytes_remain -= nbytes; 7058c2ecf20Sopenharmony_ci scatterwalk_unmap(gw->walk_ptr); 7068c2ecf20Sopenharmony_ci scatterwalk_advance(&gw->walk, nbytes); 7078c2ecf20Sopenharmony_ci scatterwalk_done(&gw->walk, 0, gw->walk_bytes_remain); 7088c2ecf20Sopenharmony_ci gw->walk_ptr = NULL; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic int gcm_in_walk_go(struct gcm_sg_walk *gw, unsigned int minbytesneeded) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci int n; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci if (gw->buf_bytes && gw->buf_bytes >= minbytesneeded) { 7168c2ecf20Sopenharmony_ci gw->ptr = gw->buf; 7178c2ecf20Sopenharmony_ci gw->nbytes = gw->buf_bytes; 7188c2ecf20Sopenharmony_ci goto out; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (gw->walk_bytes_remain == 0) { 7228c2ecf20Sopenharmony_ci gw->ptr = NULL; 7238c2ecf20Sopenharmony_ci gw->nbytes = 0; 7248c2ecf20Sopenharmony_ci goto out; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (!_gcm_sg_clamp_and_map(gw)) { 7288c2ecf20Sopenharmony_ci gw->ptr = NULL; 7298c2ecf20Sopenharmony_ci gw->nbytes = 0; 7308c2ecf20Sopenharmony_ci goto out; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci if (!gw->buf_bytes && gw->walk_bytes >= minbytesneeded) { 7348c2ecf20Sopenharmony_ci gw->ptr = gw->walk_ptr; 7358c2ecf20Sopenharmony_ci gw->nbytes = gw->walk_bytes; 7368c2ecf20Sopenharmony_ci goto out; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci while (1) { 7408c2ecf20Sopenharmony_ci n = min(gw->walk_bytes, AES_BLOCK_SIZE - gw->buf_bytes); 7418c2ecf20Sopenharmony_ci memcpy(gw->buf + gw->buf_bytes, gw->walk_ptr, n); 7428c2ecf20Sopenharmony_ci gw->buf_bytes += n; 7438c2ecf20Sopenharmony_ci _gcm_sg_unmap_and_advance(gw, n); 7448c2ecf20Sopenharmony_ci if (gw->buf_bytes >= minbytesneeded) { 7458c2ecf20Sopenharmony_ci gw->ptr = gw->buf; 7468c2ecf20Sopenharmony_ci gw->nbytes = gw->buf_bytes; 7478c2ecf20Sopenharmony_ci goto out; 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci if (!_gcm_sg_clamp_and_map(gw)) { 7508c2ecf20Sopenharmony_ci gw->ptr = NULL; 7518c2ecf20Sopenharmony_ci gw->nbytes = 0; 7528c2ecf20Sopenharmony_ci goto out; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ciout: 7578c2ecf20Sopenharmony_ci return gw->nbytes; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic int gcm_out_walk_go(struct gcm_sg_walk *gw, unsigned int minbytesneeded) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci if (gw->walk_bytes_remain == 0) { 7638c2ecf20Sopenharmony_ci gw->ptr = NULL; 7648c2ecf20Sopenharmony_ci gw->nbytes = 0; 7658c2ecf20Sopenharmony_ci goto out; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (!_gcm_sg_clamp_and_map(gw)) { 7698c2ecf20Sopenharmony_ci gw->ptr = NULL; 7708c2ecf20Sopenharmony_ci gw->nbytes = 0; 7718c2ecf20Sopenharmony_ci goto out; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (gw->walk_bytes >= minbytesneeded) { 7758c2ecf20Sopenharmony_ci gw->ptr = gw->walk_ptr; 7768c2ecf20Sopenharmony_ci gw->nbytes = gw->walk_bytes; 7778c2ecf20Sopenharmony_ci goto out; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci scatterwalk_unmap(gw->walk_ptr); 7818c2ecf20Sopenharmony_ci gw->walk_ptr = NULL; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci gw->ptr = gw->buf; 7848c2ecf20Sopenharmony_ci gw->nbytes = sizeof(gw->buf); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ciout: 7878c2ecf20Sopenharmony_ci return gw->nbytes; 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic int gcm_in_walk_done(struct gcm_sg_walk *gw, unsigned int bytesdone) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci if (gw->ptr == NULL) 7938c2ecf20Sopenharmony_ci return 0; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci if (gw->ptr == gw->buf) { 7968c2ecf20Sopenharmony_ci int n = gw->buf_bytes - bytesdone; 7978c2ecf20Sopenharmony_ci if (n > 0) { 7988c2ecf20Sopenharmony_ci memmove(gw->buf, gw->buf + bytesdone, n); 7998c2ecf20Sopenharmony_ci gw->buf_bytes = n; 8008c2ecf20Sopenharmony_ci } else 8018c2ecf20Sopenharmony_ci gw->buf_bytes = 0; 8028c2ecf20Sopenharmony_ci } else 8038c2ecf20Sopenharmony_ci _gcm_sg_unmap_and_advance(gw, bytesdone); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return bytesdone; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic int gcm_out_walk_done(struct gcm_sg_walk *gw, unsigned int bytesdone) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci int i, n; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (gw->ptr == NULL) 8138c2ecf20Sopenharmony_ci return 0; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (gw->ptr == gw->buf) { 8168c2ecf20Sopenharmony_ci for (i = 0; i < bytesdone; i += n) { 8178c2ecf20Sopenharmony_ci if (!_gcm_sg_clamp_and_map(gw)) 8188c2ecf20Sopenharmony_ci return i; 8198c2ecf20Sopenharmony_ci n = min(gw->walk_bytes, bytesdone - i); 8208c2ecf20Sopenharmony_ci memcpy(gw->walk_ptr, gw->buf + i, n); 8218c2ecf20Sopenharmony_ci _gcm_sg_unmap_and_advance(gw, n); 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci } else 8248c2ecf20Sopenharmony_ci _gcm_sg_unmap_and_advance(gw, bytesdone); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci return bytesdone; 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_cistatic int gcm_aes_crypt(struct aead_request *req, unsigned int flags) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 8328c2ecf20Sopenharmony_ci struct s390_aes_ctx *ctx = crypto_aead_ctx(tfm); 8338c2ecf20Sopenharmony_ci unsigned int ivsize = crypto_aead_ivsize(tfm); 8348c2ecf20Sopenharmony_ci unsigned int taglen = crypto_aead_authsize(tfm); 8358c2ecf20Sopenharmony_ci unsigned int aadlen = req->assoclen; 8368c2ecf20Sopenharmony_ci unsigned int pclen = req->cryptlen; 8378c2ecf20Sopenharmony_ci int ret = 0; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci unsigned int n, len, in_bytes, out_bytes, 8408c2ecf20Sopenharmony_ci min_bytes, bytes, aad_bytes, pc_bytes; 8418c2ecf20Sopenharmony_ci struct gcm_sg_walk gw_in, gw_out; 8428c2ecf20Sopenharmony_ci u8 tag[GHASH_DIGEST_SIZE]; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci struct { 8458c2ecf20Sopenharmony_ci u32 _[3]; /* reserved */ 8468c2ecf20Sopenharmony_ci u32 cv; /* Counter Value */ 8478c2ecf20Sopenharmony_ci u8 t[GHASH_DIGEST_SIZE];/* Tag */ 8488c2ecf20Sopenharmony_ci u8 h[AES_BLOCK_SIZE]; /* Hash-subkey */ 8498c2ecf20Sopenharmony_ci u64 taadl; /* Total AAD Length */ 8508c2ecf20Sopenharmony_ci u64 tpcl; /* Total Plain-/Cipher-text Length */ 8518c2ecf20Sopenharmony_ci u8 j0[GHASH_BLOCK_SIZE];/* initial counter value */ 8528c2ecf20Sopenharmony_ci u8 k[AES_MAX_KEY_SIZE]; /* Key */ 8538c2ecf20Sopenharmony_ci } param; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* 8568c2ecf20Sopenharmony_ci * encrypt 8578c2ecf20Sopenharmony_ci * req->src: aad||plaintext 8588c2ecf20Sopenharmony_ci * req->dst: aad||ciphertext||tag 8598c2ecf20Sopenharmony_ci * decrypt 8608c2ecf20Sopenharmony_ci * req->src: aad||ciphertext||tag 8618c2ecf20Sopenharmony_ci * req->dst: aad||plaintext, return 0 or -EBADMSG 8628c2ecf20Sopenharmony_ci * aad, plaintext and ciphertext may be empty. 8638c2ecf20Sopenharmony_ci */ 8648c2ecf20Sopenharmony_ci if (flags & CPACF_DECRYPT) 8658c2ecf20Sopenharmony_ci pclen -= taglen; 8668c2ecf20Sopenharmony_ci len = aadlen + pclen; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci memset(¶m, 0, sizeof(param)); 8698c2ecf20Sopenharmony_ci param.cv = 1; 8708c2ecf20Sopenharmony_ci param.taadl = aadlen * 8; 8718c2ecf20Sopenharmony_ci param.tpcl = pclen * 8; 8728c2ecf20Sopenharmony_ci memcpy(param.j0, req->iv, ivsize); 8738c2ecf20Sopenharmony_ci *(u32 *)(param.j0 + ivsize) = 1; 8748c2ecf20Sopenharmony_ci memcpy(param.k, ctx->key, ctx->key_len); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci gcm_walk_start(&gw_in, req->src, len); 8778c2ecf20Sopenharmony_ci gcm_walk_start(&gw_out, req->dst, len); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci do { 8808c2ecf20Sopenharmony_ci min_bytes = min_t(unsigned int, 8818c2ecf20Sopenharmony_ci aadlen > 0 ? aadlen : pclen, AES_BLOCK_SIZE); 8828c2ecf20Sopenharmony_ci in_bytes = gcm_in_walk_go(&gw_in, min_bytes); 8838c2ecf20Sopenharmony_ci out_bytes = gcm_out_walk_go(&gw_out, min_bytes); 8848c2ecf20Sopenharmony_ci bytes = min(in_bytes, out_bytes); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (aadlen + pclen <= bytes) { 8878c2ecf20Sopenharmony_ci aad_bytes = aadlen; 8888c2ecf20Sopenharmony_ci pc_bytes = pclen; 8898c2ecf20Sopenharmony_ci flags |= CPACF_KMA_LAAD | CPACF_KMA_LPC; 8908c2ecf20Sopenharmony_ci } else { 8918c2ecf20Sopenharmony_ci if (aadlen <= bytes) { 8928c2ecf20Sopenharmony_ci aad_bytes = aadlen; 8938c2ecf20Sopenharmony_ci pc_bytes = (bytes - aadlen) & 8948c2ecf20Sopenharmony_ci ~(AES_BLOCK_SIZE - 1); 8958c2ecf20Sopenharmony_ci flags |= CPACF_KMA_LAAD; 8968c2ecf20Sopenharmony_ci } else { 8978c2ecf20Sopenharmony_ci aad_bytes = bytes & ~(AES_BLOCK_SIZE - 1); 8988c2ecf20Sopenharmony_ci pc_bytes = 0; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (aad_bytes > 0) 9038c2ecf20Sopenharmony_ci memcpy(gw_out.ptr, gw_in.ptr, aad_bytes); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci cpacf_kma(ctx->fc | flags, ¶m, 9068c2ecf20Sopenharmony_ci gw_out.ptr + aad_bytes, 9078c2ecf20Sopenharmony_ci gw_in.ptr + aad_bytes, pc_bytes, 9088c2ecf20Sopenharmony_ci gw_in.ptr, aad_bytes); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci n = aad_bytes + pc_bytes; 9118c2ecf20Sopenharmony_ci if (gcm_in_walk_done(&gw_in, n) != n) 9128c2ecf20Sopenharmony_ci return -ENOMEM; 9138c2ecf20Sopenharmony_ci if (gcm_out_walk_done(&gw_out, n) != n) 9148c2ecf20Sopenharmony_ci return -ENOMEM; 9158c2ecf20Sopenharmony_ci aadlen -= aad_bytes; 9168c2ecf20Sopenharmony_ci pclen -= pc_bytes; 9178c2ecf20Sopenharmony_ci } while (aadlen + pclen > 0); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (flags & CPACF_DECRYPT) { 9208c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(tag, req->src, len, taglen, 0); 9218c2ecf20Sopenharmony_ci if (crypto_memneq(tag, param.t, taglen)) 9228c2ecf20Sopenharmony_ci ret = -EBADMSG; 9238c2ecf20Sopenharmony_ci } else 9248c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(param.t, req->dst, len, taglen, 1); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci memzero_explicit(¶m, sizeof(param)); 9278c2ecf20Sopenharmony_ci return ret; 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic int gcm_aes_encrypt(struct aead_request *req) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci return gcm_aes_crypt(req, CPACF_ENCRYPT); 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic int gcm_aes_decrypt(struct aead_request *req) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci return gcm_aes_crypt(req, CPACF_DECRYPT); 9388c2ecf20Sopenharmony_ci} 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic struct aead_alg gcm_aes_aead = { 9418c2ecf20Sopenharmony_ci .setkey = gcm_aes_setkey, 9428c2ecf20Sopenharmony_ci .setauthsize = gcm_aes_setauthsize, 9438c2ecf20Sopenharmony_ci .encrypt = gcm_aes_encrypt, 9448c2ecf20Sopenharmony_ci .decrypt = gcm_aes_decrypt, 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci .ivsize = GHASH_BLOCK_SIZE - sizeof(u32), 9478c2ecf20Sopenharmony_ci .maxauthsize = GHASH_DIGEST_SIZE, 9488c2ecf20Sopenharmony_ci .chunksize = AES_BLOCK_SIZE, 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci .base = { 9518c2ecf20Sopenharmony_ci .cra_blocksize = 1, 9528c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct s390_aes_ctx), 9538c2ecf20Sopenharmony_ci .cra_priority = 900, 9548c2ecf20Sopenharmony_ci .cra_name = "gcm(aes)", 9558c2ecf20Sopenharmony_ci .cra_driver_name = "gcm-aes-s390", 9568c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 9578c2ecf20Sopenharmony_ci }, 9588c2ecf20Sopenharmony_ci}; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic struct crypto_alg *aes_s390_alg; 9618c2ecf20Sopenharmony_cistatic struct skcipher_alg *aes_s390_skcipher_algs[4]; 9628c2ecf20Sopenharmony_cistatic int aes_s390_skciphers_num; 9638c2ecf20Sopenharmony_cistatic struct aead_alg *aes_s390_aead_alg; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cistatic int aes_s390_register_skcipher(struct skcipher_alg *alg) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci int ret; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci ret = crypto_register_skcipher(alg); 9708c2ecf20Sopenharmony_ci if (!ret) 9718c2ecf20Sopenharmony_ci aes_s390_skcipher_algs[aes_s390_skciphers_num++] = alg; 9728c2ecf20Sopenharmony_ci return ret; 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic void aes_s390_fini(void) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci if (aes_s390_alg) 9788c2ecf20Sopenharmony_ci crypto_unregister_alg(aes_s390_alg); 9798c2ecf20Sopenharmony_ci while (aes_s390_skciphers_num--) 9808c2ecf20Sopenharmony_ci crypto_unregister_skcipher(aes_s390_skcipher_algs[aes_s390_skciphers_num]); 9818c2ecf20Sopenharmony_ci if (ctrblk) 9828c2ecf20Sopenharmony_ci free_page((unsigned long) ctrblk); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (aes_s390_aead_alg) 9858c2ecf20Sopenharmony_ci crypto_unregister_aead(aes_s390_aead_alg); 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic int __init aes_s390_init(void) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci int ret; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci /* Query available functions for KM, KMC, KMCTR and KMA */ 9938c2ecf20Sopenharmony_ci cpacf_query(CPACF_KM, &km_functions); 9948c2ecf20Sopenharmony_ci cpacf_query(CPACF_KMC, &kmc_functions); 9958c2ecf20Sopenharmony_ci cpacf_query(CPACF_KMCTR, &kmctr_functions); 9968c2ecf20Sopenharmony_ci cpacf_query(CPACF_KMA, &kma_functions); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (cpacf_test_func(&km_functions, CPACF_KM_AES_128) || 9998c2ecf20Sopenharmony_ci cpacf_test_func(&km_functions, CPACF_KM_AES_192) || 10008c2ecf20Sopenharmony_ci cpacf_test_func(&km_functions, CPACF_KM_AES_256)) { 10018c2ecf20Sopenharmony_ci ret = crypto_register_alg(&aes_alg); 10028c2ecf20Sopenharmony_ci if (ret) 10038c2ecf20Sopenharmony_ci goto out_err; 10048c2ecf20Sopenharmony_ci aes_s390_alg = &aes_alg; 10058c2ecf20Sopenharmony_ci ret = aes_s390_register_skcipher(&ecb_aes_alg); 10068c2ecf20Sopenharmony_ci if (ret) 10078c2ecf20Sopenharmony_ci goto out_err; 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci if (cpacf_test_func(&kmc_functions, CPACF_KMC_AES_128) || 10118c2ecf20Sopenharmony_ci cpacf_test_func(&kmc_functions, CPACF_KMC_AES_192) || 10128c2ecf20Sopenharmony_ci cpacf_test_func(&kmc_functions, CPACF_KMC_AES_256)) { 10138c2ecf20Sopenharmony_ci ret = aes_s390_register_skcipher(&cbc_aes_alg); 10148c2ecf20Sopenharmony_ci if (ret) 10158c2ecf20Sopenharmony_ci goto out_err; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci if (cpacf_test_func(&km_functions, CPACF_KM_XTS_128) || 10198c2ecf20Sopenharmony_ci cpacf_test_func(&km_functions, CPACF_KM_XTS_256)) { 10208c2ecf20Sopenharmony_ci ret = aes_s390_register_skcipher(&xts_aes_alg); 10218c2ecf20Sopenharmony_ci if (ret) 10228c2ecf20Sopenharmony_ci goto out_err; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_AES_128) || 10268c2ecf20Sopenharmony_ci cpacf_test_func(&kmctr_functions, CPACF_KMCTR_AES_192) || 10278c2ecf20Sopenharmony_ci cpacf_test_func(&kmctr_functions, CPACF_KMCTR_AES_256)) { 10288c2ecf20Sopenharmony_ci ctrblk = (u8 *) __get_free_page(GFP_KERNEL); 10298c2ecf20Sopenharmony_ci if (!ctrblk) { 10308c2ecf20Sopenharmony_ci ret = -ENOMEM; 10318c2ecf20Sopenharmony_ci goto out_err; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci ret = aes_s390_register_skcipher(&ctr_aes_alg); 10348c2ecf20Sopenharmony_ci if (ret) 10358c2ecf20Sopenharmony_ci goto out_err; 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci if (cpacf_test_func(&kma_functions, CPACF_KMA_GCM_AES_128) || 10398c2ecf20Sopenharmony_ci cpacf_test_func(&kma_functions, CPACF_KMA_GCM_AES_192) || 10408c2ecf20Sopenharmony_ci cpacf_test_func(&kma_functions, CPACF_KMA_GCM_AES_256)) { 10418c2ecf20Sopenharmony_ci ret = crypto_register_aead(&gcm_aes_aead); 10428c2ecf20Sopenharmony_ci if (ret) 10438c2ecf20Sopenharmony_ci goto out_err; 10448c2ecf20Sopenharmony_ci aes_s390_aead_alg = &gcm_aes_aead; 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci return 0; 10488c2ecf20Sopenharmony_ciout_err: 10498c2ecf20Sopenharmony_ci aes_s390_fini(); 10508c2ecf20Sopenharmony_ci return ret; 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cimodule_cpu_feature_match(MSA, aes_s390_init); 10548c2ecf20Sopenharmony_cimodule_exit(aes_s390_fini); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("aes-all"); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); 10598c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1060