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 with protected keys. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * s390 Version: 88c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2017,2020 98c2ecf20Sopenharmony_ci * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 108c2ecf20Sopenharmony_ci * Harald Freudenberger <freude@de.ibm.com> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "paes_s390" 148c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <crypto/aes.h> 178c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 188c2ecf20Sopenharmony_ci#include <linux/bug.h> 198c2ecf20Sopenharmony_ci#include <linux/err.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/cpufeature.h> 228c2ecf20Sopenharmony_ci#include <linux/init.h> 238c2ecf20Sopenharmony_ci#include <linux/mutex.h> 248c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 258c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 268c2ecf20Sopenharmony_ci#include <crypto/xts.h> 278c2ecf20Sopenharmony_ci#include <asm/cpacf.h> 288c2ecf20Sopenharmony_ci#include <asm/pkey.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * Key blobs smaller/bigger than these defines are rejected 328c2ecf20Sopenharmony_ci * by the common code even before the individual setkey function 338c2ecf20Sopenharmony_ci * is called. As paes can handle different kinds of key blobs 348c2ecf20Sopenharmony_ci * and padding is also possible, the limits need to be generous. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci#define PAES_MIN_KEYSIZE 16 378c2ecf20Sopenharmony_ci#define PAES_MAX_KEYSIZE MAXEP11AESKEYBLOBSIZE 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic u8 *ctrblk; 408c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(ctrblk_lock); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic cpacf_mask_t km_functions, kmc_functions, kmctr_functions; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct key_blob { 458c2ecf20Sopenharmony_ci /* 468c2ecf20Sopenharmony_ci * Small keys will be stored in the keybuf. Larger keys are 478c2ecf20Sopenharmony_ci * stored in extra allocated memory. In both cases does 488c2ecf20Sopenharmony_ci * key point to the memory where the key is stored. 498c2ecf20Sopenharmony_ci * The code distinguishes by checking keylen against 508c2ecf20Sopenharmony_ci * sizeof(keybuf). See the two following helper functions. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci u8 *key; 538c2ecf20Sopenharmony_ci u8 keybuf[128]; 548c2ecf20Sopenharmony_ci unsigned int keylen; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic inline int _key_to_kb(struct key_blob *kb, 588c2ecf20Sopenharmony_ci const u8 *key, 598c2ecf20Sopenharmony_ci unsigned int keylen) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct clearkey_header { 628c2ecf20Sopenharmony_ci u8 type; 638c2ecf20Sopenharmony_ci u8 res0[3]; 648c2ecf20Sopenharmony_ci u8 version; 658c2ecf20Sopenharmony_ci u8 res1[3]; 668c2ecf20Sopenharmony_ci u32 keytype; 678c2ecf20Sopenharmony_ci u32 len; 688c2ecf20Sopenharmony_ci } __packed * h; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci switch (keylen) { 718c2ecf20Sopenharmony_ci case 16: 728c2ecf20Sopenharmony_ci case 24: 738c2ecf20Sopenharmony_ci case 32: 748c2ecf20Sopenharmony_ci /* clear key value, prepare pkey clear key token in keybuf */ 758c2ecf20Sopenharmony_ci memset(kb->keybuf, 0, sizeof(kb->keybuf)); 768c2ecf20Sopenharmony_ci h = (struct clearkey_header *) kb->keybuf; 778c2ecf20Sopenharmony_ci h->version = 0x02; /* TOKVER_CLEAR_KEY */ 788c2ecf20Sopenharmony_ci h->keytype = (keylen - 8) >> 3; 798c2ecf20Sopenharmony_ci h->len = keylen; 808c2ecf20Sopenharmony_ci memcpy(kb->keybuf + sizeof(*h), key, keylen); 818c2ecf20Sopenharmony_ci kb->keylen = sizeof(*h) + keylen; 828c2ecf20Sopenharmony_ci kb->key = kb->keybuf; 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci default: 858c2ecf20Sopenharmony_ci /* other key material, let pkey handle this */ 868c2ecf20Sopenharmony_ci if (keylen <= sizeof(kb->keybuf)) 878c2ecf20Sopenharmony_ci kb->key = kb->keybuf; 888c2ecf20Sopenharmony_ci else { 898c2ecf20Sopenharmony_ci kb->key = kmalloc(keylen, GFP_KERNEL); 908c2ecf20Sopenharmony_ci if (!kb->key) 918c2ecf20Sopenharmony_ci return -ENOMEM; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci memcpy(kb->key, key, keylen); 948c2ecf20Sopenharmony_ci kb->keylen = keylen; 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return 0; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic inline void _free_kb_keybuf(struct key_blob *kb) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci if (kb->key && kb->key != kb->keybuf 1048c2ecf20Sopenharmony_ci && kb->keylen > sizeof(kb->keybuf)) { 1058c2ecf20Sopenharmony_ci kfree(kb->key); 1068c2ecf20Sopenharmony_ci kb->key = NULL; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistruct s390_paes_ctx { 1118c2ecf20Sopenharmony_ci struct key_blob kb; 1128c2ecf20Sopenharmony_ci struct pkey_protkey pk; 1138c2ecf20Sopenharmony_ci spinlock_t pk_lock; 1148c2ecf20Sopenharmony_ci unsigned long fc; 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistruct s390_pxts_ctx { 1188c2ecf20Sopenharmony_ci struct key_blob kb[2]; 1198c2ecf20Sopenharmony_ci struct pkey_protkey pk[2]; 1208c2ecf20Sopenharmony_ci spinlock_t pk_lock; 1218c2ecf20Sopenharmony_ci unsigned long fc; 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic inline int __paes_keyblob2pkey(struct key_blob *kb, 1258c2ecf20Sopenharmony_ci struct pkey_protkey *pk) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci int i, ret; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* try three times in case of failure */ 1308c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 1318c2ecf20Sopenharmony_ci ret = pkey_keyblob2pkey(kb->key, kb->keylen, pk); 1328c2ecf20Sopenharmony_ci if (ret == 0) 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return ret; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic inline int __paes_convert_key(struct s390_paes_ctx *ctx) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct pkey_protkey pkey; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (__paes_keyblob2pkey(&ctx->kb, &pkey)) 1448c2ecf20Sopenharmony_ci return -EINVAL; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 1478c2ecf20Sopenharmony_ci memcpy(&ctx->pk, &pkey, sizeof(pkey)); 1488c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return 0; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic int ecb_paes_init(struct crypto_skcipher *tfm) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci ctx->kb.key = NULL; 1588c2ecf20Sopenharmony_ci spin_lock_init(&ctx->pk_lock); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void ecb_paes_exit(struct crypto_skcipher *tfm) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci _free_kb_keybuf(&ctx->kb); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic inline int __ecb_paes_set_key(struct s390_paes_ctx *ctx) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci unsigned long fc; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (__paes_convert_key(ctx)) 1758c2ecf20Sopenharmony_ci return -EINVAL; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* Pick the correct function code based on the protected key type */ 1788c2ecf20Sopenharmony_ci fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PAES_128 : 1798c2ecf20Sopenharmony_ci (ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KM_PAES_192 : 1808c2ecf20Sopenharmony_ci (ctx->pk.type == PKEY_KEYTYPE_AES_256) ? CPACF_KM_PAES_256 : 0; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* Check if the function code is available */ 1838c2ecf20Sopenharmony_ci ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return ctx->fc ? 0 : -EINVAL; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int ecb_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, 1898c2ecf20Sopenharmony_ci unsigned int key_len) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci int rc; 1928c2ecf20Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci _free_kb_keybuf(&ctx->kb); 1958c2ecf20Sopenharmony_ci rc = _key_to_kb(&ctx->kb, in_key, key_len); 1968c2ecf20Sopenharmony_ci if (rc) 1978c2ecf20Sopenharmony_ci return rc; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return __ecb_paes_set_key(ctx); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int ecb_paes_crypt(struct skcipher_request *req, unsigned long modifier) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 2058c2ecf20Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 2068c2ecf20Sopenharmony_ci struct skcipher_walk walk; 2078c2ecf20Sopenharmony_ci unsigned int nbytes, n, k; 2088c2ecf20Sopenharmony_ci int ret; 2098c2ecf20Sopenharmony_ci struct { 2108c2ecf20Sopenharmony_ci u8 key[MAXPROTKEYSIZE]; 2118c2ecf20Sopenharmony_ci } param; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 2148c2ecf20Sopenharmony_ci if (ret) 2158c2ecf20Sopenharmony_ci return ret; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 2188c2ecf20Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 2198c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 2228c2ecf20Sopenharmony_ci /* only use complete blocks */ 2238c2ecf20Sopenharmony_ci n = nbytes & ~(AES_BLOCK_SIZE - 1); 2248c2ecf20Sopenharmony_ci k = cpacf_km(ctx->fc | modifier, ¶m, 2258c2ecf20Sopenharmony_ci walk.dst.virt.addr, walk.src.virt.addr, n); 2268c2ecf20Sopenharmony_ci if (k) 2278c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - k); 2288c2ecf20Sopenharmony_ci if (k < n) { 2298c2ecf20Sopenharmony_ci if (__paes_convert_key(ctx)) 2308c2ecf20Sopenharmony_ci return skcipher_walk_done(&walk, -EIO); 2318c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 2328c2ecf20Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 2338c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci return ret; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic int ecb_paes_encrypt(struct skcipher_request *req) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci return ecb_paes_crypt(req, 0); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int ecb_paes_decrypt(struct skcipher_request *req) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci return ecb_paes_crypt(req, CPACF_DECRYPT); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic struct skcipher_alg ecb_paes_alg = { 2508c2ecf20Sopenharmony_ci .base.cra_name = "ecb(paes)", 2518c2ecf20Sopenharmony_ci .base.cra_driver_name = "ecb-paes-s390", 2528c2ecf20Sopenharmony_ci .base.cra_priority = 401, /* combo: aes + ecb + 1 */ 2538c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 2548c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_paes_ctx), 2558c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 2568c2ecf20Sopenharmony_ci .base.cra_list = LIST_HEAD_INIT(ecb_paes_alg.base.cra_list), 2578c2ecf20Sopenharmony_ci .init = ecb_paes_init, 2588c2ecf20Sopenharmony_ci .exit = ecb_paes_exit, 2598c2ecf20Sopenharmony_ci .min_keysize = PAES_MIN_KEYSIZE, 2608c2ecf20Sopenharmony_ci .max_keysize = PAES_MAX_KEYSIZE, 2618c2ecf20Sopenharmony_ci .setkey = ecb_paes_set_key, 2628c2ecf20Sopenharmony_ci .encrypt = ecb_paes_encrypt, 2638c2ecf20Sopenharmony_ci .decrypt = ecb_paes_decrypt, 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int cbc_paes_init(struct crypto_skcipher *tfm) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci ctx->kb.key = NULL; 2718c2ecf20Sopenharmony_ci spin_lock_init(&ctx->pk_lock); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic void cbc_paes_exit(struct crypto_skcipher *tfm) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci _free_kb_keybuf(&ctx->kb); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic inline int __cbc_paes_set_key(struct s390_paes_ctx *ctx) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci unsigned long fc; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (__paes_convert_key(ctx)) 2888c2ecf20Sopenharmony_ci return -EINVAL; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Pick the correct function code based on the protected key type */ 2918c2ecf20Sopenharmony_ci fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KMC_PAES_128 : 2928c2ecf20Sopenharmony_ci (ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KMC_PAES_192 : 2938c2ecf20Sopenharmony_ci (ctx->pk.type == PKEY_KEYTYPE_AES_256) ? CPACF_KMC_PAES_256 : 0; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Check if the function code is available */ 2968c2ecf20Sopenharmony_ci ctx->fc = (fc && cpacf_test_func(&kmc_functions, fc)) ? fc : 0; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci return ctx->fc ? 0 : -EINVAL; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int cbc_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, 3028c2ecf20Sopenharmony_ci unsigned int key_len) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci int rc; 3058c2ecf20Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci _free_kb_keybuf(&ctx->kb); 3088c2ecf20Sopenharmony_ci rc = _key_to_kb(&ctx->kb, in_key, key_len); 3098c2ecf20Sopenharmony_ci if (rc) 3108c2ecf20Sopenharmony_ci return rc; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return __cbc_paes_set_key(ctx); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic int cbc_paes_crypt(struct skcipher_request *req, unsigned long modifier) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 3188c2ecf20Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 3198c2ecf20Sopenharmony_ci struct skcipher_walk walk; 3208c2ecf20Sopenharmony_ci unsigned int nbytes, n, k; 3218c2ecf20Sopenharmony_ci int ret; 3228c2ecf20Sopenharmony_ci struct { 3238c2ecf20Sopenharmony_ci u8 iv[AES_BLOCK_SIZE]; 3248c2ecf20Sopenharmony_ci u8 key[MAXPROTKEYSIZE]; 3258c2ecf20Sopenharmony_ci } param; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 3288c2ecf20Sopenharmony_ci if (ret) 3298c2ecf20Sopenharmony_ci return ret; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci memcpy(param.iv, walk.iv, AES_BLOCK_SIZE); 3328c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 3338c2ecf20Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 3348c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 3378c2ecf20Sopenharmony_ci /* only use complete blocks */ 3388c2ecf20Sopenharmony_ci n = nbytes & ~(AES_BLOCK_SIZE - 1); 3398c2ecf20Sopenharmony_ci k = cpacf_kmc(ctx->fc | modifier, ¶m, 3408c2ecf20Sopenharmony_ci walk.dst.virt.addr, walk.src.virt.addr, n); 3418c2ecf20Sopenharmony_ci if (k) { 3428c2ecf20Sopenharmony_ci memcpy(walk.iv, param.iv, AES_BLOCK_SIZE); 3438c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - k); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci if (k < n) { 3468c2ecf20Sopenharmony_ci if (__paes_convert_key(ctx)) 3478c2ecf20Sopenharmony_ci return skcipher_walk_done(&walk, -EIO); 3488c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 3498c2ecf20Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 3508c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci return ret; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic int cbc_paes_encrypt(struct skcipher_request *req) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci return cbc_paes_crypt(req, 0); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int cbc_paes_decrypt(struct skcipher_request *req) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci return cbc_paes_crypt(req, CPACF_DECRYPT); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic struct skcipher_alg cbc_paes_alg = { 3678c2ecf20Sopenharmony_ci .base.cra_name = "cbc(paes)", 3688c2ecf20Sopenharmony_ci .base.cra_driver_name = "cbc-paes-s390", 3698c2ecf20Sopenharmony_ci .base.cra_priority = 402, /* ecb-paes-s390 + 1 */ 3708c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 3718c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_paes_ctx), 3728c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 3738c2ecf20Sopenharmony_ci .base.cra_list = LIST_HEAD_INIT(cbc_paes_alg.base.cra_list), 3748c2ecf20Sopenharmony_ci .init = cbc_paes_init, 3758c2ecf20Sopenharmony_ci .exit = cbc_paes_exit, 3768c2ecf20Sopenharmony_ci .min_keysize = PAES_MIN_KEYSIZE, 3778c2ecf20Sopenharmony_ci .max_keysize = PAES_MAX_KEYSIZE, 3788c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 3798c2ecf20Sopenharmony_ci .setkey = cbc_paes_set_key, 3808c2ecf20Sopenharmony_ci .encrypt = cbc_paes_encrypt, 3818c2ecf20Sopenharmony_ci .decrypt = cbc_paes_decrypt, 3828c2ecf20Sopenharmony_ci}; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic int xts_paes_init(struct crypto_skcipher *tfm) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci ctx->kb[0].key = NULL; 3898c2ecf20Sopenharmony_ci ctx->kb[1].key = NULL; 3908c2ecf20Sopenharmony_ci spin_lock_init(&ctx->pk_lock); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return 0; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic void xts_paes_exit(struct crypto_skcipher *tfm) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci _free_kb_keybuf(&ctx->kb[0]); 4008c2ecf20Sopenharmony_ci _free_kb_keybuf(&ctx->kb[1]); 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic inline int __xts_paes_convert_key(struct s390_pxts_ctx *ctx) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct pkey_protkey pkey0, pkey1; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (__paes_keyblob2pkey(&ctx->kb[0], &pkey0) || 4088c2ecf20Sopenharmony_ci __paes_keyblob2pkey(&ctx->kb[1], &pkey1)) 4098c2ecf20Sopenharmony_ci return -EINVAL; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 4128c2ecf20Sopenharmony_ci memcpy(&ctx->pk[0], &pkey0, sizeof(pkey0)); 4138c2ecf20Sopenharmony_ci memcpy(&ctx->pk[1], &pkey1, sizeof(pkey1)); 4148c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return 0; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic inline int __xts_paes_set_key(struct s390_pxts_ctx *ctx) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci unsigned long fc; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (__xts_paes_convert_key(ctx)) 4248c2ecf20Sopenharmony_ci return -EINVAL; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (ctx->pk[0].type != ctx->pk[1].type) 4278c2ecf20Sopenharmony_ci return -EINVAL; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* Pick the correct function code based on the protected key type */ 4308c2ecf20Sopenharmony_ci fc = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PXTS_128 : 4318c2ecf20Sopenharmony_ci (ctx->pk[0].type == PKEY_KEYTYPE_AES_256) ? 4328c2ecf20Sopenharmony_ci CPACF_KM_PXTS_256 : 0; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* Check if the function code is available */ 4358c2ecf20Sopenharmony_ci ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return ctx->fc ? 0 : -EINVAL; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic int xts_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, 4418c2ecf20Sopenharmony_ci unsigned int xts_key_len) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci int rc; 4448c2ecf20Sopenharmony_ci struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); 4458c2ecf20Sopenharmony_ci u8 ckey[2 * AES_MAX_KEY_SIZE]; 4468c2ecf20Sopenharmony_ci unsigned int ckey_len, key_len; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (xts_key_len % 2) 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci key_len = xts_key_len / 2; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci _free_kb_keybuf(&ctx->kb[0]); 4548c2ecf20Sopenharmony_ci _free_kb_keybuf(&ctx->kb[1]); 4558c2ecf20Sopenharmony_ci rc = _key_to_kb(&ctx->kb[0], in_key, key_len); 4568c2ecf20Sopenharmony_ci if (rc) 4578c2ecf20Sopenharmony_ci return rc; 4588c2ecf20Sopenharmony_ci rc = _key_to_kb(&ctx->kb[1], in_key + key_len, key_len); 4598c2ecf20Sopenharmony_ci if (rc) 4608c2ecf20Sopenharmony_ci return rc; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci rc = __xts_paes_set_key(ctx); 4638c2ecf20Sopenharmony_ci if (rc) 4648c2ecf20Sopenharmony_ci return rc; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* 4678c2ecf20Sopenharmony_ci * xts_check_key verifies the key length is not odd and makes 4688c2ecf20Sopenharmony_ci * sure that the two keys are not the same. This can be done 4698c2ecf20Sopenharmony_ci * on the two protected keys as well 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_ci ckey_len = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 4728c2ecf20Sopenharmony_ci AES_KEYSIZE_128 : AES_KEYSIZE_256; 4738c2ecf20Sopenharmony_ci memcpy(ckey, ctx->pk[0].protkey, ckey_len); 4748c2ecf20Sopenharmony_ci memcpy(ckey + ckey_len, ctx->pk[1].protkey, ckey_len); 4758c2ecf20Sopenharmony_ci return xts_verify_key(tfm, ckey, 2*ckey_len); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int xts_paes_crypt(struct skcipher_request *req, unsigned long modifier) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 4818c2ecf20Sopenharmony_ci struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); 4828c2ecf20Sopenharmony_ci struct skcipher_walk walk; 4838c2ecf20Sopenharmony_ci unsigned int keylen, offset, nbytes, n, k; 4848c2ecf20Sopenharmony_ci int ret; 4858c2ecf20Sopenharmony_ci struct { 4868c2ecf20Sopenharmony_ci u8 key[MAXPROTKEYSIZE]; /* key + verification pattern */ 4878c2ecf20Sopenharmony_ci u8 tweak[16]; 4888c2ecf20Sopenharmony_ci u8 block[16]; 4898c2ecf20Sopenharmony_ci u8 bit[16]; 4908c2ecf20Sopenharmony_ci u8 xts[16]; 4918c2ecf20Sopenharmony_ci } pcc_param; 4928c2ecf20Sopenharmony_ci struct { 4938c2ecf20Sopenharmony_ci u8 key[MAXPROTKEYSIZE]; /* key + verification pattern */ 4948c2ecf20Sopenharmony_ci u8 init[16]; 4958c2ecf20Sopenharmony_ci } xts_param; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 4988c2ecf20Sopenharmony_ci if (ret) 4998c2ecf20Sopenharmony_ci return ret; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci keylen = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 48 : 64; 5028c2ecf20Sopenharmony_ci offset = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 16 : 0; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci memset(&pcc_param, 0, sizeof(pcc_param)); 5058c2ecf20Sopenharmony_ci memcpy(pcc_param.tweak, walk.iv, sizeof(pcc_param.tweak)); 5068c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 5078c2ecf20Sopenharmony_ci memcpy(pcc_param.key + offset, ctx->pk[1].protkey, keylen); 5088c2ecf20Sopenharmony_ci memcpy(xts_param.key + offset, ctx->pk[0].protkey, keylen); 5098c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 5108c2ecf20Sopenharmony_ci cpacf_pcc(ctx->fc, pcc_param.key + offset); 5118c2ecf20Sopenharmony_ci memcpy(xts_param.init, pcc_param.xts, 16); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 5148c2ecf20Sopenharmony_ci /* only use complete blocks */ 5158c2ecf20Sopenharmony_ci n = nbytes & ~(AES_BLOCK_SIZE - 1); 5168c2ecf20Sopenharmony_ci k = cpacf_km(ctx->fc | modifier, xts_param.key + offset, 5178c2ecf20Sopenharmony_ci walk.dst.virt.addr, walk.src.virt.addr, n); 5188c2ecf20Sopenharmony_ci if (k) 5198c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - k); 5208c2ecf20Sopenharmony_ci if (k < n) { 5218c2ecf20Sopenharmony_ci if (__xts_paes_convert_key(ctx)) 5228c2ecf20Sopenharmony_ci return skcipher_walk_done(&walk, -EIO); 5238c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 5248c2ecf20Sopenharmony_ci memcpy(xts_param.key + offset, 5258c2ecf20Sopenharmony_ci ctx->pk[0].protkey, keylen); 5268c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return ret; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic int xts_paes_encrypt(struct skcipher_request *req) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci return xts_paes_crypt(req, 0); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic int xts_paes_decrypt(struct skcipher_request *req) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci return xts_paes_crypt(req, CPACF_DECRYPT); 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic struct skcipher_alg xts_paes_alg = { 5448c2ecf20Sopenharmony_ci .base.cra_name = "xts(paes)", 5458c2ecf20Sopenharmony_ci .base.cra_driver_name = "xts-paes-s390", 5468c2ecf20Sopenharmony_ci .base.cra_priority = 402, /* ecb-paes-s390 + 1 */ 5478c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 5488c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_pxts_ctx), 5498c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 5508c2ecf20Sopenharmony_ci .base.cra_list = LIST_HEAD_INIT(xts_paes_alg.base.cra_list), 5518c2ecf20Sopenharmony_ci .init = xts_paes_init, 5528c2ecf20Sopenharmony_ci .exit = xts_paes_exit, 5538c2ecf20Sopenharmony_ci .min_keysize = 2 * PAES_MIN_KEYSIZE, 5548c2ecf20Sopenharmony_ci .max_keysize = 2 * PAES_MAX_KEYSIZE, 5558c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 5568c2ecf20Sopenharmony_ci .setkey = xts_paes_set_key, 5578c2ecf20Sopenharmony_ci .encrypt = xts_paes_encrypt, 5588c2ecf20Sopenharmony_ci .decrypt = xts_paes_decrypt, 5598c2ecf20Sopenharmony_ci}; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic int ctr_paes_init(struct crypto_skcipher *tfm) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci ctx->kb.key = NULL; 5668c2ecf20Sopenharmony_ci spin_lock_init(&ctx->pk_lock); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci return 0; 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic void ctr_paes_exit(struct crypto_skcipher *tfm) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci _free_kb_keybuf(&ctx->kb); 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic inline int __ctr_paes_set_key(struct s390_paes_ctx *ctx) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci unsigned long fc; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (__paes_convert_key(ctx)) 5838c2ecf20Sopenharmony_ci return -EINVAL; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* Pick the correct function code based on the protected key type */ 5868c2ecf20Sopenharmony_ci fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KMCTR_PAES_128 : 5878c2ecf20Sopenharmony_ci (ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KMCTR_PAES_192 : 5888c2ecf20Sopenharmony_ci (ctx->pk.type == PKEY_KEYTYPE_AES_256) ? 5898c2ecf20Sopenharmony_ci CPACF_KMCTR_PAES_256 : 0; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* Check if the function code is available */ 5928c2ecf20Sopenharmony_ci ctx->fc = (fc && cpacf_test_func(&kmctr_functions, fc)) ? fc : 0; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return ctx->fc ? 0 : -EINVAL; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int ctr_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, 5988c2ecf20Sopenharmony_ci unsigned int key_len) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci int rc; 6018c2ecf20Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci _free_kb_keybuf(&ctx->kb); 6048c2ecf20Sopenharmony_ci rc = _key_to_kb(&ctx->kb, in_key, key_len); 6058c2ecf20Sopenharmony_ci if (rc) 6068c2ecf20Sopenharmony_ci return rc; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return __ctr_paes_set_key(ctx); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci unsigned int i, n; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* only use complete blocks, max. PAGE_SIZE */ 6168c2ecf20Sopenharmony_ci memcpy(ctrptr, iv, AES_BLOCK_SIZE); 6178c2ecf20Sopenharmony_ci n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(AES_BLOCK_SIZE - 1); 6188c2ecf20Sopenharmony_ci for (i = (n / AES_BLOCK_SIZE) - 1; i > 0; i--) { 6198c2ecf20Sopenharmony_ci memcpy(ctrptr + AES_BLOCK_SIZE, ctrptr, AES_BLOCK_SIZE); 6208c2ecf20Sopenharmony_ci crypto_inc(ctrptr + AES_BLOCK_SIZE, AES_BLOCK_SIZE); 6218c2ecf20Sopenharmony_ci ctrptr += AES_BLOCK_SIZE; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci return n; 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic int ctr_paes_crypt(struct skcipher_request *req) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 6298c2ecf20Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 6308c2ecf20Sopenharmony_ci u8 buf[AES_BLOCK_SIZE], *ctrptr; 6318c2ecf20Sopenharmony_ci struct skcipher_walk walk; 6328c2ecf20Sopenharmony_ci unsigned int nbytes, n, k; 6338c2ecf20Sopenharmony_ci int ret, locked; 6348c2ecf20Sopenharmony_ci struct { 6358c2ecf20Sopenharmony_ci u8 key[MAXPROTKEYSIZE]; 6368c2ecf20Sopenharmony_ci } param; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 6398c2ecf20Sopenharmony_ci if (ret) 6408c2ecf20Sopenharmony_ci return ret; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 6438c2ecf20Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 6448c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci locked = mutex_trylock(&ctrblk_lock); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) { 6498c2ecf20Sopenharmony_ci n = AES_BLOCK_SIZE; 6508c2ecf20Sopenharmony_ci if (nbytes >= 2*AES_BLOCK_SIZE && locked) 6518c2ecf20Sopenharmony_ci n = __ctrblk_init(ctrblk, walk.iv, nbytes); 6528c2ecf20Sopenharmony_ci ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk.iv; 6538c2ecf20Sopenharmony_ci k = cpacf_kmctr(ctx->fc, ¶m, walk.dst.virt.addr, 6548c2ecf20Sopenharmony_ci walk.src.virt.addr, n, ctrptr); 6558c2ecf20Sopenharmony_ci if (k) { 6568c2ecf20Sopenharmony_ci if (ctrptr == ctrblk) 6578c2ecf20Sopenharmony_ci memcpy(walk.iv, ctrptr + k - AES_BLOCK_SIZE, 6588c2ecf20Sopenharmony_ci AES_BLOCK_SIZE); 6598c2ecf20Sopenharmony_ci crypto_inc(walk.iv, AES_BLOCK_SIZE); 6608c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - k); 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci if (k < n) { 6638c2ecf20Sopenharmony_ci if (__paes_convert_key(ctx)) { 6648c2ecf20Sopenharmony_ci if (locked) 6658c2ecf20Sopenharmony_ci mutex_unlock(&ctrblk_lock); 6668c2ecf20Sopenharmony_ci return skcipher_walk_done(&walk, -EIO); 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 6698c2ecf20Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 6708c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci if (locked) 6748c2ecf20Sopenharmony_ci mutex_unlock(&ctrblk_lock); 6758c2ecf20Sopenharmony_ci /* 6768c2ecf20Sopenharmony_ci * final block may be < AES_BLOCK_SIZE, copy only nbytes 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_ci if (nbytes) { 6798c2ecf20Sopenharmony_ci memset(buf, 0, AES_BLOCK_SIZE); 6808c2ecf20Sopenharmony_ci memcpy(buf, walk.src.virt.addr, nbytes); 6818c2ecf20Sopenharmony_ci while (1) { 6828c2ecf20Sopenharmony_ci if (cpacf_kmctr(ctx->fc, ¶m, buf, 6838c2ecf20Sopenharmony_ci buf, AES_BLOCK_SIZE, 6848c2ecf20Sopenharmony_ci walk.iv) == AES_BLOCK_SIZE) 6858c2ecf20Sopenharmony_ci break; 6868c2ecf20Sopenharmony_ci if (__paes_convert_key(ctx)) 6878c2ecf20Sopenharmony_ci return skcipher_walk_done(&walk, -EIO); 6888c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 6898c2ecf20Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 6908c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci memcpy(walk.dst.virt.addr, buf, nbytes); 6938c2ecf20Sopenharmony_ci crypto_inc(walk.iv, AES_BLOCK_SIZE); 6948c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes); 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci return ret; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic struct skcipher_alg ctr_paes_alg = { 7018c2ecf20Sopenharmony_ci .base.cra_name = "ctr(paes)", 7028c2ecf20Sopenharmony_ci .base.cra_driver_name = "ctr-paes-s390", 7038c2ecf20Sopenharmony_ci .base.cra_priority = 402, /* ecb-paes-s390 + 1 */ 7048c2ecf20Sopenharmony_ci .base.cra_blocksize = 1, 7058c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_paes_ctx), 7068c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 7078c2ecf20Sopenharmony_ci .base.cra_list = LIST_HEAD_INIT(ctr_paes_alg.base.cra_list), 7088c2ecf20Sopenharmony_ci .init = ctr_paes_init, 7098c2ecf20Sopenharmony_ci .exit = ctr_paes_exit, 7108c2ecf20Sopenharmony_ci .min_keysize = PAES_MIN_KEYSIZE, 7118c2ecf20Sopenharmony_ci .max_keysize = PAES_MAX_KEYSIZE, 7128c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 7138c2ecf20Sopenharmony_ci .setkey = ctr_paes_set_key, 7148c2ecf20Sopenharmony_ci .encrypt = ctr_paes_crypt, 7158c2ecf20Sopenharmony_ci .decrypt = ctr_paes_crypt, 7168c2ecf20Sopenharmony_ci .chunksize = AES_BLOCK_SIZE, 7178c2ecf20Sopenharmony_ci}; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic inline void __crypto_unregister_skcipher(struct skcipher_alg *alg) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci if (!list_empty(&alg->base.cra_list)) 7228c2ecf20Sopenharmony_ci crypto_unregister_skcipher(alg); 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic void paes_s390_fini(void) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci __crypto_unregister_skcipher(&ctr_paes_alg); 7288c2ecf20Sopenharmony_ci __crypto_unregister_skcipher(&xts_paes_alg); 7298c2ecf20Sopenharmony_ci __crypto_unregister_skcipher(&cbc_paes_alg); 7308c2ecf20Sopenharmony_ci __crypto_unregister_skcipher(&ecb_paes_alg); 7318c2ecf20Sopenharmony_ci if (ctrblk) 7328c2ecf20Sopenharmony_ci free_page((unsigned long) ctrblk); 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic int __init paes_s390_init(void) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci int ret; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* Query available functions for KM, KMC and KMCTR */ 7408c2ecf20Sopenharmony_ci cpacf_query(CPACF_KM, &km_functions); 7418c2ecf20Sopenharmony_ci cpacf_query(CPACF_KMC, &kmc_functions); 7428c2ecf20Sopenharmony_ci cpacf_query(CPACF_KMCTR, &kmctr_functions); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (cpacf_test_func(&km_functions, CPACF_KM_PAES_128) || 7458c2ecf20Sopenharmony_ci cpacf_test_func(&km_functions, CPACF_KM_PAES_192) || 7468c2ecf20Sopenharmony_ci cpacf_test_func(&km_functions, CPACF_KM_PAES_256)) { 7478c2ecf20Sopenharmony_ci ret = crypto_register_skcipher(&ecb_paes_alg); 7488c2ecf20Sopenharmony_ci if (ret) 7498c2ecf20Sopenharmony_ci goto out_err; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) || 7538c2ecf20Sopenharmony_ci cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) || 7548c2ecf20Sopenharmony_ci cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256)) { 7558c2ecf20Sopenharmony_ci ret = crypto_register_skcipher(&cbc_paes_alg); 7568c2ecf20Sopenharmony_ci if (ret) 7578c2ecf20Sopenharmony_ci goto out_err; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci if (cpacf_test_func(&km_functions, CPACF_KM_PXTS_128) || 7618c2ecf20Sopenharmony_ci cpacf_test_func(&km_functions, CPACF_KM_PXTS_256)) { 7628c2ecf20Sopenharmony_ci ret = crypto_register_skcipher(&xts_paes_alg); 7638c2ecf20Sopenharmony_ci if (ret) 7648c2ecf20Sopenharmony_ci goto out_err; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_128) || 7688c2ecf20Sopenharmony_ci cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_192) || 7698c2ecf20Sopenharmony_ci cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_256)) { 7708c2ecf20Sopenharmony_ci ctrblk = (u8 *) __get_free_page(GFP_KERNEL); 7718c2ecf20Sopenharmony_ci if (!ctrblk) { 7728c2ecf20Sopenharmony_ci ret = -ENOMEM; 7738c2ecf20Sopenharmony_ci goto out_err; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci ret = crypto_register_skcipher(&ctr_paes_alg); 7768c2ecf20Sopenharmony_ci if (ret) 7778c2ecf20Sopenharmony_ci goto out_err; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci return 0; 7818c2ecf20Sopenharmony_ciout_err: 7828c2ecf20Sopenharmony_ci paes_s390_fini(); 7838c2ecf20Sopenharmony_ci return ret; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cimodule_init(paes_s390_init); 7878c2ecf20Sopenharmony_cimodule_exit(paes_s390_fini); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("paes"); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm with protected keys"); 7928c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 793