1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * Cryptographic API. 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Deflate algorithm (RFC 1951), implemented here primarily for use 5*1da177e4SLinus Torvalds * by IPCOMP (RFC 3173 & RFC 2394). 6*1da177e4SLinus Torvalds * 7*1da177e4SLinus Torvalds * Copyright (c) 2003 James Morris <jmorris@intercode.com.au> 8*1da177e4SLinus Torvalds * 9*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 10*1da177e4SLinus Torvalds * under the terms of the GNU General Public License as published by the Free 11*1da177e4SLinus Torvalds * Software Foundation; either version 2 of the License, or (at your option) 12*1da177e4SLinus Torvalds * any later version. 13*1da177e4SLinus Torvalds * 14*1da177e4SLinus Torvalds * FIXME: deflate transforms will require up to a total of about 436k of kernel 15*1da177e4SLinus Torvalds * memory on i386 (390k for compression, the rest for decompression), as the 16*1da177e4SLinus Torvalds * current zlib kernel code uses a worst case pre-allocation system by default. 17*1da177e4SLinus Torvalds * This needs to be fixed so that the amount of memory required is properly 18*1da177e4SLinus Torvalds * related to the winbits and memlevel parameters. 19*1da177e4SLinus Torvalds * 20*1da177e4SLinus Torvalds * The default winbits of 11 should suit most packets, and it may be something 21*1da177e4SLinus Torvalds * to configure on a per-tfm basis in the future. 22*1da177e4SLinus Torvalds * 23*1da177e4SLinus Torvalds * Currently, compression history is not maintained between tfm calls, as 24*1da177e4SLinus Torvalds * it is not needed for IPCOMP and keeps the code simpler. It can be 25*1da177e4SLinus Torvalds * implemented if someone wants it. 26*1da177e4SLinus Torvalds */ 27*1da177e4SLinus Torvalds #include <linux/init.h> 28*1da177e4SLinus Torvalds #include <linux/module.h> 29*1da177e4SLinus Torvalds #include <linux/crypto.h> 30*1da177e4SLinus Torvalds #include <linux/zlib.h> 31*1da177e4SLinus Torvalds #include <linux/vmalloc.h> 32*1da177e4SLinus Torvalds #include <linux/interrupt.h> 33*1da177e4SLinus Torvalds #include <linux/mm.h> 34*1da177e4SLinus Torvalds #include <linux/net.h> 35*1da177e4SLinus Torvalds #include <linux/slab.h> 36*1da177e4SLinus Torvalds 37*1da177e4SLinus Torvalds #define DEFLATE_DEF_LEVEL Z_DEFAULT_COMPRESSION 38*1da177e4SLinus Torvalds #define DEFLATE_DEF_WINBITS 11 39*1da177e4SLinus Torvalds #define DEFLATE_DEF_MEMLEVEL MAX_MEM_LEVEL 40*1da177e4SLinus Torvalds 41*1da177e4SLinus Torvalds struct deflate_ctx { 42*1da177e4SLinus Torvalds struct z_stream_s comp_stream; 43*1da177e4SLinus Torvalds struct z_stream_s decomp_stream; 44*1da177e4SLinus Torvalds }; 45*1da177e4SLinus Torvalds 46*1da177e4SLinus Torvalds static int deflate_comp_init(struct deflate_ctx *ctx) 47*1da177e4SLinus Torvalds { 48*1da177e4SLinus Torvalds int ret = 0; 49*1da177e4SLinus Torvalds struct z_stream_s *stream = &ctx->comp_stream; 50*1da177e4SLinus Torvalds 51*1da177e4SLinus Torvalds stream->workspace = vmalloc(zlib_deflate_workspacesize()); 52*1da177e4SLinus Torvalds if (!stream->workspace ) { 53*1da177e4SLinus Torvalds ret = -ENOMEM; 54*1da177e4SLinus Torvalds goto out; 55*1da177e4SLinus Torvalds } 56*1da177e4SLinus Torvalds memset(stream->workspace, 0, zlib_deflate_workspacesize()); 57*1da177e4SLinus Torvalds ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED, 58*1da177e4SLinus Torvalds -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL, 59*1da177e4SLinus Torvalds Z_DEFAULT_STRATEGY); 60*1da177e4SLinus Torvalds if (ret != Z_OK) { 61*1da177e4SLinus Torvalds ret = -EINVAL; 62*1da177e4SLinus Torvalds goto out_free; 63*1da177e4SLinus Torvalds } 64*1da177e4SLinus Torvalds out: 65*1da177e4SLinus Torvalds return ret; 66*1da177e4SLinus Torvalds out_free: 67*1da177e4SLinus Torvalds vfree(stream->workspace); 68*1da177e4SLinus Torvalds goto out; 69*1da177e4SLinus Torvalds } 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds static int deflate_decomp_init(struct deflate_ctx *ctx) 72*1da177e4SLinus Torvalds { 73*1da177e4SLinus Torvalds int ret = 0; 74*1da177e4SLinus Torvalds struct z_stream_s *stream = &ctx->decomp_stream; 75*1da177e4SLinus Torvalds 76*1da177e4SLinus Torvalds stream->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); 77*1da177e4SLinus Torvalds if (!stream->workspace ) { 78*1da177e4SLinus Torvalds ret = -ENOMEM; 79*1da177e4SLinus Torvalds goto out; 80*1da177e4SLinus Torvalds } 81*1da177e4SLinus Torvalds memset(stream->workspace, 0, zlib_inflate_workspacesize()); 82*1da177e4SLinus Torvalds ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS); 83*1da177e4SLinus Torvalds if (ret != Z_OK) { 84*1da177e4SLinus Torvalds ret = -EINVAL; 85*1da177e4SLinus Torvalds goto out_free; 86*1da177e4SLinus Torvalds } 87*1da177e4SLinus Torvalds out: 88*1da177e4SLinus Torvalds return ret; 89*1da177e4SLinus Torvalds out_free: 90*1da177e4SLinus Torvalds kfree(stream->workspace); 91*1da177e4SLinus Torvalds goto out; 92*1da177e4SLinus Torvalds } 93*1da177e4SLinus Torvalds 94*1da177e4SLinus Torvalds static void deflate_comp_exit(struct deflate_ctx *ctx) 95*1da177e4SLinus Torvalds { 96*1da177e4SLinus Torvalds vfree(ctx->comp_stream.workspace); 97*1da177e4SLinus Torvalds } 98*1da177e4SLinus Torvalds 99*1da177e4SLinus Torvalds static void deflate_decomp_exit(struct deflate_ctx *ctx) 100*1da177e4SLinus Torvalds { 101*1da177e4SLinus Torvalds kfree(ctx->decomp_stream.workspace); 102*1da177e4SLinus Torvalds } 103*1da177e4SLinus Torvalds 104*1da177e4SLinus Torvalds static int deflate_init(void *ctx) 105*1da177e4SLinus Torvalds { 106*1da177e4SLinus Torvalds int ret; 107*1da177e4SLinus Torvalds 108*1da177e4SLinus Torvalds ret = deflate_comp_init(ctx); 109*1da177e4SLinus Torvalds if (ret) 110*1da177e4SLinus Torvalds goto out; 111*1da177e4SLinus Torvalds ret = deflate_decomp_init(ctx); 112*1da177e4SLinus Torvalds if (ret) 113*1da177e4SLinus Torvalds deflate_comp_exit(ctx); 114*1da177e4SLinus Torvalds out: 115*1da177e4SLinus Torvalds return ret; 116*1da177e4SLinus Torvalds } 117*1da177e4SLinus Torvalds 118*1da177e4SLinus Torvalds static void deflate_exit(void *ctx) 119*1da177e4SLinus Torvalds { 120*1da177e4SLinus Torvalds deflate_comp_exit(ctx); 121*1da177e4SLinus Torvalds deflate_decomp_exit(ctx); 122*1da177e4SLinus Torvalds } 123*1da177e4SLinus Torvalds 124*1da177e4SLinus Torvalds static int deflate_compress(void *ctx, const u8 *src, unsigned int slen, 125*1da177e4SLinus Torvalds u8 *dst, unsigned int *dlen) 126*1da177e4SLinus Torvalds { 127*1da177e4SLinus Torvalds int ret = 0; 128*1da177e4SLinus Torvalds struct deflate_ctx *dctx = ctx; 129*1da177e4SLinus Torvalds struct z_stream_s *stream = &dctx->comp_stream; 130*1da177e4SLinus Torvalds 131*1da177e4SLinus Torvalds ret = zlib_deflateReset(stream); 132*1da177e4SLinus Torvalds if (ret != Z_OK) { 133*1da177e4SLinus Torvalds ret = -EINVAL; 134*1da177e4SLinus Torvalds goto out; 135*1da177e4SLinus Torvalds } 136*1da177e4SLinus Torvalds 137*1da177e4SLinus Torvalds stream->next_in = (u8 *)src; 138*1da177e4SLinus Torvalds stream->avail_in = slen; 139*1da177e4SLinus Torvalds stream->next_out = (u8 *)dst; 140*1da177e4SLinus Torvalds stream->avail_out = *dlen; 141*1da177e4SLinus Torvalds 142*1da177e4SLinus Torvalds ret = zlib_deflate(stream, Z_FINISH); 143*1da177e4SLinus Torvalds if (ret != Z_STREAM_END) { 144*1da177e4SLinus Torvalds ret = -EINVAL; 145*1da177e4SLinus Torvalds goto out; 146*1da177e4SLinus Torvalds } 147*1da177e4SLinus Torvalds ret = 0; 148*1da177e4SLinus Torvalds *dlen = stream->total_out; 149*1da177e4SLinus Torvalds out: 150*1da177e4SLinus Torvalds return ret; 151*1da177e4SLinus Torvalds } 152*1da177e4SLinus Torvalds 153*1da177e4SLinus Torvalds static int deflate_decompress(void *ctx, const u8 *src, unsigned int slen, 154*1da177e4SLinus Torvalds u8 *dst, unsigned int *dlen) 155*1da177e4SLinus Torvalds { 156*1da177e4SLinus Torvalds 157*1da177e4SLinus Torvalds int ret = 0; 158*1da177e4SLinus Torvalds struct deflate_ctx *dctx = ctx; 159*1da177e4SLinus Torvalds struct z_stream_s *stream = &dctx->decomp_stream; 160*1da177e4SLinus Torvalds 161*1da177e4SLinus Torvalds ret = zlib_inflateReset(stream); 162*1da177e4SLinus Torvalds if (ret != Z_OK) { 163*1da177e4SLinus Torvalds ret = -EINVAL; 164*1da177e4SLinus Torvalds goto out; 165*1da177e4SLinus Torvalds } 166*1da177e4SLinus Torvalds 167*1da177e4SLinus Torvalds stream->next_in = (u8 *)src; 168*1da177e4SLinus Torvalds stream->avail_in = slen; 169*1da177e4SLinus Torvalds stream->next_out = (u8 *)dst; 170*1da177e4SLinus Torvalds stream->avail_out = *dlen; 171*1da177e4SLinus Torvalds 172*1da177e4SLinus Torvalds ret = zlib_inflate(stream, Z_SYNC_FLUSH); 173*1da177e4SLinus Torvalds /* 174*1da177e4SLinus Torvalds * Work around a bug in zlib, which sometimes wants to taste an extra 175*1da177e4SLinus Torvalds * byte when being used in the (undocumented) raw deflate mode. 176*1da177e4SLinus Torvalds * (From USAGI). 177*1da177e4SLinus Torvalds */ 178*1da177e4SLinus Torvalds if (ret == Z_OK && !stream->avail_in && stream->avail_out) { 179*1da177e4SLinus Torvalds u8 zerostuff = 0; 180*1da177e4SLinus Torvalds stream->next_in = &zerostuff; 181*1da177e4SLinus Torvalds stream->avail_in = 1; 182*1da177e4SLinus Torvalds ret = zlib_inflate(stream, Z_FINISH); 183*1da177e4SLinus Torvalds } 184*1da177e4SLinus Torvalds if (ret != Z_STREAM_END) { 185*1da177e4SLinus Torvalds ret = -EINVAL; 186*1da177e4SLinus Torvalds goto out; 187*1da177e4SLinus Torvalds } 188*1da177e4SLinus Torvalds ret = 0; 189*1da177e4SLinus Torvalds *dlen = stream->total_out; 190*1da177e4SLinus Torvalds out: 191*1da177e4SLinus Torvalds return ret; 192*1da177e4SLinus Torvalds } 193*1da177e4SLinus Torvalds 194*1da177e4SLinus Torvalds static struct crypto_alg alg = { 195*1da177e4SLinus Torvalds .cra_name = "deflate", 196*1da177e4SLinus Torvalds .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, 197*1da177e4SLinus Torvalds .cra_ctxsize = sizeof(struct deflate_ctx), 198*1da177e4SLinus Torvalds .cra_module = THIS_MODULE, 199*1da177e4SLinus Torvalds .cra_list = LIST_HEAD_INIT(alg.cra_list), 200*1da177e4SLinus Torvalds .cra_u = { .compress = { 201*1da177e4SLinus Torvalds .coa_init = deflate_init, 202*1da177e4SLinus Torvalds .coa_exit = deflate_exit, 203*1da177e4SLinus Torvalds .coa_compress = deflate_compress, 204*1da177e4SLinus Torvalds .coa_decompress = deflate_decompress } } 205*1da177e4SLinus Torvalds }; 206*1da177e4SLinus Torvalds 207*1da177e4SLinus Torvalds static int __init init(void) 208*1da177e4SLinus Torvalds { 209*1da177e4SLinus Torvalds return crypto_register_alg(&alg); 210*1da177e4SLinus Torvalds } 211*1da177e4SLinus Torvalds 212*1da177e4SLinus Torvalds static void __exit fini(void) 213*1da177e4SLinus Torvalds { 214*1da177e4SLinus Torvalds crypto_unregister_alg(&alg); 215*1da177e4SLinus Torvalds } 216*1da177e4SLinus Torvalds 217*1da177e4SLinus Torvalds module_init(init); 218*1da177e4SLinus Torvalds module_exit(fini); 219*1da177e4SLinus Torvalds 220*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 221*1da177e4SLinus Torvalds MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP"); 222*1da177e4SLinus Torvalds MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); 223*1da177e4SLinus Torvalds 224