xref: /openbmc/linux/crypto/blowfish_generic.c (revision 14386d47)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23f2a5d2dSJussi Kivilinna /*
33f2a5d2dSJussi Kivilinna  * Cryptographic API.
43f2a5d2dSJussi Kivilinna  *
53f2a5d2dSJussi Kivilinna  * Blowfish Cipher Algorithm, by Bruce Schneier.
63f2a5d2dSJussi Kivilinna  * http://www.counterpane.com/blowfish.html
73f2a5d2dSJussi Kivilinna  *
83f2a5d2dSJussi Kivilinna  * Adapted from Kerneli implementation.
93f2a5d2dSJussi Kivilinna  *
103f2a5d2dSJussi Kivilinna  * Copyright (c) Herbert Valerio Riedel <hvr@hvrlab.org>
113f2a5d2dSJussi Kivilinna  * Copyright (c) Kyle McMartin <kyle@debian.org>
123f2a5d2dSJussi Kivilinna  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
133f2a5d2dSJussi Kivilinna  */
14*14386d47SHerbert Xu 
15*14386d47SHerbert Xu #include <crypto/algapi.h>
163f2a5d2dSJussi Kivilinna #include <linux/init.h>
173f2a5d2dSJussi Kivilinna #include <linux/module.h>
183f2a5d2dSJussi Kivilinna #include <linux/mm.h>
1950a3a9faSArd Biesheuvel #include <asm/unaligned.h>
203f2a5d2dSJussi Kivilinna #include <linux/types.h>
213f2a5d2dSJussi Kivilinna #include <crypto/blowfish.h>
223f2a5d2dSJussi Kivilinna 
233f2a5d2dSJussi Kivilinna /*
243f2a5d2dSJussi Kivilinna  * Round loop unrolling macros, S is a pointer to a S-Box array
253f2a5d2dSJussi Kivilinna  * organized in 4 unsigned longs at a row.
263f2a5d2dSJussi Kivilinna  */
273f2a5d2dSJussi Kivilinna #define GET32_3(x) (((x) & 0xff))
283f2a5d2dSJussi Kivilinna #define GET32_2(x) (((x) >> (8)) & (0xff))
293f2a5d2dSJussi Kivilinna #define GET32_1(x) (((x) >> (16)) & (0xff))
303f2a5d2dSJussi Kivilinna #define GET32_0(x) (((x) >> (24)) & (0xff))
313f2a5d2dSJussi Kivilinna 
323f2a5d2dSJussi Kivilinna #define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \
333f2a5d2dSJussi Kivilinna 		S[512 + GET32_2(x)]) + S[768 + GET32_3(x)])
343f2a5d2dSJussi Kivilinna 
353f2a5d2dSJussi Kivilinna #define ROUND(a, b, n) ({ b ^= P[n]; a ^= bf_F(b); })
363f2a5d2dSJussi Kivilinna 
bf_encrypt(struct crypto_tfm * tfm,u8 * dst,const u8 * src)373f2a5d2dSJussi Kivilinna static void bf_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
383f2a5d2dSJussi Kivilinna {
393f2a5d2dSJussi Kivilinna 	struct bf_ctx *ctx = crypto_tfm_ctx(tfm);
403f2a5d2dSJussi Kivilinna 	const u32 *P = ctx->p;
413f2a5d2dSJussi Kivilinna 	const u32 *S = ctx->s;
4250a3a9faSArd Biesheuvel 	u32 yl = get_unaligned_be32(src);
4350a3a9faSArd Biesheuvel 	u32 yr = get_unaligned_be32(src + 4);
443f2a5d2dSJussi Kivilinna 
453f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 0);
463f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 1);
473f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 2);
483f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 3);
493f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 4);
503f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 5);
513f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 6);
523f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 7);
533f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 8);
543f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 9);
553f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 10);
563f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 11);
573f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 12);
583f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 13);
593f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 14);
603f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 15);
613f2a5d2dSJussi Kivilinna 
623f2a5d2dSJussi Kivilinna 	yl ^= P[16];
633f2a5d2dSJussi Kivilinna 	yr ^= P[17];
643f2a5d2dSJussi Kivilinna 
6550a3a9faSArd Biesheuvel 	put_unaligned_be32(yr, dst);
6650a3a9faSArd Biesheuvel 	put_unaligned_be32(yl, dst + 4);
673f2a5d2dSJussi Kivilinna }
683f2a5d2dSJussi Kivilinna 
bf_decrypt(struct crypto_tfm * tfm,u8 * dst,const u8 * src)693f2a5d2dSJussi Kivilinna static void bf_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
703f2a5d2dSJussi Kivilinna {
713f2a5d2dSJussi Kivilinna 	struct bf_ctx *ctx = crypto_tfm_ctx(tfm);
723f2a5d2dSJussi Kivilinna 	const u32 *P = ctx->p;
733f2a5d2dSJussi Kivilinna 	const u32 *S = ctx->s;
7450a3a9faSArd Biesheuvel 	u32 yl = get_unaligned_be32(src);
7550a3a9faSArd Biesheuvel 	u32 yr = get_unaligned_be32(src + 4);
763f2a5d2dSJussi Kivilinna 
773f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 17);
783f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 16);
793f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 15);
803f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 14);
813f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 13);
823f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 12);
833f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 11);
843f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 10);
853f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 9);
863f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 8);
873f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 7);
883f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 6);
893f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 5);
903f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 4);
913f2a5d2dSJussi Kivilinna 	ROUND(yr, yl, 3);
923f2a5d2dSJussi Kivilinna 	ROUND(yl, yr, 2);
933f2a5d2dSJussi Kivilinna 
943f2a5d2dSJussi Kivilinna 	yl ^= P[1];
953f2a5d2dSJussi Kivilinna 	yr ^= P[0];
963f2a5d2dSJussi Kivilinna 
9750a3a9faSArd Biesheuvel 	put_unaligned_be32(yr, dst);
9850a3a9faSArd Biesheuvel 	put_unaligned_be32(yl, dst + 4);
993f2a5d2dSJussi Kivilinna }
1003f2a5d2dSJussi Kivilinna 
1013f2a5d2dSJussi Kivilinna static struct crypto_alg alg = {
1023f2a5d2dSJussi Kivilinna 	.cra_name		=	"blowfish",
1033f2a5d2dSJussi Kivilinna 	.cra_driver_name	=	"blowfish-generic",
1043f2a5d2dSJussi Kivilinna 	.cra_priority		=	100,
1053f2a5d2dSJussi Kivilinna 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
1063f2a5d2dSJussi Kivilinna 	.cra_blocksize		=	BF_BLOCK_SIZE,
1073f2a5d2dSJussi Kivilinna 	.cra_ctxsize		=	sizeof(struct bf_ctx),
1083f2a5d2dSJussi Kivilinna 	.cra_module		=	THIS_MODULE,
1093f2a5d2dSJussi Kivilinna 	.cra_u			=	{ .cipher = {
1103f2a5d2dSJussi Kivilinna 	.cia_min_keysize	=	BF_MIN_KEY_SIZE,
1113f2a5d2dSJussi Kivilinna 	.cia_max_keysize	=	BF_MAX_KEY_SIZE,
1123f2a5d2dSJussi Kivilinna 	.cia_setkey		=	blowfish_setkey,
1133f2a5d2dSJussi Kivilinna 	.cia_encrypt		=	bf_encrypt,
1143f2a5d2dSJussi Kivilinna 	.cia_decrypt		=	bf_decrypt } }
1153f2a5d2dSJussi Kivilinna };
1163f2a5d2dSJussi Kivilinna 
blowfish_mod_init(void)1173f2a5d2dSJussi Kivilinna static int __init blowfish_mod_init(void)
1183f2a5d2dSJussi Kivilinna {
1193f2a5d2dSJussi Kivilinna 	return crypto_register_alg(&alg);
1203f2a5d2dSJussi Kivilinna }
1213f2a5d2dSJussi Kivilinna 
blowfish_mod_fini(void)1223f2a5d2dSJussi Kivilinna static void __exit blowfish_mod_fini(void)
1233f2a5d2dSJussi Kivilinna {
1243f2a5d2dSJussi Kivilinna 	crypto_unregister_alg(&alg);
1253f2a5d2dSJussi Kivilinna }
1263f2a5d2dSJussi Kivilinna 
127c4741b23SEric Biggers subsys_initcall(blowfish_mod_init);
1283f2a5d2dSJussi Kivilinna module_exit(blowfish_mod_fini);
1293f2a5d2dSJussi Kivilinna 
1303f2a5d2dSJussi Kivilinna MODULE_LICENSE("GPL");
1313f2a5d2dSJussi Kivilinna MODULE_DESCRIPTION("Blowfish Cipher Algorithm");
1325d26a105SKees Cook MODULE_ALIAS_CRYPTO("blowfish");
1333e14dcf7SMathias Krause MODULE_ALIAS_CRYPTO("blowfish-generic");
134