162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Cryptographic API. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * s390 implementation of the AES Cipher Algorithm with protected keys. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * s390 Version: 862306a36Sopenharmony_ci * Copyright IBM Corp. 2017, 2023 962306a36Sopenharmony_ci * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 1062306a36Sopenharmony_ci * Harald Freudenberger <freude@de.ibm.com> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define KMSG_COMPONENT "paes_s390" 1462306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <crypto/aes.h> 1762306a36Sopenharmony_ci#include <crypto/algapi.h> 1862306a36Sopenharmony_ci#include <linux/bug.h> 1962306a36Sopenharmony_ci#include <linux/err.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/cpufeature.h> 2262306a36Sopenharmony_ci#include <linux/init.h> 2362306a36Sopenharmony_ci#include <linux/mutex.h> 2462306a36Sopenharmony_ci#include <linux/spinlock.h> 2562306a36Sopenharmony_ci#include <linux/delay.h> 2662306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 2762306a36Sopenharmony_ci#include <crypto/xts.h> 2862306a36Sopenharmony_ci#include <asm/cpacf.h> 2962306a36Sopenharmony_ci#include <asm/pkey.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * Key blobs smaller/bigger than these defines are rejected 3362306a36Sopenharmony_ci * by the common code even before the individual setkey function 3462306a36Sopenharmony_ci * is called. As paes can handle different kinds of key blobs 3562306a36Sopenharmony_ci * and padding is also possible, the limits need to be generous. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci#define PAES_MIN_KEYSIZE 16 3862306a36Sopenharmony_ci#define PAES_MAX_KEYSIZE MAXEP11AESKEYBLOBSIZE 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic u8 *ctrblk; 4162306a36Sopenharmony_cistatic DEFINE_MUTEX(ctrblk_lock); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic cpacf_mask_t km_functions, kmc_functions, kmctr_functions; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistruct key_blob { 4662306a36Sopenharmony_ci /* 4762306a36Sopenharmony_ci * Small keys will be stored in the keybuf. Larger keys are 4862306a36Sopenharmony_ci * stored in extra allocated memory. In both cases does 4962306a36Sopenharmony_ci * key point to the memory where the key is stored. 5062306a36Sopenharmony_ci * The code distinguishes by checking keylen against 5162306a36Sopenharmony_ci * sizeof(keybuf). See the two following helper functions. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci u8 *key; 5462306a36Sopenharmony_ci u8 keybuf[128]; 5562306a36Sopenharmony_ci unsigned int keylen; 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic inline int _key_to_kb(struct key_blob *kb, 5962306a36Sopenharmony_ci const u8 *key, 6062306a36Sopenharmony_ci unsigned int keylen) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct clearkey_header { 6362306a36Sopenharmony_ci u8 type; 6462306a36Sopenharmony_ci u8 res0[3]; 6562306a36Sopenharmony_ci u8 version; 6662306a36Sopenharmony_ci u8 res1[3]; 6762306a36Sopenharmony_ci u32 keytype; 6862306a36Sopenharmony_ci u32 len; 6962306a36Sopenharmony_ci } __packed * h; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci switch (keylen) { 7262306a36Sopenharmony_ci case 16: 7362306a36Sopenharmony_ci case 24: 7462306a36Sopenharmony_ci case 32: 7562306a36Sopenharmony_ci /* clear key value, prepare pkey clear key token in keybuf */ 7662306a36Sopenharmony_ci memset(kb->keybuf, 0, sizeof(kb->keybuf)); 7762306a36Sopenharmony_ci h = (struct clearkey_header *) kb->keybuf; 7862306a36Sopenharmony_ci h->version = 0x02; /* TOKVER_CLEAR_KEY */ 7962306a36Sopenharmony_ci h->keytype = (keylen - 8) >> 3; 8062306a36Sopenharmony_ci h->len = keylen; 8162306a36Sopenharmony_ci memcpy(kb->keybuf + sizeof(*h), key, keylen); 8262306a36Sopenharmony_ci kb->keylen = sizeof(*h) + keylen; 8362306a36Sopenharmony_ci kb->key = kb->keybuf; 8462306a36Sopenharmony_ci break; 8562306a36Sopenharmony_ci default: 8662306a36Sopenharmony_ci /* other key material, let pkey handle this */ 8762306a36Sopenharmony_ci if (keylen <= sizeof(kb->keybuf)) 8862306a36Sopenharmony_ci kb->key = kb->keybuf; 8962306a36Sopenharmony_ci else { 9062306a36Sopenharmony_ci kb->key = kmalloc(keylen, GFP_KERNEL); 9162306a36Sopenharmony_ci if (!kb->key) 9262306a36Sopenharmony_ci return -ENOMEM; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci memcpy(kb->key, key, keylen); 9562306a36Sopenharmony_ci kb->keylen = keylen; 9662306a36Sopenharmony_ci break; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic inline void _free_kb_keybuf(struct key_blob *kb) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci if (kb->key && kb->key != kb->keybuf 10562306a36Sopenharmony_ci && kb->keylen > sizeof(kb->keybuf)) { 10662306a36Sopenharmony_ci kfree_sensitive(kb->key); 10762306a36Sopenharmony_ci kb->key = NULL; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistruct s390_paes_ctx { 11262306a36Sopenharmony_ci struct key_blob kb; 11362306a36Sopenharmony_ci struct pkey_protkey pk; 11462306a36Sopenharmony_ci spinlock_t pk_lock; 11562306a36Sopenharmony_ci unsigned long fc; 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistruct s390_pxts_ctx { 11962306a36Sopenharmony_ci struct key_blob kb[2]; 12062306a36Sopenharmony_ci struct pkey_protkey pk[2]; 12162306a36Sopenharmony_ci spinlock_t pk_lock; 12262306a36Sopenharmony_ci unsigned long fc; 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic inline int __paes_keyblob2pkey(struct key_blob *kb, 12662306a36Sopenharmony_ci struct pkey_protkey *pk) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci int i, ret; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* try three times in case of failure */ 13162306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 13262306a36Sopenharmony_ci if (i > 0 && ret == -EAGAIN && in_task()) 13362306a36Sopenharmony_ci if (msleep_interruptible(1000)) 13462306a36Sopenharmony_ci return -EINTR; 13562306a36Sopenharmony_ci ret = pkey_keyblob2pkey(kb->key, kb->keylen, 13662306a36Sopenharmony_ci pk->protkey, &pk->len, &pk->type); 13762306a36Sopenharmony_ci if (ret == 0) 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return ret; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic inline int __paes_convert_key(struct s390_paes_ctx *ctx) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci int ret; 14762306a36Sopenharmony_ci struct pkey_protkey pkey; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci pkey.len = sizeof(pkey.protkey); 15062306a36Sopenharmony_ci ret = __paes_keyblob2pkey(&ctx->kb, &pkey); 15162306a36Sopenharmony_ci if (ret) 15262306a36Sopenharmony_ci return ret; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 15562306a36Sopenharmony_ci memcpy(&ctx->pk, &pkey, sizeof(pkey)); 15662306a36Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int ecb_paes_init(struct crypto_skcipher *tfm) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci ctx->kb.key = NULL; 16662306a36Sopenharmony_ci spin_lock_init(&ctx->pk_lock); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic void ecb_paes_exit(struct crypto_skcipher *tfm) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci _free_kb_keybuf(&ctx->kb); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic inline int __ecb_paes_set_key(struct s390_paes_ctx *ctx) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci int rc; 18162306a36Sopenharmony_ci unsigned long fc; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci rc = __paes_convert_key(ctx); 18462306a36Sopenharmony_ci if (rc) 18562306a36Sopenharmony_ci return rc; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* Pick the correct function code based on the protected key type */ 18862306a36Sopenharmony_ci fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PAES_128 : 18962306a36Sopenharmony_ci (ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KM_PAES_192 : 19062306a36Sopenharmony_ci (ctx->pk.type == PKEY_KEYTYPE_AES_256) ? CPACF_KM_PAES_256 : 0; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* Check if the function code is available */ 19362306a36Sopenharmony_ci ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return ctx->fc ? 0 : -EINVAL; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int ecb_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, 19962306a36Sopenharmony_ci unsigned int key_len) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci int rc; 20262306a36Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci _free_kb_keybuf(&ctx->kb); 20562306a36Sopenharmony_ci rc = _key_to_kb(&ctx->kb, in_key, key_len); 20662306a36Sopenharmony_ci if (rc) 20762306a36Sopenharmony_ci return rc; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return __ecb_paes_set_key(ctx); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int ecb_paes_crypt(struct skcipher_request *req, unsigned long modifier) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 21562306a36Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 21662306a36Sopenharmony_ci struct skcipher_walk walk; 21762306a36Sopenharmony_ci unsigned int nbytes, n, k; 21862306a36Sopenharmony_ci int ret; 21962306a36Sopenharmony_ci struct { 22062306a36Sopenharmony_ci u8 key[MAXPROTKEYSIZE]; 22162306a36Sopenharmony_ci } param; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 22462306a36Sopenharmony_ci if (ret) 22562306a36Sopenharmony_ci return ret; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 22862306a36Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 22962306a36Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 23262306a36Sopenharmony_ci /* only use complete blocks */ 23362306a36Sopenharmony_ci n = nbytes & ~(AES_BLOCK_SIZE - 1); 23462306a36Sopenharmony_ci k = cpacf_km(ctx->fc | modifier, ¶m, 23562306a36Sopenharmony_ci walk.dst.virt.addr, walk.src.virt.addr, n); 23662306a36Sopenharmony_ci if (k) 23762306a36Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - k); 23862306a36Sopenharmony_ci if (k < n) { 23962306a36Sopenharmony_ci if (__paes_convert_key(ctx)) 24062306a36Sopenharmony_ci return skcipher_walk_done(&walk, -EIO); 24162306a36Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 24262306a36Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 24362306a36Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci return ret; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic int ecb_paes_encrypt(struct skcipher_request *req) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci return ecb_paes_crypt(req, 0); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int ecb_paes_decrypt(struct skcipher_request *req) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci return ecb_paes_crypt(req, CPACF_DECRYPT); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic struct skcipher_alg ecb_paes_alg = { 26062306a36Sopenharmony_ci .base.cra_name = "ecb(paes)", 26162306a36Sopenharmony_ci .base.cra_driver_name = "ecb-paes-s390", 26262306a36Sopenharmony_ci .base.cra_priority = 401, /* combo: aes + ecb + 1 */ 26362306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 26462306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_paes_ctx), 26562306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 26662306a36Sopenharmony_ci .base.cra_list = LIST_HEAD_INIT(ecb_paes_alg.base.cra_list), 26762306a36Sopenharmony_ci .init = ecb_paes_init, 26862306a36Sopenharmony_ci .exit = ecb_paes_exit, 26962306a36Sopenharmony_ci .min_keysize = PAES_MIN_KEYSIZE, 27062306a36Sopenharmony_ci .max_keysize = PAES_MAX_KEYSIZE, 27162306a36Sopenharmony_ci .setkey = ecb_paes_set_key, 27262306a36Sopenharmony_ci .encrypt = ecb_paes_encrypt, 27362306a36Sopenharmony_ci .decrypt = ecb_paes_decrypt, 27462306a36Sopenharmony_ci}; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic int cbc_paes_init(struct crypto_skcipher *tfm) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci ctx->kb.key = NULL; 28162306a36Sopenharmony_ci spin_lock_init(&ctx->pk_lock); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic void cbc_paes_exit(struct crypto_skcipher *tfm) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci _free_kb_keybuf(&ctx->kb); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic inline int __cbc_paes_set_key(struct s390_paes_ctx *ctx) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci int rc; 29662306a36Sopenharmony_ci unsigned long fc; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci rc = __paes_convert_key(ctx); 29962306a36Sopenharmony_ci if (rc) 30062306a36Sopenharmony_ci return rc; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* Pick the correct function code based on the protected key type */ 30362306a36Sopenharmony_ci fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KMC_PAES_128 : 30462306a36Sopenharmony_ci (ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KMC_PAES_192 : 30562306a36Sopenharmony_ci (ctx->pk.type == PKEY_KEYTYPE_AES_256) ? CPACF_KMC_PAES_256 : 0; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* Check if the function code is available */ 30862306a36Sopenharmony_ci ctx->fc = (fc && cpacf_test_func(&kmc_functions, fc)) ? fc : 0; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci return ctx->fc ? 0 : -EINVAL; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int cbc_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, 31462306a36Sopenharmony_ci unsigned int key_len) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci int rc; 31762306a36Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci _free_kb_keybuf(&ctx->kb); 32062306a36Sopenharmony_ci rc = _key_to_kb(&ctx->kb, in_key, key_len); 32162306a36Sopenharmony_ci if (rc) 32262306a36Sopenharmony_ci return rc; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return __cbc_paes_set_key(ctx); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic int cbc_paes_crypt(struct skcipher_request *req, unsigned long modifier) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 33062306a36Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 33162306a36Sopenharmony_ci struct skcipher_walk walk; 33262306a36Sopenharmony_ci unsigned int nbytes, n, k; 33362306a36Sopenharmony_ci int ret; 33462306a36Sopenharmony_ci struct { 33562306a36Sopenharmony_ci u8 iv[AES_BLOCK_SIZE]; 33662306a36Sopenharmony_ci u8 key[MAXPROTKEYSIZE]; 33762306a36Sopenharmony_ci } param; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 34062306a36Sopenharmony_ci if (ret) 34162306a36Sopenharmony_ci return ret; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci memcpy(param.iv, walk.iv, AES_BLOCK_SIZE); 34462306a36Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 34562306a36Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 34662306a36Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 34962306a36Sopenharmony_ci /* only use complete blocks */ 35062306a36Sopenharmony_ci n = nbytes & ~(AES_BLOCK_SIZE - 1); 35162306a36Sopenharmony_ci k = cpacf_kmc(ctx->fc | modifier, ¶m, 35262306a36Sopenharmony_ci walk.dst.virt.addr, walk.src.virt.addr, n); 35362306a36Sopenharmony_ci if (k) { 35462306a36Sopenharmony_ci memcpy(walk.iv, param.iv, AES_BLOCK_SIZE); 35562306a36Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - k); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci if (k < n) { 35862306a36Sopenharmony_ci if (__paes_convert_key(ctx)) 35962306a36Sopenharmony_ci return skcipher_walk_done(&walk, -EIO); 36062306a36Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 36162306a36Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 36262306a36Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci return ret; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic int cbc_paes_encrypt(struct skcipher_request *req) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci return cbc_paes_crypt(req, 0); 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic int cbc_paes_decrypt(struct skcipher_request *req) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci return cbc_paes_crypt(req, CPACF_DECRYPT); 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic struct skcipher_alg cbc_paes_alg = { 37962306a36Sopenharmony_ci .base.cra_name = "cbc(paes)", 38062306a36Sopenharmony_ci .base.cra_driver_name = "cbc-paes-s390", 38162306a36Sopenharmony_ci .base.cra_priority = 402, /* ecb-paes-s390 + 1 */ 38262306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 38362306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_paes_ctx), 38462306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 38562306a36Sopenharmony_ci .base.cra_list = LIST_HEAD_INIT(cbc_paes_alg.base.cra_list), 38662306a36Sopenharmony_ci .init = cbc_paes_init, 38762306a36Sopenharmony_ci .exit = cbc_paes_exit, 38862306a36Sopenharmony_ci .min_keysize = PAES_MIN_KEYSIZE, 38962306a36Sopenharmony_ci .max_keysize = PAES_MAX_KEYSIZE, 39062306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 39162306a36Sopenharmony_ci .setkey = cbc_paes_set_key, 39262306a36Sopenharmony_ci .encrypt = cbc_paes_encrypt, 39362306a36Sopenharmony_ci .decrypt = cbc_paes_decrypt, 39462306a36Sopenharmony_ci}; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int xts_paes_init(struct crypto_skcipher *tfm) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci ctx->kb[0].key = NULL; 40162306a36Sopenharmony_ci ctx->kb[1].key = NULL; 40262306a36Sopenharmony_ci spin_lock_init(&ctx->pk_lock); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void xts_paes_exit(struct crypto_skcipher *tfm) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci _free_kb_keybuf(&ctx->kb[0]); 41262306a36Sopenharmony_ci _free_kb_keybuf(&ctx->kb[1]); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic inline int __xts_paes_convert_key(struct s390_pxts_ctx *ctx) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct pkey_protkey pkey0, pkey1; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci pkey0.len = sizeof(pkey0.protkey); 42062306a36Sopenharmony_ci pkey1.len = sizeof(pkey1.protkey); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (__paes_keyblob2pkey(&ctx->kb[0], &pkey0) || 42362306a36Sopenharmony_ci __paes_keyblob2pkey(&ctx->kb[1], &pkey1)) 42462306a36Sopenharmony_ci return -EINVAL; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 42762306a36Sopenharmony_ci memcpy(&ctx->pk[0], &pkey0, sizeof(pkey0)); 42862306a36Sopenharmony_ci memcpy(&ctx->pk[1], &pkey1, sizeof(pkey1)); 42962306a36Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic inline int __xts_paes_set_key(struct s390_pxts_ctx *ctx) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci unsigned long fc; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (__xts_paes_convert_key(ctx)) 43962306a36Sopenharmony_ci return -EINVAL; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (ctx->pk[0].type != ctx->pk[1].type) 44262306a36Sopenharmony_ci return -EINVAL; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* Pick the correct function code based on the protected key type */ 44562306a36Sopenharmony_ci fc = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PXTS_128 : 44662306a36Sopenharmony_ci (ctx->pk[0].type == PKEY_KEYTYPE_AES_256) ? 44762306a36Sopenharmony_ci CPACF_KM_PXTS_256 : 0; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* Check if the function code is available */ 45062306a36Sopenharmony_ci ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return ctx->fc ? 0 : -EINVAL; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic int xts_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, 45662306a36Sopenharmony_ci unsigned int xts_key_len) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci int rc; 45962306a36Sopenharmony_ci struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); 46062306a36Sopenharmony_ci u8 ckey[2 * AES_MAX_KEY_SIZE]; 46162306a36Sopenharmony_ci unsigned int ckey_len, key_len; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (xts_key_len % 2) 46462306a36Sopenharmony_ci return -EINVAL; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci key_len = xts_key_len / 2; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci _free_kb_keybuf(&ctx->kb[0]); 46962306a36Sopenharmony_ci _free_kb_keybuf(&ctx->kb[1]); 47062306a36Sopenharmony_ci rc = _key_to_kb(&ctx->kb[0], in_key, key_len); 47162306a36Sopenharmony_ci if (rc) 47262306a36Sopenharmony_ci return rc; 47362306a36Sopenharmony_ci rc = _key_to_kb(&ctx->kb[1], in_key + key_len, key_len); 47462306a36Sopenharmony_ci if (rc) 47562306a36Sopenharmony_ci return rc; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci rc = __xts_paes_set_key(ctx); 47862306a36Sopenharmony_ci if (rc) 47962306a36Sopenharmony_ci return rc; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* 48262306a36Sopenharmony_ci * xts_verify_key verifies the key length is not odd and makes 48362306a36Sopenharmony_ci * sure that the two keys are not the same. This can be done 48462306a36Sopenharmony_ci * on the two protected keys as well 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci ckey_len = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 48762306a36Sopenharmony_ci AES_KEYSIZE_128 : AES_KEYSIZE_256; 48862306a36Sopenharmony_ci memcpy(ckey, ctx->pk[0].protkey, ckey_len); 48962306a36Sopenharmony_ci memcpy(ckey + ckey_len, ctx->pk[1].protkey, ckey_len); 49062306a36Sopenharmony_ci return xts_verify_key(tfm, ckey, 2*ckey_len); 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic int xts_paes_crypt(struct skcipher_request *req, unsigned long modifier) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 49662306a36Sopenharmony_ci struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); 49762306a36Sopenharmony_ci struct skcipher_walk walk; 49862306a36Sopenharmony_ci unsigned int keylen, offset, nbytes, n, k; 49962306a36Sopenharmony_ci int ret; 50062306a36Sopenharmony_ci struct { 50162306a36Sopenharmony_ci u8 key[MAXPROTKEYSIZE]; /* key + verification pattern */ 50262306a36Sopenharmony_ci u8 tweak[16]; 50362306a36Sopenharmony_ci u8 block[16]; 50462306a36Sopenharmony_ci u8 bit[16]; 50562306a36Sopenharmony_ci u8 xts[16]; 50662306a36Sopenharmony_ci } pcc_param; 50762306a36Sopenharmony_ci struct { 50862306a36Sopenharmony_ci u8 key[MAXPROTKEYSIZE]; /* key + verification pattern */ 50962306a36Sopenharmony_ci u8 init[16]; 51062306a36Sopenharmony_ci } xts_param; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 51362306a36Sopenharmony_ci if (ret) 51462306a36Sopenharmony_ci return ret; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci keylen = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 48 : 64; 51762306a36Sopenharmony_ci offset = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 16 : 0; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci memset(&pcc_param, 0, sizeof(pcc_param)); 52062306a36Sopenharmony_ci memcpy(pcc_param.tweak, walk.iv, sizeof(pcc_param.tweak)); 52162306a36Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 52262306a36Sopenharmony_ci memcpy(pcc_param.key + offset, ctx->pk[1].protkey, keylen); 52362306a36Sopenharmony_ci memcpy(xts_param.key + offset, ctx->pk[0].protkey, keylen); 52462306a36Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 52562306a36Sopenharmony_ci cpacf_pcc(ctx->fc, pcc_param.key + offset); 52662306a36Sopenharmony_ci memcpy(xts_param.init, pcc_param.xts, 16); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 52962306a36Sopenharmony_ci /* only use complete blocks */ 53062306a36Sopenharmony_ci n = nbytes & ~(AES_BLOCK_SIZE - 1); 53162306a36Sopenharmony_ci k = cpacf_km(ctx->fc | modifier, xts_param.key + offset, 53262306a36Sopenharmony_ci walk.dst.virt.addr, walk.src.virt.addr, n); 53362306a36Sopenharmony_ci if (k) 53462306a36Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - k); 53562306a36Sopenharmony_ci if (k < n) { 53662306a36Sopenharmony_ci if (__xts_paes_convert_key(ctx)) 53762306a36Sopenharmony_ci return skcipher_walk_done(&walk, -EIO); 53862306a36Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 53962306a36Sopenharmony_ci memcpy(xts_param.key + offset, 54062306a36Sopenharmony_ci ctx->pk[0].protkey, keylen); 54162306a36Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return ret; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic int xts_paes_encrypt(struct skcipher_request *req) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci return xts_paes_crypt(req, 0); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic int xts_paes_decrypt(struct skcipher_request *req) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci return xts_paes_crypt(req, CPACF_DECRYPT); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic struct skcipher_alg xts_paes_alg = { 55962306a36Sopenharmony_ci .base.cra_name = "xts(paes)", 56062306a36Sopenharmony_ci .base.cra_driver_name = "xts-paes-s390", 56162306a36Sopenharmony_ci .base.cra_priority = 402, /* ecb-paes-s390 + 1 */ 56262306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 56362306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_pxts_ctx), 56462306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 56562306a36Sopenharmony_ci .base.cra_list = LIST_HEAD_INIT(xts_paes_alg.base.cra_list), 56662306a36Sopenharmony_ci .init = xts_paes_init, 56762306a36Sopenharmony_ci .exit = xts_paes_exit, 56862306a36Sopenharmony_ci .min_keysize = 2 * PAES_MIN_KEYSIZE, 56962306a36Sopenharmony_ci .max_keysize = 2 * PAES_MAX_KEYSIZE, 57062306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 57162306a36Sopenharmony_ci .setkey = xts_paes_set_key, 57262306a36Sopenharmony_ci .encrypt = xts_paes_encrypt, 57362306a36Sopenharmony_ci .decrypt = xts_paes_decrypt, 57462306a36Sopenharmony_ci}; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic int ctr_paes_init(struct crypto_skcipher *tfm) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci ctx->kb.key = NULL; 58162306a36Sopenharmony_ci spin_lock_init(&ctx->pk_lock); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci return 0; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic void ctr_paes_exit(struct crypto_skcipher *tfm) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci _free_kb_keybuf(&ctx->kb); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic inline int __ctr_paes_set_key(struct s390_paes_ctx *ctx) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci int rc; 59662306a36Sopenharmony_ci unsigned long fc; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci rc = __paes_convert_key(ctx); 59962306a36Sopenharmony_ci if (rc) 60062306a36Sopenharmony_ci return rc; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* Pick the correct function code based on the protected key type */ 60362306a36Sopenharmony_ci fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KMCTR_PAES_128 : 60462306a36Sopenharmony_ci (ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KMCTR_PAES_192 : 60562306a36Sopenharmony_ci (ctx->pk.type == PKEY_KEYTYPE_AES_256) ? 60662306a36Sopenharmony_ci CPACF_KMCTR_PAES_256 : 0; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* Check if the function code is available */ 60962306a36Sopenharmony_ci ctx->fc = (fc && cpacf_test_func(&kmctr_functions, fc)) ? fc : 0; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci return ctx->fc ? 0 : -EINVAL; 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic int ctr_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, 61562306a36Sopenharmony_ci unsigned int key_len) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci int rc; 61862306a36Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci _free_kb_keybuf(&ctx->kb); 62162306a36Sopenharmony_ci rc = _key_to_kb(&ctx->kb, in_key, key_len); 62262306a36Sopenharmony_ci if (rc) 62362306a36Sopenharmony_ci return rc; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci return __ctr_paes_set_key(ctx); 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci unsigned int i, n; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci /* only use complete blocks, max. PAGE_SIZE */ 63362306a36Sopenharmony_ci memcpy(ctrptr, iv, AES_BLOCK_SIZE); 63462306a36Sopenharmony_ci n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(AES_BLOCK_SIZE - 1); 63562306a36Sopenharmony_ci for (i = (n / AES_BLOCK_SIZE) - 1; i > 0; i--) { 63662306a36Sopenharmony_ci memcpy(ctrptr + AES_BLOCK_SIZE, ctrptr, AES_BLOCK_SIZE); 63762306a36Sopenharmony_ci crypto_inc(ctrptr + AES_BLOCK_SIZE, AES_BLOCK_SIZE); 63862306a36Sopenharmony_ci ctrptr += AES_BLOCK_SIZE; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci return n; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic int ctr_paes_crypt(struct skcipher_request *req) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 64662306a36Sopenharmony_ci struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); 64762306a36Sopenharmony_ci u8 buf[AES_BLOCK_SIZE], *ctrptr; 64862306a36Sopenharmony_ci struct skcipher_walk walk; 64962306a36Sopenharmony_ci unsigned int nbytes, n, k; 65062306a36Sopenharmony_ci int ret, locked; 65162306a36Sopenharmony_ci struct { 65262306a36Sopenharmony_ci u8 key[MAXPROTKEYSIZE]; 65362306a36Sopenharmony_ci } param; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 65662306a36Sopenharmony_ci if (ret) 65762306a36Sopenharmony_ci return ret; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 66062306a36Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 66162306a36Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci locked = mutex_trylock(&ctrblk_lock); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) { 66662306a36Sopenharmony_ci n = AES_BLOCK_SIZE; 66762306a36Sopenharmony_ci if (nbytes >= 2*AES_BLOCK_SIZE && locked) 66862306a36Sopenharmony_ci n = __ctrblk_init(ctrblk, walk.iv, nbytes); 66962306a36Sopenharmony_ci ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk.iv; 67062306a36Sopenharmony_ci k = cpacf_kmctr(ctx->fc, ¶m, walk.dst.virt.addr, 67162306a36Sopenharmony_ci walk.src.virt.addr, n, ctrptr); 67262306a36Sopenharmony_ci if (k) { 67362306a36Sopenharmony_ci if (ctrptr == ctrblk) 67462306a36Sopenharmony_ci memcpy(walk.iv, ctrptr + k - AES_BLOCK_SIZE, 67562306a36Sopenharmony_ci AES_BLOCK_SIZE); 67662306a36Sopenharmony_ci crypto_inc(walk.iv, AES_BLOCK_SIZE); 67762306a36Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - k); 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci if (k < n) { 68062306a36Sopenharmony_ci if (__paes_convert_key(ctx)) { 68162306a36Sopenharmony_ci if (locked) 68262306a36Sopenharmony_ci mutex_unlock(&ctrblk_lock); 68362306a36Sopenharmony_ci return skcipher_walk_done(&walk, -EIO); 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 68662306a36Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 68762306a36Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci if (locked) 69162306a36Sopenharmony_ci mutex_unlock(&ctrblk_lock); 69262306a36Sopenharmony_ci /* 69362306a36Sopenharmony_ci * final block may be < AES_BLOCK_SIZE, copy only nbytes 69462306a36Sopenharmony_ci */ 69562306a36Sopenharmony_ci if (nbytes) { 69662306a36Sopenharmony_ci memset(buf, 0, AES_BLOCK_SIZE); 69762306a36Sopenharmony_ci memcpy(buf, walk.src.virt.addr, nbytes); 69862306a36Sopenharmony_ci while (1) { 69962306a36Sopenharmony_ci if (cpacf_kmctr(ctx->fc, ¶m, buf, 70062306a36Sopenharmony_ci buf, AES_BLOCK_SIZE, 70162306a36Sopenharmony_ci walk.iv) == AES_BLOCK_SIZE) 70262306a36Sopenharmony_ci break; 70362306a36Sopenharmony_ci if (__paes_convert_key(ctx)) 70462306a36Sopenharmony_ci return skcipher_walk_done(&walk, -EIO); 70562306a36Sopenharmony_ci spin_lock_bh(&ctx->pk_lock); 70662306a36Sopenharmony_ci memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); 70762306a36Sopenharmony_ci spin_unlock_bh(&ctx->pk_lock); 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci memcpy(walk.dst.virt.addr, buf, nbytes); 71062306a36Sopenharmony_ci crypto_inc(walk.iv, AES_BLOCK_SIZE); 71162306a36Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes); 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci return ret; 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic struct skcipher_alg ctr_paes_alg = { 71862306a36Sopenharmony_ci .base.cra_name = "ctr(paes)", 71962306a36Sopenharmony_ci .base.cra_driver_name = "ctr-paes-s390", 72062306a36Sopenharmony_ci .base.cra_priority = 402, /* ecb-paes-s390 + 1 */ 72162306a36Sopenharmony_ci .base.cra_blocksize = 1, 72262306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_paes_ctx), 72362306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 72462306a36Sopenharmony_ci .base.cra_list = LIST_HEAD_INIT(ctr_paes_alg.base.cra_list), 72562306a36Sopenharmony_ci .init = ctr_paes_init, 72662306a36Sopenharmony_ci .exit = ctr_paes_exit, 72762306a36Sopenharmony_ci .min_keysize = PAES_MIN_KEYSIZE, 72862306a36Sopenharmony_ci .max_keysize = PAES_MAX_KEYSIZE, 72962306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 73062306a36Sopenharmony_ci .setkey = ctr_paes_set_key, 73162306a36Sopenharmony_ci .encrypt = ctr_paes_crypt, 73262306a36Sopenharmony_ci .decrypt = ctr_paes_crypt, 73362306a36Sopenharmony_ci .chunksize = AES_BLOCK_SIZE, 73462306a36Sopenharmony_ci}; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic inline void __crypto_unregister_skcipher(struct skcipher_alg *alg) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci if (!list_empty(&alg->base.cra_list)) 73962306a36Sopenharmony_ci crypto_unregister_skcipher(alg); 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_cistatic void paes_s390_fini(void) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci __crypto_unregister_skcipher(&ctr_paes_alg); 74562306a36Sopenharmony_ci __crypto_unregister_skcipher(&xts_paes_alg); 74662306a36Sopenharmony_ci __crypto_unregister_skcipher(&cbc_paes_alg); 74762306a36Sopenharmony_ci __crypto_unregister_skcipher(&ecb_paes_alg); 74862306a36Sopenharmony_ci if (ctrblk) 74962306a36Sopenharmony_ci free_page((unsigned long) ctrblk); 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic int __init paes_s390_init(void) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci int ret; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci /* Query available functions for KM, KMC and KMCTR */ 75762306a36Sopenharmony_ci cpacf_query(CPACF_KM, &km_functions); 75862306a36Sopenharmony_ci cpacf_query(CPACF_KMC, &kmc_functions); 75962306a36Sopenharmony_ci cpacf_query(CPACF_KMCTR, &kmctr_functions); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (cpacf_test_func(&km_functions, CPACF_KM_PAES_128) || 76262306a36Sopenharmony_ci cpacf_test_func(&km_functions, CPACF_KM_PAES_192) || 76362306a36Sopenharmony_ci cpacf_test_func(&km_functions, CPACF_KM_PAES_256)) { 76462306a36Sopenharmony_ci ret = crypto_register_skcipher(&ecb_paes_alg); 76562306a36Sopenharmony_ci if (ret) 76662306a36Sopenharmony_ci goto out_err; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) || 77062306a36Sopenharmony_ci cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) || 77162306a36Sopenharmony_ci cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256)) { 77262306a36Sopenharmony_ci ret = crypto_register_skcipher(&cbc_paes_alg); 77362306a36Sopenharmony_ci if (ret) 77462306a36Sopenharmony_ci goto out_err; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (cpacf_test_func(&km_functions, CPACF_KM_PXTS_128) || 77862306a36Sopenharmony_ci cpacf_test_func(&km_functions, CPACF_KM_PXTS_256)) { 77962306a36Sopenharmony_ci ret = crypto_register_skcipher(&xts_paes_alg); 78062306a36Sopenharmony_ci if (ret) 78162306a36Sopenharmony_ci goto out_err; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_128) || 78562306a36Sopenharmony_ci cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_192) || 78662306a36Sopenharmony_ci cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_256)) { 78762306a36Sopenharmony_ci ctrblk = (u8 *) __get_free_page(GFP_KERNEL); 78862306a36Sopenharmony_ci if (!ctrblk) { 78962306a36Sopenharmony_ci ret = -ENOMEM; 79062306a36Sopenharmony_ci goto out_err; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci ret = crypto_register_skcipher(&ctr_paes_alg); 79362306a36Sopenharmony_ci if (ret) 79462306a36Sopenharmony_ci goto out_err; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci return 0; 79862306a36Sopenharmony_ciout_err: 79962306a36Sopenharmony_ci paes_s390_fini(); 80062306a36Sopenharmony_ci return ret; 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cimodule_init(paes_s390_init); 80462306a36Sopenharmony_cimodule_exit(paes_s390_fini); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("paes"); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ciMODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm with protected keys"); 80962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 810