11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Cryptographic API. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Deflate algorithm (RFC 1951), implemented here primarily for use 51da177e4SLinus Torvalds * by IPCOMP (RFC 3173 & RFC 2394). 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Copyright (c) 2003 James Morris <jmorris@intercode.com.au> 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 101da177e4SLinus Torvalds * under the terms of the GNU General Public License as published by the Free 111da177e4SLinus Torvalds * Software Foundation; either version 2 of the License, or (at your option) 121da177e4SLinus Torvalds * any later version. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * FIXME: deflate transforms will require up to a total of about 436k of kernel 151da177e4SLinus Torvalds * memory on i386 (390k for compression, the rest for decompression), as the 161da177e4SLinus Torvalds * current zlib kernel code uses a worst case pre-allocation system by default. 171da177e4SLinus Torvalds * This needs to be fixed so that the amount of memory required is properly 181da177e4SLinus Torvalds * related to the winbits and memlevel parameters. 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds * The default winbits of 11 should suit most packets, and it may be something 211da177e4SLinus Torvalds * to configure on a per-tfm basis in the future. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * Currently, compression history is not maintained between tfm calls, as 241da177e4SLinus Torvalds * it is not needed for IPCOMP and keeps the code simpler. It can be 251da177e4SLinus Torvalds * implemented if someone wants it. 261da177e4SLinus Torvalds */ 271da177e4SLinus Torvalds #include <linux/init.h> 281da177e4SLinus Torvalds #include <linux/module.h> 291da177e4SLinus Torvalds #include <linux/crypto.h> 301da177e4SLinus Torvalds #include <linux/zlib.h> 311da177e4SLinus Torvalds #include <linux/vmalloc.h> 321da177e4SLinus Torvalds #include <linux/interrupt.h> 331da177e4SLinus Torvalds #include <linux/mm.h> 341da177e4SLinus Torvalds #include <linux/net.h> 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds #define DEFLATE_DEF_LEVEL Z_DEFAULT_COMPRESSION 371da177e4SLinus Torvalds #define DEFLATE_DEF_WINBITS 11 381da177e4SLinus Torvalds #define DEFLATE_DEF_MEMLEVEL MAX_MEM_LEVEL 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds struct deflate_ctx { 411da177e4SLinus Torvalds struct z_stream_s comp_stream; 421da177e4SLinus Torvalds struct z_stream_s decomp_stream; 431da177e4SLinus Torvalds }; 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds static int deflate_comp_init(struct deflate_ctx *ctx) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds int ret = 0; 481da177e4SLinus Torvalds struct z_stream_s *stream = &ctx->comp_stream; 491da177e4SLinus Torvalds 50565d76cbSJim Keniston stream->workspace = vzalloc(zlib_deflate_workspacesize( 51565d76cbSJim Keniston -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL)); 521da177e4SLinus Torvalds if (!stream->workspace) { 531da177e4SLinus Torvalds ret = -ENOMEM; 541da177e4SLinus Torvalds goto out; 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED, 571da177e4SLinus Torvalds -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL, 581da177e4SLinus Torvalds Z_DEFAULT_STRATEGY); 591da177e4SLinus Torvalds if (ret != Z_OK) { 601da177e4SLinus Torvalds ret = -EINVAL; 611da177e4SLinus Torvalds goto out_free; 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds out: 641da177e4SLinus Torvalds return ret; 651da177e4SLinus Torvalds out_free: 661da177e4SLinus Torvalds vfree(stream->workspace); 671da177e4SLinus Torvalds goto out; 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds static int deflate_decomp_init(struct deflate_ctx *ctx) 711da177e4SLinus Torvalds { 721da177e4SLinus Torvalds int ret = 0; 731da177e4SLinus Torvalds struct z_stream_s *stream = &ctx->decomp_stream; 741da177e4SLinus Torvalds 757ab24bfdSDavid S. Miller stream->workspace = vzalloc(zlib_inflate_workspacesize()); 761da177e4SLinus Torvalds if (!stream->workspace) { 771da177e4SLinus Torvalds ret = -ENOMEM; 781da177e4SLinus Torvalds goto out; 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS); 811da177e4SLinus Torvalds if (ret != Z_OK) { 821da177e4SLinus Torvalds ret = -EINVAL; 831da177e4SLinus Torvalds goto out_free; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds out: 861da177e4SLinus Torvalds return ret; 871da177e4SLinus Torvalds out_free: 887ab24bfdSDavid S. Miller vfree(stream->workspace); 891da177e4SLinus Torvalds goto out; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds static void deflate_comp_exit(struct deflate_ctx *ctx) 931da177e4SLinus Torvalds { 949ffb7146SArtem B. Bityuckiy zlib_deflateEnd(&ctx->comp_stream); 951da177e4SLinus Torvalds vfree(ctx->comp_stream.workspace); 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds static void deflate_decomp_exit(struct deflate_ctx *ctx) 991da177e4SLinus Torvalds { 1009ffb7146SArtem B. Bityuckiy zlib_inflateEnd(&ctx->decomp_stream); 1017ab24bfdSDavid S. Miller vfree(ctx->decomp_stream.workspace); 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 1046c2bb98bSHerbert Xu static int deflate_init(struct crypto_tfm *tfm) 1051da177e4SLinus Torvalds { 1066c2bb98bSHerbert Xu struct deflate_ctx *ctx = crypto_tfm_ctx(tfm); 1071da177e4SLinus Torvalds int ret; 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds ret = deflate_comp_init(ctx); 1101da177e4SLinus Torvalds if (ret) 1111da177e4SLinus Torvalds goto out; 1121da177e4SLinus Torvalds ret = deflate_decomp_init(ctx); 1131da177e4SLinus Torvalds if (ret) 1141da177e4SLinus Torvalds deflate_comp_exit(ctx); 1151da177e4SLinus Torvalds out: 1161da177e4SLinus Torvalds return ret; 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 1196c2bb98bSHerbert Xu static void deflate_exit(struct crypto_tfm *tfm) 1201da177e4SLinus Torvalds { 1216c2bb98bSHerbert Xu struct deflate_ctx *ctx = crypto_tfm_ctx(tfm); 1226c2bb98bSHerbert Xu 1231da177e4SLinus Torvalds deflate_comp_exit(ctx); 1241da177e4SLinus Torvalds deflate_decomp_exit(ctx); 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds 1276c2bb98bSHerbert Xu static int deflate_compress(struct crypto_tfm *tfm, const u8 *src, 1286c2bb98bSHerbert Xu unsigned int slen, u8 *dst, unsigned int *dlen) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds int ret = 0; 1316c2bb98bSHerbert Xu struct deflate_ctx *dctx = crypto_tfm_ctx(tfm); 1321da177e4SLinus Torvalds struct z_stream_s *stream = &dctx->comp_stream; 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds ret = zlib_deflateReset(stream); 1351da177e4SLinus Torvalds if (ret != Z_OK) { 1361da177e4SLinus Torvalds ret = -EINVAL; 1371da177e4SLinus Torvalds goto out; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds stream->next_in = (u8 *)src; 1411da177e4SLinus Torvalds stream->avail_in = slen; 1421da177e4SLinus Torvalds stream->next_out = (u8 *)dst; 1431da177e4SLinus Torvalds stream->avail_out = *dlen; 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds ret = zlib_deflate(stream, Z_FINISH); 1461da177e4SLinus Torvalds if (ret != Z_STREAM_END) { 1471da177e4SLinus Torvalds ret = -EINVAL; 1481da177e4SLinus Torvalds goto out; 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds ret = 0; 1511da177e4SLinus Torvalds *dlen = stream->total_out; 1521da177e4SLinus Torvalds out: 1531da177e4SLinus Torvalds return ret; 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1566c2bb98bSHerbert Xu static int deflate_decompress(struct crypto_tfm *tfm, const u8 *src, 1576c2bb98bSHerbert Xu unsigned int slen, u8 *dst, unsigned int *dlen) 1581da177e4SLinus Torvalds { 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds int ret = 0; 1616c2bb98bSHerbert Xu struct deflate_ctx *dctx = crypto_tfm_ctx(tfm); 1621da177e4SLinus Torvalds struct z_stream_s *stream = &dctx->decomp_stream; 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds ret = zlib_inflateReset(stream); 1651da177e4SLinus Torvalds if (ret != Z_OK) { 1661da177e4SLinus Torvalds ret = -EINVAL; 1671da177e4SLinus Torvalds goto out; 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds stream->next_in = (u8 *)src; 1711da177e4SLinus Torvalds stream->avail_in = slen; 1721da177e4SLinus Torvalds stream->next_out = (u8 *)dst; 1731da177e4SLinus Torvalds stream->avail_out = *dlen; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds ret = zlib_inflate(stream, Z_SYNC_FLUSH); 1761da177e4SLinus Torvalds /* 1771da177e4SLinus Torvalds * Work around a bug in zlib, which sometimes wants to taste an extra 1781da177e4SLinus Torvalds * byte when being used in the (undocumented) raw deflate mode. 1791da177e4SLinus Torvalds * (From USAGI). 1801da177e4SLinus Torvalds */ 1811da177e4SLinus Torvalds if (ret == Z_OK && !stream->avail_in && stream->avail_out) { 1821da177e4SLinus Torvalds u8 zerostuff = 0; 1831da177e4SLinus Torvalds stream->next_in = &zerostuff; 1841da177e4SLinus Torvalds stream->avail_in = 1; 1851da177e4SLinus Torvalds ret = zlib_inflate(stream, Z_FINISH); 1861da177e4SLinus Torvalds } 1871da177e4SLinus Torvalds if (ret != Z_STREAM_END) { 1881da177e4SLinus Torvalds ret = -EINVAL; 1891da177e4SLinus Torvalds goto out; 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds ret = 0; 1921da177e4SLinus Torvalds *dlen = stream->total_out; 1931da177e4SLinus Torvalds out: 1941da177e4SLinus Torvalds return ret; 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds static struct crypto_alg alg = { 1981da177e4SLinus Torvalds .cra_name = "deflate", 1991da177e4SLinus Torvalds .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, 2001da177e4SLinus Torvalds .cra_ctxsize = sizeof(struct deflate_ctx), 2011da177e4SLinus Torvalds .cra_module = THIS_MODULE, 202c7fc0599SHerbert Xu .cra_init = deflate_init, 203c7fc0599SHerbert Xu .cra_exit = deflate_exit, 2041da177e4SLinus Torvalds .cra_u = { .compress = { 2051da177e4SLinus Torvalds .coa_compress = deflate_compress, 2061da177e4SLinus Torvalds .coa_decompress = deflate_decompress } } 2071da177e4SLinus Torvalds }; 2081da177e4SLinus Torvalds 2093af5b90bSKamalesh Babulal static int __init deflate_mod_init(void) 2101da177e4SLinus Torvalds { 2111da177e4SLinus Torvalds return crypto_register_alg(&alg); 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 2143af5b90bSKamalesh Babulal static void __exit deflate_mod_fini(void) 2151da177e4SLinus Torvalds { 2161da177e4SLinus Torvalds crypto_unregister_alg(&alg); 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 2193af5b90bSKamalesh Babulal module_init(deflate_mod_init); 2203af5b90bSKamalesh Babulal module_exit(deflate_mod_fini); 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 2231da177e4SLinus Torvalds MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP"); 2241da177e4SLinus Torvalds MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); 225*5d26a105SKees Cook MODULE_ALIAS_CRYPTO("deflate"); 226