Commit bf68e65ec9ea61e32ab71bef59aa5d24d255241f

Authored by Geert Uytterhoeven
Committed by Herbert Xu
1 parent 8064efb874

crypto: zlib - New zlib crypto module, using pcomp

Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Cc: James Morris <jmorris@namei.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Showing 4 changed files with 408 additions and 0 deletions Side-by-side Diff

... ... @@ -748,6 +748,15 @@
748 748  
749 749 You will most probably want this if using IPSec.
750 750  
  751 +config CRYPTO_ZLIB
  752 + tristate "Zlib compression algorithm"
  753 + select CRYPTO_PCOMP
  754 + select ZLIB_INFLATE
  755 + select ZLIB_DEFLATE
  756 + select NLATTR
  757 + help
  758 + This is the zlib algorithm.
  759 +
751 760 config CRYPTO_LZO
752 761 tristate "LZO compression algorithm"
753 762 select CRYPTO_ALGAPI
... ... @@ -74,6 +74,7 @@
74 74 obj-$(CONFIG_CRYPTO_SEED) += seed.o
75 75 obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
76 76 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
  77 +obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
77 78 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
78 79 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
79 80 obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
  1 +/*
  2 + * Cryptographic API.
  3 + *
  4 + * Zlib algorithm
  5 + *
  6 + * Copyright 2008 Sony Corporation
  7 + *
  8 + * Based on deflate.c, which is
  9 + * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
  10 + *
  11 + * This program is free software; you can redistribute it and/or modify it
  12 + * under the terms of the GNU General Public License as published by the Free
  13 + * Software Foundation; either version 2 of the License, or (at your option)
  14 + * any later version.
  15 + *
  16 + * FIXME: deflate transforms will require up to a total of about 436k of kernel
  17 + * memory on i386 (390k for compression, the rest for decompression), as the
  18 + * current zlib kernel code uses a worst case pre-allocation system by default.
  19 + * This needs to be fixed so that the amount of memory required is properly
  20 + * related to the winbits and memlevel parameters.
  21 + */
  22 +
  23 +#define pr_fmt(fmt) "%s: " fmt, __func__
  24 +
  25 +#include <linux/init.h>
  26 +#include <linux/module.h>
  27 +#include <linux/zlib.h>
  28 +#include <linux/vmalloc.h>
  29 +#include <linux/interrupt.h>
  30 +#include <linux/mm.h>
  31 +#include <linux/net.h>
  32 +#include <linux/slab.h>
  33 +
  34 +#include <crypto/internal/compress.h>
  35 +
  36 +#include <net/netlink.h>
  37 +
  38 +
  39 +struct zlib_ctx {
  40 + struct z_stream_s comp_stream;
  41 + struct z_stream_s decomp_stream;
  42 + int decomp_windowBits;
  43 +};
  44 +
  45 +
  46 +static void zlib_comp_exit(struct zlib_ctx *ctx)
  47 +{
  48 + struct z_stream_s *stream = &ctx->comp_stream;
  49 +
  50 + if (stream->workspace) {
  51 + zlib_deflateEnd(stream);
  52 + vfree(stream->workspace);
  53 + stream->workspace = NULL;
  54 + }
  55 +}
  56 +
  57 +static void zlib_decomp_exit(struct zlib_ctx *ctx)
  58 +{
  59 + struct z_stream_s *stream = &ctx->decomp_stream;
  60 +
  61 + if (stream->workspace) {
  62 + zlib_inflateEnd(stream);
  63 + kfree(stream->workspace);
  64 + stream->workspace = NULL;
  65 + }
  66 +}
  67 +
  68 +static int zlib_init(struct crypto_tfm *tfm)
  69 +{
  70 + return 0;
  71 +}
  72 +
  73 +static void zlib_exit(struct crypto_tfm *tfm)
  74 +{
  75 + struct zlib_ctx *ctx = crypto_tfm_ctx(tfm);
  76 +
  77 + zlib_comp_exit(ctx);
  78 + zlib_decomp_exit(ctx);
  79 +}
  80 +
  81 +
  82 +static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
  83 + unsigned int len)
  84 +{
  85 + struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
  86 + struct z_stream_s *stream = &ctx->comp_stream;
  87 + struct nlattr *tb[ZLIB_COMP_MAX + 1];
  88 + size_t workspacesize;
  89 + int ret;
  90 +
  91 + ret = nla_parse(tb, ZLIB_COMP_MAX, params, len, NULL);
  92 + if (ret)
  93 + return ret;
  94 +
  95 + zlib_comp_exit(ctx);
  96 +
  97 + workspacesize = zlib_deflate_workspacesize();
  98 + stream->workspace = vmalloc(workspacesize);
  99 + if (!stream->workspace)
  100 + return -ENOMEM;
  101 +
  102 + memset(stream->workspace, 0, workspacesize);
  103 + ret = zlib_deflateInit2(stream,
  104 + tb[ZLIB_COMP_LEVEL]
  105 + ? nla_get_u32(tb[ZLIB_COMP_LEVEL])
  106 + : Z_DEFAULT_COMPRESSION,
  107 + tb[ZLIB_COMP_METHOD]
  108 + ? nla_get_u32(tb[ZLIB_COMP_METHOD])
  109 + : Z_DEFLATED,
  110 + tb[ZLIB_COMP_WINDOWBITS]
  111 + ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
  112 + : MAX_WBITS,
  113 + tb[ZLIB_COMP_MEMLEVEL]
  114 + ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
  115 + : DEF_MEM_LEVEL,
  116 + tb[ZLIB_COMP_STRATEGY]
  117 + ? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
  118 + : Z_DEFAULT_STRATEGY);
  119 + if (ret != Z_OK) {
  120 + vfree(stream->workspace);
  121 + stream->workspace = NULL;
  122 + return -EINVAL;
  123 + }
  124 +
  125 + return 0;
  126 +}
  127 +
  128 +static int zlib_compress_init(struct crypto_pcomp *tfm)
  129 +{
  130 + int ret;
  131 + struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
  132 + struct z_stream_s *stream = &dctx->comp_stream;
  133 +
  134 + ret = zlib_deflateReset(stream);
  135 + if (ret != Z_OK)
  136 + return -EINVAL;
  137 +
  138 + return 0;
  139 +}
  140 +
  141 +static int zlib_compress_update(struct crypto_pcomp *tfm,
  142 + struct comp_request *req)
  143 +{
  144 + int ret;
  145 + struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
  146 + struct z_stream_s *stream = &dctx->comp_stream;
  147 +
  148 + pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
  149 + stream->next_in = req->next_in;
  150 + stream->avail_in = req->avail_in;
  151 + stream->next_out = req->next_out;
  152 + stream->avail_out = req->avail_out;
  153 +
  154 + ret = zlib_deflate(stream, Z_NO_FLUSH);
  155 + switch (ret) {
  156 + case Z_OK:
  157 + break;
  158 +
  159 + case Z_BUF_ERROR:
  160 + pr_debug("zlib_deflate could not make progress\n");
  161 + return -EAGAIN;
  162 +
  163 + default:
  164 + pr_debug("zlib_deflate failed %d\n", ret);
  165 + return -EINVAL;
  166 + }
  167 +
  168 + pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
  169 + stream->avail_in, stream->avail_out,
  170 + req->avail_in - stream->avail_in,
  171 + req->avail_out - stream->avail_out);
  172 + req->next_in = stream->next_in;
  173 + req->avail_in = stream->avail_in;
  174 + req->next_out = stream->next_out;
  175 + req->avail_out = stream->avail_out;
  176 + return 0;
  177 +}
  178 +
  179 +static int zlib_compress_final(struct crypto_pcomp *tfm,
  180 + struct comp_request *req)
  181 +{
  182 + int ret;
  183 + struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
  184 + struct z_stream_s *stream = &dctx->comp_stream;
  185 +
  186 + pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
  187 + stream->next_in = req->next_in;
  188 + stream->avail_in = req->avail_in;
  189 + stream->next_out = req->next_out;
  190 + stream->avail_out = req->avail_out;
  191 +
  192 + ret = zlib_deflate(stream, Z_FINISH);
  193 + if (ret != Z_STREAM_END) {
  194 + pr_debug("zlib_deflate failed %d\n", ret);
  195 + return -EINVAL;
  196 + }
  197 +
  198 + pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
  199 + stream->avail_in, stream->avail_out,
  200 + req->avail_in - stream->avail_in,
  201 + req->avail_out - stream->avail_out);
  202 + req->next_in = stream->next_in;
  203 + req->avail_in = stream->avail_in;
  204 + req->next_out = stream->next_out;
  205 + req->avail_out = stream->avail_out;
  206 + return 0;
  207 +}
  208 +
  209 +
  210 +static int zlib_decompress_setup(struct crypto_pcomp *tfm, void *params,
  211 + unsigned int len)
  212 +{
  213 + struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
  214 + struct z_stream_s *stream = &ctx->decomp_stream;
  215 + struct nlattr *tb[ZLIB_DECOMP_MAX + 1];
  216 + int ret = 0;
  217 +
  218 + ret = nla_parse(tb, ZLIB_DECOMP_MAX, params, len, NULL);
  219 + if (ret)
  220 + return ret;
  221 +
  222 + zlib_decomp_exit(ctx);
  223 +
  224 + ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS]
  225 + ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS])
  226 + : DEF_WBITS;
  227 +
  228 + stream->workspace = kzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
  229 + if (!stream->workspace)
  230 + return -ENOMEM;
  231 +
  232 + ret = zlib_inflateInit2(stream, ctx->decomp_windowBits);
  233 + if (ret != Z_OK) {
  234 + kfree(stream->workspace);
  235 + stream->workspace = NULL;
  236 + return -EINVAL;
  237 + }
  238 +
  239 + return 0;
  240 +}
  241 +
  242 +static int zlib_decompress_init(struct crypto_pcomp *tfm)
  243 +{
  244 + int ret;
  245 + struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
  246 + struct z_stream_s *stream = &dctx->decomp_stream;
  247 +
  248 + ret = zlib_inflateReset(stream);
  249 + if (ret != Z_OK)
  250 + return -EINVAL;
  251 +
  252 + return 0;
  253 +}
  254 +
  255 +static int zlib_decompress_update(struct crypto_pcomp *tfm,
  256 + struct comp_request *req)
  257 +{
  258 + int ret;
  259 + struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
  260 + struct z_stream_s *stream = &dctx->decomp_stream;
  261 +
  262 + pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
  263 + stream->next_in = req->next_in;
  264 + stream->avail_in = req->avail_in;
  265 + stream->next_out = req->next_out;
  266 + stream->avail_out = req->avail_out;
  267 +
  268 + ret = zlib_inflate(stream, Z_SYNC_FLUSH);
  269 + switch (ret) {
  270 + case Z_OK:
  271 + case Z_STREAM_END:
  272 + break;
  273 +
  274 + case Z_BUF_ERROR:
  275 + pr_debug("zlib_inflate could not make progress\n");
  276 + return -EAGAIN;
  277 +
  278 + default:
  279 + pr_debug("zlib_inflate failed %d\n", ret);
  280 + return -EINVAL;
  281 + }
  282 +
  283 + pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
  284 + stream->avail_in, stream->avail_out,
  285 + req->avail_in - stream->avail_in,
  286 + req->avail_out - stream->avail_out);
  287 + req->next_in = stream->next_in;
  288 + req->avail_in = stream->avail_in;
  289 + req->next_out = stream->next_out;
  290 + req->avail_out = stream->avail_out;
  291 + return 0;
  292 +}
  293 +
  294 +static int zlib_decompress_final(struct crypto_pcomp *tfm,
  295 + struct comp_request *req)
  296 +{
  297 + int ret;
  298 + struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
  299 + struct z_stream_s *stream = &dctx->decomp_stream;
  300 +
  301 + pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
  302 + stream->next_in = req->next_in;
  303 + stream->avail_in = req->avail_in;
  304 + stream->next_out = req->next_out;
  305 + stream->avail_out = req->avail_out;
  306 +
  307 + if (dctx->decomp_windowBits < 0) {
  308 + ret = zlib_inflate(stream, Z_SYNC_FLUSH);
  309 + /*
  310 + * Work around a bug in zlib, which sometimes wants to taste an
  311 + * extra byte when being used in the (undocumented) raw deflate
  312 + * mode. (From USAGI).
  313 + */
  314 + if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
  315 + const void *saved_next_in = stream->next_in;
  316 + u8 zerostuff = 0;
  317 +
  318 + stream->next_in = &zerostuff;
  319 + stream->avail_in = 1;
  320 + ret = zlib_inflate(stream, Z_FINISH);
  321 + stream->next_in = saved_next_in;
  322 + stream->avail_in = 0;
  323 + }
  324 + } else
  325 + ret = zlib_inflate(stream, Z_FINISH);
  326 + if (ret != Z_STREAM_END) {
  327 + pr_debug("zlib_inflate failed %d\n", ret);
  328 + return -EINVAL;
  329 + }
  330 +
  331 + pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
  332 + stream->avail_in, stream->avail_out,
  333 + req->avail_in - stream->avail_in,
  334 + req->avail_out - stream->avail_out);
  335 + req->next_in = stream->next_in;
  336 + req->avail_in = stream->avail_in;
  337 + req->next_out = stream->next_out;
  338 + req->avail_out = stream->avail_out;
  339 + return 0;
  340 +}
  341 +
  342 +
  343 +static struct pcomp_alg zlib_alg = {
  344 + .compress_setup = zlib_compress_setup,
  345 + .compress_init = zlib_compress_init,
  346 + .compress_update = zlib_compress_update,
  347 + .compress_final = zlib_compress_final,
  348 + .decompress_setup = zlib_decompress_setup,
  349 + .decompress_init = zlib_decompress_init,
  350 + .decompress_update = zlib_decompress_update,
  351 + .decompress_final = zlib_decompress_final,
  352 +
  353 + .base = {
  354 + .cra_name = "zlib",
  355 + .cra_flags = CRYPTO_ALG_TYPE_PCOMPRESS,
  356 + .cra_ctxsize = sizeof(struct zlib_ctx),
  357 + .cra_module = THIS_MODULE,
  358 + .cra_init = zlib_init,
  359 + .cra_exit = zlib_exit,
  360 + }
  361 +};
  362 +
  363 +static int __init zlib_mod_init(void)
  364 +{
  365 + return crypto_register_pcomp(&zlib_alg);
  366 +}
  367 +
  368 +static void __exit zlib_mod_fini(void)
  369 +{
  370 + crypto_unregister_pcomp(&zlib_alg);
  371 +}
  372 +
  373 +module_init(zlib_mod_init);
  374 +module_exit(zlib_mod_fini);
  375 +
  376 +MODULE_LICENSE("GPL");
  377 +MODULE_DESCRIPTION("Zlib Compression Algorithm");
  378 +MODULE_AUTHOR("Sony Corporation");
include/crypto/compress.h
... ... @@ -30,6 +30,26 @@
30 30 unsigned int avail_out; /* bytes available at next_out */
31 31 };
32 32  
  33 +enum zlib_comp_params {
  34 + ZLIB_COMP_LEVEL = 1, /* e.g. Z_DEFAULT_COMPRESSION */
  35 + ZLIB_COMP_METHOD, /* e.g. Z_DEFLATED */
  36 + ZLIB_COMP_WINDOWBITS, /* e.g. MAX_WBITS */
  37 + ZLIB_COMP_MEMLEVEL, /* e.g. DEF_MEM_LEVEL */
  38 + ZLIB_COMP_STRATEGY, /* e.g. Z_DEFAULT_STRATEGY */
  39 + __ZLIB_COMP_MAX,
  40 +};
  41 +
  42 +#define ZLIB_COMP_MAX (__ZLIB_COMP_MAX - 1)
  43 +
  44 +
  45 +enum zlib_decomp_params {
  46 + ZLIB_DECOMP_WINDOWBITS = 1, /* e.g. DEF_WBITS */
  47 + __ZLIB_DECOMP_MAX,
  48 +};
  49 +
  50 +#define ZLIB_DECOMP_MAX (__ZLIB_DECOMP_MAX - 1)
  51 +
  52 +
33 53 struct crypto_pcomp {
34 54 struct crypto_tfm base;
35 55 };