xref: /openbmc/linux/arch/x86/crypto/des3_ede_glue.c (revision 09c0f03bf8ce9304e0d17131c46690b2c95209f4)
16574e6c6SJussi Kivilinna /*
26574e6c6SJussi Kivilinna  * Glue Code for assembler optimized version of 3DES
36574e6c6SJussi Kivilinna  *
46574e6c6SJussi Kivilinna  * Copyright © 2014 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
56574e6c6SJussi Kivilinna  *
66574e6c6SJussi Kivilinna  * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
76574e6c6SJussi Kivilinna  *   Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
86574e6c6SJussi Kivilinna  * CTR part based on code (crypto/ctr.c) by:
96574e6c6SJussi Kivilinna  *   (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
106574e6c6SJussi Kivilinna  *
116574e6c6SJussi Kivilinna  * This program is free software; you can redistribute it and/or modify
126574e6c6SJussi Kivilinna  * it under the terms of the GNU General Public License as published by
136574e6c6SJussi Kivilinna  * the Free Software Foundation; either version 2 of the License, or
146574e6c6SJussi Kivilinna  * (at your option) any later version.
156574e6c6SJussi Kivilinna  *
166574e6c6SJussi Kivilinna  * This program is distributed in the hope that it will be useful,
176574e6c6SJussi Kivilinna  * but WITHOUT ANY WARRANTY; without even the implied warranty of
186574e6c6SJussi Kivilinna  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
196574e6c6SJussi Kivilinna  * GNU General Public License for more details.
206574e6c6SJussi Kivilinna  *
216574e6c6SJussi Kivilinna  */
226574e6c6SJussi Kivilinna 
23*09c0f03bSEric Biggers #include <crypto/algapi.h>
246574e6c6SJussi Kivilinna #include <crypto/des.h>
25*09c0f03bSEric Biggers #include <crypto/internal/skcipher.h>
266574e6c6SJussi Kivilinna #include <linux/crypto.h>
276574e6c6SJussi Kivilinna #include <linux/init.h>
286574e6c6SJussi Kivilinna #include <linux/module.h>
296574e6c6SJussi Kivilinna #include <linux/types.h>
306574e6c6SJussi Kivilinna 
316574e6c6SJussi Kivilinna struct des3_ede_x86_ctx {
326574e6c6SJussi Kivilinna 	u32 enc_expkey[DES3_EDE_EXPKEY_WORDS];
336574e6c6SJussi Kivilinna 	u32 dec_expkey[DES3_EDE_EXPKEY_WORDS];
346574e6c6SJussi Kivilinna };
356574e6c6SJussi Kivilinna 
366574e6c6SJussi Kivilinna /* regular block cipher functions */
376574e6c6SJussi Kivilinna asmlinkage void des3_ede_x86_64_crypt_blk(const u32 *expkey, u8 *dst,
386574e6c6SJussi Kivilinna 					  const u8 *src);
396574e6c6SJussi Kivilinna 
406574e6c6SJussi Kivilinna /* 3-way parallel cipher functions */
416574e6c6SJussi Kivilinna asmlinkage void des3_ede_x86_64_crypt_blk_3way(const u32 *expkey, u8 *dst,
426574e6c6SJussi Kivilinna 					       const u8 *src);
436574e6c6SJussi Kivilinna 
446574e6c6SJussi Kivilinna static inline void des3_ede_enc_blk(struct des3_ede_x86_ctx *ctx, u8 *dst,
456574e6c6SJussi Kivilinna 				    const u8 *src)
466574e6c6SJussi Kivilinna {
476574e6c6SJussi Kivilinna 	u32 *enc_ctx = ctx->enc_expkey;
486574e6c6SJussi Kivilinna 
496574e6c6SJussi Kivilinna 	des3_ede_x86_64_crypt_blk(enc_ctx, dst, src);
506574e6c6SJussi Kivilinna }
516574e6c6SJussi Kivilinna 
526574e6c6SJussi Kivilinna static inline void des3_ede_dec_blk(struct des3_ede_x86_ctx *ctx, u8 *dst,
536574e6c6SJussi Kivilinna 				    const u8 *src)
546574e6c6SJussi Kivilinna {
556574e6c6SJussi Kivilinna 	u32 *dec_ctx = ctx->dec_expkey;
566574e6c6SJussi Kivilinna 
576574e6c6SJussi Kivilinna 	des3_ede_x86_64_crypt_blk(dec_ctx, dst, src);
586574e6c6SJussi Kivilinna }
596574e6c6SJussi Kivilinna 
606574e6c6SJussi Kivilinna static inline void des3_ede_enc_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst,
616574e6c6SJussi Kivilinna 					 const u8 *src)
626574e6c6SJussi Kivilinna {
636574e6c6SJussi Kivilinna 	u32 *enc_ctx = ctx->enc_expkey;
646574e6c6SJussi Kivilinna 
656574e6c6SJussi Kivilinna 	des3_ede_x86_64_crypt_blk_3way(enc_ctx, dst, src);
666574e6c6SJussi Kivilinna }
676574e6c6SJussi Kivilinna 
686574e6c6SJussi Kivilinna static inline void des3_ede_dec_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst,
696574e6c6SJussi Kivilinna 					 const u8 *src)
706574e6c6SJussi Kivilinna {
716574e6c6SJussi Kivilinna 	u32 *dec_ctx = ctx->dec_expkey;
726574e6c6SJussi Kivilinna 
736574e6c6SJussi Kivilinna 	des3_ede_x86_64_crypt_blk_3way(dec_ctx, dst, src);
746574e6c6SJussi Kivilinna }
756574e6c6SJussi Kivilinna 
766574e6c6SJussi Kivilinna static void des3_ede_x86_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
776574e6c6SJussi Kivilinna {
786574e6c6SJussi Kivilinna 	des3_ede_enc_blk(crypto_tfm_ctx(tfm), dst, src);
796574e6c6SJussi Kivilinna }
806574e6c6SJussi Kivilinna 
816574e6c6SJussi Kivilinna static void des3_ede_x86_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
826574e6c6SJussi Kivilinna {
836574e6c6SJussi Kivilinna 	des3_ede_dec_blk(crypto_tfm_ctx(tfm), dst, src);
846574e6c6SJussi Kivilinna }
856574e6c6SJussi Kivilinna 
86*09c0f03bSEric Biggers static int ecb_crypt(struct skcipher_request *req, const u32 *expkey)
876574e6c6SJussi Kivilinna {
88*09c0f03bSEric Biggers 	const unsigned int bsize = DES3_EDE_BLOCK_SIZE;
89*09c0f03bSEric Biggers 	struct skcipher_walk walk;
906574e6c6SJussi Kivilinna 	unsigned int nbytes;
916574e6c6SJussi Kivilinna 	int err;
926574e6c6SJussi Kivilinna 
93*09c0f03bSEric Biggers 	err = skcipher_walk_virt(&walk, req, false);
946574e6c6SJussi Kivilinna 
95*09c0f03bSEric Biggers 	while ((nbytes = walk.nbytes)) {
96*09c0f03bSEric Biggers 		u8 *wsrc = walk.src.virt.addr;
97*09c0f03bSEric Biggers 		u8 *wdst = walk.dst.virt.addr;
986574e6c6SJussi Kivilinna 
996574e6c6SJussi Kivilinna 		/* Process four block batch */
1006574e6c6SJussi Kivilinna 		if (nbytes >= bsize * 3) {
1016574e6c6SJussi Kivilinna 			do {
1026574e6c6SJussi Kivilinna 				des3_ede_x86_64_crypt_blk_3way(expkey, wdst,
1036574e6c6SJussi Kivilinna 							       wsrc);
1046574e6c6SJussi Kivilinna 
1056574e6c6SJussi Kivilinna 				wsrc += bsize * 3;
1066574e6c6SJussi Kivilinna 				wdst += bsize * 3;
1076574e6c6SJussi Kivilinna 				nbytes -= bsize * 3;
1086574e6c6SJussi Kivilinna 			} while (nbytes >= bsize * 3);
1096574e6c6SJussi Kivilinna 
1106574e6c6SJussi Kivilinna 			if (nbytes < bsize)
1116574e6c6SJussi Kivilinna 				goto done;
1126574e6c6SJussi Kivilinna 		}
1136574e6c6SJussi Kivilinna 
1146574e6c6SJussi Kivilinna 		/* Handle leftovers */
1156574e6c6SJussi Kivilinna 		do {
1166574e6c6SJussi Kivilinna 			des3_ede_x86_64_crypt_blk(expkey, wdst, wsrc);
1176574e6c6SJussi Kivilinna 
1186574e6c6SJussi Kivilinna 			wsrc += bsize;
1196574e6c6SJussi Kivilinna 			wdst += bsize;
1206574e6c6SJussi Kivilinna 			nbytes -= bsize;
1216574e6c6SJussi Kivilinna 		} while (nbytes >= bsize);
1226574e6c6SJussi Kivilinna 
1236574e6c6SJussi Kivilinna done:
124*09c0f03bSEric Biggers 		err = skcipher_walk_done(&walk, nbytes);
1256574e6c6SJussi Kivilinna 	}
1266574e6c6SJussi Kivilinna 
1276574e6c6SJussi Kivilinna 	return err;
1286574e6c6SJussi Kivilinna }
1296574e6c6SJussi Kivilinna 
130*09c0f03bSEric Biggers static int ecb_encrypt(struct skcipher_request *req)
1316574e6c6SJussi Kivilinna {
132*09c0f03bSEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
133*09c0f03bSEric Biggers 	struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
1346574e6c6SJussi Kivilinna 
135*09c0f03bSEric Biggers 	return ecb_crypt(req, ctx->enc_expkey);
1366574e6c6SJussi Kivilinna }
1376574e6c6SJussi Kivilinna 
138*09c0f03bSEric Biggers static int ecb_decrypt(struct skcipher_request *req)
1396574e6c6SJussi Kivilinna {
140*09c0f03bSEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
141*09c0f03bSEric Biggers 	struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
1426574e6c6SJussi Kivilinna 
143*09c0f03bSEric Biggers 	return ecb_crypt(req, ctx->dec_expkey);
1446574e6c6SJussi Kivilinna }
1456574e6c6SJussi Kivilinna 
146*09c0f03bSEric Biggers static unsigned int __cbc_encrypt(struct des3_ede_x86_ctx *ctx,
147*09c0f03bSEric Biggers 				  struct skcipher_walk *walk)
1486574e6c6SJussi Kivilinna {
1496574e6c6SJussi Kivilinna 	unsigned int bsize = DES3_EDE_BLOCK_SIZE;
1506574e6c6SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
1516574e6c6SJussi Kivilinna 	u64 *src = (u64 *)walk->src.virt.addr;
1526574e6c6SJussi Kivilinna 	u64 *dst = (u64 *)walk->dst.virt.addr;
1536574e6c6SJussi Kivilinna 	u64 *iv = (u64 *)walk->iv;
1546574e6c6SJussi Kivilinna 
1556574e6c6SJussi Kivilinna 	do {
1566574e6c6SJussi Kivilinna 		*dst = *src ^ *iv;
1576574e6c6SJussi Kivilinna 		des3_ede_enc_blk(ctx, (u8 *)dst, (u8 *)dst);
1586574e6c6SJussi Kivilinna 		iv = dst;
1596574e6c6SJussi Kivilinna 
1606574e6c6SJussi Kivilinna 		src += 1;
1616574e6c6SJussi Kivilinna 		dst += 1;
1626574e6c6SJussi Kivilinna 		nbytes -= bsize;
1636574e6c6SJussi Kivilinna 	} while (nbytes >= bsize);
1646574e6c6SJussi Kivilinna 
1656574e6c6SJussi Kivilinna 	*(u64 *)walk->iv = *iv;
1666574e6c6SJussi Kivilinna 	return nbytes;
1676574e6c6SJussi Kivilinna }
1686574e6c6SJussi Kivilinna 
169*09c0f03bSEric Biggers static int cbc_encrypt(struct skcipher_request *req)
1706574e6c6SJussi Kivilinna {
171*09c0f03bSEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
172*09c0f03bSEric Biggers 	struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
173*09c0f03bSEric Biggers 	struct skcipher_walk walk;
174*09c0f03bSEric Biggers 	unsigned int nbytes;
1756574e6c6SJussi Kivilinna 	int err;
1766574e6c6SJussi Kivilinna 
177*09c0f03bSEric Biggers 	err = skcipher_walk_virt(&walk, req, false);
1786574e6c6SJussi Kivilinna 
1796574e6c6SJussi Kivilinna 	while ((nbytes = walk.nbytes)) {
180*09c0f03bSEric Biggers 		nbytes = __cbc_encrypt(ctx, &walk);
181*09c0f03bSEric Biggers 		err = skcipher_walk_done(&walk, nbytes);
1826574e6c6SJussi Kivilinna 	}
1836574e6c6SJussi Kivilinna 
1846574e6c6SJussi Kivilinna 	return err;
1856574e6c6SJussi Kivilinna }
1866574e6c6SJussi Kivilinna 
187*09c0f03bSEric Biggers static unsigned int __cbc_decrypt(struct des3_ede_x86_ctx *ctx,
188*09c0f03bSEric Biggers 				  struct skcipher_walk *walk)
1896574e6c6SJussi Kivilinna {
1906574e6c6SJussi Kivilinna 	unsigned int bsize = DES3_EDE_BLOCK_SIZE;
1916574e6c6SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
1926574e6c6SJussi Kivilinna 	u64 *src = (u64 *)walk->src.virt.addr;
1936574e6c6SJussi Kivilinna 	u64 *dst = (u64 *)walk->dst.virt.addr;
1946574e6c6SJussi Kivilinna 	u64 ivs[3 - 1];
1956574e6c6SJussi Kivilinna 	u64 last_iv;
1966574e6c6SJussi Kivilinna 
1976574e6c6SJussi Kivilinna 	/* Start of the last block. */
1986574e6c6SJussi Kivilinna 	src += nbytes / bsize - 1;
1996574e6c6SJussi Kivilinna 	dst += nbytes / bsize - 1;
2006574e6c6SJussi Kivilinna 
2016574e6c6SJussi Kivilinna 	last_iv = *src;
2026574e6c6SJussi Kivilinna 
2036574e6c6SJussi Kivilinna 	/* Process four block batch */
2046574e6c6SJussi Kivilinna 	if (nbytes >= bsize * 3) {
2056574e6c6SJussi Kivilinna 		do {
2066574e6c6SJussi Kivilinna 			nbytes -= bsize * 3 - bsize;
2076574e6c6SJussi Kivilinna 			src -= 3 - 1;
2086574e6c6SJussi Kivilinna 			dst -= 3 - 1;
2096574e6c6SJussi Kivilinna 
2106574e6c6SJussi Kivilinna 			ivs[0] = src[0];
2116574e6c6SJussi Kivilinna 			ivs[1] = src[1];
2126574e6c6SJussi Kivilinna 
2136574e6c6SJussi Kivilinna 			des3_ede_dec_blk_3way(ctx, (u8 *)dst, (u8 *)src);
2146574e6c6SJussi Kivilinna 
2156574e6c6SJussi Kivilinna 			dst[1] ^= ivs[0];
2166574e6c6SJussi Kivilinna 			dst[2] ^= ivs[1];
2176574e6c6SJussi Kivilinna 
2186574e6c6SJussi Kivilinna 			nbytes -= bsize;
2196574e6c6SJussi Kivilinna 			if (nbytes < bsize)
2206574e6c6SJussi Kivilinna 				goto done;
2216574e6c6SJussi Kivilinna 
2226574e6c6SJussi Kivilinna 			*dst ^= *(src - 1);
2236574e6c6SJussi Kivilinna 			src -= 1;
2246574e6c6SJussi Kivilinna 			dst -= 1;
2256574e6c6SJussi Kivilinna 		} while (nbytes >= bsize * 3);
2266574e6c6SJussi Kivilinna 	}
2276574e6c6SJussi Kivilinna 
2286574e6c6SJussi Kivilinna 	/* Handle leftovers */
2296574e6c6SJussi Kivilinna 	for (;;) {
2306574e6c6SJussi Kivilinna 		des3_ede_dec_blk(ctx, (u8 *)dst, (u8 *)src);
2316574e6c6SJussi Kivilinna 
2326574e6c6SJussi Kivilinna 		nbytes -= bsize;
2336574e6c6SJussi Kivilinna 		if (nbytes < bsize)
2346574e6c6SJussi Kivilinna 			break;
2356574e6c6SJussi Kivilinna 
2366574e6c6SJussi Kivilinna 		*dst ^= *(src - 1);
2376574e6c6SJussi Kivilinna 		src -= 1;
2386574e6c6SJussi Kivilinna 		dst -= 1;
2396574e6c6SJussi Kivilinna 	}
2406574e6c6SJussi Kivilinna 
2416574e6c6SJussi Kivilinna done:
2426574e6c6SJussi Kivilinna 	*dst ^= *(u64 *)walk->iv;
2436574e6c6SJussi Kivilinna 	*(u64 *)walk->iv = last_iv;
2446574e6c6SJussi Kivilinna 
2456574e6c6SJussi Kivilinna 	return nbytes;
2466574e6c6SJussi Kivilinna }
2476574e6c6SJussi Kivilinna 
248*09c0f03bSEric Biggers static int cbc_decrypt(struct skcipher_request *req)
2496574e6c6SJussi Kivilinna {
250*09c0f03bSEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
251*09c0f03bSEric Biggers 	struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
252*09c0f03bSEric Biggers 	struct skcipher_walk walk;
253*09c0f03bSEric Biggers 	unsigned int nbytes;
2546574e6c6SJussi Kivilinna 	int err;
2556574e6c6SJussi Kivilinna 
256*09c0f03bSEric Biggers 	err = skcipher_walk_virt(&walk, req, false);
2576574e6c6SJussi Kivilinna 
2586574e6c6SJussi Kivilinna 	while ((nbytes = walk.nbytes)) {
259*09c0f03bSEric Biggers 		nbytes = __cbc_decrypt(ctx, &walk);
260*09c0f03bSEric Biggers 		err = skcipher_walk_done(&walk, nbytes);
2616574e6c6SJussi Kivilinna 	}
2626574e6c6SJussi Kivilinna 
2636574e6c6SJussi Kivilinna 	return err;
2646574e6c6SJussi Kivilinna }
2656574e6c6SJussi Kivilinna 
2666574e6c6SJussi Kivilinna static void ctr_crypt_final(struct des3_ede_x86_ctx *ctx,
267*09c0f03bSEric Biggers 			    struct skcipher_walk *walk)
2686574e6c6SJussi Kivilinna {
2696574e6c6SJussi Kivilinna 	u8 *ctrblk = walk->iv;
2706574e6c6SJussi Kivilinna 	u8 keystream[DES3_EDE_BLOCK_SIZE];
2716574e6c6SJussi Kivilinna 	u8 *src = walk->src.virt.addr;
2726574e6c6SJussi Kivilinna 	u8 *dst = walk->dst.virt.addr;
2736574e6c6SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
2746574e6c6SJussi Kivilinna 
2756574e6c6SJussi Kivilinna 	des3_ede_enc_blk(ctx, keystream, ctrblk);
27645fe93dfSArd Biesheuvel 	crypto_xor_cpy(dst, keystream, src, nbytes);
2776574e6c6SJussi Kivilinna 
2786574e6c6SJussi Kivilinna 	crypto_inc(ctrblk, DES3_EDE_BLOCK_SIZE);
2796574e6c6SJussi Kivilinna }
2806574e6c6SJussi Kivilinna 
281*09c0f03bSEric Biggers static unsigned int __ctr_crypt(struct des3_ede_x86_ctx *ctx,
282*09c0f03bSEric Biggers 				struct skcipher_walk *walk)
2836574e6c6SJussi Kivilinna {
2846574e6c6SJussi Kivilinna 	unsigned int bsize = DES3_EDE_BLOCK_SIZE;
2856574e6c6SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
2865e50d43dSJussi Kivilinna 	__be64 *src = (__be64 *)walk->src.virt.addr;
2875e50d43dSJussi Kivilinna 	__be64 *dst = (__be64 *)walk->dst.virt.addr;
2886574e6c6SJussi Kivilinna 	u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv);
2896574e6c6SJussi Kivilinna 	__be64 ctrblocks[3];
2906574e6c6SJussi Kivilinna 
2916574e6c6SJussi Kivilinna 	/* Process four block batch */
2926574e6c6SJussi Kivilinna 	if (nbytes >= bsize * 3) {
2936574e6c6SJussi Kivilinna 		do {
2946574e6c6SJussi Kivilinna 			/* create ctrblks for parallel encrypt */
2956574e6c6SJussi Kivilinna 			ctrblocks[0] = cpu_to_be64(ctrblk++);
2966574e6c6SJussi Kivilinna 			ctrblocks[1] = cpu_to_be64(ctrblk++);
2976574e6c6SJussi Kivilinna 			ctrblocks[2] = cpu_to_be64(ctrblk++);
2986574e6c6SJussi Kivilinna 
2996574e6c6SJussi Kivilinna 			des3_ede_enc_blk_3way(ctx, (u8 *)ctrblocks,
3006574e6c6SJussi Kivilinna 					      (u8 *)ctrblocks);
3016574e6c6SJussi Kivilinna 
3026574e6c6SJussi Kivilinna 			dst[0] = src[0] ^ ctrblocks[0];
3036574e6c6SJussi Kivilinna 			dst[1] = src[1] ^ ctrblocks[1];
3046574e6c6SJussi Kivilinna 			dst[2] = src[2] ^ ctrblocks[2];
3056574e6c6SJussi Kivilinna 
3066574e6c6SJussi Kivilinna 			src += 3;
3076574e6c6SJussi Kivilinna 			dst += 3;
3086574e6c6SJussi Kivilinna 		} while ((nbytes -= bsize * 3) >= bsize * 3);
3096574e6c6SJussi Kivilinna 
3106574e6c6SJussi Kivilinna 		if (nbytes < bsize)
3116574e6c6SJussi Kivilinna 			goto done;
3126574e6c6SJussi Kivilinna 	}
3136574e6c6SJussi Kivilinna 
3146574e6c6SJussi Kivilinna 	/* Handle leftovers */
3156574e6c6SJussi Kivilinna 	do {
3166574e6c6SJussi Kivilinna 		ctrblocks[0] = cpu_to_be64(ctrblk++);
3176574e6c6SJussi Kivilinna 
3186574e6c6SJussi Kivilinna 		des3_ede_enc_blk(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks);
3196574e6c6SJussi Kivilinna 
3206574e6c6SJussi Kivilinna 		dst[0] = src[0] ^ ctrblocks[0];
3216574e6c6SJussi Kivilinna 
3226574e6c6SJussi Kivilinna 		src += 1;
3236574e6c6SJussi Kivilinna 		dst += 1;
3246574e6c6SJussi Kivilinna 	} while ((nbytes -= bsize) >= bsize);
3256574e6c6SJussi Kivilinna 
3266574e6c6SJussi Kivilinna done:
3276574e6c6SJussi Kivilinna 	*(__be64 *)walk->iv = cpu_to_be64(ctrblk);
3286574e6c6SJussi Kivilinna 	return nbytes;
3296574e6c6SJussi Kivilinna }
3306574e6c6SJussi Kivilinna 
331*09c0f03bSEric Biggers static int ctr_crypt(struct skcipher_request *req)
3326574e6c6SJussi Kivilinna {
333*09c0f03bSEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
334*09c0f03bSEric Biggers 	struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
335*09c0f03bSEric Biggers 	struct skcipher_walk walk;
336*09c0f03bSEric Biggers 	unsigned int nbytes;
3376574e6c6SJussi Kivilinna 	int err;
3386574e6c6SJussi Kivilinna 
339*09c0f03bSEric Biggers 	err = skcipher_walk_virt(&walk, req, false);
3406574e6c6SJussi Kivilinna 
3416574e6c6SJussi Kivilinna 	while ((nbytes = walk.nbytes) >= DES3_EDE_BLOCK_SIZE) {
342*09c0f03bSEric Biggers 		nbytes = __ctr_crypt(ctx, &walk);
343*09c0f03bSEric Biggers 		err = skcipher_walk_done(&walk, nbytes);
3446574e6c6SJussi Kivilinna 	}
3456574e6c6SJussi Kivilinna 
346*09c0f03bSEric Biggers 	if (nbytes) {
347*09c0f03bSEric Biggers 		ctr_crypt_final(ctx, &walk);
348*09c0f03bSEric Biggers 		err = skcipher_walk_done(&walk, 0);
3496574e6c6SJussi Kivilinna 	}
3506574e6c6SJussi Kivilinna 
3516574e6c6SJussi Kivilinna 	return err;
3526574e6c6SJussi Kivilinna }
3536574e6c6SJussi Kivilinna 
3546574e6c6SJussi Kivilinna static int des3_ede_x86_setkey(struct crypto_tfm *tfm, const u8 *key,
3556574e6c6SJussi Kivilinna 			       unsigned int keylen)
3566574e6c6SJussi Kivilinna {
3576574e6c6SJussi Kivilinna 	struct des3_ede_x86_ctx *ctx = crypto_tfm_ctx(tfm);
3586574e6c6SJussi Kivilinna 	u32 i, j, tmp;
3596574e6c6SJussi Kivilinna 	int err;
3606574e6c6SJussi Kivilinna 
3616574e6c6SJussi Kivilinna 	/* Generate encryption context using generic implementation. */
3626574e6c6SJussi Kivilinna 	err = __des3_ede_setkey(ctx->enc_expkey, &tfm->crt_flags, key, keylen);
3636574e6c6SJussi Kivilinna 	if (err < 0)
3646574e6c6SJussi Kivilinna 		return err;
3656574e6c6SJussi Kivilinna 
3666574e6c6SJussi Kivilinna 	/* Fix encryption context for this implementation and form decryption
3676574e6c6SJussi Kivilinna 	 * context. */
3686574e6c6SJussi Kivilinna 	j = DES3_EDE_EXPKEY_WORDS - 2;
3696574e6c6SJussi Kivilinna 	for (i = 0; i < DES3_EDE_EXPKEY_WORDS; i += 2, j -= 2) {
3706574e6c6SJussi Kivilinna 		tmp = ror32(ctx->enc_expkey[i + 1], 4);
3716574e6c6SJussi Kivilinna 		ctx->enc_expkey[i + 1] = tmp;
3726574e6c6SJussi Kivilinna 
3736574e6c6SJussi Kivilinna 		ctx->dec_expkey[j + 0] = ctx->enc_expkey[i + 0];
3746574e6c6SJussi Kivilinna 		ctx->dec_expkey[j + 1] = tmp;
3756574e6c6SJussi Kivilinna 	}
3766574e6c6SJussi Kivilinna 
3776574e6c6SJussi Kivilinna 	return 0;
3786574e6c6SJussi Kivilinna }
3796574e6c6SJussi Kivilinna 
380*09c0f03bSEric Biggers static int des3_ede_x86_setkey_skcipher(struct crypto_skcipher *tfm,
381*09c0f03bSEric Biggers 					const u8 *key,
382*09c0f03bSEric Biggers 					unsigned int keylen)
383*09c0f03bSEric Biggers {
384*09c0f03bSEric Biggers 	return des3_ede_x86_setkey(&tfm->base, key, keylen);
385*09c0f03bSEric Biggers }
386*09c0f03bSEric Biggers 
387*09c0f03bSEric Biggers static struct crypto_alg des3_ede_cipher = {
3886574e6c6SJussi Kivilinna 	.cra_name		= "des3_ede",
3896574e6c6SJussi Kivilinna 	.cra_driver_name	= "des3_ede-asm",
3906574e6c6SJussi Kivilinna 	.cra_priority		= 200,
3916574e6c6SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
3926574e6c6SJussi Kivilinna 	.cra_blocksize		= DES3_EDE_BLOCK_SIZE,
3936574e6c6SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct des3_ede_x86_ctx),
3946574e6c6SJussi Kivilinna 	.cra_alignmask		= 0,
3956574e6c6SJussi Kivilinna 	.cra_module		= THIS_MODULE,
3966574e6c6SJussi Kivilinna 	.cra_u = {
3976574e6c6SJussi Kivilinna 		.cipher = {
3986574e6c6SJussi Kivilinna 			.cia_min_keysize	= DES3_EDE_KEY_SIZE,
3996574e6c6SJussi Kivilinna 			.cia_max_keysize	= DES3_EDE_KEY_SIZE,
4006574e6c6SJussi Kivilinna 			.cia_setkey		= des3_ede_x86_setkey,
4016574e6c6SJussi Kivilinna 			.cia_encrypt		= des3_ede_x86_encrypt,
4026574e6c6SJussi Kivilinna 			.cia_decrypt		= des3_ede_x86_decrypt,
4036574e6c6SJussi Kivilinna 		}
4046574e6c6SJussi Kivilinna 	}
405*09c0f03bSEric Biggers };
406*09c0f03bSEric Biggers 
407*09c0f03bSEric Biggers struct skcipher_alg des3_ede_skciphers[] = {
408*09c0f03bSEric Biggers 	{
409*09c0f03bSEric Biggers 		.base.cra_name		= "ecb(des3_ede)",
410*09c0f03bSEric Biggers 		.base.cra_driver_name	= "ecb-des3_ede-asm",
411*09c0f03bSEric Biggers 		.base.cra_priority	= 300,
412*09c0f03bSEric Biggers 		.base.cra_blocksize	= DES3_EDE_BLOCK_SIZE,
413*09c0f03bSEric Biggers 		.base.cra_ctxsize	= sizeof(struct des3_ede_x86_ctx),
414*09c0f03bSEric Biggers 		.base.cra_module	= THIS_MODULE,
4156574e6c6SJussi Kivilinna 		.min_keysize		= DES3_EDE_KEY_SIZE,
4166574e6c6SJussi Kivilinna 		.max_keysize		= DES3_EDE_KEY_SIZE,
417*09c0f03bSEric Biggers 		.setkey			= des3_ede_x86_setkey_skcipher,
4186574e6c6SJussi Kivilinna 		.encrypt		= ecb_encrypt,
4196574e6c6SJussi Kivilinna 		.decrypt		= ecb_decrypt,
4206574e6c6SJussi Kivilinna 	}, {
421*09c0f03bSEric Biggers 		.base.cra_name		= "cbc(des3_ede)",
422*09c0f03bSEric Biggers 		.base.cra_driver_name	= "cbc-des3_ede-asm",
423*09c0f03bSEric Biggers 		.base.cra_priority	= 300,
424*09c0f03bSEric Biggers 		.base.cra_blocksize	= DES3_EDE_BLOCK_SIZE,
425*09c0f03bSEric Biggers 		.base.cra_ctxsize	= sizeof(struct des3_ede_x86_ctx),
426*09c0f03bSEric Biggers 		.base.cra_module	= THIS_MODULE,
4276574e6c6SJussi Kivilinna 		.min_keysize		= DES3_EDE_KEY_SIZE,
4286574e6c6SJussi Kivilinna 		.max_keysize		= DES3_EDE_KEY_SIZE,
4296574e6c6SJussi Kivilinna 		.ivsize			= DES3_EDE_BLOCK_SIZE,
430*09c0f03bSEric Biggers 		.setkey			= des3_ede_x86_setkey_skcipher,
4316574e6c6SJussi Kivilinna 		.encrypt		= cbc_encrypt,
4326574e6c6SJussi Kivilinna 		.decrypt		= cbc_decrypt,
4336574e6c6SJussi Kivilinna 	}, {
434*09c0f03bSEric Biggers 		.base.cra_name		= "ctr(des3_ede)",
435*09c0f03bSEric Biggers 		.base.cra_driver_name	= "ctr-des3_ede-asm",
436*09c0f03bSEric Biggers 		.base.cra_priority	= 300,
437*09c0f03bSEric Biggers 		.base.cra_blocksize	= 1,
438*09c0f03bSEric Biggers 		.base.cra_ctxsize	= sizeof(struct des3_ede_x86_ctx),
439*09c0f03bSEric Biggers 		.base.cra_module	= THIS_MODULE,
4406574e6c6SJussi Kivilinna 		.min_keysize		= DES3_EDE_KEY_SIZE,
4416574e6c6SJussi Kivilinna 		.max_keysize		= DES3_EDE_KEY_SIZE,
4426574e6c6SJussi Kivilinna 		.ivsize			= DES3_EDE_BLOCK_SIZE,
443*09c0f03bSEric Biggers 		.chunksize		= DES3_EDE_BLOCK_SIZE,
444*09c0f03bSEric Biggers 		.setkey			= des3_ede_x86_setkey_skcipher,
4456574e6c6SJussi Kivilinna 		.encrypt		= ctr_crypt,
4466574e6c6SJussi Kivilinna 		.decrypt		= ctr_crypt,
447*09c0f03bSEric Biggers 	}
448*09c0f03bSEric Biggers };
4496574e6c6SJussi Kivilinna 
4506574e6c6SJussi Kivilinna static bool is_blacklisted_cpu(void)
4516574e6c6SJussi Kivilinna {
4526574e6c6SJussi Kivilinna 	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
4536574e6c6SJussi Kivilinna 		return false;
4546574e6c6SJussi Kivilinna 
4556574e6c6SJussi Kivilinna 	if (boot_cpu_data.x86 == 0x0f) {
4566574e6c6SJussi Kivilinna 		/*
4576574e6c6SJussi Kivilinna 		 * On Pentium 4, des3_ede-x86_64 is slower than generic C
4586574e6c6SJussi Kivilinna 		 * implementation because use of 64bit rotates (which are really
4596574e6c6SJussi Kivilinna 		 * slow on P4). Therefore blacklist P4s.
4606574e6c6SJussi Kivilinna 		 */
4616574e6c6SJussi Kivilinna 		return true;
4626574e6c6SJussi Kivilinna 	}
4636574e6c6SJussi Kivilinna 
4646574e6c6SJussi Kivilinna 	return false;
4656574e6c6SJussi Kivilinna }
4666574e6c6SJussi Kivilinna 
4676574e6c6SJussi Kivilinna static int force;
4686574e6c6SJussi Kivilinna module_param(force, int, 0);
4696574e6c6SJussi Kivilinna MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
4706574e6c6SJussi Kivilinna 
4716574e6c6SJussi Kivilinna static int __init des3_ede_x86_init(void)
4726574e6c6SJussi Kivilinna {
473*09c0f03bSEric Biggers 	int err;
474*09c0f03bSEric Biggers 
4756574e6c6SJussi Kivilinna 	if (!force && is_blacklisted_cpu()) {
4766574e6c6SJussi Kivilinna 		pr_info("des3_ede-x86_64: performance on this CPU would be suboptimal: disabling des3_ede-x86_64.\n");
4776574e6c6SJussi Kivilinna 		return -ENODEV;
4786574e6c6SJussi Kivilinna 	}
4796574e6c6SJussi Kivilinna 
480*09c0f03bSEric Biggers 	err = crypto_register_alg(&des3_ede_cipher);
481*09c0f03bSEric Biggers 	if (err)
482*09c0f03bSEric Biggers 		return err;
483*09c0f03bSEric Biggers 
484*09c0f03bSEric Biggers 	err = crypto_register_skciphers(des3_ede_skciphers,
485*09c0f03bSEric Biggers 					ARRAY_SIZE(des3_ede_skciphers));
486*09c0f03bSEric Biggers 	if (err)
487*09c0f03bSEric Biggers 		crypto_unregister_alg(&des3_ede_cipher);
488*09c0f03bSEric Biggers 
489*09c0f03bSEric Biggers 	return err;
4906574e6c6SJussi Kivilinna }
4916574e6c6SJussi Kivilinna 
4926574e6c6SJussi Kivilinna static void __exit des3_ede_x86_fini(void)
4936574e6c6SJussi Kivilinna {
494*09c0f03bSEric Biggers 	crypto_unregister_alg(&des3_ede_cipher);
495*09c0f03bSEric Biggers 	crypto_unregister_skciphers(des3_ede_skciphers,
496*09c0f03bSEric Biggers 				    ARRAY_SIZE(des3_ede_skciphers));
4976574e6c6SJussi Kivilinna }
4986574e6c6SJussi Kivilinna 
4996574e6c6SJussi Kivilinna module_init(des3_ede_x86_init);
5006574e6c6SJussi Kivilinna module_exit(des3_ede_x86_fini);
5016574e6c6SJussi Kivilinna 
5026574e6c6SJussi Kivilinna MODULE_LICENSE("GPL");
5036574e6c6SJussi Kivilinna MODULE_DESCRIPTION("Triple DES EDE Cipher Algorithm, asm optimized");
5045d26a105SKees Cook MODULE_ALIAS_CRYPTO("des3_ede");
5055d26a105SKees Cook MODULE_ALIAS_CRYPTO("des3_ede-asm");
5066574e6c6SJussi Kivilinna MODULE_AUTHOR("Jussi Kivilinna <jussi.kivilinna@iki.fi>");
507