Blame view

arch/x86/crypto/blowfish_glue.c 10.6 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
2
3
4
  /*
   * Glue Code for assembler optimized version of Blowfish
   *
3d387ef08   Jussi Kivilinna   Revert "crypto: b...
5
   * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
6
   *
a071d06e3   Jussi Kivilinna   crypto: blowfish-...
7
8
9
10
   * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
   *   Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
   * CTR part based on code (crypto/ctr.c) by:
   *   (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
11
   */
c1679171c   Eric Biggers   crypto: x86/blowf...
12
  #include <crypto/algapi.h>
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
13
  #include <crypto/blowfish.h>
c1679171c   Eric Biggers   crypto: x86/blowf...
14
  #include <crypto/internal/skcipher.h>
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
15
16
17
18
  #include <linux/crypto.h>
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/types.h>
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
19
20
21
22
23
24
25
26
27
28
29
  
  /* regular block cipher functions */
  asmlinkage void __blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src,
  				   bool xor);
  asmlinkage void blowfish_dec_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src);
  
  /* 4-way parallel cipher functions */
  asmlinkage void __blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst,
  					const u8 *src, bool xor);
  asmlinkage void blowfish_dec_blk_4way(struct bf_ctx *ctx, u8 *dst,
  				      const u8 *src);
3d387ef08   Jussi Kivilinna   Revert "crypto: b...
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  
  static inline void blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src)
  {
  	__blowfish_enc_blk(ctx, dst, src, false);
  }
  
  static inline void blowfish_enc_blk_xor(struct bf_ctx *ctx, u8 *dst,
  					const u8 *src)
  {
  	__blowfish_enc_blk(ctx, dst, src, true);
  }
  
  static inline void blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst,
  					 const u8 *src)
  {
  	__blowfish_enc_blk_4way(ctx, dst, src, false);
  }
  
  static inline void blowfish_enc_blk_xor_4way(struct bf_ctx *ctx, u8 *dst,
  				      const u8 *src)
  {
  	__blowfish_enc_blk_4way(ctx, dst, src, true);
  }
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
53
54
55
56
57
58
59
60
61
62
  
  static void blowfish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
  {
  	blowfish_enc_blk(crypto_tfm_ctx(tfm), dst, src);
  }
  
  static void blowfish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
  {
  	blowfish_dec_blk(crypto_tfm_ctx(tfm), dst, src);
  }
c1679171c   Eric Biggers   crypto: x86/blowf...
63
64
65
66
67
68
69
  static int blowfish_setkey_skcipher(struct crypto_skcipher *tfm,
  				    const u8 *key, unsigned int keylen)
  {
  	return blowfish_setkey(&tfm->base, key, keylen);
  }
  
  static int ecb_crypt(struct skcipher_request *req,
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
70
71
72
  		     void (*fn)(struct bf_ctx *, u8 *, const u8 *),
  		     void (*fn_4way)(struct bf_ctx *, u8 *, const u8 *))
  {
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
73
  	unsigned int bsize = BF_BLOCK_SIZE;
c1679171c   Eric Biggers   crypto: x86/blowf...
74
75
76
  	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  	struct bf_ctx *ctx = crypto_skcipher_ctx(tfm);
  	struct skcipher_walk walk;
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
77
78
  	unsigned int nbytes;
  	int err;
c1679171c   Eric Biggers   crypto: x86/blowf...
79
  	err = skcipher_walk_virt(&walk, req, false);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
80

c1679171c   Eric Biggers   crypto: x86/blowf...
81
82
83
  	while ((nbytes = walk.nbytes)) {
  		u8 *wsrc = walk.src.virt.addr;
  		u8 *wdst = walk.dst.virt.addr;
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  
  		/* Process four block batch */
  		if (nbytes >= bsize * 4) {
  			do {
  				fn_4way(ctx, wdst, wsrc);
  
  				wsrc += bsize * 4;
  				wdst += bsize * 4;
  				nbytes -= bsize * 4;
  			} while (nbytes >= bsize * 4);
  
  			if (nbytes < bsize)
  				goto done;
  		}
  
  		/* Handle leftovers */
  		do {
  			fn(ctx, wdst, wsrc);
  
  			wsrc += bsize;
  			wdst += bsize;
  			nbytes -= bsize;
  		} while (nbytes >= bsize);
  
  done:
c1679171c   Eric Biggers   crypto: x86/blowf...
109
  		err = skcipher_walk_done(&walk, nbytes);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
110
111
112
113
  	}
  
  	return err;
  }
c1679171c   Eric Biggers   crypto: x86/blowf...
114
  static int ecb_encrypt(struct skcipher_request *req)
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
115
  {
c1679171c   Eric Biggers   crypto: x86/blowf...
116
  	return ecb_crypt(req, blowfish_enc_blk, blowfish_enc_blk_4way);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
117
  }
c1679171c   Eric Biggers   crypto: x86/blowf...
118
  static int ecb_decrypt(struct skcipher_request *req)
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
119
  {
c1679171c   Eric Biggers   crypto: x86/blowf...
120
  	return ecb_crypt(req, blowfish_dec_blk, blowfish_dec_blk_4way);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
121
  }
c1679171c   Eric Biggers   crypto: x86/blowf...
122
123
  static unsigned int __cbc_encrypt(struct bf_ctx *ctx,
  				  struct skcipher_walk *walk)
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
124
  {
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  	unsigned int bsize = BF_BLOCK_SIZE;
  	unsigned int nbytes = walk->nbytes;
  	u64 *src = (u64 *)walk->src.virt.addr;
  	u64 *dst = (u64 *)walk->dst.virt.addr;
  	u64 *iv = (u64 *)walk->iv;
  
  	do {
  		*dst = *src ^ *iv;
  		blowfish_enc_blk(ctx, (u8 *)dst, (u8 *)dst);
  		iv = dst;
  
  		src += 1;
  		dst += 1;
  		nbytes -= bsize;
  	} while (nbytes >= bsize);
  
  	*(u64 *)walk->iv = *iv;
  	return nbytes;
  }
c1679171c   Eric Biggers   crypto: x86/blowf...
144
  static int cbc_encrypt(struct skcipher_request *req)
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
145
  {
c1679171c   Eric Biggers   crypto: x86/blowf...
146
147
148
149
  	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  	struct bf_ctx *ctx = crypto_skcipher_ctx(tfm);
  	struct skcipher_walk walk;
  	unsigned int nbytes;
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
150
  	int err;
c1679171c   Eric Biggers   crypto: x86/blowf...
151
  	err = skcipher_walk_virt(&walk, req, false);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
152
153
  
  	while ((nbytes = walk.nbytes)) {
c1679171c   Eric Biggers   crypto: x86/blowf...
154
155
  		nbytes = __cbc_encrypt(ctx, &walk);
  		err = skcipher_walk_done(&walk, nbytes);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
156
157
158
159
  	}
  
  	return err;
  }
c1679171c   Eric Biggers   crypto: x86/blowf...
160
161
  static unsigned int __cbc_decrypt(struct bf_ctx *ctx,
  				  struct skcipher_walk *walk)
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
162
  {
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  	unsigned int bsize = BF_BLOCK_SIZE;
  	unsigned int nbytes = walk->nbytes;
  	u64 *src = (u64 *)walk->src.virt.addr;
  	u64 *dst = (u64 *)walk->dst.virt.addr;
  	u64 ivs[4 - 1];
  	u64 last_iv;
  
  	/* Start of the last block. */
  	src += nbytes / bsize - 1;
  	dst += nbytes / bsize - 1;
  
  	last_iv = *src;
  
  	/* Process four block batch */
  	if (nbytes >= bsize * 4) {
  		do {
  			nbytes -= bsize * 4 - bsize;
  			src -= 4 - 1;
  			dst -= 4 - 1;
  
  			ivs[0] = src[0];
  			ivs[1] = src[1];
  			ivs[2] = src[2];
  
  			blowfish_dec_blk_4way(ctx, (u8 *)dst, (u8 *)src);
  
  			dst[1] ^= ivs[0];
  			dst[2] ^= ivs[1];
  			dst[3] ^= ivs[2];
  
  			nbytes -= bsize;
  			if (nbytes < bsize)
  				goto done;
  
  			*dst ^= *(src - 1);
  			src -= 1;
  			dst -= 1;
  		} while (nbytes >= bsize * 4);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  	}
  
  	/* Handle leftovers */
  	for (;;) {
  		blowfish_dec_blk(ctx, (u8 *)dst, (u8 *)src);
  
  		nbytes -= bsize;
  		if (nbytes < bsize)
  			break;
  
  		*dst ^= *(src - 1);
  		src -= 1;
  		dst -= 1;
  	}
  
  done:
  	*dst ^= *(u64 *)walk->iv;
  	*(u64 *)walk->iv = last_iv;
  
  	return nbytes;
  }
c1679171c   Eric Biggers   crypto: x86/blowf...
222
  static int cbc_decrypt(struct skcipher_request *req)
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
223
  {
c1679171c   Eric Biggers   crypto: x86/blowf...
224
225
226
227
  	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  	struct bf_ctx *ctx = crypto_skcipher_ctx(tfm);
  	struct skcipher_walk walk;
  	unsigned int nbytes;
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
228
  	int err;
c1679171c   Eric Biggers   crypto: x86/blowf...
229
  	err = skcipher_walk_virt(&walk, req, false);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
230
231
  
  	while ((nbytes = walk.nbytes)) {
c1679171c   Eric Biggers   crypto: x86/blowf...
232
233
  		nbytes = __cbc_decrypt(ctx, &walk);
  		err = skcipher_walk_done(&walk, nbytes);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
234
235
236
237
  	}
  
  	return err;
  }
c1679171c   Eric Biggers   crypto: x86/blowf...
238
  static void ctr_crypt_final(struct bf_ctx *ctx, struct skcipher_walk *walk)
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
239
240
241
242
243
244
245
246
  {
  	u8 *ctrblk = walk->iv;
  	u8 keystream[BF_BLOCK_SIZE];
  	u8 *src = walk->src.virt.addr;
  	u8 *dst = walk->dst.virt.addr;
  	unsigned int nbytes = walk->nbytes;
  
  	blowfish_enc_blk(ctx, keystream, ctrblk);
45fe93dff   Ard Biesheuvel   crypto: algapi - ...
247
  	crypto_xor_cpy(dst, keystream, src, nbytes);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
248
249
250
  
  	crypto_inc(ctrblk, BF_BLOCK_SIZE);
  }
c1679171c   Eric Biggers   crypto: x86/blowf...
251
  static unsigned int __ctr_crypt(struct bf_ctx *ctx, struct skcipher_walk *walk)
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
252
  {
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  	unsigned int bsize = BF_BLOCK_SIZE;
  	unsigned int nbytes = walk->nbytes;
  	u64 *src = (u64 *)walk->src.virt.addr;
  	u64 *dst = (u64 *)walk->dst.virt.addr;
  	u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv);
  	__be64 ctrblocks[4];
  
  	/* Process four block batch */
  	if (nbytes >= bsize * 4) {
  		do {
  			if (dst != src) {
  				dst[0] = src[0];
  				dst[1] = src[1];
  				dst[2] = src[2];
  				dst[3] = src[3];
  			}
  
  			/* create ctrblks for parallel encrypt */
  			ctrblocks[0] = cpu_to_be64(ctrblk++);
  			ctrblocks[1] = cpu_to_be64(ctrblk++);
  			ctrblocks[2] = cpu_to_be64(ctrblk++);
  			ctrblocks[3] = cpu_to_be64(ctrblk++);
  
  			blowfish_enc_blk_xor_4way(ctx, (u8 *)dst,
  						  (u8 *)ctrblocks);
  
  			src += 4;
  			dst += 4;
  		} while ((nbytes -= bsize * 4) >= bsize * 4);
  
  		if (nbytes < bsize)
  			goto done;
  	}
  
  	/* Handle leftovers */
  	do {
  		if (dst != src)
  			*dst = *src;
  
  		ctrblocks[0] = cpu_to_be64(ctrblk++);
  
  		blowfish_enc_blk_xor(ctx, (u8 *)dst, (u8 *)ctrblocks);
  
  		src += 1;
  		dst += 1;
  	} while ((nbytes -= bsize) >= bsize);
  
  done:
  	*(__be64 *)walk->iv = cpu_to_be64(ctrblk);
  	return nbytes;
  }
c1679171c   Eric Biggers   crypto: x86/blowf...
304
  static int ctr_crypt(struct skcipher_request *req)
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
305
  {
c1679171c   Eric Biggers   crypto: x86/blowf...
306
307
308
309
  	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  	struct bf_ctx *ctx = crypto_skcipher_ctx(tfm);
  	struct skcipher_walk walk;
  	unsigned int nbytes;
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
310
  	int err;
c1679171c   Eric Biggers   crypto: x86/blowf...
311
  	err = skcipher_walk_virt(&walk, req, false);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
312
313
  
  	while ((nbytes = walk.nbytes) >= BF_BLOCK_SIZE) {
c1679171c   Eric Biggers   crypto: x86/blowf...
314
315
  		nbytes = __ctr_crypt(ctx, &walk);
  		err = skcipher_walk_done(&walk, nbytes);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
316
  	}
c1679171c   Eric Biggers   crypto: x86/blowf...
317
318
319
  	if (nbytes) {
  		ctr_crypt_final(ctx, &walk);
  		err = skcipher_walk_done(&walk, 0);
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
320
321
322
323
  	}
  
  	return err;
  }
c1679171c   Eric Biggers   crypto: x86/blowf...
324
  static struct crypto_alg bf_cipher_alg = {
d433208cf   Jussi Kivilinna   crypto: blowfish-...
325
326
327
328
329
330
  	.cra_name		= "blowfish",
  	.cra_driver_name	= "blowfish-asm",
  	.cra_priority		= 200,
  	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
  	.cra_blocksize		= BF_BLOCK_SIZE,
  	.cra_ctxsize		= sizeof(struct bf_ctx),
919e2c324   Jussi Kivilinna   crypto: blowfish-...
331
  	.cra_alignmask		= 0,
d433208cf   Jussi Kivilinna   crypto: blowfish-...
332
  	.cra_module		= THIS_MODULE,
d433208cf   Jussi Kivilinna   crypto: blowfish-...
333
334
335
336
337
338
339
340
341
  	.cra_u = {
  		.cipher = {
  			.cia_min_keysize	= BF_MIN_KEY_SIZE,
  			.cia_max_keysize	= BF_MAX_KEY_SIZE,
  			.cia_setkey		= blowfish_setkey,
  			.cia_encrypt		= blowfish_encrypt,
  			.cia_decrypt		= blowfish_decrypt,
  		}
  	}
c1679171c   Eric Biggers   crypto: x86/blowf...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  };
  
  static struct skcipher_alg bf_skcipher_algs[] = {
  	{
  		.base.cra_name		= "ecb(blowfish)",
  		.base.cra_driver_name	= "ecb-blowfish-asm",
  		.base.cra_priority	= 300,
  		.base.cra_blocksize	= BF_BLOCK_SIZE,
  		.base.cra_ctxsize	= sizeof(struct bf_ctx),
  		.base.cra_module	= THIS_MODULE,
  		.min_keysize		= BF_MIN_KEY_SIZE,
  		.max_keysize		= BF_MAX_KEY_SIZE,
  		.setkey			= blowfish_setkey_skcipher,
  		.encrypt		= ecb_encrypt,
  		.decrypt		= ecb_decrypt,
  	}, {
  		.base.cra_name		= "cbc(blowfish)",
  		.base.cra_driver_name	= "cbc-blowfish-asm",
  		.base.cra_priority	= 300,
  		.base.cra_blocksize	= BF_BLOCK_SIZE,
  		.base.cra_ctxsize	= sizeof(struct bf_ctx),
  		.base.cra_module	= THIS_MODULE,
  		.min_keysize		= BF_MIN_KEY_SIZE,
  		.max_keysize		= BF_MAX_KEY_SIZE,
  		.ivsize			= BF_BLOCK_SIZE,
  		.setkey			= blowfish_setkey_skcipher,
  		.encrypt		= cbc_encrypt,
  		.decrypt		= cbc_decrypt,
  	}, {
  		.base.cra_name		= "ctr(blowfish)",
  		.base.cra_driver_name	= "ctr-blowfish-asm",
  		.base.cra_priority	= 300,
  		.base.cra_blocksize	= 1,
  		.base.cra_ctxsize	= sizeof(struct bf_ctx),
  		.base.cra_module	= THIS_MODULE,
  		.min_keysize		= BF_MIN_KEY_SIZE,
  		.max_keysize		= BF_MAX_KEY_SIZE,
  		.ivsize			= BF_BLOCK_SIZE,
  		.chunksize		= BF_BLOCK_SIZE,
  		.setkey			= blowfish_setkey_skcipher,
  		.encrypt		= ctr_crypt,
  		.decrypt		= ctr_crypt,
d433208cf   Jussi Kivilinna   crypto: blowfish-...
384
  	},
c1679171c   Eric Biggers   crypto: x86/blowf...
385
  };
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
386

4c58464b8   Jussi Kivilinna   crypto: blowfish-...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
  static bool is_blacklisted_cpu(void)
  {
  	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
  		return false;
  
  	if (boot_cpu_data.x86 == 0x0f) {
  		/*
  		 * On Pentium 4, blowfish-x86_64 is slower than generic C
  		 * implementation because use of 64bit rotates (which are really
  		 * slow on P4). Therefore blacklist P4s.
  		 */
  		return true;
  	}
  
  	return false;
  }
  
  static int force;
  module_param(force, int, 0);
  MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
407
408
  static int __init init(void)
  {
c1679171c   Eric Biggers   crypto: x86/blowf...
409
  	int err;
4c58464b8   Jussi Kivilinna   crypto: blowfish-...
410
411
412
413
414
415
416
417
  	if (!force && is_blacklisted_cpu()) {
  		printk(KERN_INFO
  			"blowfish-x86_64: performance on this CPU "
  			"would be suboptimal: disabling "
  			"blowfish-x86_64.
  ");
  		return -ENODEV;
  	}
c1679171c   Eric Biggers   crypto: x86/blowf...
418
419
420
421
422
423
424
425
426
427
  	err = crypto_register_alg(&bf_cipher_alg);
  	if (err)
  		return err;
  
  	err = crypto_register_skciphers(bf_skcipher_algs,
  					ARRAY_SIZE(bf_skcipher_algs));
  	if (err)
  		crypto_unregister_alg(&bf_cipher_alg);
  
  	return err;
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
428
429
430
431
  }
  
  static void __exit fini(void)
  {
c1679171c   Eric Biggers   crypto: x86/blowf...
432
433
434
  	crypto_unregister_alg(&bf_cipher_alg);
  	crypto_unregister_skciphers(bf_skcipher_algs,
  				    ARRAY_SIZE(bf_skcipher_algs));
64b94ceae   Jussi Kivilinna   crypto: blowfish ...
435
436
437
438
439
440
441
  }
  
  module_init(init);
  module_exit(fini);
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Blowfish Cipher Algorithm, asm optimized");
5d26a105b   Kees Cook   crypto: prefix mo...
442
443
  MODULE_ALIAS_CRYPTO("blowfish");
  MODULE_ALIAS_CRYPTO("blowfish-asm");