linux/crypto/deflate.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Cryptographic API.
   4 *
   5 * Deflate algorithm (RFC 1951), implemented here primarily for use
   6 * by IPCOMP (RFC 3173 & RFC 2394).
   7 *
   8 * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
   9 *
  10 * FIXME: deflate transforms will require up to a total of about 436k of kernel
  11 * memory on i386 (390k for compression, the rest for decompression), as the
  12 * current zlib kernel code uses a worst case pre-allocation system by default.
  13 * This needs to be fixed so that the amount of memory required is properly
  14 * related to the  winbits and memlevel parameters.
  15 *
  16 * The default winbits of 11 should suit most packets, and it may be something
  17 * to configure on a per-tfm basis in the future.
  18 *
  19 * Currently, compression history is not maintained between tfm calls, as
  20 * it is not needed for IPCOMP and keeps the code simpler.  It can be
  21 * implemented if someone wants it.
  22 */
  23#include <linux/init.h>
  24#include <linux/module.h>
  25#include <linux/crypto.h>
  26#include <linux/zlib.h>
  27#include <linux/vmalloc.h>
  28#include <linux/interrupt.h>
  29#include <linux/mm.h>
  30#include <linux/net.h>
  31#include <crypto/internal/scompress.h>
  32
  33#define DEFLATE_DEF_LEVEL               Z_DEFAULT_COMPRESSION
  34#define DEFLATE_DEF_WINBITS             11
  35#define DEFLATE_DEF_MEMLEVEL            MAX_MEM_LEVEL
  36
  37struct deflate_ctx {
  38        struct z_stream_s comp_stream;
  39        struct z_stream_s decomp_stream;
  40};
  41
  42static int deflate_comp_init(struct deflate_ctx *ctx)
  43{
  44        int ret = 0;
  45        struct z_stream_s *stream = &ctx->comp_stream;
  46
  47        stream->workspace = vzalloc(zlib_deflate_workspacesize(
  48                                    -DEFLATE_DEF_WINBITS, MAX_MEM_LEVEL));
  49        if (!stream->workspace) {
  50                ret = -ENOMEM;
  51                goto out;
  52        }
  53        ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED,
  54                                -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL,
  55                                Z_DEFAULT_STRATEGY);
  56        if (ret != Z_OK) {
  57                ret = -EINVAL;
  58                goto out_free;
  59        }
  60out:
  61        return ret;
  62out_free:
  63        vfree(stream->workspace);
  64        goto out;
  65}
  66
  67static int deflate_decomp_init(struct deflate_ctx *ctx)
  68{
  69        int ret = 0;
  70        struct z_stream_s *stream = &ctx->decomp_stream;
  71
  72        stream->workspace = vzalloc(zlib_inflate_workspacesize());
  73        if (!stream->workspace) {
  74                ret = -ENOMEM;
  75                goto out;
  76        }
  77        ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS);
  78        if (ret != Z_OK) {
  79                ret = -EINVAL;
  80                goto out_free;
  81        }
  82out:
  83        return ret;
  84out_free:
  85        vfree(stream->workspace);
  86        goto out;
  87}
  88
  89static void deflate_comp_exit(struct deflate_ctx *ctx)
  90{
  91        zlib_deflateEnd(&ctx->comp_stream);
  92        vfree(ctx->comp_stream.workspace);
  93}
  94
  95static void deflate_decomp_exit(struct deflate_ctx *ctx)
  96{
  97        zlib_inflateEnd(&ctx->decomp_stream);
  98        vfree(ctx->decomp_stream.workspace);
  99}
 100
 101static int __deflate_init(void *ctx)
 102{
 103        int ret;
 104
 105        ret = deflate_comp_init(ctx);
 106        if (ret)
 107                goto out;
 108        ret = deflate_decomp_init(ctx);
 109        if (ret)
 110                deflate_comp_exit(ctx);
 111out:
 112        return ret;
 113}
 114
 115static void *deflate_alloc_ctx(struct crypto_scomp *tfm)
 116{
 117        struct deflate_ctx *ctx;
 118        int ret;
 119
 120        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 121        if (!ctx)
 122                return ERR_PTR(-ENOMEM);
 123
 124        ret = __deflate_init(ctx);
 125        if (ret) {
 126                kfree(ctx);
 127                return ERR_PTR(ret);
 128        }
 129
 130        return ctx;
 131}
 132
 133static int deflate_init(struct crypto_tfm *tfm)
 134{
 135        struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
 136
 137        return __deflate_init(ctx);
 138}
 139
 140static void __deflate_exit(void *ctx)
 141{
 142        deflate_comp_exit(ctx);
 143        deflate_decomp_exit(ctx);
 144}
 145
 146static void deflate_free_ctx(struct crypto_scomp *tfm, void *ctx)
 147{
 148        __deflate_exit(ctx);
 149        kfree_sensitive(ctx);
 150}
 151
 152static void deflate_exit(struct crypto_tfm *tfm)
 153{
 154        struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
 155
 156        __deflate_exit(ctx);
 157}
 158
 159static int __deflate_compress(const u8 *src, unsigned int slen,
 160                              u8 *dst, unsigned int *dlen, void *ctx)
 161{
 162        int ret = 0;
 163        struct deflate_ctx *dctx = ctx;
 164        struct z_stream_s *stream = &dctx->comp_stream;
 165
 166        ret = zlib_deflateReset(stream);
 167        if (ret != Z_OK) {
 168                ret = -EINVAL;
 169                goto out;
 170        }
 171
 172        stream->next_in = (u8 *)src;
 173        stream->avail_in = slen;
 174        stream->next_out = (u8 *)dst;
 175        stream->avail_out = *dlen;
 176
 177        ret = zlib_deflate(stream, Z_FINISH);
 178        if (ret != Z_STREAM_END) {
 179                ret = -EINVAL;
 180                goto out;
 181        }
 182        ret = 0;
 183        *dlen = stream->total_out;
 184out:
 185        return ret;
 186}
 187
 188static int deflate_compress(struct crypto_tfm *tfm, const u8 *src,
 189                            unsigned int slen, u8 *dst, unsigned int *dlen)
 190{
 191        struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
 192
 193        return __deflate_compress(src, slen, dst, dlen, dctx);
 194}
 195
 196static int deflate_scompress(struct crypto_scomp *tfm, const u8 *src,
 197                             unsigned int slen, u8 *dst, unsigned int *dlen,
 198                             void *ctx)
 199{
 200        return __deflate_compress(src, slen, dst, dlen, ctx);
 201}
 202
 203static int __deflate_decompress(const u8 *src, unsigned int slen,
 204                                u8 *dst, unsigned int *dlen, void *ctx)
 205{
 206
 207        int ret = 0;
 208        struct deflate_ctx *dctx = ctx;
 209        struct z_stream_s *stream = &dctx->decomp_stream;
 210
 211        ret = zlib_inflateReset(stream);
 212        if (ret != Z_OK) {
 213                ret = -EINVAL;
 214                goto out;
 215        }
 216
 217        stream->next_in = (u8 *)src;
 218        stream->avail_in = slen;
 219        stream->next_out = (u8 *)dst;
 220        stream->avail_out = *dlen;
 221
 222        ret = zlib_inflate(stream, Z_SYNC_FLUSH);
 223        /*
 224         * Work around a bug in zlib, which sometimes wants to taste an extra
 225         * byte when being used in the (undocumented) raw deflate mode.
 226         * (From USAGI).
 227         */
 228        if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
 229                u8 zerostuff = 0;
 230                stream->next_in = &zerostuff;
 231                stream->avail_in = 1;
 232                ret = zlib_inflate(stream, Z_FINISH);
 233        }
 234        if (ret != Z_STREAM_END) {
 235                ret = -EINVAL;
 236                goto out;
 237        }
 238        ret = 0;
 239        *dlen = stream->total_out;
 240out:
 241        return ret;
 242}
 243
 244static int deflate_decompress(struct crypto_tfm *tfm, const u8 *src,
 245                              unsigned int slen, u8 *dst, unsigned int *dlen)
 246{
 247        struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
 248
 249        return __deflate_decompress(src, slen, dst, dlen, dctx);
 250}
 251
 252static int deflate_sdecompress(struct crypto_scomp *tfm, const u8 *src,
 253                               unsigned int slen, u8 *dst, unsigned int *dlen,
 254                               void *ctx)
 255{
 256        return __deflate_decompress(src, slen, dst, dlen, ctx);
 257}
 258
 259static struct crypto_alg alg = {
 260        .cra_name               = "deflate",
 261        .cra_driver_name        = "deflate-generic",
 262        .cra_flags              = CRYPTO_ALG_TYPE_COMPRESS,
 263        .cra_ctxsize            = sizeof(struct deflate_ctx),
 264        .cra_module             = THIS_MODULE,
 265        .cra_init               = deflate_init,
 266        .cra_exit               = deflate_exit,
 267        .cra_u                  = { .compress = {
 268        .coa_compress           = deflate_compress,
 269        .coa_decompress         = deflate_decompress } }
 270};
 271
 272static struct scomp_alg scomp = {
 273        .alloc_ctx              = deflate_alloc_ctx,
 274        .free_ctx               = deflate_free_ctx,
 275        .compress               = deflate_scompress,
 276        .decompress             = deflate_sdecompress,
 277        .base                   = {
 278                .cra_name       = "deflate",
 279                .cra_driver_name = "deflate-scomp",
 280                .cra_module      = THIS_MODULE,
 281        }
 282};
 283
 284static int __init deflate_mod_init(void)
 285{
 286        int ret;
 287
 288        ret = crypto_register_alg(&alg);
 289        if (ret)
 290                return ret;
 291
 292        ret = crypto_register_scomp(&scomp);
 293        if (ret) {
 294                crypto_unregister_alg(&alg);
 295                return ret;
 296        }
 297
 298        return ret;
 299}
 300
 301static void __exit deflate_mod_fini(void)
 302{
 303        crypto_unregister_alg(&alg);
 304        crypto_unregister_scomp(&scomp);
 305}
 306
 307subsys_initcall(deflate_mod_init);
 308module_exit(deflate_mod_fini);
 309
 310MODULE_LICENSE("GPL");
 311MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP");
 312MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
 313MODULE_ALIAS_CRYPTO("deflate");
 314