Blame view

crypto/deflate.c 7.86 KB
9472d763b   Richard Hartmann   crypto: deflate -...
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
   * Cryptographic API.
   *
   * Deflate algorithm (RFC 1951), implemented here primarily for use
   * by IPCOMP (RFC 3173 & RFC 2394).
   *
   * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
9472d763b   Richard Hartmann   crypto: deflate -...
8
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
   * 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
9472d763b   Richard Hartmann   crypto: deflate -...
11
   * Software Foundation; either version 2 of the License, or (at your option)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   * 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.
   *
   * The default winbits of 11 should suit most packets, and it may be something
   * to configure on a per-tfm basis in the future.
   *
   * Currently, compression history is not maintained between tfm calls, as
   * it is not needed for IPCOMP and keeps the code simpler.  It can be
   * implemented if someone wants it.
   */
  #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>
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
35
  #include <crypto/internal/scompress.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
41
42
43
44
  
  #define DEFLATE_DEF_LEVEL		Z_DEFAULT_COMPRESSION
  #define DEFLATE_DEF_WINBITS		11
  #define DEFLATE_DEF_MEMLEVEL		MAX_MEM_LEVEL
  
  struct deflate_ctx {
  	struct z_stream_s comp_stream;
  	struct z_stream_s decomp_stream;
  };
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
45
  static int deflate_comp_init(struct deflate_ctx *ctx, int format)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
  {
  	int ret = 0;
  	struct z_stream_s *stream = &ctx->comp_stream;
565d76cb7   Jim Keniston   zlib: slim down z...
49
  	stream->workspace = vzalloc(zlib_deflate_workspacesize(
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
50
  				    MAX_WBITS, MAX_MEM_LEVEL));
9472d763b   Richard Hartmann   crypto: deflate -...
51
  	if (!stream->workspace) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
  		ret = -ENOMEM;
  		goto out;
  	}
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
55
56
57
58
59
60
61
  	if (format)
  		ret = zlib_deflateInit(stream, 3);
  	else
  		ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED,
  					-DEFLATE_DEF_WINBITS,
  					DEFLATE_DEF_MEMLEVEL,
  					Z_DEFAULT_STRATEGY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
  	if (ret != Z_OK) {
  		ret = -EINVAL;
  		goto out_free;
  	}
9472d763b   Richard Hartmann   crypto: deflate -...
66
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
  	return ret;
  out_free:
  	vfree(stream->workspace);
  	goto out;
  }
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
72
  static int deflate_decomp_init(struct deflate_ctx *ctx, int format)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
  {
  	int ret = 0;
  	struct z_stream_s *stream = &ctx->decomp_stream;
7ab24bfdf   David S. Miller   net+crypto: Use v...
76
  	stream->workspace = vzalloc(zlib_inflate_workspacesize());
9472d763b   Richard Hartmann   crypto: deflate -...
77
  	if (!stream->workspace) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
  		ret = -ENOMEM;
  		goto out;
  	}
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
81
82
83
84
  	if (format)
  		ret = zlib_inflateInit(stream);
  	else
  		ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
88
89
90
91
  	if (ret != Z_OK) {
  		ret = -EINVAL;
  		goto out_free;
  	}
  out:
  	return ret;
  out_free:
7ab24bfdf   David S. Miller   net+crypto: Use v...
92
  	vfree(stream->workspace);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
96
97
  	goto out;
  }
  
  static void deflate_comp_exit(struct deflate_ctx *ctx)
  {
9ffb7146f   Artem B. Bityuckiy   [PATCH] crypto: c...
98
  	zlib_deflateEnd(&ctx->comp_stream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
103
  	vfree(ctx->comp_stream.workspace);
  }
  
  static void deflate_decomp_exit(struct deflate_ctx *ctx)
  {
9ffb7146f   Artem B. Bityuckiy   [PATCH] crypto: c...
104
  	zlib_inflateEnd(&ctx->decomp_stream);
7ab24bfdf   David S. Miller   net+crypto: Use v...
105
  	vfree(ctx->decomp_stream.workspace);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  }
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
107
  static int __deflate_init(void *ctx, int format)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
  {
  	int ret;
9472d763b   Richard Hartmann   crypto: deflate -...
110

a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
111
  	ret = deflate_comp_init(ctx, format);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
  	if (ret)
  		goto out;
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
114
  	ret = deflate_decomp_init(ctx, format);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
119
  	if (ret)
  		deflate_comp_exit(ctx);
  out:
  	return ret;
  }
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
120
  static void *gen_deflate_alloc_ctx(struct crypto_scomp *tfm, int format)
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
121
122
123
124
125
126
127
  {
  	struct deflate_ctx *ctx;
  	int ret;
  
  	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
  	if (!ctx)
  		return ERR_PTR(-ENOMEM);
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
128
  	ret = __deflate_init(ctx, format);
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
129
130
131
132
133
134
135
  	if (ret) {
  		kfree(ctx);
  		return ERR_PTR(ret);
  	}
  
  	return ctx;
  }
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
136
137
138
139
140
141
142
143
144
  static void *deflate_alloc_ctx(struct crypto_scomp *tfm)
  {
  	return gen_deflate_alloc_ctx(tfm, 0);
  }
  
  static void *zlib_deflate_alloc_ctx(struct crypto_scomp *tfm)
  {
  	return gen_deflate_alloc_ctx(tfm, 1);
  }
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
145
  static int deflate_init(struct crypto_tfm *tfm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  {
6c2bb98bc   Herbert Xu   [CRYPTO] all: Pas...
147
  	struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
148
  	return __deflate_init(ctx, 0);
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
149
150
151
152
  }
  
  static void __deflate_exit(void *ctx)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
  	deflate_comp_exit(ctx);
  	deflate_decomp_exit(ctx);
  }
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  static void deflate_free_ctx(struct crypto_scomp *tfm, void *ctx)
  {
  	__deflate_exit(ctx);
  	kzfree(ctx);
  }
  
  static void deflate_exit(struct crypto_tfm *tfm)
  {
  	struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
  
  	__deflate_exit(ctx);
  }
  
  static int __deflate_compress(const u8 *src, unsigned int slen,
  			      u8 *dst, unsigned int *dlen, void *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
  {
  	int ret = 0;
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
173
  	struct deflate_ctx *dctx = ctx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  	struct z_stream_s *stream = &dctx->comp_stream;
  
  	ret = zlib_deflateReset(stream);
  	if (ret != Z_OK) {
  		ret = -EINVAL;
  		goto out;
  	}
  
  	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) {
  		ret = -EINVAL;
  		goto out;
  	}
  	ret = 0;
  	*dlen = stream->total_out;
  out:
  	return ret;
  }
9472d763b   Richard Hartmann   crypto: deflate -...
197

f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  static int deflate_compress(struct crypto_tfm *tfm, const u8 *src,
  			    unsigned int slen, u8 *dst, unsigned int *dlen)
  {
  	struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
  
  	return __deflate_compress(src, slen, dst, dlen, dctx);
  }
  
  static int deflate_scompress(struct crypto_scomp *tfm, const u8 *src,
  			     unsigned int slen, u8 *dst, unsigned int *dlen,
  			     void *ctx)
  {
  	return __deflate_compress(src, slen, dst, dlen, ctx);
  }
  
  static int __deflate_decompress(const u8 *src, unsigned int slen,
  				u8 *dst, unsigned int *dlen, void *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  {
9472d763b   Richard Hartmann   crypto: deflate -...
216

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  	int ret = 0;
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
218
  	struct deflate_ctx *dctx = ctx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  	struct z_stream_s *stream = &dctx->decomp_stream;
  
  	ret = zlib_inflateReset(stream);
  	if (ret != Z_OK) {
  		ret = -EINVAL;
  		goto out;
  	}
  
  	stream->next_in = (u8 *)src;
  	stream->avail_in = slen;
  	stream->next_out = (u8 *)dst;
  	stream->avail_out = *dlen;
  
  	ret = zlib_inflate(stream, Z_SYNC_FLUSH);
  	/*
  	 * Work around a bug in zlib, which sometimes wants to taste an extra
  	 * byte when being used in the (undocumented) raw deflate mode.
  	 * (From USAGI).
  	 */
  	if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
  		u8 zerostuff = 0;
  		stream->next_in = &zerostuff;
9472d763b   Richard Hartmann   crypto: deflate -...
241
  		stream->avail_in = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
244
245
246
247
248
249
250
251
252
  		ret = zlib_inflate(stream, Z_FINISH);
  	}
  	if (ret != Z_STREAM_END) {
  		ret = -EINVAL;
  		goto out;
  	}
  	ret = 0;
  	*dlen = stream->total_out;
  out:
  	return ret;
  }
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  static int deflate_decompress(struct crypto_tfm *tfm, const u8 *src,
  			      unsigned int slen, u8 *dst, unsigned int *dlen)
  {
  	struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
  
  	return __deflate_decompress(src, slen, dst, dlen, dctx);
  }
  
  static int deflate_sdecompress(struct crypto_scomp *tfm, const u8 *src,
  			       unsigned int slen, u8 *dst, unsigned int *dlen,
  			       void *ctx)
  {
  	return __deflate_decompress(src, slen, dst, dlen, ctx);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
270
271
  static struct crypto_alg alg = {
  	.cra_name		= "deflate",
  	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
  	.cra_ctxsize		= sizeof(struct deflate_ctx),
  	.cra_module		= THIS_MODULE,
c7fc05992   Herbert Xu   [CRYPTO] api: Add...
272
273
  	.cra_init		= deflate_init,
  	.cra_exit		= deflate_exit,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  	.cra_u			= { .compress = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
277
  	.coa_compress 		= deflate_compress,
  	.coa_decompress  	= deflate_decompress } }
  };
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
278
  static struct scomp_alg scomp[] = { {
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
279
280
281
282
283
284
285
286
287
  	.alloc_ctx		= deflate_alloc_ctx,
  	.free_ctx		= deflate_free_ctx,
  	.compress		= deflate_scompress,
  	.decompress		= deflate_sdecompress,
  	.base			= {
  		.cra_name	= "deflate",
  		.cra_driver_name = "deflate-scomp",
  		.cra_module	 = THIS_MODULE,
  	}
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
288
289
290
291
292
293
294
295
296
297
298
  }, {
  	.alloc_ctx		= zlib_deflate_alloc_ctx,
  	.free_ctx		= deflate_free_ctx,
  	.compress		= deflate_scompress,
  	.decompress		= deflate_sdecompress,
  	.base			= {
  		.cra_name	= "zlib-deflate",
  		.cra_driver_name = "zlib-deflate-scomp",
  		.cra_module	 = THIS_MODULE,
  	}
  } };
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
299

3af5b90bd   Kamalesh Babulal   [CRYPTO] all: Cle...
300
  static int __init deflate_mod_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  {
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
302
303
304
305
306
  	int ret;
  
  	ret = crypto_register_alg(&alg);
  	if (ret)
  		return ret;
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
307
  	ret = crypto_register_scomps(scomp, ARRAY_SIZE(scomp));
f6ded09de   Giovanni Cabiddu   crypto: acomp - a...
308
309
310
311
312
313
  	if (ret) {
  		crypto_unregister_alg(&alg);
  		return ret;
  	}
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  }
3af5b90bd   Kamalesh Babulal   [CRYPTO] all: Cle...
315
  static void __exit deflate_mod_fini(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
  {
  	crypto_unregister_alg(&alg);
a368f43d6   Giovanni Cabiddu   crypto: scomp - a...
318
  	crypto_unregister_scomps(scomp, ARRAY_SIZE(scomp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  }
3af5b90bd   Kamalesh Babulal   [CRYPTO] all: Cle...
320
321
  module_init(deflate_mod_init);
  module_exit(deflate_mod_fini);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP");
  MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
5d26a105b   Kees Cook   crypto: prefix mo...
326
  MODULE_ALIAS_CRYPTO("deflate");