diff options
author | James Morris <jmorris@intercode.com.au> | 2003-03-28 11:17:21 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@home.transmeta.com> | 2003-03-28 11:17:21 -0800 |
commit | 0946befcaa7df551c1b9664506c947201007a3f0 (patch) | |
tree | 2a7cd0771027c3ace19661da3a5632635cfb9bae /crypto | |
parent | df7a3f3410c28fa93e2195c6390733b66b8ceb2c (diff) | |
download | history-0946befcaa7df551c1b9664506c947201007a3f0.tar.gz |
[CRYPTO]: Add Deflate algorithm to crypto API.
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/Kconfig | 10 | ||||
-rw-r--r-- | crypto/Makefile | 1 | ||||
-rw-r--r-- | crypto/api.c | 2 | ||||
-rw-r--r-- | crypto/compress.c | 31 | ||||
-rw-r--r-- | crypto/crypto_null.c | 10 | ||||
-rw-r--r-- | crypto/deflate.c | 224 | ||||
-rw-r--r-- | crypto/digest.c | 2 | ||||
-rw-r--r-- | crypto/internal.h | 5 | ||||
-rw-r--r-- | crypto/proc.c | 3 | ||||
-rw-r--r-- | crypto/tcrypt.c | 87 | ||||
-rw-r--r-- | crypto/tcrypt.h | 100 |
11 files changed, 455 insertions, 20 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig index 8b81dcd7da4bf6..ef70c8cd2a9905 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -131,6 +131,16 @@ config CRYPTO_AES See http://csrc.nist.gov/encryption/aes/ for more information. +config CRYPTO_DEFLATE + tristate "Deflate compression algorithm" + depends on CRYPTO + default y if INET_IPCOMP=y || INET_IPCOMP=m + help + This is the Deflate algorithm (RFC1951), specified for use in + IPSec with the IPCOMP protocol (RFC3173, RFC2394). + + You will most probably want this if using IPSec. + config CRYPTO_TEST tristate "Testing module" depends on CRYPTO diff --git a/crypto/Makefile b/crypto/Makefile index 8e7e3a8cf73537..464a7f07709496 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -20,5 +20,6 @@ obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o obj-$(CONFIG_CRYPTO_AES) += aes.o +obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o diff --git a/crypto/api.c b/crypto/api.c index 0c00daba80d8d2..4eec20b963d9c0 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -127,7 +127,7 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) if (tfm == NULL) goto out_put; - memset(tfm, 0, sizeof(*tfm)); + memset(tfm, 0, sizeof(*tfm) + alg->cra_ctxsize); tfm->__crt_alg = alg; diff --git a/crypto/compress.c b/crypto/compress.c index 7baaae04794180..eb36d9364da36b 100644 --- a/crypto/compress.c +++ b/crypto/compress.c @@ -18,29 +18,46 @@ #include <linux/string.h> #include "internal.h" -static void crypto_compress(struct crypto_tfm *tfm) +static int crypto_compress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) { - tfm->__crt_alg->cra_compress.coa_compress(); + return tfm->__crt_alg->cra_compress.coa_compress(crypto_tfm_ctx(tfm), + src, slen, dst, + dlen); } -static void crypto_decompress(struct crypto_tfm *tfm) +static int crypto_decompress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) { - tfm->__crt_alg->cra_compress.coa_decompress(); + return tfm->__crt_alg->cra_compress.coa_decompress(crypto_tfm_ctx(tfm), + src, slen, dst, + dlen); } int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags) { - return crypto_cipher_flags(flags) ? -EINVAL : 0; + return flags ? -EINVAL : 0; } int crypto_init_compress_ops(struct crypto_tfm *tfm) { + int ret = 0; struct compress_tfm *ops = &tfm->crt_compress; + ret = tfm->__crt_alg->cra_compress.coa_init(crypto_tfm_ctx(tfm)); + if (ret) + goto out; + ops->cot_compress = crypto_compress; ops->cot_decompress = crypto_decompress; - return 0; + +out: + return ret; } void crypto_exit_compress_ops(struct crypto_tfm *tfm) -{ } +{ + tfm->__crt_alg->cra_compress.coa_exit(crypto_tfm_ctx(tfm)); +} diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c index 8d66c7fd5a6d69..f8e26d1674065e 100644 --- a/crypto/crypto_null.c +++ b/crypto/crypto_null.c @@ -26,11 +26,13 @@ #define NULL_BLOCK_SIZE 1 #define NULL_DIGEST_SIZE 0 -static void null_compress(void) -{ } +static int null_compress(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ return 0; } -static void null_decompress(void) -{ } +static int null_decompress(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ return 0; } static void null_init(void *ctx) { } diff --git a/crypto/deflate.c b/crypto/deflate.c new file mode 100644 index 00000000000000..49cd5708d76313 --- /dev/null +++ b/crypto/deflate.c @@ -0,0 +1,224 @@ +/* + * 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> + * + * 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 + * Software Foundation; either version 2 of the License, or (at your option) + * 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> + +#define DEFLATE_DEF_LEVEL Z_DEFAULT_COMPRESSION +#define DEFLATE_DEF_WINBITS 11 +#define DEFLATE_DEF_MEMLEVEL MAX_MEM_LEVEL + +struct deflate_ctx { + int comp_initialized; + int decomp_initialized; + struct z_stream_s comp_stream; + struct z_stream_s decomp_stream; +}; + +static inline int deflate_gfp(void) +{ + return in_softirq() ? GFP_ATOMIC : GFP_KERNEL; +} + +static int deflate_init(void *ctx) +{ + return 0; +} + +static void deflate_exit(void *ctx) +{ + struct deflate_ctx *dctx = ctx; + + if (dctx->comp_initialized) + vfree(dctx->comp_stream.workspace); + if (dctx->decomp_initialized) + kfree(dctx->decomp_stream.workspace); +} + +/* + * Lazy initialization to make interface simple without allocating + * un-needed workspaces. Thus can be called in softirq context. + */ +static int deflate_comp_init(struct deflate_ctx *ctx) +{ + int ret = 0; + struct z_stream_s *stream = &ctx->comp_stream; + + stream->workspace = __vmalloc(zlib_deflate_workspacesize(), + deflate_gfp()|__GFP_HIGHMEM, + PAGE_KERNEL); + if (!stream->workspace ) { + ret = -ENOMEM; + goto out; + } + memset(stream->workspace, 0, sizeof(stream->workspace)); + ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED, + -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL, + Z_DEFAULT_STRATEGY); + if (ret != Z_OK) { + ret = -EINVAL; + goto out_free; + } + ctx->comp_initialized = 1; +out: + return ret; +out_free: + vfree(stream->workspace); + goto out; +} + +static int deflate_decomp_init(struct deflate_ctx *ctx) +{ + int ret = 0; + struct z_stream_s *stream = &ctx->decomp_stream; + + stream->workspace = kmalloc(zlib_inflate_workspacesize(), + deflate_gfp()); + if (!stream->workspace ) { + ret = -ENOMEM; + goto out; + } + memset(stream->workspace, 0, sizeof(stream->workspace)); + ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS); + if (ret != Z_OK) { + ret = -EINVAL; + goto out_free; + } + ctx->decomp_initialized = 1; +out: + return ret; +out_free: + kfree(stream->workspace); + goto out; +} + +static int deflate_compress(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + int ret = 0; + struct deflate_ctx *dctx = ctx; + struct z_stream_s *stream = &dctx->comp_stream; + + if (!dctx->comp_initialized) { + ret = deflate_comp_init(dctx); + if (ret) + goto out; + } + + 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; +} + +static int deflate_decompress(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + + int ret = 0; + struct deflate_ctx *dctx = ctx; + struct z_stream_s *stream = &dctx->decomp_stream; + + if (!dctx->decomp_initialized) { + ret = deflate_decomp_init(dctx); + if (ret) + goto out; + } + + 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_FINISH); + if (ret != Z_STREAM_END) { + ret = -EINVAL; + goto out; + } + ret = 0; + *dlen = stream->total_out; +out: + return ret; +} + +static struct crypto_alg alg = { + .cra_name = "deflate", + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize = sizeof(struct deflate_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_u = { .compress = { + .coa_init = deflate_init, + .coa_exit = deflate_exit, + .coa_compress = deflate_compress, + .coa_decompress = deflate_decompress } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP"); +MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); + diff --git a/crypto/digest.c b/crypto/digest.c index e82470a472be28..a62327d3c37b41 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -61,7 +61,7 @@ static void digest(struct crypto_tfm *tfm, int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) { - return crypto_cipher_flags(flags) ? -EINVAL : 0; + return flags ? -EINVAL : 0; } int crypto_init_digest_ops(struct crypto_tfm *tfm) diff --git a/crypto/internal.h b/crypto/internal.h index a19fdb1de503b5..b67c0ee8fe549b 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -41,11 +41,6 @@ static inline void crypto_yield(struct crypto_tfm *tfm) cond_resched(); } -static inline u32 crypto_cipher_flags(u32 flags) -{ - return flags & (CRYPTO_TFM_MODE_MASK|CRYPTO_TFM_REQ_WEAK_KEY); -} - static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm) { return (void *)&tfm[1]; diff --git a/crypto/proc.c b/crypto/proc.c index f51a3ccf52dba8..124a3a2709384f 100644 --- a/crypto/proc.c +++ b/crypto/proc.c @@ -54,10 +54,10 @@ static int c_show(struct seq_file *m, void *p) seq_printf(m, "name : %s\n", alg->cra_name); seq_printf(m, "module : %s\n", module_name(alg->cra_module)); - seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { case CRYPTO_ALG_TYPE_CIPHER: + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); seq_printf(m, "min keysize : %u\n", alg->cra_cipher.cia_min_keysize); seq_printf(m, "max keysize : %u\n", @@ -67,6 +67,7 @@ static int c_show(struct seq_file *m, void *p) break; case CRYPTO_ALG_TYPE_DIGEST: + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); seq_printf(m, "digestsize : %u\n", alg->cra_digest.dia_digestsize); break; diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index a45e574528f796..c2a513c2de66d7 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -48,7 +48,7 @@ static char *tvmem; static char *check[] = { "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", - "twofish", "serpent", "sha384", "sha512", "md4", "aes", + "twofish", "serpent", "sha384", "sha512", "md4", "aes", "deflate", NULL }; @@ -2193,6 +2193,86 @@ out: } static void +test_deflate(void) +{ + unsigned int i; + char result[COMP_BUF_SIZE]; + struct crypto_tfm *tfm; + struct comp_testvec *tv; + unsigned int tsize; + + printk("\ntesting deflate compression\n"); + + tsize = sizeof (deflate_comp_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, deflate_comp_tv_template, tsize); + tv = (void *) tvmem; + + tfm = crypto_alloc_tfm("deflate", 0); + if (tfm == NULL) { + printk("failed to load transform for deflate\n"); + return; + } + + for (i = 0; i < DEFLATE_COMP_TEST_VECTORS; i++) { + int ilen, ret, dlen = COMP_BUF_SIZE; + + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + ilen = tv[i].inlen; + ret = crypto_comp_compress(tfm, tv[i].input, + ilen, result, &dlen); + if (ret) { + printk("fail: ret=%d\n", ret); + continue; + } + hexdump(result, dlen); + printk("%s (ratio %d:%d)\n", + memcmp(result, tv[i].output, dlen) ? "fail" : "pass", + ilen, dlen); + } + + printk("\ntesting deflate decompression\n"); + + tsize = sizeof (deflate_decomp_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + goto out; + } + + memcpy(tvmem, deflate_decomp_tv_template, tsize); + tv = (void *) tvmem; + + for (i = 0; i < DEFLATE_DECOMP_TEST_VECTORS; i++) { + int ilen, ret, dlen = COMP_BUF_SIZE; + + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + ilen = tv[i].inlen; + ret = crypto_comp_decompress(tfm, tv[i].input, + ilen, result, &dlen); + if (ret) { + printk("fail: ret=%d\n", ret); + continue; + } + hexdump(result, dlen); + printk("%s (ratio %d:%d)\n", + memcmp(result, tv[i].output, dlen) ? "fail" : "pass", + ilen, dlen); + } +out: + crypto_free_tfm(tfm); +} + +static void test_available(void) { char **name = check; @@ -2223,6 +2303,7 @@ do_test(void) test_aes(); test_sha384(); test_sha512(); + test_deflate(); #ifdef CONFIG_CRYPTO_HMAC test_hmac_md5(); test_hmac_sha1(); @@ -2278,6 +2359,10 @@ do_test(void) test_sha512(); break; + case 13: + test_deflate(); + break; + #ifdef CONFIG_CRYPTO_HMAC case 100: test_hmac_md5(); diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h index b8e328e9054599..35419e45811651 100644 --- a/crypto/tcrypt.h +++ b/crypto/tcrypt.h @@ -1682,4 +1682,104 @@ struct aes_tv aes_dec_tv_template[] = { }, }; +/* + * Compression stuff. + */ +#define COMP_BUF_SIZE 512 + +struct comp_testvec { + int inlen, outlen; + char input[COMP_BUF_SIZE]; + char output[COMP_BUF_SIZE]; +}; + +/* + * Deflate test vectors (null-terminated strings). + * Params: winbits=11, Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL. + */ +#define DEFLATE_COMP_TEST_VECTORS 2 +#define DEFLATE_DECOMP_TEST_VECTORS 2 + +struct comp_testvec deflate_comp_tv_template[] = { + { + 70, 38, + + "Join us now and share the software " + "Join us now and share the software ", + + { 0xf3, 0xca, 0xcf, 0xcc, 0x53, 0x28, 0x2d, 0x56, + 0xc8, 0xcb, 0x2f, 0x57, 0x48, 0xcc, 0x4b, 0x51, + 0x28, 0xce, 0x48, 0x2c, 0x4a, 0x55, 0x28, 0xc9, + 0x48, 0x55, 0x28, 0xce, 0x4f, 0x2b, 0x29, 0x07, + 0x71, 0xbc, 0x08, 0x2b, 0x01, 0x00 + }, + }, + + { + 191, 122, + + "This document describes a compression method based on the DEFLATE" + "compression algorithm. This document defines the application of " + "the DEFLATE algorithm to the IP Payload Compression Protocol.", + + { 0x5d, 0x8d, 0x31, 0x0e, 0xc2, 0x30, 0x10, 0x04, + 0xbf, 0xb2, 0x2f, 0xc8, 0x1f, 0x10, 0x04, 0x09, + 0x89, 0xc2, 0x85, 0x3f, 0x70, 0xb1, 0x2f, 0xf8, + 0x24, 0xdb, 0x67, 0xd9, 0x47, 0xc1, 0xef, 0x49, + 0x68, 0x12, 0x51, 0xae, 0x76, 0x67, 0xd6, 0x27, + 0x19, 0x88, 0x1a, 0xde, 0x85, 0xab, 0x21, 0xf2, + 0x08, 0x5d, 0x16, 0x1e, 0x20, 0x04, 0x2d, 0xad, + 0xf3, 0x18, 0xa2, 0x15, 0x85, 0x2d, 0x69, 0xc4, + 0x42, 0x83, 0x23, 0xb6, 0x6c, 0x89, 0x71, 0x9b, + 0xef, 0xcf, 0x8b, 0x9f, 0xcf, 0x33, 0xca, 0x2f, + 0xed, 0x62, 0xa9, 0x4c, 0x80, 0xff, 0x13, 0xaf, + 0x52, 0x37, 0xed, 0x0e, 0x52, 0x6b, 0x59, 0x02, + 0xd9, 0x4e, 0xe8, 0x7a, 0x76, 0x1d, 0x02, 0x98, + 0xfe, 0x8a, 0x87, 0x83, 0xa3, 0x4f, 0x56, 0x8a, + 0xb8, 0x9e, 0x8e, 0x5c, 0x57, 0xd3, 0xa0, 0x79, + 0xfa, 0x02 }, + }, +}; + +struct comp_testvec deflate_decomp_tv_template[] = { + { + 122, 191, + + { 0x5d, 0x8d, 0x31, 0x0e, 0xc2, 0x30, 0x10, 0x04, + 0xbf, 0xb2, 0x2f, 0xc8, 0x1f, 0x10, 0x04, 0x09, + 0x89, 0xc2, 0x85, 0x3f, 0x70, 0xb1, 0x2f, 0xf8, + 0x24, 0xdb, 0x67, 0xd9, 0x47, 0xc1, 0xef, 0x49, + 0x68, 0x12, 0x51, 0xae, 0x76, 0x67, 0xd6, 0x27, + 0x19, 0x88, 0x1a, 0xde, 0x85, 0xab, 0x21, 0xf2, + 0x08, 0x5d, 0x16, 0x1e, 0x20, 0x04, 0x2d, 0xad, + 0xf3, 0x18, 0xa2, 0x15, 0x85, 0x2d, 0x69, 0xc4, + 0x42, 0x83, 0x23, 0xb6, 0x6c, 0x89, 0x71, 0x9b, + 0xef, 0xcf, 0x8b, 0x9f, 0xcf, 0x33, 0xca, 0x2f, + 0xed, 0x62, 0xa9, 0x4c, 0x80, 0xff, 0x13, 0xaf, + 0x52, 0x37, 0xed, 0x0e, 0x52, 0x6b, 0x59, 0x02, + 0xd9, 0x4e, 0xe8, 0x7a, 0x76, 0x1d, 0x02, 0x98, + 0xfe, 0x8a, 0x87, 0x83, 0xa3, 0x4f, 0x56, 0x8a, + 0xb8, 0x9e, 0x8e, 0x5c, 0x57, 0xd3, 0xa0, 0x79, + 0xfa, 0x02 }, + + "This document describes a compression method based on the DEFLATE" + "compression algorithm. This document defines the application of " + "the DEFLATE algorithm to the IP Payload Compression Protocol.", + }, + + { + 38, 70, + + { 0xf3, 0xca, 0xcf, 0xcc, 0x53, 0x28, 0x2d, 0x56, + 0xc8, 0xcb, 0x2f, 0x57, 0x48, 0xcc, 0x4b, 0x51, + 0x28, 0xce, 0x48, 0x2c, 0x4a, 0x55, 0x28, 0xc9, + 0x48, 0x55, 0x28, 0xce, 0x4f, 0x2b, 0x29, 0x07, + 0x71, 0xbc, 0x08, 0x2b, 0x01, 0x00 + }, + + "Join us now and share the software " + "Join us now and share the software ", + }, +}; + #endif /* _CRYPTO_TCRYPT_H */ |