xref: /openbmc/linux/arch/s390/crypto/paes_s390.c (revision d68ac388)
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 {
12827937843SMartin Schwidefsky 	int i, ret;
12927937843SMartin Schwidefsky 
13027937843SMartin Schwidefsky 	/* try three times in case of failure */
13127937843SMartin Schwidefsky 	for (i = 0; i < 3; i++) {
1321daafea4SHarald Freudenberger 		if (i > 0 && ret == -EAGAIN && in_task())
1331daafea4SHarald Freudenberger 			if (msleep_interruptible(1000))
1341daafea4SHarald Freudenberger 				return -EINTR;
135f370f45cSHarald Freudenberger 		ret = pkey_keyblob2pkey(kb->key, kb->keylen,
136f370f45cSHarald Freudenberger 					pk->protkey, &pk->len, &pk->type);
13727937843SMartin Schwidefsky 		if (ret == 0)
13827937843SMartin Schwidefsky 			break;
13927937843SMartin Schwidefsky 	}
14027937843SMartin Schwidefsky 
14127937843SMartin Schwidefsky 	return ret;
14227937843SMartin Schwidefsky }
14327937843SMartin Schwidefsky 
__paes_convert_key(struct s390_paes_ctx * ctx)1446f3196b7SHarald Freudenberger static inline int __paes_convert_key(struct s390_paes_ctx *ctx)
1456f3196b7SHarald Freudenberger {
1461daafea4SHarald Freudenberger 	int ret;
1476f3196b7SHarald Freudenberger 	struct pkey_protkey pkey;
1486f3196b7SHarald Freudenberger 
149f370f45cSHarald Freudenberger 	pkey.len = sizeof(pkey.protkey);
1501daafea4SHarald Freudenberger 	ret = __paes_keyblob2pkey(&ctx->kb, &pkey);
1511daafea4SHarald Freudenberger 	if (ret)
1521daafea4SHarald Freudenberger 		return ret;
1536f3196b7SHarald Freudenberger 
1546f3196b7SHarald Freudenberger 	spin_lock_bh(&ctx->pk_lock);
1556f3196b7SHarald Freudenberger 	memcpy(&ctx->pk, &pkey, sizeof(pkey));
1566f3196b7SHarald Freudenberger 	spin_unlock_bh(&ctx->pk_lock);
1576f3196b7SHarald Freudenberger 
1586f3196b7SHarald Freudenberger 	return 0;
1596f3196b7SHarald Freudenberger }
1606f3196b7SHarald Freudenberger 
ecb_paes_init(struct crypto_skcipher * tfm)1616f3196b7SHarald Freudenberger static int ecb_paes_init(struct crypto_skcipher *tfm)
1626f3196b7SHarald Freudenberger {
1636f3196b7SHarald Freudenberger 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
1646f3196b7SHarald Freudenberger 
1656f3196b7SHarald Freudenberger 	ctx->kb.key = NULL;
1666f3196b7SHarald Freudenberger 	spin_lock_init(&ctx->pk_lock);
1676f3196b7SHarald Freudenberger 
1686f3196b7SHarald Freudenberger 	return 0;
1696f3196b7SHarald Freudenberger }
1706f3196b7SHarald Freudenberger 
ecb_paes_exit(struct crypto_skcipher * tfm)1716f3196b7SHarald Freudenberger static void ecb_paes_exit(struct crypto_skcipher *tfm)
1726f3196b7SHarald Freudenberger {
1736f3196b7SHarald Freudenberger 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
1746f3196b7SHarald Freudenberger 
1756f3196b7SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb);
1766f3196b7SHarald Freudenberger }
1776f3196b7SHarald Freudenberger 
__ecb_paes_set_key(struct s390_paes_ctx * ctx)1786f3196b7SHarald Freudenberger static inline int __ecb_paes_set_key(struct s390_paes_ctx *ctx)
17927937843SMartin Schwidefsky {
1801daafea4SHarald Freudenberger 	int rc;
18127937843SMartin Schwidefsky 	unsigned long fc;
18227937843SMartin Schwidefsky 
1831daafea4SHarald Freudenberger 	rc = __paes_convert_key(ctx);
1841daafea4SHarald Freudenberger 	if (rc)
1851daafea4SHarald Freudenberger 		return rc;
18627937843SMartin Schwidefsky 
18727937843SMartin Schwidefsky 	/* Pick the correct function code based on the protected key type */
18827937843SMartin Schwidefsky 	fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PAES_128 :
18927937843SMartin Schwidefsky 		(ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KM_PAES_192 :
19027937843SMartin Schwidefsky 		(ctx->pk.type == PKEY_KEYTYPE_AES_256) ? CPACF_KM_PAES_256 : 0;
19127937843SMartin Schwidefsky 
19227937843SMartin Schwidefsky 	/* Check if the function code is available */
19327937843SMartin Schwidefsky 	ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0;
19427937843SMartin Schwidefsky 
19527937843SMartin Schwidefsky 	return ctx->fc ? 0 : -EINVAL;
19627937843SMartin Schwidefsky }
19727937843SMartin Schwidefsky 
ecb_paes_set_key(struct crypto_skcipher * tfm,const u8 * in_key,unsigned int key_len)198d00c0639SEric Biggers static int ecb_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
199416f79c2SHarald Freudenberger 			    unsigned int key_len)
200416f79c2SHarald Freudenberger {
201416f79c2SHarald Freudenberger 	int rc;
202d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
203416f79c2SHarald Freudenberger 
204416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb);
2057f820d05SHarald Freudenberger 	rc = _key_to_kb(&ctx->kb, in_key, key_len);
206416f79c2SHarald Freudenberger 	if (rc)
207416f79c2SHarald Freudenberger 		return rc;
208416f79c2SHarald Freudenberger 
2096f3196b7SHarald Freudenberger 	return __ecb_paes_set_key(ctx);
21027937843SMartin Schwidefsky }
21127937843SMartin Schwidefsky 
ecb_paes_crypt(struct skcipher_request * req,unsigned long modifier)212d00c0639SEric Biggers static int ecb_paes_crypt(struct skcipher_request *req, unsigned long modifier)
21327937843SMartin Schwidefsky {
214d00c0639SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
215d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
216d00c0639SEric Biggers 	struct skcipher_walk walk;
21727937843SMartin Schwidefsky 	unsigned int nbytes, n, k;
21827937843SMartin Schwidefsky 	int ret;
2196f3196b7SHarald Freudenberger 	struct {
2206f3196b7SHarald Freudenberger 		u8 key[MAXPROTKEYSIZE];
2216f3196b7SHarald Freudenberger 	} param;
22227937843SMartin Schwidefsky 
223d00c0639SEric Biggers 	ret = skcipher_walk_virt(&walk, req, false);
2246f3196b7SHarald Freudenberger 	if (ret)
2256f3196b7SHarald Freudenberger 		return ret;
2266f3196b7SHarald Freudenberger 
2276f3196b7SHarald Freudenberger 	spin_lock_bh(&ctx->pk_lock);
2286f3196b7SHarald Freudenberger 	memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
2296f3196b7SHarald Freudenberger 	spin_unlock_bh(&ctx->pk_lock);
2306f3196b7SHarald Freudenberger 
231d00c0639SEric Biggers 	while ((nbytes = walk.nbytes) != 0) {
23227937843SMartin Schwidefsky 		/* only use complete blocks */
23327937843SMartin Schwidefsky 		n = nbytes & ~(AES_BLOCK_SIZE - 1);
2346f3196b7SHarald Freudenberger 		k = cpacf_km(ctx->fc | modifier, &param,
235d00c0639SEric Biggers 			     walk.dst.virt.addr, walk.src.virt.addr, n);
23627937843SMartin Schwidefsky 		if (k)
237d00c0639SEric Biggers 			ret = skcipher_walk_done(&walk, nbytes - k);
23827937843SMartin Schwidefsky 		if (k < n) {
2396f3196b7SHarald Freudenberger 			if (__paes_convert_key(ctx))
240d00c0639SEric Biggers 				return skcipher_walk_done(&walk, -EIO);
2416f3196b7SHarald Freudenberger 			spin_lock_bh(&ctx->pk_lock);
2426f3196b7SHarald Freudenberger 			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
2436f3196b7SHarald Freudenberger 			spin_unlock_bh(&ctx->pk_lock);
24427937843SMartin Schwidefsky 		}
24527937843SMartin Schwidefsky 	}
24627937843SMartin Schwidefsky 	return ret;
24727937843SMartin Schwidefsky }
24827937843SMartin Schwidefsky 
ecb_paes_encrypt(struct skcipher_request * req)249d00c0639SEric Biggers static int ecb_paes_encrypt(struct skcipher_request *req)
25027937843SMartin Schwidefsky {
251d00c0639SEric Biggers 	return ecb_paes_crypt(req, 0);
25227937843SMartin Schwidefsky }
25327937843SMartin Schwidefsky 
ecb_paes_decrypt(struct skcipher_request * req)254d00c0639SEric Biggers static int ecb_paes_decrypt(struct skcipher_request *req)
25527937843SMartin Schwidefsky {
256d00c0639SEric Biggers 	return ecb_paes_crypt(req, CPACF_DECRYPT);
25727937843SMartin Schwidefsky }
25827937843SMartin Schwidefsky 
259d00c0639SEric Biggers static struct skcipher_alg ecb_paes_alg = {
260d00c0639SEric Biggers 	.base.cra_name		=	"ecb(paes)",
261d00c0639SEric Biggers 	.base.cra_driver_name	=	"ecb-paes-s390",
262d00c0639SEric Biggers 	.base.cra_priority	=	401,	/* combo: aes + ecb + 1 */
263d00c0639SEric Biggers 	.base.cra_blocksize	=	AES_BLOCK_SIZE,
264d00c0639SEric Biggers 	.base.cra_ctxsize	=	sizeof(struct s390_paes_ctx),
265d00c0639SEric Biggers 	.base.cra_module	=	THIS_MODULE,
266d00c0639SEric Biggers 	.base.cra_list		=	LIST_HEAD_INIT(ecb_paes_alg.base.cra_list),
267d00c0639SEric Biggers 	.init			=	ecb_paes_init,
268d00c0639SEric Biggers 	.exit			=	ecb_paes_exit,
269416f79c2SHarald Freudenberger 	.min_keysize		=	PAES_MIN_KEYSIZE,
270416f79c2SHarald Freudenberger 	.max_keysize		=	PAES_MAX_KEYSIZE,
27127937843SMartin Schwidefsky 	.setkey			=	ecb_paes_set_key,
27227937843SMartin Schwidefsky 	.encrypt		=	ecb_paes_encrypt,
27327937843SMartin Schwidefsky 	.decrypt		=	ecb_paes_decrypt,
27427937843SMartin Schwidefsky };
27527937843SMartin Schwidefsky 
cbc_paes_init(struct crypto_skcipher * tfm)276d00c0639SEric Biggers static int cbc_paes_init(struct crypto_skcipher *tfm)
277416f79c2SHarald Freudenberger {
278d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
279416f79c2SHarald Freudenberger 
280416f79c2SHarald Freudenberger 	ctx->kb.key = NULL;
2816f3196b7SHarald Freudenberger 	spin_lock_init(&ctx->pk_lock);
282416f79c2SHarald Freudenberger 
283416f79c2SHarald Freudenberger 	return 0;
284416f79c2SHarald Freudenberger }
285416f79c2SHarald Freudenberger 
cbc_paes_exit(struct crypto_skcipher * tfm)286d00c0639SEric Biggers static void cbc_paes_exit(struct crypto_skcipher *tfm)
287416f79c2SHarald Freudenberger {
288d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
289416f79c2SHarald Freudenberger 
290416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb);
291416f79c2SHarald Freudenberger }
292416f79c2SHarald Freudenberger 
__cbc_paes_set_key(struct s390_paes_ctx * ctx)2936f3196b7SHarald Freudenberger static inline int __cbc_paes_set_key(struct s390_paes_ctx *ctx)
29427937843SMartin Schwidefsky {
2951daafea4SHarald Freudenberger 	int rc;
29627937843SMartin Schwidefsky 	unsigned long fc;
29727937843SMartin Schwidefsky 
2981daafea4SHarald Freudenberger 	rc = __paes_convert_key(ctx);
2991daafea4SHarald Freudenberger 	if (rc)
3001daafea4SHarald Freudenberger 		return rc;
30127937843SMartin Schwidefsky 
30227937843SMartin Schwidefsky 	/* Pick the correct function code based on the protected key type */
30327937843SMartin Schwidefsky 	fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KMC_PAES_128 :
30427937843SMartin Schwidefsky 		(ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KMC_PAES_192 :
30527937843SMartin Schwidefsky 		(ctx->pk.type == PKEY_KEYTYPE_AES_256) ? CPACF_KMC_PAES_256 : 0;
30627937843SMartin Schwidefsky 
30727937843SMartin Schwidefsky 	/* Check if the function code is available */
30827937843SMartin Schwidefsky 	ctx->fc = (fc && cpacf_test_func(&kmc_functions, fc)) ? fc : 0;
30927937843SMartin Schwidefsky 
31027937843SMartin Schwidefsky 	return ctx->fc ? 0 : -EINVAL;
31127937843SMartin Schwidefsky }
31227937843SMartin Schwidefsky 
cbc_paes_set_key(struct crypto_skcipher * tfm,const u8 * in_key,unsigned int key_len)313d00c0639SEric Biggers static int cbc_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
31427937843SMartin Schwidefsky 			    unsigned int key_len)
31527937843SMartin Schwidefsky {
316416f79c2SHarald Freudenberger 	int rc;
317d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
31827937843SMartin Schwidefsky 
319416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb);
3207f820d05SHarald Freudenberger 	rc = _key_to_kb(&ctx->kb, in_key, key_len);
321416f79c2SHarald Freudenberger 	if (rc)
322416f79c2SHarald Freudenberger 		return rc;
323416f79c2SHarald Freudenberger 
324674f368aSEric Biggers 	return __cbc_paes_set_key(ctx);
32527937843SMartin Schwidefsky }
32627937843SMartin Schwidefsky 
cbc_paes_crypt(struct skcipher_request * req,unsigned long modifier)327d00c0639SEric Biggers static int cbc_paes_crypt(struct skcipher_request *req, unsigned long modifier)
32827937843SMartin Schwidefsky {
329d00c0639SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
330d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
331d00c0639SEric Biggers 	struct skcipher_walk walk;
33227937843SMartin Schwidefsky 	unsigned int nbytes, n, k;
33327937843SMartin Schwidefsky 	int ret;
33427937843SMartin Schwidefsky 	struct {
33527937843SMartin Schwidefsky 		u8 iv[AES_BLOCK_SIZE];
33627937843SMartin Schwidefsky 		u8 key[MAXPROTKEYSIZE];
33727937843SMartin Schwidefsky 	} param;
33827937843SMartin Schwidefsky 
339d00c0639SEric Biggers 	ret = skcipher_walk_virt(&walk, req, false);
340d00c0639SEric Biggers 	if (ret)
341d00c0639SEric Biggers 		return ret;
3426f3196b7SHarald Freudenberger 
343d00c0639SEric Biggers 	memcpy(param.iv, walk.iv, AES_BLOCK_SIZE);
3446f3196b7SHarald Freudenberger 	spin_lock_bh(&ctx->pk_lock);
34527937843SMartin Schwidefsky 	memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
3466f3196b7SHarald Freudenberger 	spin_unlock_bh(&ctx->pk_lock);
3476f3196b7SHarald Freudenberger 
348d00c0639SEric Biggers 	while ((nbytes = walk.nbytes) != 0) {
34927937843SMartin Schwidefsky 		/* only use complete blocks */
35027937843SMartin Schwidefsky 		n = nbytes & ~(AES_BLOCK_SIZE - 1);
35127937843SMartin Schwidefsky 		k = cpacf_kmc(ctx->fc | modifier, &param,
352d00c0639SEric Biggers 			      walk.dst.virt.addr, walk.src.virt.addr, n);
353d00c0639SEric Biggers 		if (k) {
354d00c0639SEric Biggers 			memcpy(walk.iv, param.iv, AES_BLOCK_SIZE);
355d00c0639SEric Biggers 			ret = skcipher_walk_done(&walk, nbytes - k);
356d00c0639SEric Biggers 		}
357b81126e0SIngo Franzki 		if (k < n) {
3586f3196b7SHarald Freudenberger 			if (__paes_convert_key(ctx))
359d00c0639SEric Biggers 				return skcipher_walk_done(&walk, -EIO);
3606f3196b7SHarald Freudenberger 			spin_lock_bh(&ctx->pk_lock);
36127937843SMartin Schwidefsky 			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
3626f3196b7SHarald Freudenberger 			spin_unlock_bh(&ctx->pk_lock);
36327937843SMartin Schwidefsky 		}
36427937843SMartin Schwidefsky 	}
36527937843SMartin Schwidefsky 	return ret;
36627937843SMartin Schwidefsky }
36727937843SMartin Schwidefsky 
cbc_paes_encrypt(struct skcipher_request * req)368d00c0639SEric Biggers static int cbc_paes_encrypt(struct skcipher_request *req)
36927937843SMartin Schwidefsky {
370d00c0639SEric Biggers 	return cbc_paes_crypt(req, 0);
37127937843SMartin Schwidefsky }
37227937843SMartin Schwidefsky 
cbc_paes_decrypt(struct skcipher_request * req)373d00c0639SEric Biggers static int cbc_paes_decrypt(struct skcipher_request *req)
37427937843SMartin Schwidefsky {
375d00c0639SEric Biggers 	return cbc_paes_crypt(req, CPACF_DECRYPT);
37627937843SMartin Schwidefsky }
37727937843SMartin Schwidefsky 
378d00c0639SEric Biggers static struct skcipher_alg cbc_paes_alg = {
379d00c0639SEric Biggers 	.base.cra_name		=	"cbc(paes)",
380d00c0639SEric Biggers 	.base.cra_driver_name	=	"cbc-paes-s390",
381d00c0639SEric Biggers 	.base.cra_priority	=	402,	/* ecb-paes-s390 + 1 */
382d00c0639SEric Biggers 	.base.cra_blocksize	=	AES_BLOCK_SIZE,
383d00c0639SEric Biggers 	.base.cra_ctxsize	=	sizeof(struct s390_paes_ctx),
384d00c0639SEric Biggers 	.base.cra_module	=	THIS_MODULE,
385d00c0639SEric Biggers 	.base.cra_list		=	LIST_HEAD_INIT(cbc_paes_alg.base.cra_list),
386d00c0639SEric Biggers 	.init			=	cbc_paes_init,
387d00c0639SEric Biggers 	.exit			=	cbc_paes_exit,
388416f79c2SHarald Freudenberger 	.min_keysize		=	PAES_MIN_KEYSIZE,
389416f79c2SHarald Freudenberger 	.max_keysize		=	PAES_MAX_KEYSIZE,
39027937843SMartin Schwidefsky 	.ivsize			=	AES_BLOCK_SIZE,
39127937843SMartin Schwidefsky 	.setkey			=	cbc_paes_set_key,
39227937843SMartin Schwidefsky 	.encrypt		=	cbc_paes_encrypt,
39327937843SMartin Schwidefsky 	.decrypt		=	cbc_paes_decrypt,
39427937843SMartin Schwidefsky };
39527937843SMartin Schwidefsky 
xts_paes_init(struct crypto_skcipher * tfm)396d00c0639SEric Biggers static int xts_paes_init(struct crypto_skcipher *tfm)
397416f79c2SHarald Freudenberger {
398d00c0639SEric Biggers 	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
399416f79c2SHarald Freudenberger 
400416f79c2SHarald Freudenberger 	ctx->kb[0].key = NULL;
401416f79c2SHarald Freudenberger 	ctx->kb[1].key = NULL;
4026f3196b7SHarald Freudenberger 	spin_lock_init(&ctx->pk_lock);
403416f79c2SHarald Freudenberger 
404416f79c2SHarald Freudenberger 	return 0;
405416f79c2SHarald Freudenberger }
406416f79c2SHarald Freudenberger 
xts_paes_exit(struct crypto_skcipher * tfm)407d00c0639SEric Biggers static void xts_paes_exit(struct crypto_skcipher *tfm)
408416f79c2SHarald Freudenberger {
409d00c0639SEric Biggers 	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
410416f79c2SHarald Freudenberger 
411416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb[0]);
412416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb[1]);
413416f79c2SHarald Freudenberger }
414416f79c2SHarald Freudenberger 
__xts_paes_convert_key(struct s390_pxts_ctx * ctx)4156f3196b7SHarald Freudenberger static inline int __xts_paes_convert_key(struct s390_pxts_ctx *ctx)
4166f3196b7SHarald Freudenberger {
4176f3196b7SHarald Freudenberger 	struct pkey_protkey pkey0, pkey1;
4186f3196b7SHarald Freudenberger 
419f370f45cSHarald Freudenberger 	pkey0.len = sizeof(pkey0.protkey);
420f370f45cSHarald Freudenberger 	pkey1.len = sizeof(pkey1.protkey);
421f370f45cSHarald Freudenberger 
4226f3196b7SHarald Freudenberger 	if (__paes_keyblob2pkey(&ctx->kb[0], &pkey0) ||
4236f3196b7SHarald Freudenberger 	    __paes_keyblob2pkey(&ctx->kb[1], &pkey1))
4246f3196b7SHarald Freudenberger 		return -EINVAL;
4256f3196b7SHarald Freudenberger 
4266f3196b7SHarald Freudenberger 	spin_lock_bh(&ctx->pk_lock);
4276f3196b7SHarald Freudenberger 	memcpy(&ctx->pk[0], &pkey0, sizeof(pkey0));
4286f3196b7SHarald Freudenberger 	memcpy(&ctx->pk[1], &pkey1, sizeof(pkey1));
4296f3196b7SHarald Freudenberger 	spin_unlock_bh(&ctx->pk_lock);
4306f3196b7SHarald Freudenberger 
4316f3196b7SHarald Freudenberger 	return 0;
4326f3196b7SHarald Freudenberger }
4336f3196b7SHarald Freudenberger 
__xts_paes_set_key(struct s390_pxts_ctx * ctx)4346f3196b7SHarald Freudenberger static inline int __xts_paes_set_key(struct s390_pxts_ctx *ctx)
43527937843SMartin Schwidefsky {
43627937843SMartin Schwidefsky 	unsigned long fc;
43727937843SMartin Schwidefsky 
4386f3196b7SHarald Freudenberger 	if (__xts_paes_convert_key(ctx))
43927937843SMartin Schwidefsky 		return -EINVAL;
44027937843SMartin Schwidefsky 
44127937843SMartin Schwidefsky 	if (ctx->pk[0].type != ctx->pk[1].type)
44227937843SMartin Schwidefsky 		return -EINVAL;
44327937843SMartin Schwidefsky 
44427937843SMartin Schwidefsky 	/* Pick the correct function code based on the protected key type */
44527937843SMartin Schwidefsky 	fc = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PXTS_128 :
44627937843SMartin Schwidefsky 		(ctx->pk[0].type == PKEY_KEYTYPE_AES_256) ?
44727937843SMartin Schwidefsky 		CPACF_KM_PXTS_256 : 0;
44827937843SMartin Schwidefsky 
44927937843SMartin Schwidefsky 	/* Check if the function code is available */
45027937843SMartin Schwidefsky 	ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0;
45127937843SMartin Schwidefsky 
45227937843SMartin Schwidefsky 	return ctx->fc ? 0 : -EINVAL;
45327937843SMartin Schwidefsky }
45427937843SMartin Schwidefsky 
xts_paes_set_key(struct crypto_skcipher * tfm,const u8 * in_key,unsigned int xts_key_len)455d00c0639SEric Biggers static int xts_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
456416f79c2SHarald Freudenberger 			    unsigned int xts_key_len)
45727937843SMartin Schwidefsky {
458416f79c2SHarald Freudenberger 	int rc;
459d00c0639SEric Biggers 	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
46027937843SMartin Schwidefsky 	u8 ckey[2 * AES_MAX_KEY_SIZE];
461416f79c2SHarald Freudenberger 	unsigned int ckey_len, key_len;
46227937843SMartin Schwidefsky 
463416f79c2SHarald Freudenberger 	if (xts_key_len % 2)
46452a34b34SIngo Franzki 		return -EINVAL;
46552a34b34SIngo Franzki 
466416f79c2SHarald Freudenberger 	key_len = xts_key_len / 2;
467416f79c2SHarald Freudenberger 
468416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb[0]);
469416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb[1]);
4707f820d05SHarald Freudenberger 	rc = _key_to_kb(&ctx->kb[0], in_key, key_len);
471416f79c2SHarald Freudenberger 	if (rc)
472416f79c2SHarald Freudenberger 		return rc;
4737f820d05SHarald Freudenberger 	rc = _key_to_kb(&ctx->kb[1], in_key + key_len, key_len);
474416f79c2SHarald Freudenberger 	if (rc)
475416f79c2SHarald Freudenberger 		return rc;
476416f79c2SHarald Freudenberger 
477674f368aSEric Biggers 	rc = __xts_paes_set_key(ctx);
478674f368aSEric Biggers 	if (rc)
479674f368aSEric Biggers 		return rc;
48027937843SMartin Schwidefsky 
48127937843SMartin Schwidefsky 	/*
4820ee43367SVladis Dronov 	 * xts_verify_key verifies the key length is not odd and makes
48327937843SMartin Schwidefsky 	 * sure that the two keys are not the same. This can be done
48427937843SMartin Schwidefsky 	 * on the two protected keys as well
48527937843SMartin Schwidefsky 	 */
48627937843SMartin Schwidefsky 	ckey_len = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ?
48727937843SMartin Schwidefsky 		AES_KEYSIZE_128 : AES_KEYSIZE_256;
48827937843SMartin Schwidefsky 	memcpy(ckey, ctx->pk[0].protkey, ckey_len);
48927937843SMartin Schwidefsky 	memcpy(ckey + ckey_len, ctx->pk[1].protkey, ckey_len);
490d00c0639SEric Biggers 	return xts_verify_key(tfm, ckey, 2*ckey_len);
49127937843SMartin Schwidefsky }
49227937843SMartin Schwidefsky 
xts_paes_crypt(struct skcipher_request * req,unsigned long modifier)493d00c0639SEric Biggers static int xts_paes_crypt(struct skcipher_request *req, unsigned long modifier)
49427937843SMartin Schwidefsky {
495d00c0639SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
496d00c0639SEric Biggers 	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
497d00c0639SEric Biggers 	struct skcipher_walk walk;
49827937843SMartin Schwidefsky 	unsigned int keylen, offset, nbytes, n, k;
49927937843SMartin Schwidefsky 	int ret;
50027937843SMartin Schwidefsky 	struct {
50127937843SMartin Schwidefsky 		u8 key[MAXPROTKEYSIZE];	/* key + verification pattern */
50227937843SMartin Schwidefsky 		u8 tweak[16];
50327937843SMartin Schwidefsky 		u8 block[16];
50427937843SMartin Schwidefsky 		u8 bit[16];
50527937843SMartin Schwidefsky 		u8 xts[16];
50627937843SMartin Schwidefsky 	} pcc_param;
50727937843SMartin Schwidefsky 	struct {
50827937843SMartin Schwidefsky 		u8 key[MAXPROTKEYSIZE];	/* key + verification pattern */
50927937843SMartin Schwidefsky 		u8 init[16];
51027937843SMartin Schwidefsky 	} xts_param;
51127937843SMartin Schwidefsky 
512d00c0639SEric Biggers 	ret = skcipher_walk_virt(&walk, req, false);
513d00c0639SEric Biggers 	if (ret)
514d00c0639SEric Biggers 		return ret;
5156f3196b7SHarald Freudenberger 
51627937843SMartin Schwidefsky 	keylen = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 48 : 64;
51727937843SMartin Schwidefsky 	offset = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 16 : 0;
5186f3196b7SHarald Freudenberger 
51927937843SMartin Schwidefsky 	memset(&pcc_param, 0, sizeof(pcc_param));
520d00c0639SEric Biggers 	memcpy(pcc_param.tweak, walk.iv, sizeof(pcc_param.tweak));
5216f3196b7SHarald Freudenberger 	spin_lock_bh(&ctx->pk_lock);
52227937843SMartin Schwidefsky 	memcpy(pcc_param.key + offset, ctx->pk[1].protkey, keylen);
52327937843SMartin Schwidefsky 	memcpy(xts_param.key + offset, ctx->pk[0].protkey, keylen);
5246f3196b7SHarald Freudenberger 	spin_unlock_bh(&ctx->pk_lock);
5256f3196b7SHarald Freudenberger 	cpacf_pcc(ctx->fc, pcc_param.key + offset);
52627937843SMartin Schwidefsky 	memcpy(xts_param.init, pcc_param.xts, 16);
52727937843SMartin Schwidefsky 
528d00c0639SEric Biggers 	while ((nbytes = walk.nbytes) != 0) {
52927937843SMartin Schwidefsky 		/* only use complete blocks */
53027937843SMartin Schwidefsky 		n = nbytes & ~(AES_BLOCK_SIZE - 1);
53127937843SMartin Schwidefsky 		k = cpacf_km(ctx->fc | modifier, xts_param.key + offset,
532d00c0639SEric Biggers 			     walk.dst.virt.addr, walk.src.virt.addr, n);
53327937843SMartin Schwidefsky 		if (k)
534d00c0639SEric Biggers 			ret = skcipher_walk_done(&walk, nbytes - k);
53527937843SMartin Schwidefsky 		if (k < n) {
5366f3196b7SHarald Freudenberger 			if (__xts_paes_convert_key(ctx))
537d00c0639SEric Biggers 				return skcipher_walk_done(&walk, -EIO);
5386f3196b7SHarald Freudenberger 			spin_lock_bh(&ctx->pk_lock);
5396f3196b7SHarald Freudenberger 			memcpy(xts_param.key + offset,
5406f3196b7SHarald Freudenberger 			       ctx->pk[0].protkey, keylen);
5416f3196b7SHarald Freudenberger 			spin_unlock_bh(&ctx->pk_lock);
54227937843SMartin Schwidefsky 		}
54327937843SMartin Schwidefsky 	}
5446f3196b7SHarald Freudenberger 
54527937843SMartin Schwidefsky 	return ret;
54627937843SMartin Schwidefsky }
54727937843SMartin Schwidefsky 
xts_paes_encrypt(struct skcipher_request * req)548d00c0639SEric Biggers static int xts_paes_encrypt(struct skcipher_request *req)
54927937843SMartin Schwidefsky {
550d00c0639SEric Biggers 	return xts_paes_crypt(req, 0);
55127937843SMartin Schwidefsky }
55227937843SMartin Schwidefsky 
xts_paes_decrypt(struct skcipher_request * req)553d00c0639SEric Biggers static int xts_paes_decrypt(struct skcipher_request *req)
55427937843SMartin Schwidefsky {
555d00c0639SEric Biggers 	return xts_paes_crypt(req, CPACF_DECRYPT);
55627937843SMartin Schwidefsky }
55727937843SMartin Schwidefsky 
558d00c0639SEric Biggers static struct skcipher_alg xts_paes_alg = {
559d00c0639SEric Biggers 	.base.cra_name		=	"xts(paes)",
560d00c0639SEric Biggers 	.base.cra_driver_name	=	"xts-paes-s390",
561d00c0639SEric Biggers 	.base.cra_priority	=	402,	/* ecb-paes-s390 + 1 */
562d00c0639SEric Biggers 	.base.cra_blocksize	=	AES_BLOCK_SIZE,
563d00c0639SEric Biggers 	.base.cra_ctxsize	=	sizeof(struct s390_pxts_ctx),
564d00c0639SEric Biggers 	.base.cra_module	=	THIS_MODULE,
565d00c0639SEric Biggers 	.base.cra_list		=	LIST_HEAD_INIT(xts_paes_alg.base.cra_list),
566d00c0639SEric Biggers 	.init			=	xts_paes_init,
567d00c0639SEric Biggers 	.exit			=	xts_paes_exit,
568416f79c2SHarald Freudenberger 	.min_keysize		=	2 * PAES_MIN_KEYSIZE,
569416f79c2SHarald Freudenberger 	.max_keysize		=	2 * PAES_MAX_KEYSIZE,
57027937843SMartin Schwidefsky 	.ivsize			=	AES_BLOCK_SIZE,
57127937843SMartin Schwidefsky 	.setkey			=	xts_paes_set_key,
57227937843SMartin Schwidefsky 	.encrypt		=	xts_paes_encrypt,
57327937843SMartin Schwidefsky 	.decrypt		=	xts_paes_decrypt,
57427937843SMartin Schwidefsky };
57527937843SMartin Schwidefsky 
ctr_paes_init(struct crypto_skcipher * tfm)576d00c0639SEric Biggers static int ctr_paes_init(struct crypto_skcipher *tfm)
577416f79c2SHarald Freudenberger {
578d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
579416f79c2SHarald Freudenberger 
580416f79c2SHarald Freudenberger 	ctx->kb.key = NULL;
5816f3196b7SHarald Freudenberger 	spin_lock_init(&ctx->pk_lock);
582416f79c2SHarald Freudenberger 
583416f79c2SHarald Freudenberger 	return 0;
584416f79c2SHarald Freudenberger }
585416f79c2SHarald Freudenberger 
ctr_paes_exit(struct crypto_skcipher * tfm)586d00c0639SEric Biggers static void ctr_paes_exit(struct crypto_skcipher *tfm)
587416f79c2SHarald Freudenberger {
588d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
589416f79c2SHarald Freudenberger 
590416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb);
591416f79c2SHarald Freudenberger }
592416f79c2SHarald Freudenberger 
__ctr_paes_set_key(struct s390_paes_ctx * ctx)5936f3196b7SHarald Freudenberger static inline int __ctr_paes_set_key(struct s390_paes_ctx *ctx)
59427937843SMartin Schwidefsky {
5951daafea4SHarald Freudenberger 	int rc;
59627937843SMartin Schwidefsky 	unsigned long fc;
59727937843SMartin Schwidefsky 
5981daafea4SHarald Freudenberger 	rc = __paes_convert_key(ctx);
5991daafea4SHarald Freudenberger 	if (rc)
6001daafea4SHarald Freudenberger 		return rc;
60127937843SMartin Schwidefsky 
60227937843SMartin Schwidefsky 	/* Pick the correct function code based on the protected key type */
60327937843SMartin Schwidefsky 	fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KMCTR_PAES_128 :
60427937843SMartin Schwidefsky 		(ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KMCTR_PAES_192 :
60527937843SMartin Schwidefsky 		(ctx->pk.type == PKEY_KEYTYPE_AES_256) ?
60627937843SMartin Schwidefsky 		CPACF_KMCTR_PAES_256 : 0;
60727937843SMartin Schwidefsky 
60827937843SMartin Schwidefsky 	/* Check if the function code is available */
60927937843SMartin Schwidefsky 	ctx->fc = (fc && cpacf_test_func(&kmctr_functions, fc)) ? fc : 0;
61027937843SMartin Schwidefsky 
61127937843SMartin Schwidefsky 	return ctx->fc ? 0 : -EINVAL;
61227937843SMartin Schwidefsky }
61327937843SMartin Schwidefsky 
ctr_paes_set_key(struct crypto_skcipher * tfm,const u8 * in_key,unsigned int key_len)614d00c0639SEric Biggers static int ctr_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
61527937843SMartin Schwidefsky 			    unsigned int key_len)
61627937843SMartin Schwidefsky {
617416f79c2SHarald Freudenberger 	int rc;
618d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
61927937843SMartin Schwidefsky 
620416f79c2SHarald Freudenberger 	_free_kb_keybuf(&ctx->kb);
6217f820d05SHarald Freudenberger 	rc = _key_to_kb(&ctx->kb, in_key, key_len);
622416f79c2SHarald Freudenberger 	if (rc)
623416f79c2SHarald Freudenberger 		return rc;
624416f79c2SHarald Freudenberger 
625674f368aSEric Biggers 	return __ctr_paes_set_key(ctx);
62627937843SMartin Schwidefsky }
62727937843SMartin Schwidefsky 
__ctrblk_init(u8 * ctrptr,u8 * iv,unsigned int nbytes)62827937843SMartin Schwidefsky static unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes)
62927937843SMartin Schwidefsky {
63027937843SMartin Schwidefsky 	unsigned int i, n;
63127937843SMartin Schwidefsky 
63227937843SMartin Schwidefsky 	/* only use complete blocks, max. PAGE_SIZE */
63327937843SMartin Schwidefsky 	memcpy(ctrptr, iv, AES_BLOCK_SIZE);
63427937843SMartin Schwidefsky 	n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(AES_BLOCK_SIZE - 1);
63527937843SMartin Schwidefsky 	for (i = (n / AES_BLOCK_SIZE) - 1; i > 0; i--) {
63627937843SMartin Schwidefsky 		memcpy(ctrptr + AES_BLOCK_SIZE, ctrptr, AES_BLOCK_SIZE);
63727937843SMartin Schwidefsky 		crypto_inc(ctrptr + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
63827937843SMartin Schwidefsky 		ctrptr += AES_BLOCK_SIZE;
63927937843SMartin Schwidefsky 	}
64027937843SMartin Schwidefsky 	return n;
64127937843SMartin Schwidefsky }
64227937843SMartin Schwidefsky 
ctr_paes_crypt(struct skcipher_request * req)643d00c0639SEric Biggers static int ctr_paes_crypt(struct skcipher_request *req)
64427937843SMartin Schwidefsky {
645d00c0639SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
646d00c0639SEric Biggers 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
64727937843SMartin Schwidefsky 	u8 buf[AES_BLOCK_SIZE], *ctrptr;
648d00c0639SEric Biggers 	struct skcipher_walk walk;
64927937843SMartin Schwidefsky 	unsigned int nbytes, n, k;
65027937843SMartin Schwidefsky 	int ret, locked;
6516f3196b7SHarald Freudenberger 	struct {
6526f3196b7SHarald Freudenberger 		u8 key[MAXPROTKEYSIZE];
6536f3196b7SHarald Freudenberger 	} param;
65427937843SMartin Schwidefsky 
655d00c0639SEric Biggers 	ret = skcipher_walk_virt(&walk, req, false);
6566f3196b7SHarald Freudenberger 	if (ret)
6576f3196b7SHarald Freudenberger 		return ret;
6586f3196b7SHarald Freudenberger 
6596f3196b7SHarald Freudenberger 	spin_lock_bh(&ctx->pk_lock);
6606f3196b7SHarald Freudenberger 	memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
6616f3196b7SHarald Freudenberger 	spin_unlock_bh(&ctx->pk_lock);
6626f3196b7SHarald Freudenberger 
6636f3196b7SHarald Freudenberger 	locked = mutex_trylock(&ctrblk_lock);
6646f3196b7SHarald Freudenberger 
665d00c0639SEric Biggers 	while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
66627937843SMartin Schwidefsky 		n = AES_BLOCK_SIZE;
66727937843SMartin Schwidefsky 		if (nbytes >= 2*AES_BLOCK_SIZE && locked)
668d00c0639SEric Biggers 			n = __ctrblk_init(ctrblk, walk.iv, nbytes);
669d00c0639SEric Biggers 		ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk.iv;
6706f3196b7SHarald Freudenberger 		k = cpacf_kmctr(ctx->fc, &param, walk.dst.virt.addr,
671d00c0639SEric Biggers 				walk.src.virt.addr, n, ctrptr);
67227937843SMartin Schwidefsky 		if (k) {
67327937843SMartin Schwidefsky 			if (ctrptr == ctrblk)
674d00c0639SEric Biggers 				memcpy(walk.iv, ctrptr + k - AES_BLOCK_SIZE,
67527937843SMartin Schwidefsky 				       AES_BLOCK_SIZE);
676d00c0639SEric Biggers 			crypto_inc(walk.iv, AES_BLOCK_SIZE);
6776f3196b7SHarald Freudenberger 			ret = skcipher_walk_done(&walk, nbytes - k);
67827937843SMartin Schwidefsky 		}
67927937843SMartin Schwidefsky 		if (k < n) {
6806f3196b7SHarald Freudenberger 			if (__paes_convert_key(ctx)) {
681e7c95effSMartin Schwidefsky 				if (locked)
6826f3196b7SHarald Freudenberger 					mutex_unlock(&ctrblk_lock);
683d00c0639SEric Biggers 				return skcipher_walk_done(&walk, -EIO);
68427937843SMartin Schwidefsky 			}
6856f3196b7SHarald Freudenberger 			spin_lock_bh(&ctx->pk_lock);
6866f3196b7SHarald Freudenberger 			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
6876f3196b7SHarald Freudenberger 			spin_unlock_bh(&ctx->pk_lock);
68827937843SMartin Schwidefsky 		}
689e7c95effSMartin Schwidefsky 	}
69027937843SMartin Schwidefsky 	if (locked)
6916f3196b7SHarald Freudenberger 		mutex_unlock(&ctrblk_lock);
69227937843SMartin Schwidefsky 	/*
69327937843SMartin Schwidefsky 	 * final block may be < AES_BLOCK_SIZE, copy only nbytes
69427937843SMartin Schwidefsky 	 */
69527937843SMartin Schwidefsky 	if (nbytes) {
696*d68ac388SHerbert Xu 		memset(buf, 0, AES_BLOCK_SIZE);
697*d68ac388SHerbert Xu 		memcpy(buf, walk.src.virt.addr, nbytes);
69827937843SMartin Schwidefsky 		while (1) {
6996f3196b7SHarald Freudenberger 			if (cpacf_kmctr(ctx->fc, &param, buf,
700*d68ac388SHerbert Xu 					buf, AES_BLOCK_SIZE,
701d00c0639SEric Biggers 					walk.iv) == AES_BLOCK_SIZE)
70227937843SMartin Schwidefsky 				break;
7036f3196b7SHarald Freudenberger 			if (__paes_convert_key(ctx))
704d00c0639SEric Biggers 				return skcipher_walk_done(&walk, -EIO);
7056f3196b7SHarald Freudenberger 			spin_lock_bh(&ctx->pk_lock);
7066f3196b7SHarald Freudenberger 			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
7076f3196b7SHarald Freudenberger 			spin_unlock_bh(&ctx->pk_lock);
70827937843SMartin Schwidefsky 		}
709d00c0639SEric Biggers 		memcpy(walk.dst.virt.addr, buf, nbytes);
710d00c0639SEric Biggers 		crypto_inc(walk.iv, AES_BLOCK_SIZE);
7116f3196b7SHarald Freudenberger 		ret = skcipher_walk_done(&walk, nbytes);
71227937843SMartin Schwidefsky 	}
71327937843SMartin Schwidefsky 
71427937843SMartin Schwidefsky 	return ret;
71527937843SMartin Schwidefsky }
71627937843SMartin Schwidefsky 
717d00c0639SEric Biggers static struct skcipher_alg ctr_paes_alg = {
718d00c0639SEric Biggers 	.base.cra_name		=	"ctr(paes)",
719d00c0639SEric Biggers 	.base.cra_driver_name	=	"ctr-paes-s390",
720d00c0639SEric Biggers 	.base.cra_priority	=	402,	/* ecb-paes-s390 + 1 */
721d00c0639SEric Biggers 	.base.cra_blocksize	=	1,
722d00c0639SEric Biggers 	.base.cra_ctxsize	=	sizeof(struct s390_paes_ctx),
723d00c0639SEric Biggers 	.base.cra_module	=	THIS_MODULE,
724d00c0639SEric Biggers 	.base.cra_list		=	LIST_HEAD_INIT(ctr_paes_alg.base.cra_list),
725d00c0639SEric Biggers 	.init			=	ctr_paes_init,
726d00c0639SEric Biggers 	.exit			=	ctr_paes_exit,
727416f79c2SHarald Freudenberger 	.min_keysize		=	PAES_MIN_KEYSIZE,
728416f79c2SHarald Freudenberger 	.max_keysize		=	PAES_MAX_KEYSIZE,
72927937843SMartin Schwidefsky 	.ivsize			=	AES_BLOCK_SIZE,
73027937843SMartin Schwidefsky 	.setkey			=	ctr_paes_set_key,
731d00c0639SEric Biggers 	.encrypt		=	ctr_paes_crypt,
732d00c0639SEric Biggers 	.decrypt		=	ctr_paes_crypt,
733d00c0639SEric Biggers 	.chunksize		=	AES_BLOCK_SIZE,
73427937843SMartin Schwidefsky };
73527937843SMartin Schwidefsky 
__crypto_unregister_skcipher(struct skcipher_alg * alg)736d00c0639SEric Biggers static inline void __crypto_unregister_skcipher(struct skcipher_alg *alg)
73727937843SMartin Schwidefsky {
738d00c0639SEric Biggers 	if (!list_empty(&alg->base.cra_list))
739d00c0639SEric Biggers 		crypto_unregister_skcipher(alg);
74027937843SMartin Schwidefsky }
74127937843SMartin Schwidefsky 
paes_s390_fini(void)74227937843SMartin Schwidefsky static void paes_s390_fini(void)
74327937843SMartin Schwidefsky {
744d00c0639SEric Biggers 	__crypto_unregister_skcipher(&ctr_paes_alg);
745d00c0639SEric Biggers 	__crypto_unregister_skcipher(&xts_paes_alg);
746d00c0639SEric Biggers 	__crypto_unregister_skcipher(&cbc_paes_alg);
747d00c0639SEric Biggers 	__crypto_unregister_skcipher(&ecb_paes_alg);
7487f820d05SHarald Freudenberger 	if (ctrblk)
7497f820d05SHarald Freudenberger 		free_page((unsigned long) ctrblk);
75027937843SMartin Schwidefsky }
75127937843SMartin Schwidefsky 
paes_s390_init(void)75227937843SMartin Schwidefsky static int __init paes_s390_init(void)
75327937843SMartin Schwidefsky {
75427937843SMartin Schwidefsky 	int ret;
75527937843SMartin Schwidefsky 
75627937843SMartin Schwidefsky 	/* Query available functions for KM, KMC and KMCTR */
75727937843SMartin Schwidefsky 	cpacf_query(CPACF_KM, &km_functions);
75827937843SMartin Schwidefsky 	cpacf_query(CPACF_KMC, &kmc_functions);
75927937843SMartin Schwidefsky 	cpacf_query(CPACF_KMCTR, &kmctr_functions);
76027937843SMartin Schwidefsky 
76127937843SMartin Schwidefsky 	if (cpacf_test_func(&km_functions, CPACF_KM_PAES_128) ||
76227937843SMartin Schwidefsky 	    cpacf_test_func(&km_functions, CPACF_KM_PAES_192) ||
76327937843SMartin Schwidefsky 	    cpacf_test_func(&km_functions, CPACF_KM_PAES_256)) {
764d00c0639SEric Biggers 		ret = crypto_register_skcipher(&ecb_paes_alg);
76527937843SMartin Schwidefsky 		if (ret)
76627937843SMartin Schwidefsky 			goto out_err;
76727937843SMartin Schwidefsky 	}
76827937843SMartin Schwidefsky 
76927937843SMartin Schwidefsky 	if (cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) ||
77027937843SMartin Schwidefsky 	    cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) ||
77127937843SMartin Schwidefsky 	    cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256)) {
772d00c0639SEric Biggers 		ret = crypto_register_skcipher(&cbc_paes_alg);
77327937843SMartin Schwidefsky 		if (ret)
77427937843SMartin Schwidefsky 			goto out_err;
77527937843SMartin Schwidefsky 	}
77627937843SMartin Schwidefsky 
77727937843SMartin Schwidefsky 	if (cpacf_test_func(&km_functions, CPACF_KM_PXTS_128) ||
77827937843SMartin Schwidefsky 	    cpacf_test_func(&km_functions, CPACF_KM_PXTS_256)) {
779d00c0639SEric Biggers 		ret = crypto_register_skcipher(&xts_paes_alg);
78027937843SMartin Schwidefsky 		if (ret)
78127937843SMartin Schwidefsky 			goto out_err;
78227937843SMartin Schwidefsky 	}
78327937843SMartin Schwidefsky 
78427937843SMartin Schwidefsky 	if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_128) ||
78527937843SMartin Schwidefsky 	    cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_192) ||
78627937843SMartin Schwidefsky 	    cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_256)) {
78727937843SMartin Schwidefsky 		ctrblk = (u8 *) __get_free_page(GFP_KERNEL);
78827937843SMartin Schwidefsky 		if (!ctrblk) {
78927937843SMartin Schwidefsky 			ret = -ENOMEM;
79027937843SMartin Schwidefsky 			goto out_err;
79127937843SMartin Schwidefsky 		}
7927f820d05SHarald Freudenberger 		ret = crypto_register_skcipher(&ctr_paes_alg);
7937f820d05SHarald Freudenberger 		if (ret)
7947f820d05SHarald Freudenberger 			goto out_err;
79527937843SMartin Schwidefsky 	}
79627937843SMartin Schwidefsky 
79727937843SMartin Schwidefsky 	return 0;
79827937843SMartin Schwidefsky out_err:
79927937843SMartin Schwidefsky 	paes_s390_fini();
80027937843SMartin Schwidefsky 	return ret;
80127937843SMartin Schwidefsky }
80227937843SMartin Schwidefsky 
80327937843SMartin Schwidefsky module_init(paes_s390_init);
80427937843SMartin Schwidefsky module_exit(paes_s390_fini);
80527937843SMartin Schwidefsky 
806284c43e6SHarald Freudenberger MODULE_ALIAS_CRYPTO("paes");
80727937843SMartin Schwidefsky 
80827937843SMartin Schwidefsky MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm with protected keys");
80927937843SMartin Schwidefsky MODULE_LICENSE("GPL");
810