xref: /linux/crypto/arc4.c (revision 7ebdfaa52d15b947503f76474477f92854796d96)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Cryptographic API
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * ARC4 Cipher Algorithm
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Jon Oberheide <jon@oberheide.org>
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
91da177e4SLinus Torvalds  * it under the terms of the GNU General Public License as published by
101da177e4SLinus Torvalds  * the Free Software Foundation; either version 2 of the License, or
111da177e4SLinus Torvalds  * (at your option) any later version.
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  */
14ce6dd368SJussi Kivilinna 
151da177e4SLinus Torvalds #include <linux/module.h>
161da177e4SLinus Torvalds #include <linux/init.h>
171da177e4SLinus Torvalds #include <linux/crypto.h>
18ce6dd368SJussi Kivilinna #include <crypto/algapi.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #define ARC4_MIN_KEY_SIZE	1
211da177e4SLinus Torvalds #define ARC4_MAX_KEY_SIZE	256
221da177e4SLinus Torvalds #define ARC4_BLOCK_SIZE		1
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds struct arc4_ctx {
25d366db60SJussi Kivilinna 	u32 S[256];
26d366db60SJussi Kivilinna 	u32 x, y;
271da177e4SLinus Torvalds };
281da177e4SLinus Torvalds 
296c2bb98bSHerbert Xu static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key,
30560c06aeSHerbert Xu 			unsigned int key_len)
311da177e4SLinus Torvalds {
326c2bb98bSHerbert Xu 	struct arc4_ctx *ctx = crypto_tfm_ctx(tfm);
331da177e4SLinus Torvalds 	int i, j = 0, k = 0;
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds 	ctx->x = 1;
361da177e4SLinus Torvalds 	ctx->y = 0;
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds 	for (i = 0; i < 256; i++)
391da177e4SLinus Torvalds 		ctx->S[i] = i;
401da177e4SLinus Torvalds 
41cfa2b54eSMati Vait 	for (i = 0; i < 256; i++) {
42d366db60SJussi Kivilinna 		u32 a = ctx->S[i];
431da177e4SLinus Torvalds 		j = (j + in_key[k] + a) & 0xff;
441da177e4SLinus Torvalds 		ctx->S[i] = ctx->S[j];
451da177e4SLinus Torvalds 		ctx->S[j] = a;
461da177e4SLinus Torvalds 		if (++k >= key_len)
471da177e4SLinus Torvalds 			k = 0;
481da177e4SLinus Torvalds 	}
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds 	return 0;
511da177e4SLinus Torvalds }
521da177e4SLinus Torvalds 
53ce6dd368SJussi Kivilinna static void arc4_crypt(struct arc4_ctx *ctx, u8 *out, const u8 *in,
54ce6dd368SJussi Kivilinna 		       unsigned int len)
551da177e4SLinus Torvalds {
56d366db60SJussi Kivilinna 	u32 *const S = ctx->S;
57d366db60SJussi Kivilinna 	u32 x, y, a, b;
58d366db60SJussi Kivilinna 	u32 ty, ta, tb;
59ce6dd368SJussi Kivilinna 
60ce6dd368SJussi Kivilinna 	if (len == 0)
61ce6dd368SJussi Kivilinna 		return;
62ce6dd368SJussi Kivilinna 
63ce6dd368SJussi Kivilinna 	x = ctx->x;
64ce6dd368SJussi Kivilinna 	y = ctx->y;
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 	a = S[x];
671da177e4SLinus Torvalds 	y = (y + a) & 0xff;
681da177e4SLinus Torvalds 	b = S[y];
69ce6dd368SJussi Kivilinna 
70ce6dd368SJussi Kivilinna 	do {
711da177e4SLinus Torvalds 		S[y] = a;
72ce6dd368SJussi Kivilinna 		a = (a + b) & 0xff;
73ce6dd368SJussi Kivilinna 		S[x] = b;
741da177e4SLinus Torvalds 		x = (x + 1) & 0xff;
75ce6dd368SJussi Kivilinna 		ta = S[x];
76ce6dd368SJussi Kivilinna 		ty = (y + ta) & 0xff;
77ce6dd368SJussi Kivilinna 		tb = S[ty];
78ce6dd368SJussi Kivilinna 		*out++ = *in++ ^ S[a];
79ce6dd368SJussi Kivilinna 		if (--len == 0)
80ce6dd368SJussi Kivilinna 			break;
81ce6dd368SJussi Kivilinna 		y = ty;
82ce6dd368SJussi Kivilinna 		a = ta;
83ce6dd368SJussi Kivilinna 		b = tb;
84ce6dd368SJussi Kivilinna 	} while (true);
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	ctx->x = x;
871da177e4SLinus Torvalds 	ctx->y = y;
881da177e4SLinus Torvalds }
891da177e4SLinus Torvalds 
90ce6dd368SJussi Kivilinna static void arc4_crypt_one(struct crypto_tfm *tfm, u8 *out, const u8 *in)
91ce6dd368SJussi Kivilinna {
92ce6dd368SJussi Kivilinna 	arc4_crypt(crypto_tfm_ctx(tfm), out, in, 1);
93ce6dd368SJussi Kivilinna }
94ce6dd368SJussi Kivilinna 
95ce6dd368SJussi Kivilinna static int ecb_arc4_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
96ce6dd368SJussi Kivilinna 			  struct scatterlist *src, unsigned int nbytes)
97ce6dd368SJussi Kivilinna {
98ce6dd368SJussi Kivilinna 	struct arc4_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
99ce6dd368SJussi Kivilinna 	struct blkcipher_walk walk;
100ce6dd368SJussi Kivilinna 	int err;
101ce6dd368SJussi Kivilinna 
102ce6dd368SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
103ce6dd368SJussi Kivilinna 
104ce6dd368SJussi Kivilinna 	err = blkcipher_walk_virt(desc, &walk);
105ce6dd368SJussi Kivilinna 
106ce6dd368SJussi Kivilinna 	while (walk.nbytes > 0) {
107ce6dd368SJussi Kivilinna 		u8 *wsrc = walk.src.virt.addr;
108ce6dd368SJussi Kivilinna 		u8 *wdst = walk.dst.virt.addr;
109ce6dd368SJussi Kivilinna 
110ce6dd368SJussi Kivilinna 		arc4_crypt(ctx, wdst, wsrc, walk.nbytes);
111ce6dd368SJussi Kivilinna 
112ce6dd368SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, 0);
113ce6dd368SJussi Kivilinna 	}
114ce6dd368SJussi Kivilinna 
115ce6dd368SJussi Kivilinna 	return err;
116ce6dd368SJussi Kivilinna }
117ce6dd368SJussi Kivilinna 
118ce6dd368SJussi Kivilinna static struct crypto_alg arc4_algs[2] = { {
1191da177e4SLinus Torvalds 	.cra_name		=	"arc4",
1201da177e4SLinus Torvalds 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
1211da177e4SLinus Torvalds 	.cra_blocksize		=	ARC4_BLOCK_SIZE,
1221da177e4SLinus Torvalds 	.cra_ctxsize		=	sizeof(struct arc4_ctx),
1231da177e4SLinus Torvalds 	.cra_module		=	THIS_MODULE,
124ce6dd368SJussi Kivilinna 	.cra_u			=	{
125ce6dd368SJussi Kivilinna 		.cipher = {
1261da177e4SLinus Torvalds 			.cia_min_keysize	=	ARC4_MIN_KEY_SIZE,
1271da177e4SLinus Torvalds 			.cia_max_keysize	=	ARC4_MAX_KEY_SIZE,
1281da177e4SLinus Torvalds 			.cia_setkey		=	arc4_set_key,
129ce6dd368SJussi Kivilinna 			.cia_encrypt		=	arc4_crypt_one,
130ce6dd368SJussi Kivilinna 			.cia_decrypt		=	arc4_crypt_one,
131ce6dd368SJussi Kivilinna 		},
132ce6dd368SJussi Kivilinna 	},
133ce6dd368SJussi Kivilinna }, {
134ce6dd368SJussi Kivilinna 	.cra_name		=	"ecb(arc4)",
135ce6dd368SJussi Kivilinna 	.cra_priority		=	100,
136ce6dd368SJussi Kivilinna 	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
137ce6dd368SJussi Kivilinna 	.cra_blocksize		=	ARC4_BLOCK_SIZE,
138ce6dd368SJussi Kivilinna 	.cra_ctxsize		=	sizeof(struct arc4_ctx),
139ce6dd368SJussi Kivilinna 	.cra_alignmask		=	0,
140ce6dd368SJussi Kivilinna 	.cra_type		=	&crypto_blkcipher_type,
141ce6dd368SJussi Kivilinna 	.cra_module		=	THIS_MODULE,
142ce6dd368SJussi Kivilinna 	.cra_u			=	{
143ce6dd368SJussi Kivilinna 		.blkcipher = {
144ce6dd368SJussi Kivilinna 			.min_keysize	=	ARC4_MIN_KEY_SIZE,
145ce6dd368SJussi Kivilinna 			.max_keysize	=	ARC4_MAX_KEY_SIZE,
146ce6dd368SJussi Kivilinna 			.setkey		=	arc4_set_key,
147ce6dd368SJussi Kivilinna 			.encrypt	=	ecb_arc4_crypt,
148ce6dd368SJussi Kivilinna 			.decrypt	=	ecb_arc4_crypt,
149ce6dd368SJussi Kivilinna 		},
150ce6dd368SJussi Kivilinna 	},
151ce6dd368SJussi Kivilinna } };
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds static int __init arc4_init(void)
1541da177e4SLinus Torvalds {
155ce6dd368SJussi Kivilinna 	return crypto_register_algs(arc4_algs, ARRAY_SIZE(arc4_algs));
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds static void __exit arc4_exit(void)
1591da177e4SLinus Torvalds {
160ce6dd368SJussi Kivilinna 	crypto_unregister_algs(arc4_algs, ARRAY_SIZE(arc4_algs));
1611da177e4SLinus Torvalds }
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds module_init(arc4_init);
1641da177e4SLinus Torvalds module_exit(arc4_exit);
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds MODULE_LICENSE("GPL");
1671da177e4SLinus Torvalds MODULE_DESCRIPTION("ARC4 Cipher Algorithm");
1681da177e4SLinus Torvalds MODULE_AUTHOR("Jon Oberheide <jon@oberheide.org>");
169*5d26a105SKees Cook MODULE_ALIAS_CRYPTO("arc4");
170