xref: /linux/arch/s390/crypto/paes_s390.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
120a884f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
227937843SMartin Schwidefsky /*
327937843SMartin Schwidefsky  * Cryptographic API.
427937843SMartin Schwidefsky  *
527937843SMartin Schwidefsky  * s390 implementation of the AES Cipher Algorithm with protected keys.
627937843SMartin Schwidefsky  *
727937843SMartin Schwidefsky  * s390 Version:
8f370f45cSHarald Freudenberger  *   Copyright IBM Corp. 2017, 2023
927937843SMartin Schwidefsky  *   Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
1027937843SMartin Schwidefsky  *		Harald Freudenberger <freude@de.ibm.com>
1127937843SMartin Schwidefsky  */
1227937843SMartin Schwidefsky 
1327937843SMartin Schwidefsky #define KMSG_COMPONENT "paes_s390"
1427937843SMartin Schwidefsky #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1527937843SMartin Schwidefsky 
1627937843SMartin Schwidefsky #include <crypto/aes.h>
1727937843SMartin Schwidefsky #include <crypto/algapi.h>
1827937843SMartin Schwidefsky #include <linux/bug.h>
1927937843SMartin Schwidefsky #include <linux/err.h>
2027937843SMartin Schwidefsky #include <linux/module.h>
2127937843SMartin Schwidefsky #include <linux/cpufeature.h>
2227937843SMartin Schwidefsky #include <linux/init.h>
236f3196b7SHarald Freudenberger #include <linux/mutex.h>
2427937843SMartin Schwidefsky #include <linux/spinlock.h>
251daafea4SHarald Freudenberger #include <linux/delay.h>
26d00c0639SEric Biggers #include <crypto/internal/skcipher.h>
2727937843SMartin Schwidefsky #include <crypto/xts.h>
2827937843SMartin Schwidefsky #include <asm/cpacf.h>
2927937843SMartin Schwidefsky #include <asm/pkey.h>
3027937843SMartin Schwidefsky 
31416f79c2SHarald Freudenberger /*
32416f79c2SHarald Freudenberger  * Key blobs smaller/bigger than these defines are rejected
33416f79c2SHarald Freudenberger  * by the common code even before the individual setkey function
34416f79c2SHarald Freudenberger  * is called. As paes can handle different kinds of key blobs
35416f79c2SHarald Freudenberger  * and padding is also possible, the limits need to be generous.
36416f79c2SHarald Freudenberger  */
377f820d05SHarald Freudenberger #define PAES_MIN_KEYSIZE 16
38cba33db3SHolger Dengler #define PAES_MAX_KEYSIZE MAXEP11AESKEYBLOBSIZE
39416f79c2SHarald Freudenberger 
4027937843SMartin Schwidefsky static u8 *ctrblk;
416f3196b7SHarald Freudenberger static DEFINE_MUTEX(ctrblk_lock);
4227937843SMartin Schwidefsky 
4327937843SMartin Schwidefsky static cpacf_mask_t km_functions, kmc_functions, kmctr_functions;
4427937843SMartin Schwidefsky 
4552a34b34SIngo Franzki struct key_blob {
46416f79c2SHarald Freudenberger 	/*
47416f79c2SHarald Freudenberger 	 * Small keys will be stored in the keybuf. Larger keys are
48416f79c2SHarald Freudenberger 	 * stored in extra allocated memory. In both cases does
49416f79c2SHarald Freudenberger 	 * key point to the memory where the key is stored.
50416f79c2SHarald Freudenberger 	 * The code distinguishes by checking keylen against
51416f79c2SHarald Freudenberger 	 * sizeof(keybuf). See the two following helper functions.
52416f79c2SHarald Freudenberger 	 */
53416f79c2SHarald Freudenberger 	u8 *key;
54416f79c2SHarald Freudenberger 	u8 keybuf[128];
5552a34b34SIngo Franzki 	unsigned int keylen;
5652a34b34SIngo Franzki };
5752a34b34SIngo Franzki 
_key_to_kb(struct key_blob * kb,const u8 * key,unsigned int keylen)587f820d05SHarald Freudenberger static inline int _key_to_kb(struct key_blob *kb,
59416f79c2SHarald Freudenberger 			     const u8 *key,
60416f79c2SHarald Freudenberger 			     unsigned int keylen)
61416f79c2SHarald Freudenberger {
627f820d05SHarald Freudenberger 	struct clearkey_header {
637f820d05SHarald Freudenberger 		u8  type;
647f820d05SHarald Freudenberger 		u8  res0[3];
657f820d05SHarald Freudenberger 		u8  version;
667f820d05SHarald Freudenberger 		u8  res1[3];
677f820d05SHarald Freudenberger 		u32 keytype;
687f820d05SHarald Freudenberger 		u32 len;
697f820d05SHarald Freudenberger 	} __packed * h;
707f820d05SHarald Freudenberger 
717f820d05SHarald Freudenberger 	switch (keylen) {
727f820d05SHarald Freudenberger 	case 16:
737f820d05SHarald Freudenberger 	case 24:
747f820d05SHarald Freudenberger 	case 32:
757f820d05SHarald Freudenberger 		/* clear key value, prepare pkey clear key token in keybuf */
767f820d05SHarald Freudenberger 		memset(kb->keybuf, 0, sizeof(kb->keybuf));
777f820d05SHarald Freudenberger 		h = (struct clearkey_header *) kb->keybuf;
787f820d05SHarald Freudenberger 		h->version = 0x02; /* TOKVER_CLEAR_KEY */
797f820d05SHarald Freudenberger 		h->keytype = (keylen - 8) >> 3;
807f820d05SHarald Freudenberger 		h->len = keylen;
817f820d05SHarald Freudenberger 		memcpy(kb->keybuf + sizeof(*h), key, keylen);
827f820d05SHarald Freudenberger 		kb->keylen = sizeof(*h) + keylen;
837f820d05SHarald Freudenberger 		kb->key = kb->keybuf;
847f820d05SHarald Freudenberger 		break;
857f820d05SHarald Freudenberger 	default:
867f820d05SHarald Freudenberger 		/* other key material, let pkey handle this */
87416f79c2SHarald Freudenberger 		if (keylen <= sizeof(kb->keybuf))
88416f79c2SHarald Freudenberger 			kb->key = kb->keybuf;
89416f79c2SHarald Freudenberger 		else {
90416f79c2SHarald Freudenberger 			kb->key = kmalloc(keylen, GFP_KERNEL);
91416f79c2SHarald Freudenberger 			if (!kb->key)
92416f79c2SHarald Freudenberger 				return -ENOMEM;
93416f79c2SHarald Freudenberger 		}
94416f79c2SHarald Freudenberger 		memcpy(kb->key, key, keylen);
95416f79c2SHarald Freudenberger 		kb->keylen = keylen;
967f820d05SHarald Freudenberger 		break;
977f820d05SHarald Freudenberger 	}
98416f79c2SHarald Freudenberger 
99416f79c2SHarald Freudenberger 	return 0;
100416f79c2SHarald Freudenberger }
101416f79c2SHarald Freudenberger 
_free_kb_keybuf(struct key_blob * kb)102416f79c2SHarald Freudenberger static inline void _free_kb_keybuf(struct key_blob *kb)
103416f79c2SHarald Freudenberger {
104416f79c2SHarald Freudenberger 	if (kb->key && kb->key != kb->keybuf
105416f79c2SHarald Freudenberger 	    && kb->keylen > sizeof(kb->keybuf)) {
1061f7e9067SWang Ming 		kfree_sensitive(kb->key);
107416f79c2SHarald Freudenberger 		kb->key = NULL;
108416f79c2SHarald Freudenberger 	}
109416f79c2SHarald Freudenberger }
110416f79c2SHarald Freudenberger 
11127937843SMartin Schwidefsky struct s390_paes_ctx {
11252a34b34SIngo Franzki 	struct key_blob kb;
11327937843SMartin Schwidefsky 	struct pkey_protkey pk;
1146f3196b7SHarald Freudenberger 	spinlock_t pk_lock;
11527937843SMartin Schwidefsky 	unsigned long fc;
11627937843SMartin Schwidefsky };
11727937843SMartin Schwidefsky 
11827937843SMartin Schwidefsky struct s390_pxts_ctx {
11952a34b34SIngo Franzki 	struct key_blob kb[2];
12027937843SMartin Schwidefsky 	struct pkey_protkey pk[2];
1216f3196b7SHarald Freudenberger 	spinlock_t pk_lock;
12227937843SMartin Schwidefsky 	unsigned long fc;
12327937843SMartin Schwidefsky };
12427937843SMartin Schwidefsky 
__paes_keyblob2pkey(struct key_blob * kb,struct pkey_protkey * pk)1256f3196b7SHarald Freudenberger static inline int __paes_keyblob2pkey(struct key_blob *kb,
12627937843SMartin Schwidefsky 				     struct pkey_protkey *pk)
12727937843SMartin Schwidefsky {
1287bbe449dSHarald Freudenberger 	int i, ret = -EIO;
1297bbe449dSHarald Freudenberger 
1307bbe449dSHarald Freudenberger 	/* try three times in case of busy card */
1317bbe449dSHarald Freudenberger 	for (i = 0; ret && i < 3; i++) {
1327bbe449dSHarald Freudenberger 		if (ret == -EBUSY && in_task()) {
1337bbe449dSHarald Freudenberger 			if (msleep_interruptible(1000))
1347bbe449dSHarald Freudenberger 				return -EINTR;
1357bbe449dSHarald Freudenberger 		}
13686fbf5e2SHarald Freudenberger 		ret = pkey_key2protkey(kb->key, kb->keylen,
137f370f45cSHarald Freudenberger 				       pk->protkey, &pk->len, &pk->type);
13827937843SMartin Schwidefsky 	}
13927937843SMartin Schwidefsky 
1407bbe449dSHarald Freudenberger 	return ret;
1417bbe449dSHarald Freudenberger }
1427bbe449dSHarald Freudenberger 
__paes_convert_key(struct s390_paes_ctx * ctx)1436f3196b7SHarald Freudenberger static inline int __paes_convert_key(struct s390_paes_ctx *ctx)
1446f3196b7SHarald Freudenberger {
1451daafea4SHarald Freudenberger 	int ret;
1466f3196b7SHarald Freudenberger 	struct pkey_protkey pkey;
1476f3196b7SHarald Freudenberger 
148f370f45cSHarald Freudenberger 	pkey.len = sizeof(pkey.protkey);
1491daafea4SHarald Freudenberger 	ret = __paes_keyblob2pkey(&ctx->kb, &pkey);
1501daafea4SHarald Freudenberger 	if (ret)
1511daafea4SHarald Freudenberger 		return ret;
1526f3196b7SHarald Freudenberger 
1536f3196b7SHarald Freudenberger 	spin_lock_bh(&ctx->pk_lock);
1546f3196b7SHarald Freudenberger 	memcpy(&ctx->pk, &pkey, sizeof(pkey));
1556f3196b7SHarald Freudenberger 	spin_unlock_bh(&ctx->pk_lock);
1566f3196b7SHarald Freudenberger 
1576f3196b7SHarald Freudenberger 	return 0;
1586f3196b7SHarald Freudenberger }
1596f3196b7SHarald Freudenberger 
ecb_paes_init(struct crypto_skcipher * tfm)1606f3196b7SHarald Freudenberger static int ecb_paes_init(struct crypto_skcipher *tfm)
1616f3196b7SHarald Freudenberger {
1626f3196b7SHarald Freudenberger 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
1636f3196b7SHarald Freudenberger 
1646f3196b7SHarald Freudenberger 	ctx->kb.key = NULL;
1656f3196b7SHarald Freudenberger 	spin_lock_init(&ctx->pk_lock);
1666f3196b7SHarald Freudenberger 
1676f3196b7SHarald Freudenberger 	return 0;
1686f3196b7SHarald Freudenberger }
1696f3196b7SHarald Freudenberger 
ecb_paes_exit(struct crypto_skcipher * tfm)1706f3196b7SHarald Freudenberger static void ecb_paes_exit(struct crypto_skcipher *tfm)
1716f3196b7SHarald Freudenberger {
1726f3196b7SHarald Freudenberger 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
1736f3196b7SHarald Freudenberger 
1746f3196b7SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb);
1756f3196b7SHarald Freudenberger }
1766f3196b7SHarald Freudenberger 
__ecb_paes_set_key(struct s390_paes_ctx * ctx)1776f3196b7SHarald Freudenberger static inline int __ecb_paes_set_key(struct s390_paes_ctx *ctx)
17827937843SMartin Schwidefsky {
1791daafea4SHarald Freudenberger 	int rc;
18027937843SMartin Schwidefsky 	unsigned long fc;
18127937843SMartin Schwidefsky 
1821daafea4SHarald Freudenberger 	rc = __paes_convert_key(ctx);
1831daafea4SHarald Freudenberger 	if (rc)
1841daafea4SHarald Freudenberger 		return rc;
18527937843SMartin Schwidefsky 
18627937843SMartin Schwidefsky 	/* Pick the correct function code based on the protected key type */
18727937843SMartin Schwidefsky 	fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PAES_128 :
18827937843SMartin Schwidefsky 		(ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KM_PAES_192 :
18927937843SMartin Schwidefsky 		(ctx->pk.type == PKEY_KEYTYPE_AES_256) ? CPACF_KM_PAES_256 : 0;
19027937843SMartin Schwidefsky 
19127937843SMartin Schwidefsky 	/* Check if the function code is available */
19227937843SMartin Schwidefsky 	ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0;
19327937843SMartin Schwidefsky 
19427937843SMartin Schwidefsky 	return ctx->fc ? 0 : -EINVAL;
19527937843SMartin Schwidefsky }
19627937843SMartin Schwidefsky 
ecb_paes_set_key(struct crypto_skcipher * tfm,const u8 * in_key,unsigned int key_len)197d00c0639SEric Biggers static int ecb_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
198416f79c2SHarald Freudenberger 			    unsigned int key_len)
199416f79c2SHarald Freudenberger {
200416f79c2SHarald Freudenberger 	int rc;
201d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
202416f79c2SHarald Freudenberger 
203416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb);
2047f820d05SHarald Freudenberger 	rc = _key_to_kb(&ctx->kb, in_key, key_len);
205416f79c2SHarald Freudenberger 	if (rc)
206416f79c2SHarald Freudenberger 		return rc;
207416f79c2SHarald Freudenberger 
2086f3196b7SHarald Freudenberger 	return __ecb_paes_set_key(ctx);
20927937843SMartin Schwidefsky }
21027937843SMartin Schwidefsky 
ecb_paes_crypt(struct skcipher_request * req,unsigned long modifier)211d00c0639SEric Biggers static int ecb_paes_crypt(struct skcipher_request *req, unsigned long modifier)
21227937843SMartin Schwidefsky {
213d00c0639SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
214d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
215d00c0639SEric Biggers 	struct skcipher_walk walk;
21627937843SMartin Schwidefsky 	unsigned int nbytes, n, k;
21727937843SMartin Schwidefsky 	int ret;
2186f3196b7SHarald Freudenberger 	struct {
2196f3196b7SHarald Freudenberger 		u8 key[MAXPROTKEYSIZE];
2206f3196b7SHarald Freudenberger 	} param;
22127937843SMartin Schwidefsky 
222d00c0639SEric Biggers 	ret = skcipher_walk_virt(&walk, req, false);
2236f3196b7SHarald Freudenberger 	if (ret)
2246f3196b7SHarald Freudenberger 		return ret;
2256f3196b7SHarald Freudenberger 
2266f3196b7SHarald Freudenberger 	spin_lock_bh(&ctx->pk_lock);
2276f3196b7SHarald Freudenberger 	memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
2286f3196b7SHarald Freudenberger 	spin_unlock_bh(&ctx->pk_lock);
2296f3196b7SHarald Freudenberger 
230d00c0639SEric Biggers 	while ((nbytes = walk.nbytes) != 0) {
23127937843SMartin Schwidefsky 		/* only use complete blocks */
23227937843SMartin Schwidefsky 		n = nbytes & ~(AES_BLOCK_SIZE - 1);
2336f3196b7SHarald Freudenberger 		k = cpacf_km(ctx->fc | modifier, &param,
234d00c0639SEric Biggers 			     walk.dst.virt.addr, walk.src.virt.addr, n);
23527937843SMartin Schwidefsky 		if (k)
236d00c0639SEric Biggers 			ret = skcipher_walk_done(&walk, nbytes - k);
23727937843SMartin Schwidefsky 		if (k < n) {
2386f3196b7SHarald Freudenberger 			if (__paes_convert_key(ctx))
239d00c0639SEric Biggers 				return skcipher_walk_done(&walk, -EIO);
2406f3196b7SHarald Freudenberger 			spin_lock_bh(&ctx->pk_lock);
2416f3196b7SHarald Freudenberger 			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
2426f3196b7SHarald Freudenberger 			spin_unlock_bh(&ctx->pk_lock);
24327937843SMartin Schwidefsky 		}
24427937843SMartin Schwidefsky 	}
24527937843SMartin Schwidefsky 	return ret;
24627937843SMartin Schwidefsky }
24727937843SMartin Schwidefsky 
ecb_paes_encrypt(struct skcipher_request * req)248d00c0639SEric Biggers static int ecb_paes_encrypt(struct skcipher_request *req)
24927937843SMartin Schwidefsky {
250d00c0639SEric Biggers 	return ecb_paes_crypt(req, 0);
25127937843SMartin Schwidefsky }
25227937843SMartin Schwidefsky 
ecb_paes_decrypt(struct skcipher_request * req)253d00c0639SEric Biggers static int ecb_paes_decrypt(struct skcipher_request *req)
25427937843SMartin Schwidefsky {
255d00c0639SEric Biggers 	return ecb_paes_crypt(req, CPACF_DECRYPT);
25627937843SMartin Schwidefsky }
25727937843SMartin Schwidefsky 
258d00c0639SEric Biggers static struct skcipher_alg ecb_paes_alg = {
259d00c0639SEric Biggers 	.base.cra_name		=	"ecb(paes)",
260d00c0639SEric Biggers 	.base.cra_driver_name	=	"ecb-paes-s390",
261d00c0639SEric Biggers 	.base.cra_priority	=	401,	/* combo: aes + ecb + 1 */
262d00c0639SEric Biggers 	.base.cra_blocksize	=	AES_BLOCK_SIZE,
263d00c0639SEric Biggers 	.base.cra_ctxsize	=	sizeof(struct s390_paes_ctx),
264d00c0639SEric Biggers 	.base.cra_module	=	THIS_MODULE,
265d00c0639SEric Biggers 	.base.cra_list		=	LIST_HEAD_INIT(ecb_paes_alg.base.cra_list),
266d00c0639SEric Biggers 	.init			=	ecb_paes_init,
267d00c0639SEric Biggers 	.exit			=	ecb_paes_exit,
268416f79c2SHarald Freudenberger 	.min_keysize		=	PAES_MIN_KEYSIZE,
269416f79c2SHarald Freudenberger 	.max_keysize		=	PAES_MAX_KEYSIZE,
27027937843SMartin Schwidefsky 	.setkey			=	ecb_paes_set_key,
27127937843SMartin Schwidefsky 	.encrypt		=	ecb_paes_encrypt,
27227937843SMartin Schwidefsky 	.decrypt		=	ecb_paes_decrypt,
27327937843SMartin Schwidefsky };
27427937843SMartin Schwidefsky 
cbc_paes_init(struct crypto_skcipher * tfm)275d00c0639SEric Biggers static int cbc_paes_init(struct crypto_skcipher *tfm)
276416f79c2SHarald Freudenberger {
277d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
278416f79c2SHarald Freudenberger 
279416f79c2SHarald Freudenberger 	ctx->kb.key = NULL;
2806f3196b7SHarald Freudenberger 	spin_lock_init(&ctx->pk_lock);
281416f79c2SHarald Freudenberger 
282416f79c2SHarald Freudenberger 	return 0;
283416f79c2SHarald Freudenberger }
284416f79c2SHarald Freudenberger 
cbc_paes_exit(struct crypto_skcipher * tfm)285d00c0639SEric Biggers static void cbc_paes_exit(struct crypto_skcipher *tfm)
286416f79c2SHarald Freudenberger {
287d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
288416f79c2SHarald Freudenberger 
289416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb);
290416f79c2SHarald Freudenberger }
291416f79c2SHarald Freudenberger 
__cbc_paes_set_key(struct s390_paes_ctx * ctx)2926f3196b7SHarald Freudenberger static inline int __cbc_paes_set_key(struct s390_paes_ctx *ctx)
29327937843SMartin Schwidefsky {
2941daafea4SHarald Freudenberger 	int rc;
29527937843SMartin Schwidefsky 	unsigned long fc;
29627937843SMartin Schwidefsky 
2971daafea4SHarald Freudenberger 	rc = __paes_convert_key(ctx);
2981daafea4SHarald Freudenberger 	if (rc)
2991daafea4SHarald Freudenberger 		return rc;
30027937843SMartin Schwidefsky 
30127937843SMartin Schwidefsky 	/* Pick the correct function code based on the protected key type */
30227937843SMartin Schwidefsky 	fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KMC_PAES_128 :
30327937843SMartin Schwidefsky 		(ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KMC_PAES_192 :
30427937843SMartin Schwidefsky 		(ctx->pk.type == PKEY_KEYTYPE_AES_256) ? CPACF_KMC_PAES_256 : 0;
30527937843SMartin Schwidefsky 
30627937843SMartin Schwidefsky 	/* Check if the function code is available */
30727937843SMartin Schwidefsky 	ctx->fc = (fc && cpacf_test_func(&kmc_functions, fc)) ? fc : 0;
30827937843SMartin Schwidefsky 
30927937843SMartin Schwidefsky 	return ctx->fc ? 0 : -EINVAL;
31027937843SMartin Schwidefsky }
31127937843SMartin Schwidefsky 
cbc_paes_set_key(struct crypto_skcipher * tfm,const u8 * in_key,unsigned int key_len)312d00c0639SEric Biggers static int cbc_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
31327937843SMartin Schwidefsky 			    unsigned int key_len)
31427937843SMartin Schwidefsky {
315416f79c2SHarald Freudenberger 	int rc;
316d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
31727937843SMartin Schwidefsky 
318416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb);
3197f820d05SHarald Freudenberger 	rc = _key_to_kb(&ctx->kb, in_key, key_len);
320416f79c2SHarald Freudenberger 	if (rc)
321416f79c2SHarald Freudenberger 		return rc;
322416f79c2SHarald Freudenberger 
323674f368aSEric Biggers 	return __cbc_paes_set_key(ctx);
32427937843SMartin Schwidefsky }
32527937843SMartin Schwidefsky 
cbc_paes_crypt(struct skcipher_request * req,unsigned long modifier)326d00c0639SEric Biggers static int cbc_paes_crypt(struct skcipher_request *req, unsigned long modifier)
32727937843SMartin Schwidefsky {
328d00c0639SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
329d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
330d00c0639SEric Biggers 	struct skcipher_walk walk;
33127937843SMartin Schwidefsky 	unsigned int nbytes, n, k;
33227937843SMartin Schwidefsky 	int ret;
33327937843SMartin Schwidefsky 	struct {
33427937843SMartin Schwidefsky 		u8 iv[AES_BLOCK_SIZE];
33527937843SMartin Schwidefsky 		u8 key[MAXPROTKEYSIZE];
33627937843SMartin Schwidefsky 	} param;
33727937843SMartin Schwidefsky 
338d00c0639SEric Biggers 	ret = skcipher_walk_virt(&walk, req, false);
339d00c0639SEric Biggers 	if (ret)
340d00c0639SEric Biggers 		return ret;
3416f3196b7SHarald Freudenberger 
342d00c0639SEric Biggers 	memcpy(param.iv, walk.iv, AES_BLOCK_SIZE);
3436f3196b7SHarald Freudenberger 	spin_lock_bh(&ctx->pk_lock);
34427937843SMartin Schwidefsky 	memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
3456f3196b7SHarald Freudenberger 	spin_unlock_bh(&ctx->pk_lock);
3466f3196b7SHarald Freudenberger 
347d00c0639SEric Biggers 	while ((nbytes = walk.nbytes) != 0) {
34827937843SMartin Schwidefsky 		/* only use complete blocks */
34927937843SMartin Schwidefsky 		n = nbytes & ~(AES_BLOCK_SIZE - 1);
35027937843SMartin Schwidefsky 		k = cpacf_kmc(ctx->fc | modifier, &param,
351d00c0639SEric Biggers 			      walk.dst.virt.addr, walk.src.virt.addr, n);
352d00c0639SEric Biggers 		if (k) {
353d00c0639SEric Biggers 			memcpy(walk.iv, param.iv, AES_BLOCK_SIZE);
354d00c0639SEric Biggers 			ret = skcipher_walk_done(&walk, nbytes - k);
355d00c0639SEric Biggers 		}
356b81126e0SIngo Franzki 		if (k < n) {
3576f3196b7SHarald Freudenberger 			if (__paes_convert_key(ctx))
358d00c0639SEric Biggers 				return skcipher_walk_done(&walk, -EIO);
3596f3196b7SHarald Freudenberger 			spin_lock_bh(&ctx->pk_lock);
36027937843SMartin Schwidefsky 			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
3616f3196b7SHarald Freudenberger 			spin_unlock_bh(&ctx->pk_lock);
36227937843SMartin Schwidefsky 		}
36327937843SMartin Schwidefsky 	}
36427937843SMartin Schwidefsky 	return ret;
36527937843SMartin Schwidefsky }
36627937843SMartin Schwidefsky 
cbc_paes_encrypt(struct skcipher_request * req)367d00c0639SEric Biggers static int cbc_paes_encrypt(struct skcipher_request *req)
36827937843SMartin Schwidefsky {
369d00c0639SEric Biggers 	return cbc_paes_crypt(req, 0);
37027937843SMartin Schwidefsky }
37127937843SMartin Schwidefsky 
cbc_paes_decrypt(struct skcipher_request * req)372d00c0639SEric Biggers static int cbc_paes_decrypt(struct skcipher_request *req)
37327937843SMartin Schwidefsky {
374d00c0639SEric Biggers 	return cbc_paes_crypt(req, CPACF_DECRYPT);
37527937843SMartin Schwidefsky }
37627937843SMartin Schwidefsky 
377d00c0639SEric Biggers static struct skcipher_alg cbc_paes_alg = {
378d00c0639SEric Biggers 	.base.cra_name		=	"cbc(paes)",
379d00c0639SEric Biggers 	.base.cra_driver_name	=	"cbc-paes-s390",
380d00c0639SEric Biggers 	.base.cra_priority	=	402,	/* ecb-paes-s390 + 1 */
381d00c0639SEric Biggers 	.base.cra_blocksize	=	AES_BLOCK_SIZE,
382d00c0639SEric Biggers 	.base.cra_ctxsize	=	sizeof(struct s390_paes_ctx),
383d00c0639SEric Biggers 	.base.cra_module	=	THIS_MODULE,
384d00c0639SEric Biggers 	.base.cra_list		=	LIST_HEAD_INIT(cbc_paes_alg.base.cra_list),
385d00c0639SEric Biggers 	.init			=	cbc_paes_init,
386d00c0639SEric Biggers 	.exit			=	cbc_paes_exit,
387416f79c2SHarald Freudenberger 	.min_keysize		=	PAES_MIN_KEYSIZE,
388416f79c2SHarald Freudenberger 	.max_keysize		=	PAES_MAX_KEYSIZE,
38927937843SMartin Schwidefsky 	.ivsize			=	AES_BLOCK_SIZE,
39027937843SMartin Schwidefsky 	.setkey			=	cbc_paes_set_key,
39127937843SMartin Schwidefsky 	.encrypt		=	cbc_paes_encrypt,
39227937843SMartin Schwidefsky 	.decrypt		=	cbc_paes_decrypt,
39327937843SMartin Schwidefsky };
39427937843SMartin Schwidefsky 
xts_paes_init(struct crypto_skcipher * tfm)395d00c0639SEric Biggers static int xts_paes_init(struct crypto_skcipher *tfm)
396416f79c2SHarald Freudenberger {
397d00c0639SEric Biggers 	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
398416f79c2SHarald Freudenberger 
399416f79c2SHarald Freudenberger 	ctx->kb[0].key = NULL;
400416f79c2SHarald Freudenberger 	ctx->kb[1].key = NULL;
4016f3196b7SHarald Freudenberger 	spin_lock_init(&ctx->pk_lock);
402416f79c2SHarald Freudenberger 
403416f79c2SHarald Freudenberger 	return 0;
404416f79c2SHarald Freudenberger }
405416f79c2SHarald Freudenberger 
xts_paes_exit(struct crypto_skcipher * tfm)406d00c0639SEric Biggers static void xts_paes_exit(struct crypto_skcipher *tfm)
407416f79c2SHarald Freudenberger {
408d00c0639SEric Biggers 	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
409416f79c2SHarald Freudenberger 
410416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb[0]);
411416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb[1]);
412416f79c2SHarald Freudenberger }
413416f79c2SHarald Freudenberger 
__xts_paes_convert_key(struct s390_pxts_ctx * ctx)4146f3196b7SHarald Freudenberger static inline int __xts_paes_convert_key(struct s390_pxts_ctx *ctx)
4156f3196b7SHarald Freudenberger {
4166f3196b7SHarald Freudenberger 	struct pkey_protkey pkey0, pkey1;
4176f3196b7SHarald Freudenberger 
418f370f45cSHarald Freudenberger 	pkey0.len = sizeof(pkey0.protkey);
419f370f45cSHarald Freudenberger 	pkey1.len = sizeof(pkey1.protkey);
420f370f45cSHarald Freudenberger 
4216f3196b7SHarald Freudenberger 	if (__paes_keyblob2pkey(&ctx->kb[0], &pkey0) ||
4226f3196b7SHarald Freudenberger 	    __paes_keyblob2pkey(&ctx->kb[1], &pkey1))
4236f3196b7SHarald Freudenberger 		return -EINVAL;
4246f3196b7SHarald Freudenberger 
4256f3196b7SHarald Freudenberger 	spin_lock_bh(&ctx->pk_lock);
4266f3196b7SHarald Freudenberger 	memcpy(&ctx->pk[0], &pkey0, sizeof(pkey0));
4276f3196b7SHarald Freudenberger 	memcpy(&ctx->pk[1], &pkey1, sizeof(pkey1));
4286f3196b7SHarald Freudenberger 	spin_unlock_bh(&ctx->pk_lock);
4296f3196b7SHarald Freudenberger 
4306f3196b7SHarald Freudenberger 	return 0;
4316f3196b7SHarald Freudenberger }
4326f3196b7SHarald Freudenberger 
__xts_paes_set_key(struct s390_pxts_ctx * ctx)4336f3196b7SHarald Freudenberger static inline int __xts_paes_set_key(struct s390_pxts_ctx *ctx)
43427937843SMartin Schwidefsky {
43527937843SMartin Schwidefsky 	unsigned long fc;
43627937843SMartin Schwidefsky 
4376f3196b7SHarald Freudenberger 	if (__xts_paes_convert_key(ctx))
43827937843SMartin Schwidefsky 		return -EINVAL;
43927937843SMartin Schwidefsky 
44027937843SMartin Schwidefsky 	if (ctx->pk[0].type != ctx->pk[1].type)
44127937843SMartin Schwidefsky 		return -EINVAL;
44227937843SMartin Schwidefsky 
44327937843SMartin Schwidefsky 	/* Pick the correct function code based on the protected key type */
44427937843SMartin Schwidefsky 	fc = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PXTS_128 :
44527937843SMartin Schwidefsky 		(ctx->pk[0].type == PKEY_KEYTYPE_AES_256) ?
44627937843SMartin Schwidefsky 		CPACF_KM_PXTS_256 : 0;
44727937843SMartin Schwidefsky 
44827937843SMartin Schwidefsky 	/* Check if the function code is available */
44927937843SMartin Schwidefsky 	ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0;
45027937843SMartin Schwidefsky 
45127937843SMartin Schwidefsky 	return ctx->fc ? 0 : -EINVAL;
45227937843SMartin Schwidefsky }
45327937843SMartin Schwidefsky 
xts_paes_set_key(struct crypto_skcipher * tfm,const u8 * in_key,unsigned int xts_key_len)454d00c0639SEric Biggers static int xts_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
455416f79c2SHarald Freudenberger 			    unsigned int xts_key_len)
45627937843SMartin Schwidefsky {
457416f79c2SHarald Freudenberger 	int rc;
458d00c0639SEric Biggers 	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
45927937843SMartin Schwidefsky 	u8 ckey[2 * AES_MAX_KEY_SIZE];
460416f79c2SHarald Freudenberger 	unsigned int ckey_len, key_len;
46127937843SMartin Schwidefsky 
462416f79c2SHarald Freudenberger 	if (xts_key_len % 2)
46352a34b34SIngo Franzki 		return -EINVAL;
46452a34b34SIngo Franzki 
465416f79c2SHarald Freudenberger 	key_len = xts_key_len / 2;
466416f79c2SHarald Freudenberger 
467416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb[0]);
468416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb[1]);
4697f820d05SHarald Freudenberger 	rc = _key_to_kb(&ctx->kb[0], in_key, key_len);
470416f79c2SHarald Freudenberger 	if (rc)
471416f79c2SHarald Freudenberger 		return rc;
4727f820d05SHarald Freudenberger 	rc = _key_to_kb(&ctx->kb[1], in_key + key_len, key_len);
473416f79c2SHarald Freudenberger 	if (rc)
474416f79c2SHarald Freudenberger 		return rc;
475416f79c2SHarald Freudenberger 
476674f368aSEric Biggers 	rc = __xts_paes_set_key(ctx);
477674f368aSEric Biggers 	if (rc)
478674f368aSEric Biggers 		return rc;
47927937843SMartin Schwidefsky 
48027937843SMartin Schwidefsky 	/*
4810ee43367SVladis Dronov 	 * xts_verify_key verifies the key length is not odd and makes
48227937843SMartin Schwidefsky 	 * sure that the two keys are not the same. This can be done
48327937843SMartin Schwidefsky 	 * on the two protected keys as well
48427937843SMartin Schwidefsky 	 */
48527937843SMartin Schwidefsky 	ckey_len = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ?
48627937843SMartin Schwidefsky 		AES_KEYSIZE_128 : AES_KEYSIZE_256;
48727937843SMartin Schwidefsky 	memcpy(ckey, ctx->pk[0].protkey, ckey_len);
48827937843SMartin Schwidefsky 	memcpy(ckey + ckey_len, ctx->pk[1].protkey, ckey_len);
489d00c0639SEric Biggers 	return xts_verify_key(tfm, ckey, 2*ckey_len);
49027937843SMartin Schwidefsky }
49127937843SMartin Schwidefsky 
xts_paes_crypt(struct skcipher_request * req,unsigned long modifier)492d00c0639SEric Biggers static int xts_paes_crypt(struct skcipher_request *req, unsigned long modifier)
49327937843SMartin Schwidefsky {
494d00c0639SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
495d00c0639SEric Biggers 	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
496d00c0639SEric Biggers 	struct skcipher_walk walk;
49727937843SMartin Schwidefsky 	unsigned int keylen, offset, nbytes, n, k;
49827937843SMartin Schwidefsky 	int ret;
49927937843SMartin Schwidefsky 	struct {
50027937843SMartin Schwidefsky 		u8 key[MAXPROTKEYSIZE];	/* key + verification pattern */
50127937843SMartin Schwidefsky 		u8 tweak[16];
50227937843SMartin Schwidefsky 		u8 block[16];
50327937843SMartin Schwidefsky 		u8 bit[16];
50427937843SMartin Schwidefsky 		u8 xts[16];
50527937843SMartin Schwidefsky 	} pcc_param;
50627937843SMartin Schwidefsky 	struct {
50727937843SMartin Schwidefsky 		u8 key[MAXPROTKEYSIZE];	/* key + verification pattern */
50827937843SMartin Schwidefsky 		u8 init[16];
50927937843SMartin Schwidefsky 	} xts_param;
51027937843SMartin Schwidefsky 
511d00c0639SEric Biggers 	ret = skcipher_walk_virt(&walk, req, false);
512d00c0639SEric Biggers 	if (ret)
513d00c0639SEric Biggers 		return ret;
5146f3196b7SHarald Freudenberger 
51527937843SMartin Schwidefsky 	keylen = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 48 : 64;
51627937843SMartin Schwidefsky 	offset = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 16 : 0;
5176f3196b7SHarald Freudenberger 
51827937843SMartin Schwidefsky 	memset(&pcc_param, 0, sizeof(pcc_param));
519d00c0639SEric Biggers 	memcpy(pcc_param.tweak, walk.iv, sizeof(pcc_param.tweak));
5206f3196b7SHarald Freudenberger 	spin_lock_bh(&ctx->pk_lock);
52127937843SMartin Schwidefsky 	memcpy(pcc_param.key + offset, ctx->pk[1].protkey, keylen);
52227937843SMartin Schwidefsky 	memcpy(xts_param.key + offset, ctx->pk[0].protkey, keylen);
5236f3196b7SHarald Freudenberger 	spin_unlock_bh(&ctx->pk_lock);
5246f3196b7SHarald Freudenberger 	cpacf_pcc(ctx->fc, pcc_param.key + offset);
52527937843SMartin Schwidefsky 	memcpy(xts_param.init, pcc_param.xts, 16);
52627937843SMartin Schwidefsky 
527d00c0639SEric Biggers 	while ((nbytes = walk.nbytes) != 0) {
52827937843SMartin Schwidefsky 		/* only use complete blocks */
52927937843SMartin Schwidefsky 		n = nbytes & ~(AES_BLOCK_SIZE - 1);
53027937843SMartin Schwidefsky 		k = cpacf_km(ctx->fc | modifier, xts_param.key + offset,
531d00c0639SEric Biggers 			     walk.dst.virt.addr, walk.src.virt.addr, n);
53227937843SMartin Schwidefsky 		if (k)
533d00c0639SEric Biggers 			ret = skcipher_walk_done(&walk, nbytes - k);
53427937843SMartin Schwidefsky 		if (k < n) {
5356f3196b7SHarald Freudenberger 			if (__xts_paes_convert_key(ctx))
536d00c0639SEric Biggers 				return skcipher_walk_done(&walk, -EIO);
5376f3196b7SHarald Freudenberger 			spin_lock_bh(&ctx->pk_lock);
5386f3196b7SHarald Freudenberger 			memcpy(xts_param.key + offset,
5396f3196b7SHarald Freudenberger 			       ctx->pk[0].protkey, keylen);
5406f3196b7SHarald Freudenberger 			spin_unlock_bh(&ctx->pk_lock);
54127937843SMartin Schwidefsky 		}
54227937843SMartin Schwidefsky 	}
5436f3196b7SHarald Freudenberger 
54427937843SMartin Schwidefsky 	return ret;
54527937843SMartin Schwidefsky }
54627937843SMartin Schwidefsky 
xts_paes_encrypt(struct skcipher_request * req)547d00c0639SEric Biggers static int xts_paes_encrypt(struct skcipher_request *req)
54827937843SMartin Schwidefsky {
549d00c0639SEric Biggers 	return xts_paes_crypt(req, 0);
55027937843SMartin Schwidefsky }
55127937843SMartin Schwidefsky 
xts_paes_decrypt(struct skcipher_request * req)552d00c0639SEric Biggers static int xts_paes_decrypt(struct skcipher_request *req)
55327937843SMartin Schwidefsky {
554d00c0639SEric Biggers 	return xts_paes_crypt(req, CPACF_DECRYPT);
55527937843SMartin Schwidefsky }
55627937843SMartin Schwidefsky 
557d00c0639SEric Biggers static struct skcipher_alg xts_paes_alg = {
558d00c0639SEric Biggers 	.base.cra_name		=	"xts(paes)",
559d00c0639SEric Biggers 	.base.cra_driver_name	=	"xts-paes-s390",
560d00c0639SEric Biggers 	.base.cra_priority	=	402,	/* ecb-paes-s390 + 1 */
561d00c0639SEric Biggers 	.base.cra_blocksize	=	AES_BLOCK_SIZE,
562d00c0639SEric Biggers 	.base.cra_ctxsize	=	sizeof(struct s390_pxts_ctx),
563d00c0639SEric Biggers 	.base.cra_module	=	THIS_MODULE,
564d00c0639SEric Biggers 	.base.cra_list		=	LIST_HEAD_INIT(xts_paes_alg.base.cra_list),
565d00c0639SEric Biggers 	.init			=	xts_paes_init,
566d00c0639SEric Biggers 	.exit			=	xts_paes_exit,
567416f79c2SHarald Freudenberger 	.min_keysize		=	2 * PAES_MIN_KEYSIZE,
568416f79c2SHarald Freudenberger 	.max_keysize		=	2 * PAES_MAX_KEYSIZE,
56927937843SMartin Schwidefsky 	.ivsize			=	AES_BLOCK_SIZE,
57027937843SMartin Schwidefsky 	.setkey			=	xts_paes_set_key,
57127937843SMartin Schwidefsky 	.encrypt		=	xts_paes_encrypt,
57227937843SMartin Schwidefsky 	.decrypt		=	xts_paes_decrypt,
57327937843SMartin Schwidefsky };
57427937843SMartin Schwidefsky 
ctr_paes_init(struct crypto_skcipher * tfm)575d00c0639SEric Biggers static int ctr_paes_init(struct crypto_skcipher *tfm)
576416f79c2SHarald Freudenberger {
577d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
578416f79c2SHarald Freudenberger 
579416f79c2SHarald Freudenberger 	ctx->kb.key = NULL;
5806f3196b7SHarald Freudenberger 	spin_lock_init(&ctx->pk_lock);
581416f79c2SHarald Freudenberger 
582416f79c2SHarald Freudenberger 	return 0;
583416f79c2SHarald Freudenberger }
584416f79c2SHarald Freudenberger 
ctr_paes_exit(struct crypto_skcipher * tfm)585d00c0639SEric Biggers static void ctr_paes_exit(struct crypto_skcipher *tfm)
586416f79c2SHarald Freudenberger {
587d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
588416f79c2SHarald Freudenberger 
589416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb);
590416f79c2SHarald Freudenberger }
591416f79c2SHarald Freudenberger 
__ctr_paes_set_key(struct s390_paes_ctx * ctx)5926f3196b7SHarald Freudenberger static inline int __ctr_paes_set_key(struct s390_paes_ctx *ctx)
59327937843SMartin Schwidefsky {
5941daafea4SHarald Freudenberger 	int rc;
59527937843SMartin Schwidefsky 	unsigned long fc;
59627937843SMartin Schwidefsky 
5971daafea4SHarald Freudenberger 	rc = __paes_convert_key(ctx);
5981daafea4SHarald Freudenberger 	if (rc)
5991daafea4SHarald Freudenberger 		return rc;
60027937843SMartin Schwidefsky 
60127937843SMartin Schwidefsky 	/* Pick the correct function code based on the protected key type */
60227937843SMartin Schwidefsky 	fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KMCTR_PAES_128 :
60327937843SMartin Schwidefsky 		(ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KMCTR_PAES_192 :
60427937843SMartin Schwidefsky 		(ctx->pk.type == PKEY_KEYTYPE_AES_256) ?
60527937843SMartin Schwidefsky 		CPACF_KMCTR_PAES_256 : 0;
60627937843SMartin Schwidefsky 
60727937843SMartin Schwidefsky 	/* Check if the function code is available */
60827937843SMartin Schwidefsky 	ctx->fc = (fc && cpacf_test_func(&kmctr_functions, fc)) ? fc : 0;
60927937843SMartin Schwidefsky 
61027937843SMartin Schwidefsky 	return ctx->fc ? 0 : -EINVAL;
61127937843SMartin Schwidefsky }
61227937843SMartin Schwidefsky 
ctr_paes_set_key(struct crypto_skcipher * tfm,const u8 * in_key,unsigned int key_len)613d00c0639SEric Biggers static int ctr_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
61427937843SMartin Schwidefsky 			    unsigned int key_len)
61527937843SMartin Schwidefsky {
616416f79c2SHarald Freudenberger 	int rc;
617d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
61827937843SMartin Schwidefsky 
619416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb);
6207f820d05SHarald Freudenberger 	rc = _key_to_kb(&ctx->kb, in_key, key_len);
621416f79c2SHarald Freudenberger 	if (rc)
622416f79c2SHarald Freudenberger 		return rc;
623416f79c2SHarald Freudenberger 
624674f368aSEric Biggers 	return __ctr_paes_set_key(ctx);
62527937843SMartin Schwidefsky }
62627937843SMartin Schwidefsky 
__ctrblk_init(u8 * ctrptr,u8 * iv,unsigned int nbytes)62727937843SMartin Schwidefsky static unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes)
62827937843SMartin Schwidefsky {
62927937843SMartin Schwidefsky 	unsigned int i, n;
63027937843SMartin Schwidefsky 
63127937843SMartin Schwidefsky 	/* only use complete blocks, max. PAGE_SIZE */
63227937843SMartin Schwidefsky 	memcpy(ctrptr, iv, AES_BLOCK_SIZE);
63327937843SMartin Schwidefsky 	n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(AES_BLOCK_SIZE - 1);
63427937843SMartin Schwidefsky 	for (i = (n / AES_BLOCK_SIZE) - 1; i > 0; i--) {
63527937843SMartin Schwidefsky 		memcpy(ctrptr + AES_BLOCK_SIZE, ctrptr, AES_BLOCK_SIZE);
63627937843SMartin Schwidefsky 		crypto_inc(ctrptr + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
63727937843SMartin Schwidefsky 		ctrptr += AES_BLOCK_SIZE;
63827937843SMartin Schwidefsky 	}
63927937843SMartin Schwidefsky 	return n;
64027937843SMartin Schwidefsky }
64127937843SMartin Schwidefsky 
ctr_paes_crypt(struct skcipher_request * req)642d00c0639SEric Biggers static int ctr_paes_crypt(struct skcipher_request *req)
64327937843SMartin Schwidefsky {
644d00c0639SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
645d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
64627937843SMartin Schwidefsky 	u8 buf[AES_BLOCK_SIZE], *ctrptr;
647d00c0639SEric Biggers 	struct skcipher_walk walk;
64827937843SMartin Schwidefsky 	unsigned int nbytes, n, k;
64927937843SMartin Schwidefsky 	int ret, locked;
6506f3196b7SHarald Freudenberger 	struct {
6516f3196b7SHarald Freudenberger 		u8 key[MAXPROTKEYSIZE];
6526f3196b7SHarald Freudenberger 	} param;
65327937843SMartin Schwidefsky 
654d00c0639SEric Biggers 	ret = skcipher_walk_virt(&walk, req, false);
6556f3196b7SHarald Freudenberger 	if (ret)
6566f3196b7SHarald Freudenberger 		return ret;
6576f3196b7SHarald Freudenberger 
6586f3196b7SHarald Freudenberger 	spin_lock_bh(&ctx->pk_lock);
6596f3196b7SHarald Freudenberger 	memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
6606f3196b7SHarald Freudenberger 	spin_unlock_bh(&ctx->pk_lock);
6616f3196b7SHarald Freudenberger 
6626f3196b7SHarald Freudenberger 	locked = mutex_trylock(&ctrblk_lock);
6636f3196b7SHarald Freudenberger 
664d00c0639SEric Biggers 	while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
66527937843SMartin Schwidefsky 		n = AES_BLOCK_SIZE;
66627937843SMartin Schwidefsky 		if (nbytes >= 2*AES_BLOCK_SIZE && locked)
667d00c0639SEric Biggers 			n = __ctrblk_init(ctrblk, walk.iv, nbytes);
668d00c0639SEric Biggers 		ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk.iv;
6696f3196b7SHarald Freudenberger 		k = cpacf_kmctr(ctx->fc, &param, walk.dst.virt.addr,
670d00c0639SEric Biggers 				walk.src.virt.addr, n, ctrptr);
67127937843SMartin Schwidefsky 		if (k) {
67227937843SMartin Schwidefsky 			if (ctrptr == ctrblk)
673d00c0639SEric Biggers 				memcpy(walk.iv, ctrptr + k - AES_BLOCK_SIZE,
67427937843SMartin Schwidefsky 				       AES_BLOCK_SIZE);
675d00c0639SEric Biggers 			crypto_inc(walk.iv, AES_BLOCK_SIZE);
6766f3196b7SHarald Freudenberger 			ret = skcipher_walk_done(&walk, nbytes - k);
67727937843SMartin Schwidefsky 		}
67827937843SMartin Schwidefsky 		if (k < n) {
6796f3196b7SHarald Freudenberger 			if (__paes_convert_key(ctx)) {
680e7c95effSMartin Schwidefsky 				if (locked)
6816f3196b7SHarald Freudenberger 					mutex_unlock(&ctrblk_lock);
682d00c0639SEric Biggers 				return skcipher_walk_done(&walk, -EIO);
68327937843SMartin Schwidefsky 			}
6846f3196b7SHarald Freudenberger 			spin_lock_bh(&ctx->pk_lock);
6856f3196b7SHarald Freudenberger 			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
6866f3196b7SHarald Freudenberger 			spin_unlock_bh(&ctx->pk_lock);
68727937843SMartin Schwidefsky 		}
688e7c95effSMartin Schwidefsky 	}
68927937843SMartin Schwidefsky 	if (locked)
6906f3196b7SHarald Freudenberger 		mutex_unlock(&ctrblk_lock);
69127937843SMartin Schwidefsky 	/*
69227937843SMartin Schwidefsky 	 * final block may be < AES_BLOCK_SIZE, copy only nbytes
69327937843SMartin Schwidefsky 	 */
69427937843SMartin Schwidefsky 	if (nbytes) {
695d07f9519SHerbert Xu 		memset(buf, 0, AES_BLOCK_SIZE);
696d07f9519SHerbert Xu 		memcpy(buf, walk.src.virt.addr, nbytes);
69727937843SMartin Schwidefsky 		while (1) {
6986f3196b7SHarald Freudenberger 			if (cpacf_kmctr(ctx->fc, &param, buf,
699d07f9519SHerbert Xu 					buf, AES_BLOCK_SIZE,
700d00c0639SEric Biggers 					walk.iv) == AES_BLOCK_SIZE)
70127937843SMartin Schwidefsky 				break;
7026f3196b7SHarald Freudenberger 			if (__paes_convert_key(ctx))
703d00c0639SEric Biggers 				return skcipher_walk_done(&walk, -EIO);
7046f3196b7SHarald Freudenberger 			spin_lock_bh(&ctx->pk_lock);
7056f3196b7SHarald Freudenberger 			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
7066f3196b7SHarald Freudenberger 			spin_unlock_bh(&ctx->pk_lock);
70727937843SMartin Schwidefsky 		}
708d00c0639SEric Biggers 		memcpy(walk.dst.virt.addr, buf, nbytes);
709d00c0639SEric Biggers 		crypto_inc(walk.iv, AES_BLOCK_SIZE);
7106f3196b7SHarald Freudenberger 		ret = skcipher_walk_done(&walk, nbytes);
71127937843SMartin Schwidefsky 	}
71227937843SMartin Schwidefsky 
71327937843SMartin Schwidefsky 	return ret;
71427937843SMartin Schwidefsky }
71527937843SMartin Schwidefsky 
716d00c0639SEric Biggers static struct skcipher_alg ctr_paes_alg = {
717d00c0639SEric Biggers 	.base.cra_name		=	"ctr(paes)",
718d00c0639SEric Biggers 	.base.cra_driver_name	=	"ctr-paes-s390",
719d00c0639SEric Biggers 	.base.cra_priority	=	402,	/* ecb-paes-s390 + 1 */
720d00c0639SEric Biggers 	.base.cra_blocksize	=	1,
721d00c0639SEric Biggers 	.base.cra_ctxsize	=	sizeof(struct s390_paes_ctx),
722d00c0639SEric Biggers 	.base.cra_module	=	THIS_MODULE,
723d00c0639SEric Biggers 	.base.cra_list		=	LIST_HEAD_INIT(ctr_paes_alg.base.cra_list),
724d00c0639SEric Biggers 	.init			=	ctr_paes_init,
725d00c0639SEric Biggers 	.exit			=	ctr_paes_exit,
726416f79c2SHarald Freudenberger 	.min_keysize		=	PAES_MIN_KEYSIZE,
727416f79c2SHarald Freudenberger 	.max_keysize		=	PAES_MAX_KEYSIZE,
72827937843SMartin Schwidefsky 	.ivsize			=	AES_BLOCK_SIZE,
72927937843SMartin Schwidefsky 	.setkey			=	ctr_paes_set_key,
730d00c0639SEric Biggers 	.encrypt		=	ctr_paes_crypt,
731d00c0639SEric Biggers 	.decrypt		=	ctr_paes_crypt,
732d00c0639SEric Biggers 	.chunksize		=	AES_BLOCK_SIZE,
73327937843SMartin Schwidefsky };
73427937843SMartin Schwidefsky 
__crypto_unregister_skcipher(struct skcipher_alg * alg)735d00c0639SEric Biggers static inline void __crypto_unregister_skcipher(struct skcipher_alg *alg)
73627937843SMartin Schwidefsky {
737d00c0639SEric Biggers 	if (!list_empty(&alg->base.cra_list))
738d00c0639SEric Biggers 		crypto_unregister_skcipher(alg);
73927937843SMartin Schwidefsky }
74027937843SMartin Schwidefsky 
paes_s390_fini(void)74127937843SMartin Schwidefsky static void paes_s390_fini(void)
74227937843SMartin Schwidefsky {
743d00c0639SEric Biggers 	__crypto_unregister_skcipher(&ctr_paes_alg);
744d00c0639SEric Biggers 	__crypto_unregister_skcipher(&xts_paes_alg);
745d00c0639SEric Biggers 	__crypto_unregister_skcipher(&cbc_paes_alg);
746d00c0639SEric Biggers 	__crypto_unregister_skcipher(&ecb_paes_alg);
7477f820d05SHarald Freudenberger 	if (ctrblk)
7487f820d05SHarald Freudenberger 		free_page((unsigned long) ctrblk);
74927937843SMartin Schwidefsky }
75027937843SMartin Schwidefsky 
paes_s390_init(void)75127937843SMartin Schwidefsky static int __init paes_s390_init(void)
75227937843SMartin Schwidefsky {
75327937843SMartin Schwidefsky 	int ret;
75427937843SMartin Schwidefsky 
75527937843SMartin Schwidefsky 	/* Query available functions for KM, KMC and KMCTR */
75627937843SMartin Schwidefsky 	cpacf_query(CPACF_KM, &km_functions);
75727937843SMartin Schwidefsky 	cpacf_query(CPACF_KMC, &kmc_functions);
75827937843SMartin Schwidefsky 	cpacf_query(CPACF_KMCTR, &kmctr_functions);
75927937843SMartin Schwidefsky 
76027937843SMartin Schwidefsky 	if (cpacf_test_func(&km_functions, CPACF_KM_PAES_128) ||
76127937843SMartin Schwidefsky 	    cpacf_test_func(&km_functions, CPACF_KM_PAES_192) ||
76227937843SMartin Schwidefsky 	    cpacf_test_func(&km_functions, CPACF_KM_PAES_256)) {
763d00c0639SEric Biggers 		ret = crypto_register_skcipher(&ecb_paes_alg);
76427937843SMartin Schwidefsky 		if (ret)
76527937843SMartin Schwidefsky 			goto out_err;
76627937843SMartin Schwidefsky 	}
76727937843SMartin Schwidefsky 
76827937843SMartin Schwidefsky 	if (cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) ||
76927937843SMartin Schwidefsky 	    cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) ||
77027937843SMartin Schwidefsky 	    cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256)) {
771d00c0639SEric Biggers 		ret = crypto_register_skcipher(&cbc_paes_alg);
77227937843SMartin Schwidefsky 		if (ret)
77327937843SMartin Schwidefsky 			goto out_err;
77427937843SMartin Schwidefsky 	}
77527937843SMartin Schwidefsky 
77627937843SMartin Schwidefsky 	if (cpacf_test_func(&km_functions, CPACF_KM_PXTS_128) ||
77727937843SMartin Schwidefsky 	    cpacf_test_func(&km_functions, CPACF_KM_PXTS_256)) {
778d00c0639SEric Biggers 		ret = crypto_register_skcipher(&xts_paes_alg);
77927937843SMartin Schwidefsky 		if (ret)
78027937843SMartin Schwidefsky 			goto out_err;
78127937843SMartin Schwidefsky 	}
78227937843SMartin Schwidefsky 
78327937843SMartin Schwidefsky 	if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_128) ||
78427937843SMartin Schwidefsky 	    cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_192) ||
78527937843SMartin Schwidefsky 	    cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_256)) {
78627937843SMartin Schwidefsky 		ctrblk = (u8 *) __get_free_page(GFP_KERNEL);
78727937843SMartin Schwidefsky 		if (!ctrblk) {
78827937843SMartin Schwidefsky 			ret = -ENOMEM;
78927937843SMartin Schwidefsky 			goto out_err;
79027937843SMartin Schwidefsky 		}
7917f820d05SHarald Freudenberger 		ret = crypto_register_skcipher(&ctr_paes_alg);
7927f820d05SHarald Freudenberger 		if (ret)
7937f820d05SHarald Freudenberger 			goto out_err;
79427937843SMartin Schwidefsky 	}
79527937843SMartin Schwidefsky 
79627937843SMartin Schwidefsky 	return 0;
79727937843SMartin Schwidefsky out_err:
79827937843SMartin Schwidefsky 	paes_s390_fini();
79927937843SMartin Schwidefsky 	return ret;
80027937843SMartin Schwidefsky }
80127937843SMartin Schwidefsky 
80227937843SMartin Schwidefsky module_init(paes_s390_init);
80327937843SMartin Schwidefsky module_exit(paes_s390_fini);
80427937843SMartin Schwidefsky 
805*4330869aSHerbert Xu MODULE_ALIAS_CRYPTO("ecb(paes)");
806*4330869aSHerbert Xu MODULE_ALIAS_CRYPTO("cbc(paes)");
807*4330869aSHerbert Xu MODULE_ALIAS_CRYPTO("ctr(paes)");
808*4330869aSHerbert Xu MODULE_ALIAS_CRYPTO("xts(paes)");
80927937843SMartin Schwidefsky 
81027937843SMartin Schwidefsky MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm with protected keys");
81127937843SMartin Schwidefsky MODULE_LICENSE("GPL");
812