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 <[EMAIL PROTECTED]>
---
 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 <[EMAIL PROTECTED]>
+ * 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:   [EMAIL PROTECTED]
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 [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to