diff mbox series

[v2,1/7] crypto: arc4 - refactor arc4 core code into separate library

Message ID 20190609115509.26260-2-ard.biesheuvel@linaro.org (mailing list archive)
State Superseded
Delegated to: Herbert Xu
Headers show
Series crypto: rc4 cleanup | expand

Commit Message

Ard Biesheuvel June 9, 2019, 11:55 a.m. UTC
Refactor the core rc4 handling so we can move most users to a library
interface, permitting us to drop the cipher interface entirely in a
future patch. This is part of an effort to simplify the crypto API
and improve its robustness against incorrect use.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 MAINTAINERS           |  1 +
 crypto/Kconfig        |  4 ++
 crypto/arc4.c         | 74 +++-----------------
 include/crypto/arc4.h | 13 ++++
 lib/Makefile          |  2 +-
 lib/crypto/Makefile   |  3 +
 lib/crypto/libarc4.c  | 74 ++++++++++++++++++++
 7 files changed, 104 insertions(+), 67 deletions(-)

Comments

Eric Biggers June 10, 2019, 4:06 p.m. UTC | #1
Just some bike shedding:

On Sun, Jun 09, 2019 at 01:55:03PM +0200, Ard Biesheuvel wrote:
> diff --git a/include/crypto/arc4.h b/include/crypto/arc4.h
> index 5b2c24ab0139..62ac95ec6860 100644
> --- a/include/crypto/arc4.h
> +++ b/include/crypto/arc4.h
> @@ -6,8 +6,21 @@
>  #ifndef _CRYPTO_ARC4_H
>  #define _CRYPTO_ARC4_H
>  
> +#include <linux/types.h>
> +
>  #define ARC4_MIN_KEY_SIZE	1
>  #define ARC4_MAX_KEY_SIZE	256
>  #define ARC4_BLOCK_SIZE		1
>  
> +struct crypto_arc4_ctx {
> +	u32 S[256];
> +	u32 x, y;
> +};
> +
> +int crypto_arc4_set_key(struct crypto_arc4_ctx *ctx, const u8 *in_key,
> +			unsigned int key_len);
> +
> +void crypto_arc4_crypt(struct crypto_arc4_ctx *ctx, u8 *out, const u8 *in,
> +		       unsigned int len);

How about naming these just arc4_* instead of crypto_arc4_*?  The crypto_*
prefix is already used mostly for crypto API helper functions, i.e. functions
that take take one of the abstract crypto API types like crypto_skcipher,
shash_desc, etc.  For lib functions, the bare name seems more appropriate.  See
e.g. sha256_update() vs. crypto_sha256_update().

> +++ b/lib/crypto/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-$(CONFIG_CRYPTO_LIB_ARC4) += libarc4.o
> diff --git a/lib/crypto/libarc4.c b/lib/crypto/libarc4.c
> new file mode 100644
> index 000000000000..b828af2cc03b
> --- /dev/null
> +++ b/lib/crypto/libarc4.c
> @@ -0,0 +1,74 @@

How about arc4.c instead of libarc4.c?  The second "lib" is redundant, given
that the file is already in the lib/ directory.

- Eric
Ard Biesheuvel June 10, 2019, 4:10 p.m. UTC | #2
On Mon, 10 Jun 2019 at 18:06, Eric Biggers <ebiggers@kernel.org> wrote:
>
> Just some bike shedding:
>
> On Sun, Jun 09, 2019 at 01:55:03PM +0200, Ard Biesheuvel wrote:
> > diff --git a/include/crypto/arc4.h b/include/crypto/arc4.h
> > index 5b2c24ab0139..62ac95ec6860 100644
> > --- a/include/crypto/arc4.h
> > +++ b/include/crypto/arc4.h
> > @@ -6,8 +6,21 @@
> >  #ifndef _CRYPTO_ARC4_H
> >  #define _CRYPTO_ARC4_H
> >
> > +#include <linux/types.h>
> > +
> >  #define ARC4_MIN_KEY_SIZE    1
> >  #define ARC4_MAX_KEY_SIZE    256
> >  #define ARC4_BLOCK_SIZE              1
> >
> > +struct crypto_arc4_ctx {
> > +     u32 S[256];
> > +     u32 x, y;
> > +};
> > +
> > +int crypto_arc4_set_key(struct crypto_arc4_ctx *ctx, const u8 *in_key,
> > +                     unsigned int key_len);
> > +
> > +void crypto_arc4_crypt(struct crypto_arc4_ctx *ctx, u8 *out, const u8 *in,
> > +                    unsigned int len);
>
> How about naming these just arc4_* instead of crypto_arc4_*?  The crypto_*
> prefix is already used mostly for crypto API helper functions, i.e. functions
> that take take one of the abstract crypto API types like crypto_skcipher,
> shash_desc, etc.  For lib functions, the bare name seems more appropriate.  See
> e.g. sha256_update() vs. crypto_sha256_update().
>

That is also fine, although I am slightly concerned that we may run
into trouble with other algorithms in the future. But I do agree it
makes sense to make a clear distinction with the full blown API.

> > +++ b/lib/crypto/Makefile
> > @@ -0,0 +1,3 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +obj-$(CONFIG_CRYPTO_LIB_ARC4) += libarc4.o
> > diff --git a/lib/crypto/libarc4.c b/lib/crypto/libarc4.c
> > new file mode 100644
> > index 000000000000..b828af2cc03b
> > --- /dev/null
> > +++ b/lib/crypto/libarc4.c
> > @@ -0,0 +1,74 @@
>
> How about arc4.c instead of libarc4.c?  The second "lib" is redundant, given
> that the file is already in the lib/ directory.
>

The problem here is that we'll end up with two modules named arc4.ko,
one in crypto/ and one in lib/crypto/. Perhaps we should rename the
other one? (especially once it implements ecb(arc4) only.)
Eric Biggers June 10, 2019, 4:32 p.m. UTC | #3
On Mon, Jun 10, 2019 at 06:10:41PM +0200, Ard Biesheuvel wrote:
> On Mon, 10 Jun 2019 at 18:06, Eric Biggers <ebiggers@kernel.org> wrote:
> >
> > Just some bike shedding:
> >
> > On Sun, Jun 09, 2019 at 01:55:03PM +0200, Ard Biesheuvel wrote:
> > > diff --git a/include/crypto/arc4.h b/include/crypto/arc4.h
> > > index 5b2c24ab0139..62ac95ec6860 100644
> > > --- a/include/crypto/arc4.h
> > > +++ b/include/crypto/arc4.h
> > > @@ -6,8 +6,21 @@
> > >  #ifndef _CRYPTO_ARC4_H
> > >  #define _CRYPTO_ARC4_H
> > >
> > > +#include <linux/types.h>
> > > +
> > >  #define ARC4_MIN_KEY_SIZE    1
> > >  #define ARC4_MAX_KEY_SIZE    256
> > >  #define ARC4_BLOCK_SIZE              1
> > >
> > > +struct crypto_arc4_ctx {
> > > +     u32 S[256];
> > > +     u32 x, y;
> > > +};
> > > +
> > > +int crypto_arc4_set_key(struct crypto_arc4_ctx *ctx, const u8 *in_key,
> > > +                     unsigned int key_len);
> > > +
> > > +void crypto_arc4_crypt(struct crypto_arc4_ctx *ctx, u8 *out, const u8 *in,
> > > +                    unsigned int len);
> >
> > How about naming these just arc4_* instead of crypto_arc4_*?  The crypto_*
> > prefix is already used mostly for crypto API helper functions, i.e. functions
> > that take take one of the abstract crypto API types like crypto_skcipher,
> > shash_desc, etc.  For lib functions, the bare name seems more appropriate.  See
> > e.g. sha256_update() vs. crypto_sha256_update().
> >
> 
> That is also fine, although I am slightly concerned that we may run
> into trouble with other algorithms in the future. But I do agree it
> makes sense to make a clear distinction with the full blown API.
> 
> > > +++ b/lib/crypto/Makefile
> > > @@ -0,0 +1,3 @@
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +
> > > +obj-$(CONFIG_CRYPTO_LIB_ARC4) += libarc4.o
> > > diff --git a/lib/crypto/libarc4.c b/lib/crypto/libarc4.c
> > > new file mode 100644
> > > index 000000000000..b828af2cc03b
> > > --- /dev/null
> > > +++ b/lib/crypto/libarc4.c
> > > @@ -0,0 +1,74 @@
> >
> > How about arc4.c instead of libarc4.c?  The second "lib" is redundant, given
> > that the file is already in the lib/ directory.
> >
> 
> The problem here is that we'll end up with two modules named arc4.ko,
> one in crypto/ and one in lib/crypto/. Perhaps we should rename the
> other one? (especially once it implements ecb(arc4) only.)

Another option is to do:

obj-$(CONFIG_CRYPTO_LIB_ARC4) += libarc4.o
libarc4-y := arc4.o

Also, CONFIG_CRYPTO_LIB_ARC4 needs to actually be a tristate.
It seems you accidentally made it a bool:

> +config CRYPTO_LIB_ARC4
> +	bool
> +

- Eric
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 57f496cff999..112f21066141 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4241,6 +4241,7 @@  F:	crypto/
 F:	drivers/crypto/
 F:	include/crypto/
 F:	include/linux/crypto*
+F:	lib/crypto/
 
 CRYPTOGRAPHIC RANDOM NUMBER GENERATOR
 M:	Neil Horman <nhorman@tuxdriver.com>
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 3d056e7da65f..310e2a5de59d 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1230,9 +1230,13 @@  config CRYPTO_ANUBIS
 	  <https://www.cosic.esat.kuleuven.be/nessie/reports/>
 	  <http://www.larc.usp.br/~pbarreto/AnubisPage.html>
 
+config CRYPTO_LIB_ARC4
+	bool
+
 config CRYPTO_ARC4
 	tristate "ARC4 cipher algorithm"
 	select CRYPTO_BLKCIPHER
+	select CRYPTO_LIB_ARC4
 	help
 	  ARC4 cipher algorithm.
 
diff --git a/crypto/arc4.c b/crypto/arc4.c
index a2120e06bf84..7f80623aa66a 100644
--- a/crypto/arc4.c
+++ b/crypto/arc4.c
@@ -13,33 +13,12 @@ 
 #include <linux/init.h>
 #include <linux/module.h>
 
-struct arc4_ctx {
-	u32 S[256];
-	u32 x, y;
-};
-
 static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 			unsigned int key_len)
 {
-	struct arc4_ctx *ctx = crypto_tfm_ctx(tfm);
-	int i, j = 0, k = 0;
-
-	ctx->x = 1;
-	ctx->y = 0;
-
-	for (i = 0; i < 256; i++)
-		ctx->S[i] = i;
-
-	for (i = 0; i < 256; i++) {
-		u32 a = ctx->S[i];
-		j = (j + in_key[k] + a) & 0xff;
-		ctx->S[i] = ctx->S[j];
-		ctx->S[j] = a;
-		if (++k >= key_len)
-			k = 0;
-	}
+	struct crypto_arc4_ctx *ctx = crypto_tfm_ctx(tfm);
 
-	return 0;
+	return crypto_arc4_set_key(ctx, in_key, key_len);
 }
 
 static int arc4_set_key_skcipher(struct crypto_skcipher *tfm, const u8 *in_key,
@@ -48,60 +27,23 @@  static int arc4_set_key_skcipher(struct crypto_skcipher *tfm, const u8 *in_key,
 	return arc4_set_key(&tfm->base, in_key, key_len);
 }
 
-static void arc4_crypt(struct arc4_ctx *ctx, u8 *out, const u8 *in,
-		       unsigned int len)
-{
-	u32 *const S = ctx->S;
-	u32 x, y, a, b;
-	u32 ty, ta, tb;
-
-	if (len == 0)
-		return;
-
-	x = ctx->x;
-	y = ctx->y;
-
-	a = S[x];
-	y = (y + a) & 0xff;
-	b = S[y];
-
-	do {
-		S[y] = a;
-		a = (a + b) & 0xff;
-		S[x] = b;
-		x = (x + 1) & 0xff;
-		ta = S[x];
-		ty = (y + ta) & 0xff;
-		tb = S[ty];
-		*out++ = *in++ ^ S[a];
-		if (--len == 0)
-			break;
-		y = ty;
-		a = ta;
-		b = tb;
-	} while (true);
-
-	ctx->x = x;
-	ctx->y = y;
-}
-
 static void arc4_crypt_one(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	arc4_crypt(crypto_tfm_ctx(tfm), out, in, 1);
+	crypto_arc4_crypt(crypto_tfm_ctx(tfm), out, in, 1);
 }
 
 static int ecb_arc4_crypt(struct skcipher_request *req)
 {
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
-	struct arc4_ctx *ctx = crypto_skcipher_ctx(tfm);
+	struct crypto_arc4_ctx *ctx = crypto_skcipher_ctx(tfm);
 	struct skcipher_walk walk;
 	int err;
 
 	err = skcipher_walk_virt(&walk, req, false);
 
 	while (walk.nbytes > 0) {
-		arc4_crypt(ctx, walk.dst.virt.addr, walk.src.virt.addr,
-			   walk.nbytes);
+		crypto_arc4_crypt(ctx, walk.dst.virt.addr, walk.src.virt.addr,
+				  walk.nbytes);
 		err = skcipher_walk_done(&walk, 0);
 	}
 
@@ -112,7 +54,7 @@  static struct crypto_alg arc4_cipher = {
 	.cra_name		=	"arc4",
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_blocksize		=	ARC4_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct arc4_ctx),
+	.cra_ctxsize		=	sizeof(struct crypto_arc4_ctx),
 	.cra_module		=	THIS_MODULE,
 	.cra_u			=	{
 		.cipher = {
@@ -129,7 +71,7 @@  static struct skcipher_alg arc4_skcipher = {
 	.base.cra_name		=	"ecb(arc4)",
 	.base.cra_priority	=	100,
 	.base.cra_blocksize	=	ARC4_BLOCK_SIZE,
-	.base.cra_ctxsize	=	sizeof(struct arc4_ctx),
+	.base.cra_ctxsize	=	sizeof(struct crypto_arc4_ctx),
 	.base.cra_module	=	THIS_MODULE,
 	.min_keysize		=	ARC4_MIN_KEY_SIZE,
 	.max_keysize		=	ARC4_MAX_KEY_SIZE,
diff --git a/include/crypto/arc4.h b/include/crypto/arc4.h
index 5b2c24ab0139..62ac95ec6860 100644
--- a/include/crypto/arc4.h
+++ b/include/crypto/arc4.h
@@ -6,8 +6,21 @@ 
 #ifndef _CRYPTO_ARC4_H
 #define _CRYPTO_ARC4_H
 
+#include <linux/types.h>
+
 #define ARC4_MIN_KEY_SIZE	1
 #define ARC4_MAX_KEY_SIZE	256
 #define ARC4_BLOCK_SIZE		1
 
+struct crypto_arc4_ctx {
+	u32 S[256];
+	u32 x, y;
+};
+
+int crypto_arc4_set_key(struct crypto_arc4_ctx *ctx, const u8 *in_key,
+			unsigned int key_len);
+
+void crypto_arc4_crypt(struct crypto_arc4_ctx *ctx, u8 *out, const u8 *in,
+		       unsigned int len);
+
 #endif /* _CRYPTO_ARC4_H */
diff --git a/lib/Makefile b/lib/Makefile
index fb7697031a79..d3daedf93c5a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -102,7 +102,7 @@  endif
 obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o
 CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any)
 
-obj-y += math/
+obj-y += math/ crypto/
 
 obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
 obj-$(CONFIG_GENERIC_PCI_IOMAP) += pci_iomap.o
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
new file mode 100644
index 000000000000..e375d150a547
--- /dev/null
+++ b/lib/crypto/Makefile
@@ -0,0 +1,3 @@ 
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_CRYPTO_LIB_ARC4) += libarc4.o
diff --git a/lib/crypto/libarc4.c b/lib/crypto/libarc4.c
new file mode 100644
index 000000000000..b828af2cc03b
--- /dev/null
+++ b/lib/crypto/libarc4.c
@@ -0,0 +1,74 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Cryptographic API
+ *
+ * ARC4 Cipher Algorithm
+ *
+ * Jon Oberheide <jon@oberheide.org>
+ */
+
+#include <crypto/arc4.h>
+#include <linux/module.h>
+
+int crypto_arc4_set_key(struct crypto_arc4_ctx *ctx, const u8 *in_key,
+			unsigned int key_len)
+{
+	int i, j = 0, k = 0;
+
+	ctx->x = 1;
+	ctx->y = 0;
+
+	for (i = 0; i < 256; i++)
+		ctx->S[i] = i;
+
+	for (i = 0; i < 256; i++) {
+		u32 a = ctx->S[i];
+
+		j = (j + in_key[k] + a) & 0xff;
+		ctx->S[i] = ctx->S[j];
+		ctx->S[j] = a;
+		if (++k >= key_len)
+			k = 0;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(crypto_arc4_set_key);
+
+void crypto_arc4_crypt(struct crypto_arc4_ctx *ctx, u8 *out, const u8 *in,
+		       unsigned int len)
+{
+	u32 *const S = ctx->S;
+	u32 x, y, a, b;
+	u32 ty, ta, tb;
+
+	if (len == 0)
+		return;
+
+	x = ctx->x;
+	y = ctx->y;
+
+	a = S[x];
+	y = (y + a) & 0xff;
+	b = S[y];
+
+	do {
+		S[y] = a;
+		a = (a + b) & 0xff;
+		S[x] = b;
+		x = (x + 1) & 0xff;
+		ta = S[x];
+		ty = (y + ta) & 0xff;
+		tb = S[ty];
+		*out++ = *in++ ^ S[a];
+		if (--len == 0)
+			break;
+		y = ty;
+		a = ta;
+		b = tb;
+	} while (true);
+
+	ctx->x = x;
+	ctx->y = y;
+}
+EXPORT_SYMBOL(crypto_arc4_crypt);