[PATCH/RFC 2/4] crypto: Add a "zlib" crypto module

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add a "zlib" crypto module, which differs from the existing "deflate" crypto
module in the following aspects:
  - Support for the new partial (de)compression API has been added,
  - The (de)compression parameters have been changed to accomodate SquashFS
    ("zlib" format with 15 window bits instead of "raw deflate" format with 11
     windows bits).

Todo:
  - Make the (de)compression parameters configurable, so it can be merged
    back into the "deflate" crypto module

Caveats:
  - Compression hasn't been tested yet

Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@xxxxxxxxxxx>
---
 Kconfig  |    8 +
 Makefile |    1 
 zlib.c   |  389 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 398 insertions(+)

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 39dbd8e..51bf6fa 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -695,6 +695,14 @@ config CRYPTO_LZO
 	help
 	  This is the LZO algorithm.
 
+config CRYPTO_ZLIB
+	tristate "Zlib compression algorithm"
+	select CRYPTO_ALGAPI
+	select ZLIB_INFLATE
+	select ZLIB_DEFLATE
+	help
+	  This is the Zlib algorithm.
+
 comment "Random Number Generation"
 
 config CRYPTO_ANSI_CPRNG
diff --git a/crypto/Makefile b/crypto/Makefile
index 5862b80..8d4cdb7 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_CRYPTO_LZO) += lzo.o
 obj-$(CONFIG_CRYPTO_RNG) += rng.o
 obj-$(CONFIG_CRYPTO_RNG) += krng.o
 obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o
+obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
 
 #
diff --git a/crypto/zlib.c b/crypto/zlib.c
new file mode 100644
index 0000000..a95340d
--- /dev/null
+++ b/crypto/zlib.c
@@ -0,0 +1,389 @@
+#define DEBUG
+/*
+ * Cryptographic API.
+ *
+ * "zlib" crypto module, based on the "deflate" crypto module
+ *
+ * Copyright (c) 2003 James Morris <jmorris@xxxxxxxxxxxxxxxx>
+ * Copyright 2008 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * FIXME: deflate transforms will require up to a total of about 436k of kernel
+ * memory on i386 (390k for compression, the rest for decompression), as the
+ * current zlib kernel code uses a worst case pre-allocation system by default.
+ * This needs to be fixed so that the amount of memory required is properly
+ * related to the  winbits and memlevel parameters.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/zlib.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/net.h>
+#include <linux/slab.h>
+
+#define ZLIB_DEF_LEVEL		Z_DEFAULT_COMPRESSION
+
+struct zlib_ctx {
+	struct z_stream_s comp_stream;
+	struct z_stream_s decomp_stream;
+};
+
+static int zlib_comp_init(struct zlib_ctx *ctx)
+{
+	int ret = 0;
+	struct z_stream_s *stream = &ctx->comp_stream;
+
+	stream->workspace = vmalloc(zlib_deflate_workspacesize());
+	if (!stream->workspace) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	memset(stream->workspace, 0, zlib_deflate_workspacesize());
+	ret = zlib_deflateInit(stream, ZLIB_DEF_LEVEL);
+	if (ret != Z_OK) {
+		ret = -EINVAL;
+		goto out_free;
+	}
+out:
+	return ret;
+out_free:
+	vfree(stream->workspace);
+	goto out;
+}
+
+static int zlib_decomp_init(struct zlib_ctx *ctx)
+{
+	int ret = 0;
+	struct z_stream_s *stream = &ctx->decomp_stream;
+
+	stream->workspace = kzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+	if (!stream->workspace) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	ret = zlib_inflateInit(stream);
+	if (ret != Z_OK) {
+		ret = -EINVAL;
+		goto out_free;
+	}
+out:
+	return ret;
+out_free:
+	kfree(stream->workspace);
+	goto out;
+}
+
+static void zlib_comp_exit(struct zlib_ctx *ctx)
+{
+	zlib_deflateEnd(&ctx->comp_stream);
+	vfree(ctx->comp_stream.workspace);
+}
+
+static void zlib_decomp_exit(struct zlib_ctx *ctx)
+{
+	zlib_inflateEnd(&ctx->decomp_stream);
+	kfree(ctx->decomp_stream.workspace);
+}
+
+static int zlib_init(struct crypto_tfm *tfm)
+{
+	struct zlib_ctx *ctx = crypto_tfm_ctx(tfm);
+	int ret;
+
+	ret = zlib_comp_init(ctx);
+	if (ret)
+		goto out;
+	ret = zlib_decomp_init(ctx);
+	if (ret)
+		zlib_comp_exit(ctx);
+out:
+	return ret;
+}
+
+static void zlib_exit(struct crypto_tfm *tfm)
+{
+	struct zlib_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	zlib_comp_exit(ctx);
+	zlib_decomp_exit(ctx);
+}
+
+static int zlib_compress(struct crypto_tfm *tfm, const u8 *src,
+			 unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+	int ret;
+	struct zlib_ctx *dctx = crypto_tfm_ctx(tfm);
+	struct z_stream_s *stream = &dctx->comp_stream;
+
+	pr_debug("%s: slen %u, dlen %u\n", __func__, slen, *dlen);
+	ret = zlib_deflateReset(stream);
+	if (ret != Z_OK) {
+		pr_err("%s: zlib_deflateReset failed %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	stream->next_in = (u8 *)src;
+	stream->avail_in = slen;
+	stream->next_out = (u8 *)dst;
+	stream->avail_out = *dlen;
+
+	ret = zlib_deflate(stream, Z_FINISH);
+	if (ret != Z_STREAM_END) {
+		pr_err("%s: zlib_deflate failed %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	*dlen = stream->total_out;
+	pr_debug("%s: dlen_out %u\n", __func__, *dlen);
+	return 0;
+}
+
+static int zlib_decompress(struct crypto_tfm *tfm, const u8 *src,
+			   unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+	int ret;
+	struct zlib_ctx *dctx = crypto_tfm_ctx(tfm);
+	struct z_stream_s *stream = &dctx->decomp_stream;
+
+	pr_debug("%s: slen %u, dlen %u\n", __func__, slen, *dlen);
+	ret = zlib_inflateReset(stream);
+	if (ret != Z_OK) {
+		pr_err("%s: zlib_inflateReset failed %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	stream->next_in = (u8 *)src;
+	stream->avail_in = slen;
+	stream->next_out = (u8 *)dst;
+	stream->avail_out = *dlen;
+
+	ret = zlib_inflate(stream, Z_FINISH);
+	if (ret != Z_STREAM_END) {
+		pr_err("%s: zlib_inflate failed %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	*dlen = stream->total_out;
+	pr_debug("%s: dlen_out %u\n", __func__, *dlen);
+	return 0;
+}
+
+static int zlib_compress_update(struct crypto_tfm *tfm,
+				struct comp_request *req)
+{
+	int ret;
+	struct zlib_ctx *dctx = crypto_tfm_ctx(tfm);
+	struct z_stream_s *stream = &dctx->comp_stream;
+
+	pr_debug("%s: avail_in %u, avail_out %u\n", __func__, req->avail_in,
+		 req->avail_out);
+	stream->next_in = req->next_in;
+	stream->avail_in = req->avail_in;
+	stream->next_out = req->next_out;
+	stream->avail_out = req->avail_out;
+
+	ret = zlib_deflate(stream, Z_NO_FLUSH);
+	switch (ret) {
+	case Z_OK:
+		break;
+
+	case Z_BUF_ERROR:
+		pr_err("%s: zlib_deflate could not make progress\n", __func__);
+		return -EAGAIN;
+
+	default:
+		pr_err("%s: zlib_deflate failed %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: avail_in %u, avail_out %u (consumed %u, produced %u)\n",
+		 __func__, stream->avail_in, stream->avail_out,
+		 req->avail_in - stream->avail_in,
+		 req->avail_out - stream->avail_out);
+	req->next_in = stream->next_in;
+	req->avail_in = stream->avail_in;
+	req->next_out = stream->next_out;
+	req->avail_out = stream->avail_out;
+	return 0;
+}
+
+static int zlib_compress_init(struct crypto_tfm *tfm, struct comp_request *req)
+{
+	int ret;
+	struct zlib_ctx *dctx = crypto_tfm_ctx(tfm);
+	struct z_stream_s *stream = &dctx->comp_stream;
+
+	pr_debug("%s: avail_in %u, avail_out %u\n", __func__, req->avail_in,
+		 req->avail_out);
+	ret = zlib_deflateReset(stream);
+	if (ret != Z_OK)
+		return -EINVAL;
+
+	return zlib_compress_update(tfm, req);
+}
+
+static int zlib_compress_final(struct crypto_tfm *tfm,
+			       struct comp_request *req)
+{
+	int ret;
+	struct zlib_ctx *dctx = crypto_tfm_ctx(tfm);
+	struct z_stream_s *stream = &dctx->comp_stream;
+
+	pr_debug("%s: avail_in %u, avail_out %u\n", __func__, req->avail_in,
+		 req->avail_out);
+	stream->next_in = req->next_in;
+	stream->avail_in = req->avail_in;
+	stream->next_out = req->next_out;
+	stream->avail_out = req->avail_out;
+
+	ret = zlib_deflate(stream, Z_FINISH);
+	if (ret != Z_OK) {
+		pr_err("%s: zlib_deflate failed %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: avail_in %u, avail_out %u (consumed %u, produced %u)\n",
+		 __func__, stream->avail_in, stream->avail_out,
+		 req->avail_in - stream->avail_in,
+		 req->avail_out - stream->avail_out);
+	req->next_in = stream->next_in;
+	req->avail_in = stream->avail_in;
+	req->next_out = stream->next_out;
+	req->avail_out = stream->avail_out;
+	return 0;
+}
+
+static int zlib_decompress_update(struct crypto_tfm *tfm,
+				  struct comp_request *req)
+{
+	int ret;
+	struct zlib_ctx *dctx = crypto_tfm_ctx(tfm);
+	struct z_stream_s *stream = &dctx->decomp_stream;
+
+	pr_debug("%s: avail_in %u, avail_out %u\n", __func__, req->avail_in,
+		 req->avail_out);
+	stream->next_in = req->next_in;
+	stream->avail_in = req->avail_in;
+	stream->next_out = req->next_out;
+	stream->avail_out = req->avail_out;
+
+	ret = zlib_inflate(stream, Z_SYNC_FLUSH);
+	switch (ret) {
+	case Z_OK:
+	case Z_STREAM_END:
+		break;
+
+	case Z_BUF_ERROR:
+		pr_err("%s: zlib_inflate could not make progress\n", __func__);
+		return -EAGAIN;
+
+	default:
+		pr_err("%s: zlib_inflate failed %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: avail_in %u, avail_out %u (consumed %u, produced %u)\n",
+		 __func__, stream->avail_in, stream->avail_out,
+		 req->avail_in - stream->avail_in,
+		 req->avail_out - stream->avail_out);
+	req->next_in = stream->next_in;
+	req->avail_in = stream->avail_in;
+	req->next_out = stream->next_out;
+	req->avail_out = stream->avail_out;
+	return 0;
+}
+
+static int zlib_decompress_init(struct crypto_tfm *tfm,
+				struct comp_request *req)
+{
+	int ret;
+	struct zlib_ctx *dctx = crypto_tfm_ctx(tfm);
+	struct z_stream_s *stream = &dctx->decomp_stream;
+
+	pr_debug("%s: avail_in %u, avail_out %u\n", __func__, req->avail_in,
+		 req->avail_out);
+	ret = zlib_inflateReset(stream);
+	if (ret != Z_OK)
+		return -EINVAL;
+
+	return zlib_decompress_update(tfm, req);
+}
+
+static int zlib_decompress_final(struct crypto_tfm *tfm,
+				 struct comp_request *req)
+{
+	int ret;
+	struct zlib_ctx *dctx = crypto_tfm_ctx(tfm);
+	struct z_stream_s *stream = &dctx->decomp_stream;
+
+	pr_debug("%s: avail_in %u, avail_out %u\n", __func__, req->avail_in,
+		 req->avail_out);
+	stream->next_in = req->next_in;
+	stream->avail_in = req->avail_in;
+	stream->next_out = req->next_out;
+	stream->avail_out = req->avail_out;
+
+	ret = zlib_inflate(stream, Z_FINISH);
+	if (ret != Z_STREAM_END) {
+		pr_err("%s: zlib_inflate failed %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: avail_in %u, avail_out %u (consumed %u, produced %u)\n",
+		 __func__, stream->avail_in, stream->avail_out,
+		 req->avail_in - stream->avail_in,
+		 req->avail_out - stream->avail_out);
+	req->next_in = stream->next_in;
+	req->avail_in = stream->avail_in;
+	req->next_out = stream->next_out;
+	req->avail_out = stream->avail_out;
+	return 0;
+}
+
+static struct crypto_alg alg = {
+	.cra_name	= "zlib",
+	.cra_flags	= CRYPTO_ALG_TYPE_COMPRESS,
+	.cra_ctxsize	= sizeof(struct zlib_ctx),
+	.cra_module	= THIS_MODULE,
+	.cra_list	= LIST_HEAD_INIT(alg.cra_list),
+	.cra_init	= zlib_init,
+	.cra_exit	= zlib_exit,
+	.cra_u		= {
+		.compress = {
+			/* one shot */
+			.coa_compress		= zlib_compress,
+			.coa_decompress		= zlib_decompress,
+			/* partial */
+			.coa_compress_init	= zlib_compress_init,
+			.coa_compress_update	= zlib_compress_update,
+			.coa_compress_final	= zlib_compress_final,
+			.coa_decompress_init	= zlib_decompress_init,
+			.coa_decompress_update	= zlib_decompress_update,
+			.coa_decompress_final	= zlib_decompress_final
+		}
+	}
+};
+
+static int __init zlib_mod_init(void)
+{
+	return crypto_register_alg(&alg);
+}
+
+static void __exit zlib_mod_fini(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(zlib_mod_init);
+module_exit(zlib_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Zlib Compression Algorithm");
+

With kind regards,

Geert Uytterhoeven
Software Architect

Sony Techsoft Centre Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium

Phone:    +32 (0)2 700 8453
Fax:      +32 (0)2 700 8622
E-mail:   Geert.Uytterhoeven@xxxxxxxxxxx
Internet: http://www.sony-europe.com/

A division of Sony Europe (Belgium) N.V.
VAT BE 0413.825.160 · RPR Brussels
Fortis · BIC GEBABEBB · IBAN BE41293037680010
--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux