18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Cryptographic API. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * s390 implementation of the DES Cipher Algorithm. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2003, 2011 88c2ecf20Sopenharmony_ci * Author(s): Thomas Spatzier 98c2ecf20Sopenharmony_ci * Jan Glauber (jan.glauber@de.ibm.com) 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/cpufeature.h> 158c2ecf20Sopenharmony_ci#include <linux/crypto.h> 168c2ecf20Sopenharmony_ci#include <linux/fips.h> 178c2ecf20Sopenharmony_ci#include <linux/mutex.h> 188c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 198c2ecf20Sopenharmony_ci#include <crypto/internal/des.h> 208c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 218c2ecf20Sopenharmony_ci#include <asm/cpacf.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define DES3_KEY_SIZE (3 * DES_KEY_SIZE) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic u8 *ctrblk; 268c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(ctrblk_lock); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic cpacf_mask_t km_functions, kmc_functions, kmctr_functions; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct s390_des_ctx { 318c2ecf20Sopenharmony_ci u8 iv[DES_BLOCK_SIZE]; 328c2ecf20Sopenharmony_ci u8 key[DES3_KEY_SIZE]; 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int des_setkey(struct crypto_tfm *tfm, const u8 *key, 368c2ecf20Sopenharmony_ci unsigned int key_len) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); 398c2ecf20Sopenharmony_ci int err; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci err = crypto_des_verify_key(tfm, key); 428c2ecf20Sopenharmony_ci if (err) 438c2ecf20Sopenharmony_ci return err; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci memcpy(ctx->key, key, key_len); 468c2ecf20Sopenharmony_ci return 0; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int des_setkey_skcipher(struct crypto_skcipher *tfm, const u8 *key, 508c2ecf20Sopenharmony_ci unsigned int key_len) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci return des_setkey(crypto_skcipher_tfm(tfm), key, key_len); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void s390_des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci cpacf_km(CPACF_KM_DEA, ctx->key, out, in, DES_BLOCK_SIZE); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void s390_des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci cpacf_km(CPACF_KM_DEA | CPACF_DECRYPT, 678c2ecf20Sopenharmony_ci ctx->key, out, in, DES_BLOCK_SIZE); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic struct crypto_alg des_alg = { 718c2ecf20Sopenharmony_ci .cra_name = "des", 728c2ecf20Sopenharmony_ci .cra_driver_name = "des-s390", 738c2ecf20Sopenharmony_ci .cra_priority = 300, 748c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 758c2ecf20Sopenharmony_ci .cra_blocksize = DES_BLOCK_SIZE, 768c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct s390_des_ctx), 778c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 788c2ecf20Sopenharmony_ci .cra_u = { 798c2ecf20Sopenharmony_ci .cipher = { 808c2ecf20Sopenharmony_ci .cia_min_keysize = DES_KEY_SIZE, 818c2ecf20Sopenharmony_ci .cia_max_keysize = DES_KEY_SIZE, 828c2ecf20Sopenharmony_ci .cia_setkey = des_setkey, 838c2ecf20Sopenharmony_ci .cia_encrypt = s390_des_encrypt, 848c2ecf20Sopenharmony_ci .cia_decrypt = s390_des_decrypt, 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic int ecb_desall_crypt(struct skcipher_request *req, unsigned long fc) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 928c2ecf20Sopenharmony_ci struct s390_des_ctx *ctx = crypto_skcipher_ctx(tfm); 938c2ecf20Sopenharmony_ci struct skcipher_walk walk; 948c2ecf20Sopenharmony_ci unsigned int nbytes, n; 958c2ecf20Sopenharmony_ci int ret; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 988c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 998c2ecf20Sopenharmony_ci /* only use complete blocks */ 1008c2ecf20Sopenharmony_ci n = nbytes & ~(DES_BLOCK_SIZE - 1); 1018c2ecf20Sopenharmony_ci cpacf_km(fc, ctx->key, walk.dst.virt.addr, 1028c2ecf20Sopenharmony_ci walk.src.virt.addr, n); 1038c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - n); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci return ret; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int cbc_desall_crypt(struct skcipher_request *req, unsigned long fc) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 1118c2ecf20Sopenharmony_ci struct s390_des_ctx *ctx = crypto_skcipher_ctx(tfm); 1128c2ecf20Sopenharmony_ci struct skcipher_walk walk; 1138c2ecf20Sopenharmony_ci unsigned int nbytes, n; 1148c2ecf20Sopenharmony_ci int ret; 1158c2ecf20Sopenharmony_ci struct { 1168c2ecf20Sopenharmony_ci u8 iv[DES_BLOCK_SIZE]; 1178c2ecf20Sopenharmony_ci u8 key[DES3_KEY_SIZE]; 1188c2ecf20Sopenharmony_ci } param; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 1218c2ecf20Sopenharmony_ci if (ret) 1228c2ecf20Sopenharmony_ci return ret; 1238c2ecf20Sopenharmony_ci memcpy(param.iv, walk.iv, DES_BLOCK_SIZE); 1248c2ecf20Sopenharmony_ci memcpy(param.key, ctx->key, DES3_KEY_SIZE); 1258c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 1268c2ecf20Sopenharmony_ci /* only use complete blocks */ 1278c2ecf20Sopenharmony_ci n = nbytes & ~(DES_BLOCK_SIZE - 1); 1288c2ecf20Sopenharmony_ci cpacf_kmc(fc, ¶m, walk.dst.virt.addr, 1298c2ecf20Sopenharmony_ci walk.src.virt.addr, n); 1308c2ecf20Sopenharmony_ci memcpy(walk.iv, param.iv, DES_BLOCK_SIZE); 1318c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - n); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci return ret; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int ecb_des_encrypt(struct skcipher_request *req) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci return ecb_desall_crypt(req, CPACF_KM_DEA); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int ecb_des_decrypt(struct skcipher_request *req) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci return ecb_desall_crypt(req, CPACF_KM_DEA | CPACF_DECRYPT); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic struct skcipher_alg ecb_des_alg = { 1478c2ecf20Sopenharmony_ci .base.cra_name = "ecb(des)", 1488c2ecf20Sopenharmony_ci .base.cra_driver_name = "ecb-des-s390", 1498c2ecf20Sopenharmony_ci .base.cra_priority = 400, /* combo: des + ecb */ 1508c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 1518c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_des_ctx), 1528c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 1538c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 1548c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 1558c2ecf20Sopenharmony_ci .setkey = des_setkey_skcipher, 1568c2ecf20Sopenharmony_ci .encrypt = ecb_des_encrypt, 1578c2ecf20Sopenharmony_ci .decrypt = ecb_des_decrypt, 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic int cbc_des_encrypt(struct skcipher_request *req) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci return cbc_desall_crypt(req, CPACF_KMC_DEA); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int cbc_des_decrypt(struct skcipher_request *req) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci return cbc_desall_crypt(req, CPACF_KMC_DEA | CPACF_DECRYPT); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic struct skcipher_alg cbc_des_alg = { 1718c2ecf20Sopenharmony_ci .base.cra_name = "cbc(des)", 1728c2ecf20Sopenharmony_ci .base.cra_driver_name = "cbc-des-s390", 1738c2ecf20Sopenharmony_ci .base.cra_priority = 400, /* combo: des + cbc */ 1748c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 1758c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_des_ctx), 1768c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 1778c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 1788c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 1798c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 1808c2ecf20Sopenharmony_ci .setkey = des_setkey_skcipher, 1818c2ecf20Sopenharmony_ci .encrypt = cbc_des_encrypt, 1828c2ecf20Sopenharmony_ci .decrypt = cbc_des_decrypt, 1838c2ecf20Sopenharmony_ci}; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/* 1868c2ecf20Sopenharmony_ci * RFC2451: 1878c2ecf20Sopenharmony_ci * 1888c2ecf20Sopenharmony_ci * For DES-EDE3, there is no known need to reject weak or 1898c2ecf20Sopenharmony_ci * complementation keys. Any weakness is obviated by the use of 1908c2ecf20Sopenharmony_ci * multiple keys. 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * However, if the first two or last two independent 64-bit keys are 1938c2ecf20Sopenharmony_ci * equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the 1948c2ecf20Sopenharmony_ci * same as DES. Implementers MUST reject keys that exhibit this 1958c2ecf20Sopenharmony_ci * property. 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * In fips mode additinally check for all 3 keys are unique. 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_cistatic int des3_setkey(struct crypto_tfm *tfm, const u8 *key, 2018c2ecf20Sopenharmony_ci unsigned int key_len) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); 2048c2ecf20Sopenharmony_ci int err; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci err = crypto_des3_ede_verify_key(tfm, key); 2078c2ecf20Sopenharmony_ci if (err) 2088c2ecf20Sopenharmony_ci return err; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci memcpy(ctx->key, key, key_len); 2118c2ecf20Sopenharmony_ci return 0; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int des3_setkey_skcipher(struct crypto_skcipher *tfm, const u8 *key, 2158c2ecf20Sopenharmony_ci unsigned int key_len) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci return des3_setkey(crypto_skcipher_tfm(tfm), key, key_len); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void des3_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci cpacf_km(CPACF_KM_TDEA_192, ctx->key, dst, src, DES_BLOCK_SIZE); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic void des3_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci cpacf_km(CPACF_KM_TDEA_192 | CPACF_DECRYPT, 2328c2ecf20Sopenharmony_ci ctx->key, dst, src, DES_BLOCK_SIZE); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic struct crypto_alg des3_alg = { 2368c2ecf20Sopenharmony_ci .cra_name = "des3_ede", 2378c2ecf20Sopenharmony_ci .cra_driver_name = "des3_ede-s390", 2388c2ecf20Sopenharmony_ci .cra_priority = 300, 2398c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 2408c2ecf20Sopenharmony_ci .cra_blocksize = DES_BLOCK_SIZE, 2418c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct s390_des_ctx), 2428c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 2438c2ecf20Sopenharmony_ci .cra_u = { 2448c2ecf20Sopenharmony_ci .cipher = { 2458c2ecf20Sopenharmony_ci .cia_min_keysize = DES3_KEY_SIZE, 2468c2ecf20Sopenharmony_ci .cia_max_keysize = DES3_KEY_SIZE, 2478c2ecf20Sopenharmony_ci .cia_setkey = des3_setkey, 2488c2ecf20Sopenharmony_ci .cia_encrypt = des3_encrypt, 2498c2ecf20Sopenharmony_ci .cia_decrypt = des3_decrypt, 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int ecb_des3_encrypt(struct skcipher_request *req) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci return ecb_desall_crypt(req, CPACF_KM_TDEA_192); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int ecb_des3_decrypt(struct skcipher_request *req) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci return ecb_desall_crypt(req, CPACF_KM_TDEA_192 | CPACF_DECRYPT); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic struct skcipher_alg ecb_des3_alg = { 2658c2ecf20Sopenharmony_ci .base.cra_name = "ecb(des3_ede)", 2668c2ecf20Sopenharmony_ci .base.cra_driver_name = "ecb-des3_ede-s390", 2678c2ecf20Sopenharmony_ci .base.cra_priority = 400, /* combo: des3 + ecb */ 2688c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 2698c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_des_ctx), 2708c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 2718c2ecf20Sopenharmony_ci .min_keysize = DES3_KEY_SIZE, 2728c2ecf20Sopenharmony_ci .max_keysize = DES3_KEY_SIZE, 2738c2ecf20Sopenharmony_ci .setkey = des3_setkey_skcipher, 2748c2ecf20Sopenharmony_ci .encrypt = ecb_des3_encrypt, 2758c2ecf20Sopenharmony_ci .decrypt = ecb_des3_decrypt, 2768c2ecf20Sopenharmony_ci}; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int cbc_des3_encrypt(struct skcipher_request *req) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci return cbc_desall_crypt(req, CPACF_KMC_TDEA_192); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int cbc_des3_decrypt(struct skcipher_request *req) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci return cbc_desall_crypt(req, CPACF_KMC_TDEA_192 | CPACF_DECRYPT); 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic struct skcipher_alg cbc_des3_alg = { 2898c2ecf20Sopenharmony_ci .base.cra_name = "cbc(des3_ede)", 2908c2ecf20Sopenharmony_ci .base.cra_driver_name = "cbc-des3_ede-s390", 2918c2ecf20Sopenharmony_ci .base.cra_priority = 400, /* combo: des3 + cbc */ 2928c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 2938c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_des_ctx), 2948c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 2958c2ecf20Sopenharmony_ci .min_keysize = DES3_KEY_SIZE, 2968c2ecf20Sopenharmony_ci .max_keysize = DES3_KEY_SIZE, 2978c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 2988c2ecf20Sopenharmony_ci .setkey = des3_setkey_skcipher, 2998c2ecf20Sopenharmony_ci .encrypt = cbc_des3_encrypt, 3008c2ecf20Sopenharmony_ci .decrypt = cbc_des3_decrypt, 3018c2ecf20Sopenharmony_ci}; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci unsigned int i, n; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* align to block size, max. PAGE_SIZE */ 3088c2ecf20Sopenharmony_ci n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(DES_BLOCK_SIZE - 1); 3098c2ecf20Sopenharmony_ci memcpy(ctrptr, iv, DES_BLOCK_SIZE); 3108c2ecf20Sopenharmony_ci for (i = (n / DES_BLOCK_SIZE) - 1; i > 0; i--) { 3118c2ecf20Sopenharmony_ci memcpy(ctrptr + DES_BLOCK_SIZE, ctrptr, DES_BLOCK_SIZE); 3128c2ecf20Sopenharmony_ci crypto_inc(ctrptr + DES_BLOCK_SIZE, DES_BLOCK_SIZE); 3138c2ecf20Sopenharmony_ci ctrptr += DES_BLOCK_SIZE; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci return n; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int ctr_desall_crypt(struct skcipher_request *req, unsigned long fc) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 3218c2ecf20Sopenharmony_ci struct s390_des_ctx *ctx = crypto_skcipher_ctx(tfm); 3228c2ecf20Sopenharmony_ci u8 buf[DES_BLOCK_SIZE], *ctrptr; 3238c2ecf20Sopenharmony_ci struct skcipher_walk walk; 3248c2ecf20Sopenharmony_ci unsigned int n, nbytes; 3258c2ecf20Sopenharmony_ci int ret, locked; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci locked = mutex_trylock(&ctrblk_lock); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 3308c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) >= DES_BLOCK_SIZE) { 3318c2ecf20Sopenharmony_ci n = DES_BLOCK_SIZE; 3328c2ecf20Sopenharmony_ci if (nbytes >= 2*DES_BLOCK_SIZE && locked) 3338c2ecf20Sopenharmony_ci n = __ctrblk_init(ctrblk, walk.iv, nbytes); 3348c2ecf20Sopenharmony_ci ctrptr = (n > DES_BLOCK_SIZE) ? ctrblk : walk.iv; 3358c2ecf20Sopenharmony_ci cpacf_kmctr(fc, ctx->key, walk.dst.virt.addr, 3368c2ecf20Sopenharmony_ci walk.src.virt.addr, n, ctrptr); 3378c2ecf20Sopenharmony_ci if (ctrptr == ctrblk) 3388c2ecf20Sopenharmony_ci memcpy(walk.iv, ctrptr + n - DES_BLOCK_SIZE, 3398c2ecf20Sopenharmony_ci DES_BLOCK_SIZE); 3408c2ecf20Sopenharmony_ci crypto_inc(walk.iv, DES_BLOCK_SIZE); 3418c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes - n); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci if (locked) 3448c2ecf20Sopenharmony_ci mutex_unlock(&ctrblk_lock); 3458c2ecf20Sopenharmony_ci /* final block may be < DES_BLOCK_SIZE, copy only nbytes */ 3468c2ecf20Sopenharmony_ci if (nbytes) { 3478c2ecf20Sopenharmony_ci cpacf_kmctr(fc, ctx->key, buf, walk.src.virt.addr, 3488c2ecf20Sopenharmony_ci DES_BLOCK_SIZE, walk.iv); 3498c2ecf20Sopenharmony_ci memcpy(walk.dst.virt.addr, buf, nbytes); 3508c2ecf20Sopenharmony_ci crypto_inc(walk.iv, DES_BLOCK_SIZE); 3518c2ecf20Sopenharmony_ci ret = skcipher_walk_done(&walk, 0); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci return ret; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic int ctr_des_crypt(struct skcipher_request *req) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci return ctr_desall_crypt(req, CPACF_KMCTR_DEA); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic struct skcipher_alg ctr_des_alg = { 3628c2ecf20Sopenharmony_ci .base.cra_name = "ctr(des)", 3638c2ecf20Sopenharmony_ci .base.cra_driver_name = "ctr-des-s390", 3648c2ecf20Sopenharmony_ci .base.cra_priority = 400, /* combo: des + ctr */ 3658c2ecf20Sopenharmony_ci .base.cra_blocksize = 1, 3668c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_des_ctx), 3678c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 3688c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 3698c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 3708c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 3718c2ecf20Sopenharmony_ci .setkey = des_setkey_skcipher, 3728c2ecf20Sopenharmony_ci .encrypt = ctr_des_crypt, 3738c2ecf20Sopenharmony_ci .decrypt = ctr_des_crypt, 3748c2ecf20Sopenharmony_ci .chunksize = DES_BLOCK_SIZE, 3758c2ecf20Sopenharmony_ci}; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int ctr_des3_crypt(struct skcipher_request *req) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci return ctr_desall_crypt(req, CPACF_KMCTR_TDEA_192); 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic struct skcipher_alg ctr_des3_alg = { 3838c2ecf20Sopenharmony_ci .base.cra_name = "ctr(des3_ede)", 3848c2ecf20Sopenharmony_ci .base.cra_driver_name = "ctr-des3_ede-s390", 3858c2ecf20Sopenharmony_ci .base.cra_priority = 400, /* combo: des3 + ede */ 3868c2ecf20Sopenharmony_ci .base.cra_blocksize = 1, 3878c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s390_des_ctx), 3888c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 3898c2ecf20Sopenharmony_ci .min_keysize = DES3_KEY_SIZE, 3908c2ecf20Sopenharmony_ci .max_keysize = DES3_KEY_SIZE, 3918c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 3928c2ecf20Sopenharmony_ci .setkey = des3_setkey_skcipher, 3938c2ecf20Sopenharmony_ci .encrypt = ctr_des3_crypt, 3948c2ecf20Sopenharmony_ci .decrypt = ctr_des3_crypt, 3958c2ecf20Sopenharmony_ci .chunksize = DES_BLOCK_SIZE, 3968c2ecf20Sopenharmony_ci}; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic struct crypto_alg *des_s390_algs_ptr[2]; 3998c2ecf20Sopenharmony_cistatic int des_s390_algs_num; 4008c2ecf20Sopenharmony_cistatic struct skcipher_alg *des_s390_skciphers_ptr[6]; 4018c2ecf20Sopenharmony_cistatic int des_s390_skciphers_num; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int des_s390_register_alg(struct crypto_alg *alg) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci int ret; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci ret = crypto_register_alg(alg); 4088c2ecf20Sopenharmony_ci if (!ret) 4098c2ecf20Sopenharmony_ci des_s390_algs_ptr[des_s390_algs_num++] = alg; 4108c2ecf20Sopenharmony_ci return ret; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic int des_s390_register_skcipher(struct skcipher_alg *alg) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci int ret; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci ret = crypto_register_skcipher(alg); 4188c2ecf20Sopenharmony_ci if (!ret) 4198c2ecf20Sopenharmony_ci des_s390_skciphers_ptr[des_s390_skciphers_num++] = alg; 4208c2ecf20Sopenharmony_ci return ret; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic void des_s390_exit(void) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci while (des_s390_algs_num--) 4268c2ecf20Sopenharmony_ci crypto_unregister_alg(des_s390_algs_ptr[des_s390_algs_num]); 4278c2ecf20Sopenharmony_ci while (des_s390_skciphers_num--) 4288c2ecf20Sopenharmony_ci crypto_unregister_skcipher(des_s390_skciphers_ptr[des_s390_skciphers_num]); 4298c2ecf20Sopenharmony_ci if (ctrblk) 4308c2ecf20Sopenharmony_ci free_page((unsigned long) ctrblk); 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int __init des_s390_init(void) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci int ret; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* Query available functions for KM, KMC and KMCTR */ 4388c2ecf20Sopenharmony_ci cpacf_query(CPACF_KM, &km_functions); 4398c2ecf20Sopenharmony_ci cpacf_query(CPACF_KMC, &kmc_functions); 4408c2ecf20Sopenharmony_ci cpacf_query(CPACF_KMCTR, &kmctr_functions); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (cpacf_test_func(&km_functions, CPACF_KM_DEA)) { 4438c2ecf20Sopenharmony_ci ret = des_s390_register_alg(&des_alg); 4448c2ecf20Sopenharmony_ci if (ret) 4458c2ecf20Sopenharmony_ci goto out_err; 4468c2ecf20Sopenharmony_ci ret = des_s390_register_skcipher(&ecb_des_alg); 4478c2ecf20Sopenharmony_ci if (ret) 4488c2ecf20Sopenharmony_ci goto out_err; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci if (cpacf_test_func(&kmc_functions, CPACF_KMC_DEA)) { 4518c2ecf20Sopenharmony_ci ret = des_s390_register_skcipher(&cbc_des_alg); 4528c2ecf20Sopenharmony_ci if (ret) 4538c2ecf20Sopenharmony_ci goto out_err; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci if (cpacf_test_func(&km_functions, CPACF_KM_TDEA_192)) { 4568c2ecf20Sopenharmony_ci ret = des_s390_register_alg(&des3_alg); 4578c2ecf20Sopenharmony_ci if (ret) 4588c2ecf20Sopenharmony_ci goto out_err; 4598c2ecf20Sopenharmony_ci ret = des_s390_register_skcipher(&ecb_des3_alg); 4608c2ecf20Sopenharmony_ci if (ret) 4618c2ecf20Sopenharmony_ci goto out_err; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci if (cpacf_test_func(&kmc_functions, CPACF_KMC_TDEA_192)) { 4648c2ecf20Sopenharmony_ci ret = des_s390_register_skcipher(&cbc_des3_alg); 4658c2ecf20Sopenharmony_ci if (ret) 4668c2ecf20Sopenharmony_ci goto out_err; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_DEA) || 4708c2ecf20Sopenharmony_ci cpacf_test_func(&kmctr_functions, CPACF_KMCTR_TDEA_192)) { 4718c2ecf20Sopenharmony_ci ctrblk = (u8 *) __get_free_page(GFP_KERNEL); 4728c2ecf20Sopenharmony_ci if (!ctrblk) { 4738c2ecf20Sopenharmony_ci ret = -ENOMEM; 4748c2ecf20Sopenharmony_ci goto out_err; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_DEA)) { 4798c2ecf20Sopenharmony_ci ret = des_s390_register_skcipher(&ctr_des_alg); 4808c2ecf20Sopenharmony_ci if (ret) 4818c2ecf20Sopenharmony_ci goto out_err; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_TDEA_192)) { 4848c2ecf20Sopenharmony_ci ret = des_s390_register_skcipher(&ctr_des3_alg); 4858c2ecf20Sopenharmony_ci if (ret) 4868c2ecf20Sopenharmony_ci goto out_err; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return 0; 4908c2ecf20Sopenharmony_ciout_err: 4918c2ecf20Sopenharmony_ci des_s390_exit(); 4928c2ecf20Sopenharmony_ci return ret; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cimodule_cpu_feature_match(MSA, des_s390_init); 4968c2ecf20Sopenharmony_cimodule_exit(des_s390_exit); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("des"); 4998c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("des3_ede"); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 5028c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); 503