xref: /openbmc/linux/arch/x86/crypto/des3_ede_glue.c (revision 6574e6c64e971c9adb629e81e497afdb52b1c9df)
1*6574e6c6SJussi Kivilinna /*
2*6574e6c6SJussi Kivilinna  * Glue Code for assembler optimized version of 3DES
3*6574e6c6SJussi Kivilinna  *
4*6574e6c6SJussi Kivilinna  * Copyright © 2014 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
5*6574e6c6SJussi Kivilinna  *
6*6574e6c6SJussi Kivilinna  * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
7*6574e6c6SJussi Kivilinna  *   Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
8*6574e6c6SJussi Kivilinna  * CTR part based on code (crypto/ctr.c) by:
9*6574e6c6SJussi Kivilinna  *   (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
10*6574e6c6SJussi Kivilinna  *
11*6574e6c6SJussi Kivilinna  * This program is free software; you can redistribute it and/or modify
12*6574e6c6SJussi Kivilinna  * it under the terms of the GNU General Public License as published by
13*6574e6c6SJussi Kivilinna  * the Free Software Foundation; either version 2 of the License, or
14*6574e6c6SJussi Kivilinna  * (at your option) any later version.
15*6574e6c6SJussi Kivilinna  *
16*6574e6c6SJussi Kivilinna  * This program is distributed in the hope that it will be useful,
17*6574e6c6SJussi Kivilinna  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18*6574e6c6SJussi Kivilinna  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19*6574e6c6SJussi Kivilinna  * GNU General Public License for more details.
20*6574e6c6SJussi Kivilinna  *
21*6574e6c6SJussi Kivilinna  */
22*6574e6c6SJussi Kivilinna 
23*6574e6c6SJussi Kivilinna #include <asm/processor.h>
24*6574e6c6SJussi Kivilinna #include <crypto/des.h>
25*6574e6c6SJussi Kivilinna #include <linux/crypto.h>
26*6574e6c6SJussi Kivilinna #include <linux/init.h>
27*6574e6c6SJussi Kivilinna #include <linux/module.h>
28*6574e6c6SJussi Kivilinna #include <linux/types.h>
29*6574e6c6SJussi Kivilinna #include <crypto/algapi.h>
30*6574e6c6SJussi Kivilinna 
31*6574e6c6SJussi Kivilinna struct des3_ede_x86_ctx {
32*6574e6c6SJussi Kivilinna 	u32 enc_expkey[DES3_EDE_EXPKEY_WORDS];
33*6574e6c6SJussi Kivilinna 	u32 dec_expkey[DES3_EDE_EXPKEY_WORDS];
34*6574e6c6SJussi Kivilinna };
35*6574e6c6SJussi Kivilinna 
36*6574e6c6SJussi Kivilinna /* regular block cipher functions */
37*6574e6c6SJussi Kivilinna asmlinkage void des3_ede_x86_64_crypt_blk(const u32 *expkey, u8 *dst,
38*6574e6c6SJussi Kivilinna 					  const u8 *src);
39*6574e6c6SJussi Kivilinna 
40*6574e6c6SJussi Kivilinna /* 3-way parallel cipher functions */
41*6574e6c6SJussi Kivilinna asmlinkage void des3_ede_x86_64_crypt_blk_3way(const u32 *expkey, u8 *dst,
42*6574e6c6SJussi Kivilinna 					       const u8 *src);
43*6574e6c6SJussi Kivilinna 
44*6574e6c6SJussi Kivilinna static inline void des3_ede_enc_blk(struct des3_ede_x86_ctx *ctx, u8 *dst,
45*6574e6c6SJussi Kivilinna 				    const u8 *src)
46*6574e6c6SJussi Kivilinna {
47*6574e6c6SJussi Kivilinna 	u32 *enc_ctx = ctx->enc_expkey;
48*6574e6c6SJussi Kivilinna 
49*6574e6c6SJussi Kivilinna 	des3_ede_x86_64_crypt_blk(enc_ctx, dst, src);
50*6574e6c6SJussi Kivilinna }
51*6574e6c6SJussi Kivilinna 
52*6574e6c6SJussi Kivilinna static inline void des3_ede_dec_blk(struct des3_ede_x86_ctx *ctx, u8 *dst,
53*6574e6c6SJussi Kivilinna 				    const u8 *src)
54*6574e6c6SJussi Kivilinna {
55*6574e6c6SJussi Kivilinna 	u32 *dec_ctx = ctx->dec_expkey;
56*6574e6c6SJussi Kivilinna 
57*6574e6c6SJussi Kivilinna 	des3_ede_x86_64_crypt_blk(dec_ctx, dst, src);
58*6574e6c6SJussi Kivilinna }
59*6574e6c6SJussi Kivilinna 
60*6574e6c6SJussi Kivilinna static inline void des3_ede_enc_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst,
61*6574e6c6SJussi Kivilinna 					 const u8 *src)
62*6574e6c6SJussi Kivilinna {
63*6574e6c6SJussi Kivilinna 	u32 *enc_ctx = ctx->enc_expkey;
64*6574e6c6SJussi Kivilinna 
65*6574e6c6SJussi Kivilinna 	des3_ede_x86_64_crypt_blk_3way(enc_ctx, dst, src);
66*6574e6c6SJussi Kivilinna }
67*6574e6c6SJussi Kivilinna 
68*6574e6c6SJussi Kivilinna static inline void des3_ede_dec_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst,
69*6574e6c6SJussi Kivilinna 					 const u8 *src)
70*6574e6c6SJussi Kivilinna {
71*6574e6c6SJussi Kivilinna 	u32 *dec_ctx = ctx->dec_expkey;
72*6574e6c6SJussi Kivilinna 
73*6574e6c6SJussi Kivilinna 	des3_ede_x86_64_crypt_blk_3way(dec_ctx, dst, src);
74*6574e6c6SJussi Kivilinna }
75*6574e6c6SJussi Kivilinna 
76*6574e6c6SJussi Kivilinna static void des3_ede_x86_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
77*6574e6c6SJussi Kivilinna {
78*6574e6c6SJussi Kivilinna 	des3_ede_enc_blk(crypto_tfm_ctx(tfm), dst, src);
79*6574e6c6SJussi Kivilinna }
80*6574e6c6SJussi Kivilinna 
81*6574e6c6SJussi Kivilinna static void des3_ede_x86_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
82*6574e6c6SJussi Kivilinna {
83*6574e6c6SJussi Kivilinna 	des3_ede_dec_blk(crypto_tfm_ctx(tfm), dst, src);
84*6574e6c6SJussi Kivilinna }
85*6574e6c6SJussi Kivilinna 
86*6574e6c6SJussi Kivilinna static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
87*6574e6c6SJussi Kivilinna 		     const u32 *expkey)
88*6574e6c6SJussi Kivilinna {
89*6574e6c6SJussi Kivilinna 	unsigned int bsize = DES3_EDE_BLOCK_SIZE;
90*6574e6c6SJussi Kivilinna 	unsigned int nbytes;
91*6574e6c6SJussi Kivilinna 	int err;
92*6574e6c6SJussi Kivilinna 
93*6574e6c6SJussi Kivilinna 	err = blkcipher_walk_virt(desc, walk);
94*6574e6c6SJussi Kivilinna 
95*6574e6c6SJussi Kivilinna 	while ((nbytes = walk->nbytes)) {
96*6574e6c6SJussi Kivilinna 		u8 *wsrc = walk->src.virt.addr;
97*6574e6c6SJussi Kivilinna 		u8 *wdst = walk->dst.virt.addr;
98*6574e6c6SJussi Kivilinna 
99*6574e6c6SJussi Kivilinna 		/* Process four block batch */
100*6574e6c6SJussi Kivilinna 		if (nbytes >= bsize * 3) {
101*6574e6c6SJussi Kivilinna 			do {
102*6574e6c6SJussi Kivilinna 				des3_ede_x86_64_crypt_blk_3way(expkey, wdst,
103*6574e6c6SJussi Kivilinna 							       wsrc);
104*6574e6c6SJussi Kivilinna 
105*6574e6c6SJussi Kivilinna 				wsrc += bsize * 3;
106*6574e6c6SJussi Kivilinna 				wdst += bsize * 3;
107*6574e6c6SJussi Kivilinna 				nbytes -= bsize * 3;
108*6574e6c6SJussi Kivilinna 			} while (nbytes >= bsize * 3);
109*6574e6c6SJussi Kivilinna 
110*6574e6c6SJussi Kivilinna 			if (nbytes < bsize)
111*6574e6c6SJussi Kivilinna 				goto done;
112*6574e6c6SJussi Kivilinna 		}
113*6574e6c6SJussi Kivilinna 
114*6574e6c6SJussi Kivilinna 		/* Handle leftovers */
115*6574e6c6SJussi Kivilinna 		do {
116*6574e6c6SJussi Kivilinna 			des3_ede_x86_64_crypt_blk(expkey, wdst, wsrc);
117*6574e6c6SJussi Kivilinna 
118*6574e6c6SJussi Kivilinna 			wsrc += bsize;
119*6574e6c6SJussi Kivilinna 			wdst += bsize;
120*6574e6c6SJussi Kivilinna 			nbytes -= bsize;
121*6574e6c6SJussi Kivilinna 		} while (nbytes >= bsize);
122*6574e6c6SJussi Kivilinna 
123*6574e6c6SJussi Kivilinna done:
124*6574e6c6SJussi Kivilinna 		err = blkcipher_walk_done(desc, walk, nbytes);
125*6574e6c6SJussi Kivilinna 	}
126*6574e6c6SJussi Kivilinna 
127*6574e6c6SJussi Kivilinna 	return err;
128*6574e6c6SJussi Kivilinna }
129*6574e6c6SJussi Kivilinna 
130*6574e6c6SJussi Kivilinna static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
131*6574e6c6SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
132*6574e6c6SJussi Kivilinna {
133*6574e6c6SJussi Kivilinna 	struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
134*6574e6c6SJussi Kivilinna 	struct blkcipher_walk walk;
135*6574e6c6SJussi Kivilinna 
136*6574e6c6SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
137*6574e6c6SJussi Kivilinna 	return ecb_crypt(desc, &walk, ctx->enc_expkey);
138*6574e6c6SJussi Kivilinna }
139*6574e6c6SJussi Kivilinna 
140*6574e6c6SJussi Kivilinna static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
141*6574e6c6SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
142*6574e6c6SJussi Kivilinna {
143*6574e6c6SJussi Kivilinna 	struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
144*6574e6c6SJussi Kivilinna 	struct blkcipher_walk walk;
145*6574e6c6SJussi Kivilinna 
146*6574e6c6SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
147*6574e6c6SJussi Kivilinna 	return ecb_crypt(desc, &walk, ctx->dec_expkey);
148*6574e6c6SJussi Kivilinna }
149*6574e6c6SJussi Kivilinna 
150*6574e6c6SJussi Kivilinna static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
151*6574e6c6SJussi Kivilinna 				  struct blkcipher_walk *walk)
152*6574e6c6SJussi Kivilinna {
153*6574e6c6SJussi Kivilinna 	struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
154*6574e6c6SJussi Kivilinna 	unsigned int bsize = DES3_EDE_BLOCK_SIZE;
155*6574e6c6SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
156*6574e6c6SJussi Kivilinna 	u64 *src = (u64 *)walk->src.virt.addr;
157*6574e6c6SJussi Kivilinna 	u64 *dst = (u64 *)walk->dst.virt.addr;
158*6574e6c6SJussi Kivilinna 	u64 *iv = (u64 *)walk->iv;
159*6574e6c6SJussi Kivilinna 
160*6574e6c6SJussi Kivilinna 	do {
161*6574e6c6SJussi Kivilinna 		*dst = *src ^ *iv;
162*6574e6c6SJussi Kivilinna 		des3_ede_enc_blk(ctx, (u8 *)dst, (u8 *)dst);
163*6574e6c6SJussi Kivilinna 		iv = dst;
164*6574e6c6SJussi Kivilinna 
165*6574e6c6SJussi Kivilinna 		src += 1;
166*6574e6c6SJussi Kivilinna 		dst += 1;
167*6574e6c6SJussi Kivilinna 		nbytes -= bsize;
168*6574e6c6SJussi Kivilinna 	} while (nbytes >= bsize);
169*6574e6c6SJussi Kivilinna 
170*6574e6c6SJussi Kivilinna 	*(u64 *)walk->iv = *iv;
171*6574e6c6SJussi Kivilinna 	return nbytes;
172*6574e6c6SJussi Kivilinna }
173*6574e6c6SJussi Kivilinna 
174*6574e6c6SJussi Kivilinna static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
175*6574e6c6SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
176*6574e6c6SJussi Kivilinna {
177*6574e6c6SJussi Kivilinna 	struct blkcipher_walk walk;
178*6574e6c6SJussi Kivilinna 	int err;
179*6574e6c6SJussi Kivilinna 
180*6574e6c6SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
181*6574e6c6SJussi Kivilinna 	err = blkcipher_walk_virt(desc, &walk);
182*6574e6c6SJussi Kivilinna 
183*6574e6c6SJussi Kivilinna 	while ((nbytes = walk.nbytes)) {
184*6574e6c6SJussi Kivilinna 		nbytes = __cbc_encrypt(desc, &walk);
185*6574e6c6SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, nbytes);
186*6574e6c6SJussi Kivilinna 	}
187*6574e6c6SJussi Kivilinna 
188*6574e6c6SJussi Kivilinna 	return err;
189*6574e6c6SJussi Kivilinna }
190*6574e6c6SJussi Kivilinna 
191*6574e6c6SJussi Kivilinna static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
192*6574e6c6SJussi Kivilinna 				  struct blkcipher_walk *walk)
193*6574e6c6SJussi Kivilinna {
194*6574e6c6SJussi Kivilinna 	struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
195*6574e6c6SJussi Kivilinna 	unsigned int bsize = DES3_EDE_BLOCK_SIZE;
196*6574e6c6SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
197*6574e6c6SJussi Kivilinna 	u64 *src = (u64 *)walk->src.virt.addr;
198*6574e6c6SJussi Kivilinna 	u64 *dst = (u64 *)walk->dst.virt.addr;
199*6574e6c6SJussi Kivilinna 	u64 ivs[3 - 1];
200*6574e6c6SJussi Kivilinna 	u64 last_iv;
201*6574e6c6SJussi Kivilinna 
202*6574e6c6SJussi Kivilinna 	/* Start of the last block. */
203*6574e6c6SJussi Kivilinna 	src += nbytes / bsize - 1;
204*6574e6c6SJussi Kivilinna 	dst += nbytes / bsize - 1;
205*6574e6c6SJussi Kivilinna 
206*6574e6c6SJussi Kivilinna 	last_iv = *src;
207*6574e6c6SJussi Kivilinna 
208*6574e6c6SJussi Kivilinna 	/* Process four block batch */
209*6574e6c6SJussi Kivilinna 	if (nbytes >= bsize * 3) {
210*6574e6c6SJussi Kivilinna 		do {
211*6574e6c6SJussi Kivilinna 			nbytes -= bsize * 3 - bsize;
212*6574e6c6SJussi Kivilinna 			src -= 3 - 1;
213*6574e6c6SJussi Kivilinna 			dst -= 3 - 1;
214*6574e6c6SJussi Kivilinna 
215*6574e6c6SJussi Kivilinna 			ivs[0] = src[0];
216*6574e6c6SJussi Kivilinna 			ivs[1] = src[1];
217*6574e6c6SJussi Kivilinna 
218*6574e6c6SJussi Kivilinna 			des3_ede_dec_blk_3way(ctx, (u8 *)dst, (u8 *)src);
219*6574e6c6SJussi Kivilinna 
220*6574e6c6SJussi Kivilinna 			dst[1] ^= ivs[0];
221*6574e6c6SJussi Kivilinna 			dst[2] ^= ivs[1];
222*6574e6c6SJussi Kivilinna 
223*6574e6c6SJussi Kivilinna 			nbytes -= bsize;
224*6574e6c6SJussi Kivilinna 			if (nbytes < bsize)
225*6574e6c6SJussi Kivilinna 				goto done;
226*6574e6c6SJussi Kivilinna 
227*6574e6c6SJussi Kivilinna 			*dst ^= *(src - 1);
228*6574e6c6SJussi Kivilinna 			src -= 1;
229*6574e6c6SJussi Kivilinna 			dst -= 1;
230*6574e6c6SJussi Kivilinna 		} while (nbytes >= bsize * 3);
231*6574e6c6SJussi Kivilinna 	}
232*6574e6c6SJussi Kivilinna 
233*6574e6c6SJussi Kivilinna 	/* Handle leftovers */
234*6574e6c6SJussi Kivilinna 	for (;;) {
235*6574e6c6SJussi Kivilinna 		des3_ede_dec_blk(ctx, (u8 *)dst, (u8 *)src);
236*6574e6c6SJussi Kivilinna 
237*6574e6c6SJussi Kivilinna 		nbytes -= bsize;
238*6574e6c6SJussi Kivilinna 		if (nbytes < bsize)
239*6574e6c6SJussi Kivilinna 			break;
240*6574e6c6SJussi Kivilinna 
241*6574e6c6SJussi Kivilinna 		*dst ^= *(src - 1);
242*6574e6c6SJussi Kivilinna 		src -= 1;
243*6574e6c6SJussi Kivilinna 		dst -= 1;
244*6574e6c6SJussi Kivilinna 	}
245*6574e6c6SJussi Kivilinna 
246*6574e6c6SJussi Kivilinna done:
247*6574e6c6SJussi Kivilinna 	*dst ^= *(u64 *)walk->iv;
248*6574e6c6SJussi Kivilinna 	*(u64 *)walk->iv = last_iv;
249*6574e6c6SJussi Kivilinna 
250*6574e6c6SJussi Kivilinna 	return nbytes;
251*6574e6c6SJussi Kivilinna }
252*6574e6c6SJussi Kivilinna 
253*6574e6c6SJussi Kivilinna static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
254*6574e6c6SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
255*6574e6c6SJussi Kivilinna {
256*6574e6c6SJussi Kivilinna 	struct blkcipher_walk walk;
257*6574e6c6SJussi Kivilinna 	int err;
258*6574e6c6SJussi Kivilinna 
259*6574e6c6SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
260*6574e6c6SJussi Kivilinna 	err = blkcipher_walk_virt(desc, &walk);
261*6574e6c6SJussi Kivilinna 
262*6574e6c6SJussi Kivilinna 	while ((nbytes = walk.nbytes)) {
263*6574e6c6SJussi Kivilinna 		nbytes = __cbc_decrypt(desc, &walk);
264*6574e6c6SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, nbytes);
265*6574e6c6SJussi Kivilinna 	}
266*6574e6c6SJussi Kivilinna 
267*6574e6c6SJussi Kivilinna 	return err;
268*6574e6c6SJussi Kivilinna }
269*6574e6c6SJussi Kivilinna 
270*6574e6c6SJussi Kivilinna static void ctr_crypt_final(struct des3_ede_x86_ctx *ctx,
271*6574e6c6SJussi Kivilinna 			    struct blkcipher_walk *walk)
272*6574e6c6SJussi Kivilinna {
273*6574e6c6SJussi Kivilinna 	u8 *ctrblk = walk->iv;
274*6574e6c6SJussi Kivilinna 	u8 keystream[DES3_EDE_BLOCK_SIZE];
275*6574e6c6SJussi Kivilinna 	u8 *src = walk->src.virt.addr;
276*6574e6c6SJussi Kivilinna 	u8 *dst = walk->dst.virt.addr;
277*6574e6c6SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
278*6574e6c6SJussi Kivilinna 
279*6574e6c6SJussi Kivilinna 	des3_ede_enc_blk(ctx, keystream, ctrblk);
280*6574e6c6SJussi Kivilinna 	crypto_xor(keystream, src, nbytes);
281*6574e6c6SJussi Kivilinna 	memcpy(dst, keystream, nbytes);
282*6574e6c6SJussi Kivilinna 
283*6574e6c6SJussi Kivilinna 	crypto_inc(ctrblk, DES3_EDE_BLOCK_SIZE);
284*6574e6c6SJussi Kivilinna }
285*6574e6c6SJussi Kivilinna 
286*6574e6c6SJussi Kivilinna static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
287*6574e6c6SJussi Kivilinna 				struct blkcipher_walk *walk)
288*6574e6c6SJussi Kivilinna {
289*6574e6c6SJussi Kivilinna 	struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
290*6574e6c6SJussi Kivilinna 	unsigned int bsize = DES3_EDE_BLOCK_SIZE;
291*6574e6c6SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
292*6574e6c6SJussi Kivilinna 	u64 *src = (u64 *)walk->src.virt.addr;
293*6574e6c6SJussi Kivilinna 	u64 *dst = (u64 *)walk->dst.virt.addr;
294*6574e6c6SJussi Kivilinna 	u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv);
295*6574e6c6SJussi Kivilinna 	__be64 ctrblocks[3];
296*6574e6c6SJussi Kivilinna 
297*6574e6c6SJussi Kivilinna 	/* Process four block batch */
298*6574e6c6SJussi Kivilinna 	if (nbytes >= bsize * 3) {
299*6574e6c6SJussi Kivilinna 		do {
300*6574e6c6SJussi Kivilinna 			/* create ctrblks for parallel encrypt */
301*6574e6c6SJussi Kivilinna 			ctrblocks[0] = cpu_to_be64(ctrblk++);
302*6574e6c6SJussi Kivilinna 			ctrblocks[1] = cpu_to_be64(ctrblk++);
303*6574e6c6SJussi Kivilinna 			ctrblocks[2] = cpu_to_be64(ctrblk++);
304*6574e6c6SJussi Kivilinna 
305*6574e6c6SJussi Kivilinna 			des3_ede_enc_blk_3way(ctx, (u8 *)ctrblocks,
306*6574e6c6SJussi Kivilinna 					      (u8 *)ctrblocks);
307*6574e6c6SJussi Kivilinna 
308*6574e6c6SJussi Kivilinna 			dst[0] = src[0] ^ ctrblocks[0];
309*6574e6c6SJussi Kivilinna 			dst[1] = src[1] ^ ctrblocks[1];
310*6574e6c6SJussi Kivilinna 			dst[2] = src[2] ^ ctrblocks[2];
311*6574e6c6SJussi Kivilinna 
312*6574e6c6SJussi Kivilinna 			src += 3;
313*6574e6c6SJussi Kivilinna 			dst += 3;
314*6574e6c6SJussi Kivilinna 		} while ((nbytes -= bsize * 3) >= bsize * 3);
315*6574e6c6SJussi Kivilinna 
316*6574e6c6SJussi Kivilinna 		if (nbytes < bsize)
317*6574e6c6SJussi Kivilinna 			goto done;
318*6574e6c6SJussi Kivilinna 	}
319*6574e6c6SJussi Kivilinna 
320*6574e6c6SJussi Kivilinna 	/* Handle leftovers */
321*6574e6c6SJussi Kivilinna 	do {
322*6574e6c6SJussi Kivilinna 		ctrblocks[0] = cpu_to_be64(ctrblk++);
323*6574e6c6SJussi Kivilinna 
324*6574e6c6SJussi Kivilinna 		des3_ede_enc_blk(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks);
325*6574e6c6SJussi Kivilinna 
326*6574e6c6SJussi Kivilinna 		dst[0] = src[0] ^ ctrblocks[0];
327*6574e6c6SJussi Kivilinna 
328*6574e6c6SJussi Kivilinna 		src += 1;
329*6574e6c6SJussi Kivilinna 		dst += 1;
330*6574e6c6SJussi Kivilinna 	} while ((nbytes -= bsize) >= bsize);
331*6574e6c6SJussi Kivilinna 
332*6574e6c6SJussi Kivilinna done:
333*6574e6c6SJussi Kivilinna 	*(__be64 *)walk->iv = cpu_to_be64(ctrblk);
334*6574e6c6SJussi Kivilinna 	return nbytes;
335*6574e6c6SJussi Kivilinna }
336*6574e6c6SJussi Kivilinna 
337*6574e6c6SJussi Kivilinna static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
338*6574e6c6SJussi Kivilinna 		     struct scatterlist *src, unsigned int nbytes)
339*6574e6c6SJussi Kivilinna {
340*6574e6c6SJussi Kivilinna 	struct blkcipher_walk walk;
341*6574e6c6SJussi Kivilinna 	int err;
342*6574e6c6SJussi Kivilinna 
343*6574e6c6SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
344*6574e6c6SJussi Kivilinna 	err = blkcipher_walk_virt_block(desc, &walk, DES3_EDE_BLOCK_SIZE);
345*6574e6c6SJussi Kivilinna 
346*6574e6c6SJussi Kivilinna 	while ((nbytes = walk.nbytes) >= DES3_EDE_BLOCK_SIZE) {
347*6574e6c6SJussi Kivilinna 		nbytes = __ctr_crypt(desc, &walk);
348*6574e6c6SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, nbytes);
349*6574e6c6SJussi Kivilinna 	}
350*6574e6c6SJussi Kivilinna 
351*6574e6c6SJussi Kivilinna 	if (walk.nbytes) {
352*6574e6c6SJussi Kivilinna 		ctr_crypt_final(crypto_blkcipher_ctx(desc->tfm), &walk);
353*6574e6c6SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, 0);
354*6574e6c6SJussi Kivilinna 	}
355*6574e6c6SJussi Kivilinna 
356*6574e6c6SJussi Kivilinna 	return err;
357*6574e6c6SJussi Kivilinna }
358*6574e6c6SJussi Kivilinna 
359*6574e6c6SJussi Kivilinna static int des3_ede_x86_setkey(struct crypto_tfm *tfm, const u8 *key,
360*6574e6c6SJussi Kivilinna 			       unsigned int keylen)
361*6574e6c6SJussi Kivilinna {
362*6574e6c6SJussi Kivilinna 	struct des3_ede_x86_ctx *ctx = crypto_tfm_ctx(tfm);
363*6574e6c6SJussi Kivilinna 	u32 i, j, tmp;
364*6574e6c6SJussi Kivilinna 	int err;
365*6574e6c6SJussi Kivilinna 
366*6574e6c6SJussi Kivilinna 	/* Generate encryption context using generic implementation. */
367*6574e6c6SJussi Kivilinna 	err = __des3_ede_setkey(ctx->enc_expkey, &tfm->crt_flags, key, keylen);
368*6574e6c6SJussi Kivilinna 	if (err < 0)
369*6574e6c6SJussi Kivilinna 		return err;
370*6574e6c6SJussi Kivilinna 
371*6574e6c6SJussi Kivilinna 	/* Fix encryption context for this implementation and form decryption
372*6574e6c6SJussi Kivilinna 	 * context. */
373*6574e6c6SJussi Kivilinna 	j = DES3_EDE_EXPKEY_WORDS - 2;
374*6574e6c6SJussi Kivilinna 	for (i = 0; i < DES3_EDE_EXPKEY_WORDS; i += 2, j -= 2) {
375*6574e6c6SJussi Kivilinna 		tmp = ror32(ctx->enc_expkey[i + 1], 4);
376*6574e6c6SJussi Kivilinna 		ctx->enc_expkey[i + 1] = tmp;
377*6574e6c6SJussi Kivilinna 
378*6574e6c6SJussi Kivilinna 		ctx->dec_expkey[j + 0] = ctx->enc_expkey[i + 0];
379*6574e6c6SJussi Kivilinna 		ctx->dec_expkey[j + 1] = tmp;
380*6574e6c6SJussi Kivilinna 	}
381*6574e6c6SJussi Kivilinna 
382*6574e6c6SJussi Kivilinna 	return 0;
383*6574e6c6SJussi Kivilinna }
384*6574e6c6SJussi Kivilinna 
385*6574e6c6SJussi Kivilinna static struct crypto_alg des3_ede_algs[4] = { {
386*6574e6c6SJussi Kivilinna 	.cra_name		= "des3_ede",
387*6574e6c6SJussi Kivilinna 	.cra_driver_name	= "des3_ede-asm",
388*6574e6c6SJussi Kivilinna 	.cra_priority		= 200,
389*6574e6c6SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
390*6574e6c6SJussi Kivilinna 	.cra_blocksize		= DES3_EDE_BLOCK_SIZE,
391*6574e6c6SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct des3_ede_x86_ctx),
392*6574e6c6SJussi Kivilinna 	.cra_alignmask		= 0,
393*6574e6c6SJussi Kivilinna 	.cra_module		= THIS_MODULE,
394*6574e6c6SJussi Kivilinna 	.cra_u = {
395*6574e6c6SJussi Kivilinna 		.cipher = {
396*6574e6c6SJussi Kivilinna 			.cia_min_keysize	= DES3_EDE_KEY_SIZE,
397*6574e6c6SJussi Kivilinna 			.cia_max_keysize	= DES3_EDE_KEY_SIZE,
398*6574e6c6SJussi Kivilinna 			.cia_setkey		= des3_ede_x86_setkey,
399*6574e6c6SJussi Kivilinna 			.cia_encrypt		= des3_ede_x86_encrypt,
400*6574e6c6SJussi Kivilinna 			.cia_decrypt		= des3_ede_x86_decrypt,
401*6574e6c6SJussi Kivilinna 		}
402*6574e6c6SJussi Kivilinna 	}
403*6574e6c6SJussi Kivilinna }, {
404*6574e6c6SJussi Kivilinna 	.cra_name		= "ecb(des3_ede)",
405*6574e6c6SJussi Kivilinna 	.cra_driver_name	= "ecb-des3_ede-asm",
406*6574e6c6SJussi Kivilinna 	.cra_priority		= 300,
407*6574e6c6SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
408*6574e6c6SJussi Kivilinna 	.cra_blocksize		= DES3_EDE_BLOCK_SIZE,
409*6574e6c6SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct des3_ede_x86_ctx),
410*6574e6c6SJussi Kivilinna 	.cra_alignmask		= 0,
411*6574e6c6SJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
412*6574e6c6SJussi Kivilinna 	.cra_module		= THIS_MODULE,
413*6574e6c6SJussi Kivilinna 	.cra_u = {
414*6574e6c6SJussi Kivilinna 		.blkcipher = {
415*6574e6c6SJussi Kivilinna 			.min_keysize	= DES3_EDE_KEY_SIZE,
416*6574e6c6SJussi Kivilinna 			.max_keysize	= DES3_EDE_KEY_SIZE,
417*6574e6c6SJussi Kivilinna 			.setkey		= des3_ede_x86_setkey,
418*6574e6c6SJussi Kivilinna 			.encrypt	= ecb_encrypt,
419*6574e6c6SJussi Kivilinna 			.decrypt	= ecb_decrypt,
420*6574e6c6SJussi Kivilinna 		},
421*6574e6c6SJussi Kivilinna 	},
422*6574e6c6SJussi Kivilinna }, {
423*6574e6c6SJussi Kivilinna 	.cra_name		= "cbc(des3_ede)",
424*6574e6c6SJussi Kivilinna 	.cra_driver_name	= "cbc-des3_ede-asm",
425*6574e6c6SJussi Kivilinna 	.cra_priority		= 300,
426*6574e6c6SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
427*6574e6c6SJussi Kivilinna 	.cra_blocksize		= DES3_EDE_BLOCK_SIZE,
428*6574e6c6SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct des3_ede_x86_ctx),
429*6574e6c6SJussi Kivilinna 	.cra_alignmask		= 0,
430*6574e6c6SJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
431*6574e6c6SJussi Kivilinna 	.cra_module		= THIS_MODULE,
432*6574e6c6SJussi Kivilinna 	.cra_u = {
433*6574e6c6SJussi Kivilinna 		.blkcipher = {
434*6574e6c6SJussi Kivilinna 			.min_keysize	= DES3_EDE_KEY_SIZE,
435*6574e6c6SJussi Kivilinna 			.max_keysize	= DES3_EDE_KEY_SIZE,
436*6574e6c6SJussi Kivilinna 			.ivsize		= DES3_EDE_BLOCK_SIZE,
437*6574e6c6SJussi Kivilinna 			.setkey		= des3_ede_x86_setkey,
438*6574e6c6SJussi Kivilinna 			.encrypt	= cbc_encrypt,
439*6574e6c6SJussi Kivilinna 			.decrypt	= cbc_decrypt,
440*6574e6c6SJussi Kivilinna 		},
441*6574e6c6SJussi Kivilinna 	},
442*6574e6c6SJussi Kivilinna }, {
443*6574e6c6SJussi Kivilinna 	.cra_name		= "ctr(des3_ede)",
444*6574e6c6SJussi Kivilinna 	.cra_driver_name	= "ctr-des3_ede-asm",
445*6574e6c6SJussi Kivilinna 	.cra_priority		= 300,
446*6574e6c6SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
447*6574e6c6SJussi Kivilinna 	.cra_blocksize		= 1,
448*6574e6c6SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct des3_ede_x86_ctx),
449*6574e6c6SJussi Kivilinna 	.cra_alignmask		= 0,
450*6574e6c6SJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
451*6574e6c6SJussi Kivilinna 	.cra_module		= THIS_MODULE,
452*6574e6c6SJussi Kivilinna 	.cra_u = {
453*6574e6c6SJussi Kivilinna 		.blkcipher = {
454*6574e6c6SJussi Kivilinna 			.min_keysize	= DES3_EDE_KEY_SIZE,
455*6574e6c6SJussi Kivilinna 			.max_keysize	= DES3_EDE_KEY_SIZE,
456*6574e6c6SJussi Kivilinna 			.ivsize		= DES3_EDE_BLOCK_SIZE,
457*6574e6c6SJussi Kivilinna 			.setkey		= des3_ede_x86_setkey,
458*6574e6c6SJussi Kivilinna 			.encrypt	= ctr_crypt,
459*6574e6c6SJussi Kivilinna 			.decrypt	= ctr_crypt,
460*6574e6c6SJussi Kivilinna 		},
461*6574e6c6SJussi Kivilinna 	},
462*6574e6c6SJussi Kivilinna } };
463*6574e6c6SJussi Kivilinna 
464*6574e6c6SJussi Kivilinna static bool is_blacklisted_cpu(void)
465*6574e6c6SJussi Kivilinna {
466*6574e6c6SJussi Kivilinna 	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
467*6574e6c6SJussi Kivilinna 		return false;
468*6574e6c6SJussi Kivilinna 
469*6574e6c6SJussi Kivilinna 	if (boot_cpu_data.x86 == 0x0f) {
470*6574e6c6SJussi Kivilinna 		/*
471*6574e6c6SJussi Kivilinna 		 * On Pentium 4, des3_ede-x86_64 is slower than generic C
472*6574e6c6SJussi Kivilinna 		 * implementation because use of 64bit rotates (which are really
473*6574e6c6SJussi Kivilinna 		 * slow on P4). Therefore blacklist P4s.
474*6574e6c6SJussi Kivilinna 		 */
475*6574e6c6SJussi Kivilinna 		return true;
476*6574e6c6SJussi Kivilinna 	}
477*6574e6c6SJussi Kivilinna 
478*6574e6c6SJussi Kivilinna 	return false;
479*6574e6c6SJussi Kivilinna }
480*6574e6c6SJussi Kivilinna 
481*6574e6c6SJussi Kivilinna static int force;
482*6574e6c6SJussi Kivilinna module_param(force, int, 0);
483*6574e6c6SJussi Kivilinna MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
484*6574e6c6SJussi Kivilinna 
485*6574e6c6SJussi Kivilinna static int __init des3_ede_x86_init(void)
486*6574e6c6SJussi Kivilinna {
487*6574e6c6SJussi Kivilinna 	if (!force && is_blacklisted_cpu()) {
488*6574e6c6SJussi Kivilinna 		pr_info("des3_ede-x86_64: performance on this CPU would be suboptimal: disabling des3_ede-x86_64.\n");
489*6574e6c6SJussi Kivilinna 		return -ENODEV;
490*6574e6c6SJussi Kivilinna 	}
491*6574e6c6SJussi Kivilinna 
492*6574e6c6SJussi Kivilinna 	return crypto_register_algs(des3_ede_algs, ARRAY_SIZE(des3_ede_algs));
493*6574e6c6SJussi Kivilinna }
494*6574e6c6SJussi Kivilinna 
495*6574e6c6SJussi Kivilinna static void __exit des3_ede_x86_fini(void)
496*6574e6c6SJussi Kivilinna {
497*6574e6c6SJussi Kivilinna 	crypto_unregister_algs(des3_ede_algs, ARRAY_SIZE(des3_ede_algs));
498*6574e6c6SJussi Kivilinna }
499*6574e6c6SJussi Kivilinna 
500*6574e6c6SJussi Kivilinna module_init(des3_ede_x86_init);
501*6574e6c6SJussi Kivilinna module_exit(des3_ede_x86_fini);
502*6574e6c6SJussi Kivilinna 
503*6574e6c6SJussi Kivilinna MODULE_LICENSE("GPL");
504*6574e6c6SJussi Kivilinna MODULE_DESCRIPTION("Triple DES EDE Cipher Algorithm, asm optimized");
505*6574e6c6SJussi Kivilinna MODULE_ALIAS("des3_ede");
506*6574e6c6SJussi Kivilinna MODULE_ALIAS("des3_ede-asm");
507*6574e6c6SJussi Kivilinna MODULE_ALIAS("des");
508*6574e6c6SJussi Kivilinna MODULE_ALIAS("des-asm");
509*6574e6c6SJussi Kivilinna MODULE_AUTHOR("Jussi Kivilinna <jussi.kivilinna@iki.fi>");
510