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, ¶m,
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, ¶m,
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, ¶m, 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, ¶m, 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