162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Cryptographic API.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * s390 implementation of the DES Cipher Algorithm.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright IBM Corp. 2003, 2011
862306a36Sopenharmony_ci * Author(s): Thomas Spatzier
962306a36Sopenharmony_ci *	      Jan Glauber (jan.glauber@de.ibm.com)
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/cpufeature.h>
1562306a36Sopenharmony_ci#include <linux/crypto.h>
1662306a36Sopenharmony_ci#include <linux/fips.h>
1762306a36Sopenharmony_ci#include <linux/mutex.h>
1862306a36Sopenharmony_ci#include <crypto/algapi.h>
1962306a36Sopenharmony_ci#include <crypto/internal/des.h>
2062306a36Sopenharmony_ci#include <crypto/internal/skcipher.h>
2162306a36Sopenharmony_ci#include <asm/cpacf.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define DES3_KEY_SIZE	(3 * DES_KEY_SIZE)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic u8 *ctrblk;
2662306a36Sopenharmony_cistatic DEFINE_MUTEX(ctrblk_lock);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic cpacf_mask_t km_functions, kmc_functions, kmctr_functions;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct s390_des_ctx {
3162306a36Sopenharmony_ci	u8 iv[DES_BLOCK_SIZE];
3262306a36Sopenharmony_ci	u8 key[DES3_KEY_SIZE];
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic int des_setkey(struct crypto_tfm *tfm, const u8 *key,
3662306a36Sopenharmony_ci		      unsigned int key_len)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
3962306a36Sopenharmony_ci	int err;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	err = crypto_des_verify_key(tfm, key);
4262306a36Sopenharmony_ci	if (err)
4362306a36Sopenharmony_ci		return err;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	memcpy(ctx->key, key, key_len);
4662306a36Sopenharmony_ci	return 0;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic int des_setkey_skcipher(struct crypto_skcipher *tfm, const u8 *key,
5062306a36Sopenharmony_ci			       unsigned int key_len)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	return des_setkey(crypto_skcipher_tfm(tfm), key, key_len);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic void s390_des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	cpacf_km(CPACF_KM_DEA, ctx->key, out, in, DES_BLOCK_SIZE);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic void s390_des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	cpacf_km(CPACF_KM_DEA | CPACF_DECRYPT,
6762306a36Sopenharmony_ci		 ctx->key, out, in, DES_BLOCK_SIZE);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic struct crypto_alg des_alg = {
7162306a36Sopenharmony_ci	.cra_name		=	"des",
7262306a36Sopenharmony_ci	.cra_driver_name	=	"des-s390",
7362306a36Sopenharmony_ci	.cra_priority		=	300,
7462306a36Sopenharmony_ci	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
7562306a36Sopenharmony_ci	.cra_blocksize		=	DES_BLOCK_SIZE,
7662306a36Sopenharmony_ci	.cra_ctxsize		=	sizeof(struct s390_des_ctx),
7762306a36Sopenharmony_ci	.cra_module		=	THIS_MODULE,
7862306a36Sopenharmony_ci	.cra_u			=	{
7962306a36Sopenharmony_ci		.cipher = {
8062306a36Sopenharmony_ci			.cia_min_keysize	=	DES_KEY_SIZE,
8162306a36Sopenharmony_ci			.cia_max_keysize	=	DES_KEY_SIZE,
8262306a36Sopenharmony_ci			.cia_setkey		=	des_setkey,
8362306a36Sopenharmony_ci			.cia_encrypt		=	s390_des_encrypt,
8462306a36Sopenharmony_ci			.cia_decrypt		=	s390_des_decrypt,
8562306a36Sopenharmony_ci		}
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic int ecb_desall_crypt(struct skcipher_request *req, unsigned long fc)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
9262306a36Sopenharmony_ci	struct s390_des_ctx *ctx = crypto_skcipher_ctx(tfm);
9362306a36Sopenharmony_ci	struct skcipher_walk walk;
9462306a36Sopenharmony_ci	unsigned int nbytes, n;
9562306a36Sopenharmony_ci	int ret;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	ret = skcipher_walk_virt(&walk, req, false);
9862306a36Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
9962306a36Sopenharmony_ci		/* only use complete blocks */
10062306a36Sopenharmony_ci		n = nbytes & ~(DES_BLOCK_SIZE - 1);
10162306a36Sopenharmony_ci		cpacf_km(fc, ctx->key, walk.dst.virt.addr,
10262306a36Sopenharmony_ci			 walk.src.virt.addr, n);
10362306a36Sopenharmony_ci		ret = skcipher_walk_done(&walk, nbytes - n);
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci	return ret;
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic int cbc_desall_crypt(struct skcipher_request *req, unsigned long fc)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
11162306a36Sopenharmony_ci	struct s390_des_ctx *ctx = crypto_skcipher_ctx(tfm);
11262306a36Sopenharmony_ci	struct skcipher_walk walk;
11362306a36Sopenharmony_ci	unsigned int nbytes, n;
11462306a36Sopenharmony_ci	int ret;
11562306a36Sopenharmony_ci	struct {
11662306a36Sopenharmony_ci		u8 iv[DES_BLOCK_SIZE];
11762306a36Sopenharmony_ci		u8 key[DES3_KEY_SIZE];
11862306a36Sopenharmony_ci	} param;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	ret = skcipher_walk_virt(&walk, req, false);
12162306a36Sopenharmony_ci	if (ret)
12262306a36Sopenharmony_ci		return ret;
12362306a36Sopenharmony_ci	memcpy(param.iv, walk.iv, DES_BLOCK_SIZE);
12462306a36Sopenharmony_ci	memcpy(param.key, ctx->key, DES3_KEY_SIZE);
12562306a36Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
12662306a36Sopenharmony_ci		/* only use complete blocks */
12762306a36Sopenharmony_ci		n = nbytes & ~(DES_BLOCK_SIZE - 1);
12862306a36Sopenharmony_ci		cpacf_kmc(fc, &param, walk.dst.virt.addr,
12962306a36Sopenharmony_ci			  walk.src.virt.addr, n);
13062306a36Sopenharmony_ci		memcpy(walk.iv, param.iv, DES_BLOCK_SIZE);
13162306a36Sopenharmony_ci		ret = skcipher_walk_done(&walk, nbytes - n);
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci	return ret;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic int ecb_des_encrypt(struct skcipher_request *req)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	return ecb_desall_crypt(req, CPACF_KM_DEA);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic int ecb_des_decrypt(struct skcipher_request *req)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	return ecb_desall_crypt(req, CPACF_KM_DEA | CPACF_DECRYPT);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic struct skcipher_alg ecb_des_alg = {
14762306a36Sopenharmony_ci	.base.cra_name		=	"ecb(des)",
14862306a36Sopenharmony_ci	.base.cra_driver_name	=	"ecb-des-s390",
14962306a36Sopenharmony_ci	.base.cra_priority	=	400,	/* combo: des + ecb */
15062306a36Sopenharmony_ci	.base.cra_blocksize	=	DES_BLOCK_SIZE,
15162306a36Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_des_ctx),
15262306a36Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
15362306a36Sopenharmony_ci	.min_keysize		=	DES_KEY_SIZE,
15462306a36Sopenharmony_ci	.max_keysize		=	DES_KEY_SIZE,
15562306a36Sopenharmony_ci	.setkey			=	des_setkey_skcipher,
15662306a36Sopenharmony_ci	.encrypt		=	ecb_des_encrypt,
15762306a36Sopenharmony_ci	.decrypt		=	ecb_des_decrypt,
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int cbc_des_encrypt(struct skcipher_request *req)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	return cbc_desall_crypt(req, CPACF_KMC_DEA);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int cbc_des_decrypt(struct skcipher_request *req)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	return cbc_desall_crypt(req, CPACF_KMC_DEA | CPACF_DECRYPT);
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic struct skcipher_alg cbc_des_alg = {
17162306a36Sopenharmony_ci	.base.cra_name		=	"cbc(des)",
17262306a36Sopenharmony_ci	.base.cra_driver_name	=	"cbc-des-s390",
17362306a36Sopenharmony_ci	.base.cra_priority	=	400,	/* combo: des + cbc */
17462306a36Sopenharmony_ci	.base.cra_blocksize	=	DES_BLOCK_SIZE,
17562306a36Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_des_ctx),
17662306a36Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
17762306a36Sopenharmony_ci	.min_keysize		=	DES_KEY_SIZE,
17862306a36Sopenharmony_ci	.max_keysize		=	DES_KEY_SIZE,
17962306a36Sopenharmony_ci	.ivsize			=	DES_BLOCK_SIZE,
18062306a36Sopenharmony_ci	.setkey			=	des_setkey_skcipher,
18162306a36Sopenharmony_ci	.encrypt		=	cbc_des_encrypt,
18262306a36Sopenharmony_ci	.decrypt		=	cbc_des_decrypt,
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/*
18662306a36Sopenharmony_ci * RFC2451:
18762306a36Sopenharmony_ci *
18862306a36Sopenharmony_ci *   For DES-EDE3, there is no known need to reject weak or
18962306a36Sopenharmony_ci *   complementation keys.  Any weakness is obviated by the use of
19062306a36Sopenharmony_ci *   multiple keys.
19162306a36Sopenharmony_ci *
19262306a36Sopenharmony_ci *   However, if the first two or last two independent 64-bit keys are
19362306a36Sopenharmony_ci *   equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the
19462306a36Sopenharmony_ci *   same as DES.  Implementers MUST reject keys that exhibit this
19562306a36Sopenharmony_ci *   property.
19662306a36Sopenharmony_ci *
19762306a36Sopenharmony_ci *   In fips mode additionally check for all 3 keys are unique.
19862306a36Sopenharmony_ci *
19962306a36Sopenharmony_ci */
20062306a36Sopenharmony_cistatic int des3_setkey(struct crypto_tfm *tfm, const u8 *key,
20162306a36Sopenharmony_ci		       unsigned int key_len)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
20462306a36Sopenharmony_ci	int err;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	err = crypto_des3_ede_verify_key(tfm, key);
20762306a36Sopenharmony_ci	if (err)
20862306a36Sopenharmony_ci		return err;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	memcpy(ctx->key, key, key_len);
21162306a36Sopenharmony_ci	return 0;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic int des3_setkey_skcipher(struct crypto_skcipher *tfm, const u8 *key,
21562306a36Sopenharmony_ci				unsigned int key_len)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	return des3_setkey(crypto_skcipher_tfm(tfm), key, key_len);
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic void des3_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	cpacf_km(CPACF_KM_TDEA_192, ctx->key, dst, src, DES_BLOCK_SIZE);
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic void des3_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	cpacf_km(CPACF_KM_TDEA_192 | CPACF_DECRYPT,
23262306a36Sopenharmony_ci		 ctx->key, dst, src, DES_BLOCK_SIZE);
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic struct crypto_alg des3_alg = {
23662306a36Sopenharmony_ci	.cra_name		=	"des3_ede",
23762306a36Sopenharmony_ci	.cra_driver_name	=	"des3_ede-s390",
23862306a36Sopenharmony_ci	.cra_priority		=	300,
23962306a36Sopenharmony_ci	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
24062306a36Sopenharmony_ci	.cra_blocksize		=	DES_BLOCK_SIZE,
24162306a36Sopenharmony_ci	.cra_ctxsize		=	sizeof(struct s390_des_ctx),
24262306a36Sopenharmony_ci	.cra_module		=	THIS_MODULE,
24362306a36Sopenharmony_ci	.cra_u			=	{
24462306a36Sopenharmony_ci		.cipher = {
24562306a36Sopenharmony_ci			.cia_min_keysize	=	DES3_KEY_SIZE,
24662306a36Sopenharmony_ci			.cia_max_keysize	=	DES3_KEY_SIZE,
24762306a36Sopenharmony_ci			.cia_setkey		=	des3_setkey,
24862306a36Sopenharmony_ci			.cia_encrypt		=	des3_encrypt,
24962306a36Sopenharmony_ci			.cia_decrypt		=	des3_decrypt,
25062306a36Sopenharmony_ci		}
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int ecb_des3_encrypt(struct skcipher_request *req)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	return ecb_desall_crypt(req, CPACF_KM_TDEA_192);
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic int ecb_des3_decrypt(struct skcipher_request *req)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	return ecb_desall_crypt(req, CPACF_KM_TDEA_192 | CPACF_DECRYPT);
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic struct skcipher_alg ecb_des3_alg = {
26562306a36Sopenharmony_ci	.base.cra_name		=	"ecb(des3_ede)",
26662306a36Sopenharmony_ci	.base.cra_driver_name	=	"ecb-des3_ede-s390",
26762306a36Sopenharmony_ci	.base.cra_priority	=	400,	/* combo: des3 + ecb */
26862306a36Sopenharmony_ci	.base.cra_blocksize	=	DES_BLOCK_SIZE,
26962306a36Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_des_ctx),
27062306a36Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
27162306a36Sopenharmony_ci	.min_keysize		=	DES3_KEY_SIZE,
27262306a36Sopenharmony_ci	.max_keysize		=	DES3_KEY_SIZE,
27362306a36Sopenharmony_ci	.setkey			=	des3_setkey_skcipher,
27462306a36Sopenharmony_ci	.encrypt		=	ecb_des3_encrypt,
27562306a36Sopenharmony_ci	.decrypt		=	ecb_des3_decrypt,
27662306a36Sopenharmony_ci};
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic int cbc_des3_encrypt(struct skcipher_request *req)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	return cbc_desall_crypt(req, CPACF_KMC_TDEA_192);
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic int cbc_des3_decrypt(struct skcipher_request *req)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	return cbc_desall_crypt(req, CPACF_KMC_TDEA_192 | CPACF_DECRYPT);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic struct skcipher_alg cbc_des3_alg = {
28962306a36Sopenharmony_ci	.base.cra_name		=	"cbc(des3_ede)",
29062306a36Sopenharmony_ci	.base.cra_driver_name	=	"cbc-des3_ede-s390",
29162306a36Sopenharmony_ci	.base.cra_priority	=	400,	/* combo: des3 + cbc */
29262306a36Sopenharmony_ci	.base.cra_blocksize	=	DES_BLOCK_SIZE,
29362306a36Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_des_ctx),
29462306a36Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
29562306a36Sopenharmony_ci	.min_keysize		=	DES3_KEY_SIZE,
29662306a36Sopenharmony_ci	.max_keysize		=	DES3_KEY_SIZE,
29762306a36Sopenharmony_ci	.ivsize			=	DES_BLOCK_SIZE,
29862306a36Sopenharmony_ci	.setkey			=	des3_setkey_skcipher,
29962306a36Sopenharmony_ci	.encrypt		=	cbc_des3_encrypt,
30062306a36Sopenharmony_ci	.decrypt		=	cbc_des3_decrypt,
30162306a36Sopenharmony_ci};
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	unsigned int i, n;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/* align to block size, max. PAGE_SIZE */
30862306a36Sopenharmony_ci	n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(DES_BLOCK_SIZE - 1);
30962306a36Sopenharmony_ci	memcpy(ctrptr, iv, DES_BLOCK_SIZE);
31062306a36Sopenharmony_ci	for (i = (n / DES_BLOCK_SIZE) - 1; i > 0; i--) {
31162306a36Sopenharmony_ci		memcpy(ctrptr + DES_BLOCK_SIZE, ctrptr, DES_BLOCK_SIZE);
31262306a36Sopenharmony_ci		crypto_inc(ctrptr + DES_BLOCK_SIZE, DES_BLOCK_SIZE);
31362306a36Sopenharmony_ci		ctrptr += DES_BLOCK_SIZE;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci	return n;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic int ctr_desall_crypt(struct skcipher_request *req, unsigned long fc)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
32162306a36Sopenharmony_ci	struct s390_des_ctx *ctx = crypto_skcipher_ctx(tfm);
32262306a36Sopenharmony_ci	u8 buf[DES_BLOCK_SIZE], *ctrptr;
32362306a36Sopenharmony_ci	struct skcipher_walk walk;
32462306a36Sopenharmony_ci	unsigned int n, nbytes;
32562306a36Sopenharmony_ci	int ret, locked;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	locked = mutex_trylock(&ctrblk_lock);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	ret = skcipher_walk_virt(&walk, req, false);
33062306a36Sopenharmony_ci	while ((nbytes = walk.nbytes) >= DES_BLOCK_SIZE) {
33162306a36Sopenharmony_ci		n = DES_BLOCK_SIZE;
33262306a36Sopenharmony_ci		if (nbytes >= 2*DES_BLOCK_SIZE && locked)
33362306a36Sopenharmony_ci			n = __ctrblk_init(ctrblk, walk.iv, nbytes);
33462306a36Sopenharmony_ci		ctrptr = (n > DES_BLOCK_SIZE) ? ctrblk : walk.iv;
33562306a36Sopenharmony_ci		cpacf_kmctr(fc, ctx->key, walk.dst.virt.addr,
33662306a36Sopenharmony_ci			    walk.src.virt.addr, n, ctrptr);
33762306a36Sopenharmony_ci		if (ctrptr == ctrblk)
33862306a36Sopenharmony_ci			memcpy(walk.iv, ctrptr + n - DES_BLOCK_SIZE,
33962306a36Sopenharmony_ci				DES_BLOCK_SIZE);
34062306a36Sopenharmony_ci		crypto_inc(walk.iv, DES_BLOCK_SIZE);
34162306a36Sopenharmony_ci		ret = skcipher_walk_done(&walk, nbytes - n);
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci	if (locked)
34462306a36Sopenharmony_ci		mutex_unlock(&ctrblk_lock);
34562306a36Sopenharmony_ci	/* final block may be < DES_BLOCK_SIZE, copy only nbytes */
34662306a36Sopenharmony_ci	if (nbytes) {
34762306a36Sopenharmony_ci		cpacf_kmctr(fc, ctx->key, buf, walk.src.virt.addr,
34862306a36Sopenharmony_ci			    DES_BLOCK_SIZE, walk.iv);
34962306a36Sopenharmony_ci		memcpy(walk.dst.virt.addr, buf, nbytes);
35062306a36Sopenharmony_ci		crypto_inc(walk.iv, DES_BLOCK_SIZE);
35162306a36Sopenharmony_ci		ret = skcipher_walk_done(&walk, 0);
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci	return ret;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic int ctr_des_crypt(struct skcipher_request *req)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	return ctr_desall_crypt(req, CPACF_KMCTR_DEA);
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic struct skcipher_alg ctr_des_alg = {
36262306a36Sopenharmony_ci	.base.cra_name		=	"ctr(des)",
36362306a36Sopenharmony_ci	.base.cra_driver_name	=	"ctr-des-s390",
36462306a36Sopenharmony_ci	.base.cra_priority	=	400,	/* combo: des + ctr */
36562306a36Sopenharmony_ci	.base.cra_blocksize	=	1,
36662306a36Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_des_ctx),
36762306a36Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
36862306a36Sopenharmony_ci	.min_keysize		=	DES_KEY_SIZE,
36962306a36Sopenharmony_ci	.max_keysize		=	DES_KEY_SIZE,
37062306a36Sopenharmony_ci	.ivsize			=	DES_BLOCK_SIZE,
37162306a36Sopenharmony_ci	.setkey			=	des_setkey_skcipher,
37262306a36Sopenharmony_ci	.encrypt		=	ctr_des_crypt,
37362306a36Sopenharmony_ci	.decrypt		=	ctr_des_crypt,
37462306a36Sopenharmony_ci	.chunksize		=	DES_BLOCK_SIZE,
37562306a36Sopenharmony_ci};
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic int ctr_des3_crypt(struct skcipher_request *req)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	return ctr_desall_crypt(req, CPACF_KMCTR_TDEA_192);
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic struct skcipher_alg ctr_des3_alg = {
38362306a36Sopenharmony_ci	.base.cra_name		=	"ctr(des3_ede)",
38462306a36Sopenharmony_ci	.base.cra_driver_name	=	"ctr-des3_ede-s390",
38562306a36Sopenharmony_ci	.base.cra_priority	=	400,	/* combo: des3 + ede */
38662306a36Sopenharmony_ci	.base.cra_blocksize	=	1,
38762306a36Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_des_ctx),
38862306a36Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
38962306a36Sopenharmony_ci	.min_keysize		=	DES3_KEY_SIZE,
39062306a36Sopenharmony_ci	.max_keysize		=	DES3_KEY_SIZE,
39162306a36Sopenharmony_ci	.ivsize			=	DES_BLOCK_SIZE,
39262306a36Sopenharmony_ci	.setkey			=	des3_setkey_skcipher,
39362306a36Sopenharmony_ci	.encrypt		=	ctr_des3_crypt,
39462306a36Sopenharmony_ci	.decrypt		=	ctr_des3_crypt,
39562306a36Sopenharmony_ci	.chunksize		=	DES_BLOCK_SIZE,
39662306a36Sopenharmony_ci};
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic struct crypto_alg *des_s390_algs_ptr[2];
39962306a36Sopenharmony_cistatic int des_s390_algs_num;
40062306a36Sopenharmony_cistatic struct skcipher_alg *des_s390_skciphers_ptr[6];
40162306a36Sopenharmony_cistatic int des_s390_skciphers_num;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic int des_s390_register_alg(struct crypto_alg *alg)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	int ret;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	ret = crypto_register_alg(alg);
40862306a36Sopenharmony_ci	if (!ret)
40962306a36Sopenharmony_ci		des_s390_algs_ptr[des_s390_algs_num++] = alg;
41062306a36Sopenharmony_ci	return ret;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic int des_s390_register_skcipher(struct skcipher_alg *alg)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	int ret;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	ret = crypto_register_skcipher(alg);
41862306a36Sopenharmony_ci	if (!ret)
41962306a36Sopenharmony_ci		des_s390_skciphers_ptr[des_s390_skciphers_num++] = alg;
42062306a36Sopenharmony_ci	return ret;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic void des_s390_exit(void)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	while (des_s390_algs_num--)
42662306a36Sopenharmony_ci		crypto_unregister_alg(des_s390_algs_ptr[des_s390_algs_num]);
42762306a36Sopenharmony_ci	while (des_s390_skciphers_num--)
42862306a36Sopenharmony_ci		crypto_unregister_skcipher(des_s390_skciphers_ptr[des_s390_skciphers_num]);
42962306a36Sopenharmony_ci	if (ctrblk)
43062306a36Sopenharmony_ci		free_page((unsigned long) ctrblk);
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic int __init des_s390_init(void)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	int ret;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	/* Query available functions for KM, KMC and KMCTR */
43862306a36Sopenharmony_ci	cpacf_query(CPACF_KM, &km_functions);
43962306a36Sopenharmony_ci	cpacf_query(CPACF_KMC, &kmc_functions);
44062306a36Sopenharmony_ci	cpacf_query(CPACF_KMCTR, &kmctr_functions);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (cpacf_test_func(&km_functions, CPACF_KM_DEA)) {
44362306a36Sopenharmony_ci		ret = des_s390_register_alg(&des_alg);
44462306a36Sopenharmony_ci		if (ret)
44562306a36Sopenharmony_ci			goto out_err;
44662306a36Sopenharmony_ci		ret = des_s390_register_skcipher(&ecb_des_alg);
44762306a36Sopenharmony_ci		if (ret)
44862306a36Sopenharmony_ci			goto out_err;
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci	if (cpacf_test_func(&kmc_functions, CPACF_KMC_DEA)) {
45162306a36Sopenharmony_ci		ret = des_s390_register_skcipher(&cbc_des_alg);
45262306a36Sopenharmony_ci		if (ret)
45362306a36Sopenharmony_ci			goto out_err;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci	if (cpacf_test_func(&km_functions, CPACF_KM_TDEA_192)) {
45662306a36Sopenharmony_ci		ret = des_s390_register_alg(&des3_alg);
45762306a36Sopenharmony_ci		if (ret)
45862306a36Sopenharmony_ci			goto out_err;
45962306a36Sopenharmony_ci		ret = des_s390_register_skcipher(&ecb_des3_alg);
46062306a36Sopenharmony_ci		if (ret)
46162306a36Sopenharmony_ci			goto out_err;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci	if (cpacf_test_func(&kmc_functions, CPACF_KMC_TDEA_192)) {
46462306a36Sopenharmony_ci		ret = des_s390_register_skcipher(&cbc_des3_alg);
46562306a36Sopenharmony_ci		if (ret)
46662306a36Sopenharmony_ci			goto out_err;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_DEA) ||
47062306a36Sopenharmony_ci	    cpacf_test_func(&kmctr_functions, CPACF_KMCTR_TDEA_192)) {
47162306a36Sopenharmony_ci		ctrblk = (u8 *) __get_free_page(GFP_KERNEL);
47262306a36Sopenharmony_ci		if (!ctrblk) {
47362306a36Sopenharmony_ci			ret = -ENOMEM;
47462306a36Sopenharmony_ci			goto out_err;
47562306a36Sopenharmony_ci		}
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_DEA)) {
47962306a36Sopenharmony_ci		ret = des_s390_register_skcipher(&ctr_des_alg);
48062306a36Sopenharmony_ci		if (ret)
48162306a36Sopenharmony_ci			goto out_err;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci	if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_TDEA_192)) {
48462306a36Sopenharmony_ci		ret = des_s390_register_skcipher(&ctr_des3_alg);
48562306a36Sopenharmony_ci		if (ret)
48662306a36Sopenharmony_ci			goto out_err;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	return 0;
49062306a36Sopenharmony_ciout_err:
49162306a36Sopenharmony_ci	des_s390_exit();
49262306a36Sopenharmony_ci	return ret;
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cimodule_cpu_feature_match(S390_CPU_FEATURE_MSA, des_s390_init);
49662306a36Sopenharmony_cimodule_exit(des_s390_exit);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("des");
49962306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("des3_ede");
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
50262306a36Sopenharmony_ciMODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms");
503