18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Glue Code for assembler optimized version of Blowfish
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2011 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/blowfish.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_ci/* regular block cipher functions */
228c2ecf20Sopenharmony_ciasmlinkage void __blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src,
238c2ecf20Sopenharmony_ci				   bool xor);
248c2ecf20Sopenharmony_ciasmlinkage void blowfish_dec_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* 4-way parallel cipher functions */
278c2ecf20Sopenharmony_ciasmlinkage void __blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst,
288c2ecf20Sopenharmony_ci					const u8 *src, bool xor);
298c2ecf20Sopenharmony_ciasmlinkage void blowfish_dec_blk_4way(struct bf_ctx *ctx, u8 *dst,
308c2ecf20Sopenharmony_ci				      const u8 *src);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic inline void blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	__blowfish_enc_blk(ctx, dst, src, false);
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic inline void blowfish_enc_blk_xor(struct bf_ctx *ctx, u8 *dst,
388c2ecf20Sopenharmony_ci					const u8 *src)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	__blowfish_enc_blk(ctx, dst, src, true);
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic inline void blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst,
448c2ecf20Sopenharmony_ci					 const u8 *src)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	__blowfish_enc_blk_4way(ctx, dst, src, false);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic inline void blowfish_enc_blk_xor_4way(struct bf_ctx *ctx, u8 *dst,
508c2ecf20Sopenharmony_ci				      const u8 *src)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	__blowfish_enc_blk_4way(ctx, dst, src, true);
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic void blowfish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	blowfish_enc_blk(crypto_tfm_ctx(tfm), dst, src);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic void blowfish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	blowfish_dec_blk(crypto_tfm_ctx(tfm), dst, src);
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic int blowfish_setkey_skcipher(struct crypto_skcipher *tfm,
668c2ecf20Sopenharmony_ci				    const u8 *key, unsigned int keylen)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	return blowfish_setkey(&tfm->base, key, keylen);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic int ecb_crypt(struct skcipher_request *req,
728c2ecf20Sopenharmony_ci		     void (*fn)(struct bf_ctx *, u8 *, const u8 *),
738c2ecf20Sopenharmony_ci		     void (*fn_4way)(struct bf_ctx *, u8 *, const u8 *))
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	unsigned int bsize = BF_BLOCK_SIZE;
768c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
778c2ecf20Sopenharmony_ci	struct bf_ctx *ctx = crypto_skcipher_ctx(tfm);
788c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
798c2ecf20Sopenharmony_ci	unsigned int nbytes;
808c2ecf20Sopenharmony_ci	int err;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes)) {
858c2ecf20Sopenharmony_ci		u8 *wsrc = walk.src.virt.addr;
868c2ecf20Sopenharmony_ci		u8 *wdst = walk.dst.virt.addr;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		/* Process four block batch */
898c2ecf20Sopenharmony_ci		if (nbytes >= bsize * 4) {
908c2ecf20Sopenharmony_ci			do {
918c2ecf20Sopenharmony_ci				fn_4way(ctx, wdst, wsrc);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci				wsrc += bsize * 4;
948c2ecf20Sopenharmony_ci				wdst += bsize * 4;
958c2ecf20Sopenharmony_ci				nbytes -= bsize * 4;
968c2ecf20Sopenharmony_ci			} while (nbytes >= bsize * 4);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci			if (nbytes < bsize)
998c2ecf20Sopenharmony_ci				goto done;
1008c2ecf20Sopenharmony_ci		}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci		/* Handle leftovers */
1038c2ecf20Sopenharmony_ci		do {
1048c2ecf20Sopenharmony_ci			fn(ctx, wdst, wsrc);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci			wsrc += bsize;
1078c2ecf20Sopenharmony_ci			wdst += bsize;
1088c2ecf20Sopenharmony_ci			nbytes -= bsize;
1098c2ecf20Sopenharmony_ci		} while (nbytes >= bsize);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cidone:
1128c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	return err;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic int ecb_encrypt(struct skcipher_request *req)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	return ecb_crypt(req, blowfish_enc_blk, blowfish_enc_blk_4way);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic int ecb_decrypt(struct skcipher_request *req)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	return ecb_crypt(req, blowfish_dec_blk, blowfish_dec_blk_4way);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic unsigned int __cbc_encrypt(struct bf_ctx *ctx,
1298c2ecf20Sopenharmony_ci				  struct skcipher_walk *walk)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	unsigned int bsize = BF_BLOCK_SIZE;
1328c2ecf20Sopenharmony_ci	unsigned int nbytes = walk->nbytes;
1338c2ecf20Sopenharmony_ci	u64 *src = (u64 *)walk->src.virt.addr;
1348c2ecf20Sopenharmony_ci	u64 *dst = (u64 *)walk->dst.virt.addr;
1358c2ecf20Sopenharmony_ci	u64 *iv = (u64 *)walk->iv;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	do {
1388c2ecf20Sopenharmony_ci		*dst = *src ^ *iv;
1398c2ecf20Sopenharmony_ci		blowfish_enc_blk(ctx, (u8 *)dst, (u8 *)dst);
1408c2ecf20Sopenharmony_ci		iv = dst;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci		src += 1;
1438c2ecf20Sopenharmony_ci		dst += 1;
1448c2ecf20Sopenharmony_ci		nbytes -= bsize;
1458c2ecf20Sopenharmony_ci	} while (nbytes >= bsize);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	*(u64 *)walk->iv = *iv;
1488c2ecf20Sopenharmony_ci	return nbytes;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic int cbc_encrypt(struct skcipher_request *req)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
1548c2ecf20Sopenharmony_ci	struct bf_ctx *ctx = crypto_skcipher_ctx(tfm);
1558c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
1568c2ecf20Sopenharmony_ci	unsigned int nbytes;
1578c2ecf20Sopenharmony_ci	int err;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes)) {
1628c2ecf20Sopenharmony_ci		nbytes = __cbc_encrypt(ctx, &walk);
1638c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	return err;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic unsigned int __cbc_decrypt(struct bf_ctx *ctx,
1708c2ecf20Sopenharmony_ci				  struct skcipher_walk *walk)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	unsigned int bsize = BF_BLOCK_SIZE;
1738c2ecf20Sopenharmony_ci	unsigned int nbytes = walk->nbytes;
1748c2ecf20Sopenharmony_ci	u64 *src = (u64 *)walk->src.virt.addr;
1758c2ecf20Sopenharmony_ci	u64 *dst = (u64 *)walk->dst.virt.addr;
1768c2ecf20Sopenharmony_ci	u64 ivs[4 - 1];
1778c2ecf20Sopenharmony_ci	u64 last_iv;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	/* Start of the last block. */
1808c2ecf20Sopenharmony_ci	src += nbytes / bsize - 1;
1818c2ecf20Sopenharmony_ci	dst += nbytes / bsize - 1;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	last_iv = *src;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	/* Process four block batch */
1868c2ecf20Sopenharmony_ci	if (nbytes >= bsize * 4) {
1878c2ecf20Sopenharmony_ci		do {
1888c2ecf20Sopenharmony_ci			nbytes -= bsize * 4 - bsize;
1898c2ecf20Sopenharmony_ci			src -= 4 - 1;
1908c2ecf20Sopenharmony_ci			dst -= 4 - 1;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci			ivs[0] = src[0];
1938c2ecf20Sopenharmony_ci			ivs[1] = src[1];
1948c2ecf20Sopenharmony_ci			ivs[2] = src[2];
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci			blowfish_dec_blk_4way(ctx, (u8 *)dst, (u8 *)src);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci			dst[1] ^= ivs[0];
1998c2ecf20Sopenharmony_ci			dst[2] ^= ivs[1];
2008c2ecf20Sopenharmony_ci			dst[3] ^= ivs[2];
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci			nbytes -= bsize;
2038c2ecf20Sopenharmony_ci			if (nbytes < bsize)
2048c2ecf20Sopenharmony_ci				goto done;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci			*dst ^= *(src - 1);
2078c2ecf20Sopenharmony_ci			src -= 1;
2088c2ecf20Sopenharmony_ci			dst -= 1;
2098c2ecf20Sopenharmony_ci		} while (nbytes >= bsize * 4);
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	/* Handle leftovers */
2138c2ecf20Sopenharmony_ci	for (;;) {
2148c2ecf20Sopenharmony_ci		blowfish_dec_blk(ctx, (u8 *)dst, (u8 *)src);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci		nbytes -= bsize;
2178c2ecf20Sopenharmony_ci		if (nbytes < bsize)
2188c2ecf20Sopenharmony_ci			break;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci		*dst ^= *(src - 1);
2218c2ecf20Sopenharmony_ci		src -= 1;
2228c2ecf20Sopenharmony_ci		dst -= 1;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cidone:
2268c2ecf20Sopenharmony_ci	*dst ^= *(u64 *)walk->iv;
2278c2ecf20Sopenharmony_ci	*(u64 *)walk->iv = last_iv;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	return nbytes;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic int cbc_decrypt(struct skcipher_request *req)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
2358c2ecf20Sopenharmony_ci	struct bf_ctx *ctx = crypto_skcipher_ctx(tfm);
2368c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
2378c2ecf20Sopenharmony_ci	unsigned int nbytes;
2388c2ecf20Sopenharmony_ci	int err;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes)) {
2438c2ecf20Sopenharmony_ci		nbytes = __cbc_decrypt(ctx, &walk);
2448c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return err;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic void ctr_crypt_final(struct bf_ctx *ctx, struct skcipher_walk *walk)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	u8 *ctrblk = walk->iv;
2538c2ecf20Sopenharmony_ci	u8 keystream[BF_BLOCK_SIZE];
2548c2ecf20Sopenharmony_ci	u8 *src = walk->src.virt.addr;
2558c2ecf20Sopenharmony_ci	u8 *dst = walk->dst.virt.addr;
2568c2ecf20Sopenharmony_ci	unsigned int nbytes = walk->nbytes;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	blowfish_enc_blk(ctx, keystream, ctrblk);
2598c2ecf20Sopenharmony_ci	crypto_xor_cpy(dst, keystream, src, nbytes);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	crypto_inc(ctrblk, BF_BLOCK_SIZE);
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic unsigned int __ctr_crypt(struct bf_ctx *ctx, struct skcipher_walk *walk)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	unsigned int bsize = BF_BLOCK_SIZE;
2678c2ecf20Sopenharmony_ci	unsigned int nbytes = walk->nbytes;
2688c2ecf20Sopenharmony_ci	u64 *src = (u64 *)walk->src.virt.addr;
2698c2ecf20Sopenharmony_ci	u64 *dst = (u64 *)walk->dst.virt.addr;
2708c2ecf20Sopenharmony_ci	u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv);
2718c2ecf20Sopenharmony_ci	__be64 ctrblocks[4];
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/* Process four block batch */
2748c2ecf20Sopenharmony_ci	if (nbytes >= bsize * 4) {
2758c2ecf20Sopenharmony_ci		do {
2768c2ecf20Sopenharmony_ci			if (dst != src) {
2778c2ecf20Sopenharmony_ci				dst[0] = src[0];
2788c2ecf20Sopenharmony_ci				dst[1] = src[1];
2798c2ecf20Sopenharmony_ci				dst[2] = src[2];
2808c2ecf20Sopenharmony_ci				dst[3] = src[3];
2818c2ecf20Sopenharmony_ci			}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci			/* create ctrblks for parallel encrypt */
2848c2ecf20Sopenharmony_ci			ctrblocks[0] = cpu_to_be64(ctrblk++);
2858c2ecf20Sopenharmony_ci			ctrblocks[1] = cpu_to_be64(ctrblk++);
2868c2ecf20Sopenharmony_ci			ctrblocks[2] = cpu_to_be64(ctrblk++);
2878c2ecf20Sopenharmony_ci			ctrblocks[3] = cpu_to_be64(ctrblk++);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci			blowfish_enc_blk_xor_4way(ctx, (u8 *)dst,
2908c2ecf20Sopenharmony_ci						  (u8 *)ctrblocks);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci			src += 4;
2938c2ecf20Sopenharmony_ci			dst += 4;
2948c2ecf20Sopenharmony_ci		} while ((nbytes -= bsize * 4) >= bsize * 4);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci		if (nbytes < bsize)
2978c2ecf20Sopenharmony_ci			goto done;
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	/* Handle leftovers */
3018c2ecf20Sopenharmony_ci	do {
3028c2ecf20Sopenharmony_ci		if (dst != src)
3038c2ecf20Sopenharmony_ci			*dst = *src;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci		ctrblocks[0] = cpu_to_be64(ctrblk++);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		blowfish_enc_blk_xor(ctx, (u8 *)dst, (u8 *)ctrblocks);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		src += 1;
3108c2ecf20Sopenharmony_ci		dst += 1;
3118c2ecf20Sopenharmony_ci	} while ((nbytes -= bsize) >= bsize);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cidone:
3148c2ecf20Sopenharmony_ci	*(__be64 *)walk->iv = cpu_to_be64(ctrblk);
3158c2ecf20Sopenharmony_ci	return nbytes;
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic int ctr_crypt(struct skcipher_request *req)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
3218c2ecf20Sopenharmony_ci	struct bf_ctx *ctx = crypto_skcipher_ctx(tfm);
3228c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
3238c2ecf20Sopenharmony_ci	unsigned int nbytes;
3248c2ecf20Sopenharmony_ci	int err;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) >= BF_BLOCK_SIZE) {
3298c2ecf20Sopenharmony_ci		nbytes = __ctr_crypt(ctx, &walk);
3308c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (nbytes) {
3348c2ecf20Sopenharmony_ci		ctr_crypt_final(ctx, &walk);
3358c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, 0);
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	return err;
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic struct crypto_alg bf_cipher_alg = {
3428c2ecf20Sopenharmony_ci	.cra_name		= "blowfish",
3438c2ecf20Sopenharmony_ci	.cra_driver_name	= "blowfish-asm",
3448c2ecf20Sopenharmony_ci	.cra_priority		= 200,
3458c2ecf20Sopenharmony_ci	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
3468c2ecf20Sopenharmony_ci	.cra_blocksize		= BF_BLOCK_SIZE,
3478c2ecf20Sopenharmony_ci	.cra_ctxsize		= sizeof(struct bf_ctx),
3488c2ecf20Sopenharmony_ci	.cra_alignmask		= 0,
3498c2ecf20Sopenharmony_ci	.cra_module		= THIS_MODULE,
3508c2ecf20Sopenharmony_ci	.cra_u = {
3518c2ecf20Sopenharmony_ci		.cipher = {
3528c2ecf20Sopenharmony_ci			.cia_min_keysize	= BF_MIN_KEY_SIZE,
3538c2ecf20Sopenharmony_ci			.cia_max_keysize	= BF_MAX_KEY_SIZE,
3548c2ecf20Sopenharmony_ci			.cia_setkey		= blowfish_setkey,
3558c2ecf20Sopenharmony_ci			.cia_encrypt		= blowfish_encrypt,
3568c2ecf20Sopenharmony_ci			.cia_decrypt		= blowfish_decrypt,
3578c2ecf20Sopenharmony_ci		}
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci};
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic struct skcipher_alg bf_skcipher_algs[] = {
3628c2ecf20Sopenharmony_ci	{
3638c2ecf20Sopenharmony_ci		.base.cra_name		= "ecb(blowfish)",
3648c2ecf20Sopenharmony_ci		.base.cra_driver_name	= "ecb-blowfish-asm",
3658c2ecf20Sopenharmony_ci		.base.cra_priority	= 300,
3668c2ecf20Sopenharmony_ci		.base.cra_blocksize	= BF_BLOCK_SIZE,
3678c2ecf20Sopenharmony_ci		.base.cra_ctxsize	= sizeof(struct bf_ctx),
3688c2ecf20Sopenharmony_ci		.base.cra_module	= THIS_MODULE,
3698c2ecf20Sopenharmony_ci		.min_keysize		= BF_MIN_KEY_SIZE,
3708c2ecf20Sopenharmony_ci		.max_keysize		= BF_MAX_KEY_SIZE,
3718c2ecf20Sopenharmony_ci		.setkey			= blowfish_setkey_skcipher,
3728c2ecf20Sopenharmony_ci		.encrypt		= ecb_encrypt,
3738c2ecf20Sopenharmony_ci		.decrypt		= ecb_decrypt,
3748c2ecf20Sopenharmony_ci	}, {
3758c2ecf20Sopenharmony_ci		.base.cra_name		= "cbc(blowfish)",
3768c2ecf20Sopenharmony_ci		.base.cra_driver_name	= "cbc-blowfish-asm",
3778c2ecf20Sopenharmony_ci		.base.cra_priority	= 300,
3788c2ecf20Sopenharmony_ci		.base.cra_blocksize	= BF_BLOCK_SIZE,
3798c2ecf20Sopenharmony_ci		.base.cra_ctxsize	= sizeof(struct bf_ctx),
3808c2ecf20Sopenharmony_ci		.base.cra_module	= THIS_MODULE,
3818c2ecf20Sopenharmony_ci		.min_keysize		= BF_MIN_KEY_SIZE,
3828c2ecf20Sopenharmony_ci		.max_keysize		= BF_MAX_KEY_SIZE,
3838c2ecf20Sopenharmony_ci		.ivsize			= BF_BLOCK_SIZE,
3848c2ecf20Sopenharmony_ci		.setkey			= blowfish_setkey_skcipher,
3858c2ecf20Sopenharmony_ci		.encrypt		= cbc_encrypt,
3868c2ecf20Sopenharmony_ci		.decrypt		= cbc_decrypt,
3878c2ecf20Sopenharmony_ci	}, {
3888c2ecf20Sopenharmony_ci		.base.cra_name		= "ctr(blowfish)",
3898c2ecf20Sopenharmony_ci		.base.cra_driver_name	= "ctr-blowfish-asm",
3908c2ecf20Sopenharmony_ci		.base.cra_priority	= 300,
3918c2ecf20Sopenharmony_ci		.base.cra_blocksize	= 1,
3928c2ecf20Sopenharmony_ci		.base.cra_ctxsize	= sizeof(struct bf_ctx),
3938c2ecf20Sopenharmony_ci		.base.cra_module	= THIS_MODULE,
3948c2ecf20Sopenharmony_ci		.min_keysize		= BF_MIN_KEY_SIZE,
3958c2ecf20Sopenharmony_ci		.max_keysize		= BF_MAX_KEY_SIZE,
3968c2ecf20Sopenharmony_ci		.ivsize			= BF_BLOCK_SIZE,
3978c2ecf20Sopenharmony_ci		.chunksize		= BF_BLOCK_SIZE,
3988c2ecf20Sopenharmony_ci		.setkey			= blowfish_setkey_skcipher,
3998c2ecf20Sopenharmony_ci		.encrypt		= ctr_crypt,
4008c2ecf20Sopenharmony_ci		.decrypt		= ctr_crypt,
4018c2ecf20Sopenharmony_ci	},
4028c2ecf20Sopenharmony_ci};
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic bool is_blacklisted_cpu(void)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
4078c2ecf20Sopenharmony_ci		return false;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	if (boot_cpu_data.x86 == 0x0f) {
4108c2ecf20Sopenharmony_ci		/*
4118c2ecf20Sopenharmony_ci		 * On Pentium 4, blowfish-x86_64 is slower than generic C
4128c2ecf20Sopenharmony_ci		 * implementation because use of 64bit rotates (which are really
4138c2ecf20Sopenharmony_ci		 * slow on P4). Therefore blacklist P4s.
4148c2ecf20Sopenharmony_ci		 */
4158c2ecf20Sopenharmony_ci		return true;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	return false;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic int force;
4228c2ecf20Sopenharmony_cimodule_param(force, int, 0);
4238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic int __init init(void)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	int err;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if (!force && is_blacklisted_cpu()) {
4308c2ecf20Sopenharmony_ci		printk(KERN_INFO
4318c2ecf20Sopenharmony_ci			"blowfish-x86_64: performance on this CPU "
4328c2ecf20Sopenharmony_ci			"would be suboptimal: disabling "
4338c2ecf20Sopenharmony_ci			"blowfish-x86_64.\n");
4348c2ecf20Sopenharmony_ci		return -ENODEV;
4358c2ecf20Sopenharmony_ci	}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	err = crypto_register_alg(&bf_cipher_alg);
4388c2ecf20Sopenharmony_ci	if (err)
4398c2ecf20Sopenharmony_ci		return err;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	err = crypto_register_skciphers(bf_skcipher_algs,
4428c2ecf20Sopenharmony_ci					ARRAY_SIZE(bf_skcipher_algs));
4438c2ecf20Sopenharmony_ci	if (err)
4448c2ecf20Sopenharmony_ci		crypto_unregister_alg(&bf_cipher_alg);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	return err;
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_cistatic void __exit fini(void)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	crypto_unregister_alg(&bf_cipher_alg);
4528c2ecf20Sopenharmony_ci	crypto_unregister_skciphers(bf_skcipher_algs,
4538c2ecf20Sopenharmony_ci				    ARRAY_SIZE(bf_skcipher_algs));
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cimodule_init(init);
4578c2ecf20Sopenharmony_cimodule_exit(fini);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4608c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Blowfish Cipher Algorithm, asm optimized");
4618c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("blowfish");
4628c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("blowfish-asm");
463