18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Glue Code for assembler optimized version of 3DES
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright © 2014 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
88c2ecf20Sopenharmony_ci *   Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
98c2ecf20Sopenharmony_ci * CTR part based on code (crypto/ctr.c) by:
108c2ecf20Sopenharmony_ci *   (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <crypto/algapi.h>
148c2ecf20Sopenharmony_ci#include <crypto/des.h>
158c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h>
168c2ecf20Sopenharmony_ci#include <linux/crypto.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/types.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistruct des3_ede_x86_ctx {
228c2ecf20Sopenharmony_ci	struct des3_ede_ctx enc;
238c2ecf20Sopenharmony_ci	struct des3_ede_ctx dec;
248c2ecf20Sopenharmony_ci};
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* regular block cipher functions */
278c2ecf20Sopenharmony_ciasmlinkage void des3_ede_x86_64_crypt_blk(const u32 *expkey, u8 *dst,
288c2ecf20Sopenharmony_ci					  const u8 *src);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* 3-way parallel cipher functions */
318c2ecf20Sopenharmony_ciasmlinkage void des3_ede_x86_64_crypt_blk_3way(const u32 *expkey, u8 *dst,
328c2ecf20Sopenharmony_ci					       const u8 *src);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic inline void des3_ede_enc_blk(struct des3_ede_x86_ctx *ctx, u8 *dst,
358c2ecf20Sopenharmony_ci				    const u8 *src)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	u32 *enc_ctx = ctx->enc.expkey;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	des3_ede_x86_64_crypt_blk(enc_ctx, dst, src);
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic inline void des3_ede_dec_blk(struct des3_ede_x86_ctx *ctx, u8 *dst,
438c2ecf20Sopenharmony_ci				    const u8 *src)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	u32 *dec_ctx = ctx->dec.expkey;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	des3_ede_x86_64_crypt_blk(dec_ctx, dst, src);
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic inline void des3_ede_enc_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst,
518c2ecf20Sopenharmony_ci					 const u8 *src)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	u32 *enc_ctx = ctx->enc.expkey;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	des3_ede_x86_64_crypt_blk_3way(enc_ctx, dst, src);
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic inline void des3_ede_dec_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst,
598c2ecf20Sopenharmony_ci					 const u8 *src)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	u32 *dec_ctx = ctx->dec.expkey;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	des3_ede_x86_64_crypt_blk_3way(dec_ctx, dst, src);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic void des3_ede_x86_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	des3_ede_enc_blk(crypto_tfm_ctx(tfm), dst, src);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic void des3_ede_x86_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	des3_ede_dec_blk(crypto_tfm_ctx(tfm), dst, src);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic int ecb_crypt(struct skcipher_request *req, const u32 *expkey)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	const unsigned int bsize = DES3_EDE_BLOCK_SIZE;
798c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
808c2ecf20Sopenharmony_ci	unsigned int nbytes;
818c2ecf20Sopenharmony_ci	int err;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes)) {
868c2ecf20Sopenharmony_ci		u8 *wsrc = walk.src.virt.addr;
878c2ecf20Sopenharmony_ci		u8 *wdst = walk.dst.virt.addr;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci		/* Process four block batch */
908c2ecf20Sopenharmony_ci		if (nbytes >= bsize * 3) {
918c2ecf20Sopenharmony_ci			do {
928c2ecf20Sopenharmony_ci				des3_ede_x86_64_crypt_blk_3way(expkey, wdst,
938c2ecf20Sopenharmony_ci							       wsrc);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci				wsrc += bsize * 3;
968c2ecf20Sopenharmony_ci				wdst += bsize * 3;
978c2ecf20Sopenharmony_ci				nbytes -= bsize * 3;
988c2ecf20Sopenharmony_ci			} while (nbytes >= bsize * 3);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci			if (nbytes < bsize)
1018c2ecf20Sopenharmony_ci				goto done;
1028c2ecf20Sopenharmony_ci		}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci		/* Handle leftovers */
1058c2ecf20Sopenharmony_ci		do {
1068c2ecf20Sopenharmony_ci			des3_ede_x86_64_crypt_blk(expkey, wdst, wsrc);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci			wsrc += bsize;
1098c2ecf20Sopenharmony_ci			wdst += bsize;
1108c2ecf20Sopenharmony_ci			nbytes -= bsize;
1118c2ecf20Sopenharmony_ci		} while (nbytes >= bsize);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cidone:
1148c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return err;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int ecb_encrypt(struct skcipher_request *req)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
1238c2ecf20Sopenharmony_ci	struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	return ecb_crypt(req, ctx->enc.expkey);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic int ecb_decrypt(struct skcipher_request *req)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
1318c2ecf20Sopenharmony_ci	struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return ecb_crypt(req, ctx->dec.expkey);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic unsigned int __cbc_encrypt(struct des3_ede_x86_ctx *ctx,
1378c2ecf20Sopenharmony_ci				  struct skcipher_walk *walk)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	unsigned int bsize = DES3_EDE_BLOCK_SIZE;
1408c2ecf20Sopenharmony_ci	unsigned int nbytes = walk->nbytes;
1418c2ecf20Sopenharmony_ci	u64 *src = (u64 *)walk->src.virt.addr;
1428c2ecf20Sopenharmony_ci	u64 *dst = (u64 *)walk->dst.virt.addr;
1438c2ecf20Sopenharmony_ci	u64 *iv = (u64 *)walk->iv;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	do {
1468c2ecf20Sopenharmony_ci		*dst = *src ^ *iv;
1478c2ecf20Sopenharmony_ci		des3_ede_enc_blk(ctx, (u8 *)dst, (u8 *)dst);
1488c2ecf20Sopenharmony_ci		iv = dst;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci		src += 1;
1518c2ecf20Sopenharmony_ci		dst += 1;
1528c2ecf20Sopenharmony_ci		nbytes -= bsize;
1538c2ecf20Sopenharmony_ci	} while (nbytes >= bsize);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	*(u64 *)walk->iv = *iv;
1568c2ecf20Sopenharmony_ci	return nbytes;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic int cbc_encrypt(struct skcipher_request *req)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
1628c2ecf20Sopenharmony_ci	struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
1638c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
1648c2ecf20Sopenharmony_ci	unsigned int nbytes;
1658c2ecf20Sopenharmony_ci	int err;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes)) {
1708c2ecf20Sopenharmony_ci		nbytes = __cbc_encrypt(ctx, &walk);
1718c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	return err;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic unsigned int __cbc_decrypt(struct des3_ede_x86_ctx *ctx,
1788c2ecf20Sopenharmony_ci				  struct skcipher_walk *walk)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	unsigned int bsize = DES3_EDE_BLOCK_SIZE;
1818c2ecf20Sopenharmony_ci	unsigned int nbytes = walk->nbytes;
1828c2ecf20Sopenharmony_ci	u64 *src = (u64 *)walk->src.virt.addr;
1838c2ecf20Sopenharmony_ci	u64 *dst = (u64 *)walk->dst.virt.addr;
1848c2ecf20Sopenharmony_ci	u64 ivs[3 - 1];
1858c2ecf20Sopenharmony_ci	u64 last_iv;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/* Start of the last block. */
1888c2ecf20Sopenharmony_ci	src += nbytes / bsize - 1;
1898c2ecf20Sopenharmony_ci	dst += nbytes / bsize - 1;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	last_iv = *src;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* Process four block batch */
1948c2ecf20Sopenharmony_ci	if (nbytes >= bsize * 3) {
1958c2ecf20Sopenharmony_ci		do {
1968c2ecf20Sopenharmony_ci			nbytes -= bsize * 3 - bsize;
1978c2ecf20Sopenharmony_ci			src -= 3 - 1;
1988c2ecf20Sopenharmony_ci			dst -= 3 - 1;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci			ivs[0] = src[0];
2018c2ecf20Sopenharmony_ci			ivs[1] = src[1];
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci			des3_ede_dec_blk_3way(ctx, (u8 *)dst, (u8 *)src);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci			dst[1] ^= ivs[0];
2068c2ecf20Sopenharmony_ci			dst[2] ^= ivs[1];
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci			nbytes -= bsize;
2098c2ecf20Sopenharmony_ci			if (nbytes < bsize)
2108c2ecf20Sopenharmony_ci				goto done;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci			*dst ^= *(src - 1);
2138c2ecf20Sopenharmony_ci			src -= 1;
2148c2ecf20Sopenharmony_ci			dst -= 1;
2158c2ecf20Sopenharmony_ci		} while (nbytes >= bsize * 3);
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* Handle leftovers */
2198c2ecf20Sopenharmony_ci	for (;;) {
2208c2ecf20Sopenharmony_ci		des3_ede_dec_blk(ctx, (u8 *)dst, (u8 *)src);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		nbytes -= bsize;
2238c2ecf20Sopenharmony_ci		if (nbytes < bsize)
2248c2ecf20Sopenharmony_ci			break;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci		*dst ^= *(src - 1);
2278c2ecf20Sopenharmony_ci		src -= 1;
2288c2ecf20Sopenharmony_ci		dst -= 1;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cidone:
2328c2ecf20Sopenharmony_ci	*dst ^= *(u64 *)walk->iv;
2338c2ecf20Sopenharmony_ci	*(u64 *)walk->iv = last_iv;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	return nbytes;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic int cbc_decrypt(struct skcipher_request *req)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
2418c2ecf20Sopenharmony_ci	struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
2428c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
2438c2ecf20Sopenharmony_ci	unsigned int nbytes;
2448c2ecf20Sopenharmony_ci	int err;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes)) {
2498c2ecf20Sopenharmony_ci		nbytes = __cbc_decrypt(ctx, &walk);
2508c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	return err;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic void ctr_crypt_final(struct des3_ede_x86_ctx *ctx,
2578c2ecf20Sopenharmony_ci			    struct skcipher_walk *walk)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	u8 *ctrblk = walk->iv;
2608c2ecf20Sopenharmony_ci	u8 keystream[DES3_EDE_BLOCK_SIZE];
2618c2ecf20Sopenharmony_ci	u8 *src = walk->src.virt.addr;
2628c2ecf20Sopenharmony_ci	u8 *dst = walk->dst.virt.addr;
2638c2ecf20Sopenharmony_ci	unsigned int nbytes = walk->nbytes;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	des3_ede_enc_blk(ctx, keystream, ctrblk);
2668c2ecf20Sopenharmony_ci	crypto_xor_cpy(dst, keystream, src, nbytes);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	crypto_inc(ctrblk, DES3_EDE_BLOCK_SIZE);
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic unsigned int __ctr_crypt(struct des3_ede_x86_ctx *ctx,
2728c2ecf20Sopenharmony_ci				struct skcipher_walk *walk)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	unsigned int bsize = DES3_EDE_BLOCK_SIZE;
2758c2ecf20Sopenharmony_ci	unsigned int nbytes = walk->nbytes;
2768c2ecf20Sopenharmony_ci	__be64 *src = (__be64 *)walk->src.virt.addr;
2778c2ecf20Sopenharmony_ci	__be64 *dst = (__be64 *)walk->dst.virt.addr;
2788c2ecf20Sopenharmony_ci	u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv);
2798c2ecf20Sopenharmony_ci	__be64 ctrblocks[3];
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	/* Process four block batch */
2828c2ecf20Sopenharmony_ci	if (nbytes >= bsize * 3) {
2838c2ecf20Sopenharmony_ci		do {
2848c2ecf20Sopenharmony_ci			/* create ctrblks for parallel encrypt */
2858c2ecf20Sopenharmony_ci			ctrblocks[0] = cpu_to_be64(ctrblk++);
2868c2ecf20Sopenharmony_ci			ctrblocks[1] = cpu_to_be64(ctrblk++);
2878c2ecf20Sopenharmony_ci			ctrblocks[2] = cpu_to_be64(ctrblk++);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci			des3_ede_enc_blk_3way(ctx, (u8 *)ctrblocks,
2908c2ecf20Sopenharmony_ci					      (u8 *)ctrblocks);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci			dst[0] = src[0] ^ ctrblocks[0];
2938c2ecf20Sopenharmony_ci			dst[1] = src[1] ^ ctrblocks[1];
2948c2ecf20Sopenharmony_ci			dst[2] = src[2] ^ ctrblocks[2];
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci			src += 3;
2978c2ecf20Sopenharmony_ci			dst += 3;
2988c2ecf20Sopenharmony_ci		} while ((nbytes -= bsize * 3) >= bsize * 3);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		if (nbytes < bsize)
3018c2ecf20Sopenharmony_ci			goto done;
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/* Handle leftovers */
3058c2ecf20Sopenharmony_ci	do {
3068c2ecf20Sopenharmony_ci		ctrblocks[0] = cpu_to_be64(ctrblk++);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci		des3_ede_enc_blk(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci		dst[0] = src[0] ^ ctrblocks[0];
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci		src += 1;
3138c2ecf20Sopenharmony_ci		dst += 1;
3148c2ecf20Sopenharmony_ci	} while ((nbytes -= bsize) >= bsize);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cidone:
3178c2ecf20Sopenharmony_ci	*(__be64 *)walk->iv = cpu_to_be64(ctrblk);
3188c2ecf20Sopenharmony_ci	return nbytes;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic int ctr_crypt(struct skcipher_request *req)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
3248c2ecf20Sopenharmony_ci	struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
3258c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
3268c2ecf20Sopenharmony_ci	unsigned int nbytes;
3278c2ecf20Sopenharmony_ci	int err;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) >= DES3_EDE_BLOCK_SIZE) {
3328c2ecf20Sopenharmony_ci		nbytes = __ctr_crypt(ctx, &walk);
3338c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (nbytes) {
3378c2ecf20Sopenharmony_ci		ctr_crypt_final(ctx, &walk);
3388c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, 0);
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	return err;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic int des3_ede_x86_setkey(struct crypto_tfm *tfm, const u8 *key,
3458c2ecf20Sopenharmony_ci			       unsigned int keylen)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	struct des3_ede_x86_ctx *ctx = crypto_tfm_ctx(tfm);
3488c2ecf20Sopenharmony_ci	u32 i, j, tmp;
3498c2ecf20Sopenharmony_ci	int err;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	err = des3_ede_expand_key(&ctx->enc, key, keylen);
3528c2ecf20Sopenharmony_ci	if (err == -ENOKEY) {
3538c2ecf20Sopenharmony_ci		if (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)
3548c2ecf20Sopenharmony_ci			err = -EINVAL;
3558c2ecf20Sopenharmony_ci		else
3568c2ecf20Sopenharmony_ci			err = 0;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (err) {
3608c2ecf20Sopenharmony_ci		memset(ctx, 0, sizeof(*ctx));
3618c2ecf20Sopenharmony_ci		return err;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	/* Fix encryption context for this implementation and form decryption
3658c2ecf20Sopenharmony_ci	 * context. */
3668c2ecf20Sopenharmony_ci	j = DES3_EDE_EXPKEY_WORDS - 2;
3678c2ecf20Sopenharmony_ci	for (i = 0; i < DES3_EDE_EXPKEY_WORDS; i += 2, j -= 2) {
3688c2ecf20Sopenharmony_ci		tmp = ror32(ctx->enc.expkey[i + 1], 4);
3698c2ecf20Sopenharmony_ci		ctx->enc.expkey[i + 1] = tmp;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci		ctx->dec.expkey[j + 0] = ctx->enc.expkey[i + 0];
3728c2ecf20Sopenharmony_ci		ctx->dec.expkey[j + 1] = tmp;
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return 0;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic int des3_ede_x86_setkey_skcipher(struct crypto_skcipher *tfm,
3798c2ecf20Sopenharmony_ci					const u8 *key,
3808c2ecf20Sopenharmony_ci					unsigned int keylen)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	return des3_ede_x86_setkey(&tfm->base, key, keylen);
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic struct crypto_alg des3_ede_cipher = {
3868c2ecf20Sopenharmony_ci	.cra_name		= "des3_ede",
3878c2ecf20Sopenharmony_ci	.cra_driver_name	= "des3_ede-asm",
3888c2ecf20Sopenharmony_ci	.cra_priority		= 200,
3898c2ecf20Sopenharmony_ci	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
3908c2ecf20Sopenharmony_ci	.cra_blocksize		= DES3_EDE_BLOCK_SIZE,
3918c2ecf20Sopenharmony_ci	.cra_ctxsize		= sizeof(struct des3_ede_x86_ctx),
3928c2ecf20Sopenharmony_ci	.cra_alignmask		= 0,
3938c2ecf20Sopenharmony_ci	.cra_module		= THIS_MODULE,
3948c2ecf20Sopenharmony_ci	.cra_u = {
3958c2ecf20Sopenharmony_ci		.cipher = {
3968c2ecf20Sopenharmony_ci			.cia_min_keysize	= DES3_EDE_KEY_SIZE,
3978c2ecf20Sopenharmony_ci			.cia_max_keysize	= DES3_EDE_KEY_SIZE,
3988c2ecf20Sopenharmony_ci			.cia_setkey		= des3_ede_x86_setkey,
3998c2ecf20Sopenharmony_ci			.cia_encrypt		= des3_ede_x86_encrypt,
4008c2ecf20Sopenharmony_ci			.cia_decrypt		= des3_ede_x86_decrypt,
4018c2ecf20Sopenharmony_ci		}
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci};
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic struct skcipher_alg des3_ede_skciphers[] = {
4068c2ecf20Sopenharmony_ci	{
4078c2ecf20Sopenharmony_ci		.base.cra_name		= "ecb(des3_ede)",
4088c2ecf20Sopenharmony_ci		.base.cra_driver_name	= "ecb-des3_ede-asm",
4098c2ecf20Sopenharmony_ci		.base.cra_priority	= 300,
4108c2ecf20Sopenharmony_ci		.base.cra_blocksize	= DES3_EDE_BLOCK_SIZE,
4118c2ecf20Sopenharmony_ci		.base.cra_ctxsize	= sizeof(struct des3_ede_x86_ctx),
4128c2ecf20Sopenharmony_ci		.base.cra_module	= THIS_MODULE,
4138c2ecf20Sopenharmony_ci		.min_keysize		= DES3_EDE_KEY_SIZE,
4148c2ecf20Sopenharmony_ci		.max_keysize		= DES3_EDE_KEY_SIZE,
4158c2ecf20Sopenharmony_ci		.setkey			= des3_ede_x86_setkey_skcipher,
4168c2ecf20Sopenharmony_ci		.encrypt		= ecb_encrypt,
4178c2ecf20Sopenharmony_ci		.decrypt		= ecb_decrypt,
4188c2ecf20Sopenharmony_ci	}, {
4198c2ecf20Sopenharmony_ci		.base.cra_name		= "cbc(des3_ede)",
4208c2ecf20Sopenharmony_ci		.base.cra_driver_name	= "cbc-des3_ede-asm",
4218c2ecf20Sopenharmony_ci		.base.cra_priority	= 300,
4228c2ecf20Sopenharmony_ci		.base.cra_blocksize	= DES3_EDE_BLOCK_SIZE,
4238c2ecf20Sopenharmony_ci		.base.cra_ctxsize	= sizeof(struct des3_ede_x86_ctx),
4248c2ecf20Sopenharmony_ci		.base.cra_module	= THIS_MODULE,
4258c2ecf20Sopenharmony_ci		.min_keysize		= DES3_EDE_KEY_SIZE,
4268c2ecf20Sopenharmony_ci		.max_keysize		= DES3_EDE_KEY_SIZE,
4278c2ecf20Sopenharmony_ci		.ivsize			= DES3_EDE_BLOCK_SIZE,
4288c2ecf20Sopenharmony_ci		.setkey			= des3_ede_x86_setkey_skcipher,
4298c2ecf20Sopenharmony_ci		.encrypt		= cbc_encrypt,
4308c2ecf20Sopenharmony_ci		.decrypt		= cbc_decrypt,
4318c2ecf20Sopenharmony_ci	}, {
4328c2ecf20Sopenharmony_ci		.base.cra_name		= "ctr(des3_ede)",
4338c2ecf20Sopenharmony_ci		.base.cra_driver_name	= "ctr-des3_ede-asm",
4348c2ecf20Sopenharmony_ci		.base.cra_priority	= 300,
4358c2ecf20Sopenharmony_ci		.base.cra_blocksize	= 1,
4368c2ecf20Sopenharmony_ci		.base.cra_ctxsize	= sizeof(struct des3_ede_x86_ctx),
4378c2ecf20Sopenharmony_ci		.base.cra_module	= THIS_MODULE,
4388c2ecf20Sopenharmony_ci		.min_keysize		= DES3_EDE_KEY_SIZE,
4398c2ecf20Sopenharmony_ci		.max_keysize		= DES3_EDE_KEY_SIZE,
4408c2ecf20Sopenharmony_ci		.ivsize			= DES3_EDE_BLOCK_SIZE,
4418c2ecf20Sopenharmony_ci		.chunksize		= DES3_EDE_BLOCK_SIZE,
4428c2ecf20Sopenharmony_ci		.setkey			= des3_ede_x86_setkey_skcipher,
4438c2ecf20Sopenharmony_ci		.encrypt		= ctr_crypt,
4448c2ecf20Sopenharmony_ci		.decrypt		= ctr_crypt,
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci};
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistatic bool is_blacklisted_cpu(void)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
4518c2ecf20Sopenharmony_ci		return false;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (boot_cpu_data.x86 == 0x0f) {
4548c2ecf20Sopenharmony_ci		/*
4558c2ecf20Sopenharmony_ci		 * On Pentium 4, des3_ede-x86_64 is slower than generic C
4568c2ecf20Sopenharmony_ci		 * implementation because use of 64bit rotates (which are really
4578c2ecf20Sopenharmony_ci		 * slow on P4). Therefore blacklist P4s.
4588c2ecf20Sopenharmony_ci		 */
4598c2ecf20Sopenharmony_ci		return true;
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	return false;
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cistatic int force;
4668c2ecf20Sopenharmony_cimodule_param(force, int, 0);
4678c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic int __init des3_ede_x86_init(void)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	int err;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	if (!force && is_blacklisted_cpu()) {
4748c2ecf20Sopenharmony_ci		pr_info("des3_ede-x86_64: performance on this CPU would be suboptimal: disabling des3_ede-x86_64.\n");
4758c2ecf20Sopenharmony_ci		return -ENODEV;
4768c2ecf20Sopenharmony_ci	}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	err = crypto_register_alg(&des3_ede_cipher);
4798c2ecf20Sopenharmony_ci	if (err)
4808c2ecf20Sopenharmony_ci		return err;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	err = crypto_register_skciphers(des3_ede_skciphers,
4838c2ecf20Sopenharmony_ci					ARRAY_SIZE(des3_ede_skciphers));
4848c2ecf20Sopenharmony_ci	if (err)
4858c2ecf20Sopenharmony_ci		crypto_unregister_alg(&des3_ede_cipher);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	return err;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_cistatic void __exit des3_ede_x86_fini(void)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	crypto_unregister_alg(&des3_ede_cipher);
4938c2ecf20Sopenharmony_ci	crypto_unregister_skciphers(des3_ede_skciphers,
4948c2ecf20Sopenharmony_ci				    ARRAY_SIZE(des3_ede_skciphers));
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cimodule_init(des3_ede_x86_init);
4988c2ecf20Sopenharmony_cimodule_exit(des3_ede_x86_fini);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
5018c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Triple DES EDE Cipher Algorithm, asm optimized");
5028c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("des3_ede");
5038c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("des3_ede-asm");
5048c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jussi Kivilinna <jussi.kivilinna@iki.fi>");
505