| From 308795a7713ca6fcd468b60fba9a2fca99cee6a0 Mon Sep 17 00:00:00 2001 |
| From: Nick Terrell <terrelln@fb.com> |
| Date: Wed, 2 Aug 2017 18:02:13 -0700 |
| Subject: [PATCH v5 5/5] crypto: Add zstd support |
| |
| Adds zstd support to crypto and scompress. Only supports the default |
| level. |
| |
| Signed-off-by: Nick Terrell <terrelln@fb.com> |
| --- |
| crypto/Kconfig | 9 ++ |
| crypto/Makefile | 1 + |
| crypto/testmgr.c | 10 +++ |
| crypto/testmgr.h | 71 +++++++++++++++ |
| crypto/zstd.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| 5 files changed, 356 insertions(+) |
| create mode 100644 crypto/zstd.c |
| |
| diff --git a/crypto/Kconfig b/crypto/Kconfig |
| index caa770e..4fc3936 100644 |
| --- a/crypto/Kconfig |
| +++ b/crypto/Kconfig |
| @@ -1662,6 +1662,15 @@ config CRYPTO_LZ4HC |
| help |
| This is the LZ4 high compression mode algorithm. |
| |
| +config CRYPTO_ZSTD |
| + tristate "Zstd compression algorithm" |
| + select CRYPTO_ALGAPI |
| + select CRYPTO_ACOMP2 |
| + select ZSTD_COMPRESS |
| + select ZSTD_DECOMPRESS |
| + help |
| + This is the zstd algorithm. |
| + |
| comment "Random Number Generation" |
| |
| config CRYPTO_ANSI_CPRNG |
| diff --git a/crypto/Makefile b/crypto/Makefile |
| index d41f033..b22e1e8 100644 |
| --- a/crypto/Makefile |
| +++ b/crypto/Makefile |
| @@ -133,6 +133,7 @@ obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o |
| obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o |
| obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o |
| obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o |
| +obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o |
| |
| ecdh_generic-y := ecc.o |
| ecdh_generic-y += ecdh.o |
| diff --git a/crypto/testmgr.c b/crypto/testmgr.c |
| index 7125ba3..8a124d3 100644 |
| --- a/crypto/testmgr.c |
| +++ b/crypto/testmgr.c |
| @@ -3603,6 +3603,16 @@ static const struct alg_test_desc alg_test_descs[] = { |
| .decomp = __VECS(zlib_deflate_decomp_tv_template) |
| } |
| } |
| + }, { |
| + .alg = "zstd", |
| + .test = alg_test_comp, |
| + .fips_allowed = 1, |
| + .suite = { |
| + .comp = { |
| + .comp = __VECS(zstd_comp_tv_template), |
| + .decomp = __VECS(zstd_decomp_tv_template) |
| + } |
| + } |
| } |
| }; |
| |
| diff --git a/crypto/testmgr.h b/crypto/testmgr.h |
| index 6ceb0e2..e6b5920 100644 |
| --- a/crypto/testmgr.h |
| +++ b/crypto/testmgr.h |
| @@ -34631,4 +34631,75 @@ static const struct comp_testvec lz4hc_decomp_tv_template[] = { |
| }, |
| }; |
| |
| +static const struct comp_testvec zstd_comp_tv_template[] = { |
| + { |
| + .inlen = 68, |
| + .outlen = 39, |
| + .input = "The algorithm is zstd. " |
| + "The algorithm is zstd. " |
| + "The algorithm is zstd.", |
| + .output = "\x28\xb5\x2f\xfd\x00\x50\xf5\x00\x00\xb8\x54\x68\x65" |
| + "\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x20\x69\x73" |
| + "\x20\x7a\x73\x74\x64\x2e\x20\x01\x00\x55\x73\x36\x01" |
| + , |
| + }, |
| + { |
| + .inlen = 244, |
| + .outlen = 151, |
| + .input = "zstd, short for Zstandard, is a fast lossless " |
| + "compression algorithm, targeting real-time " |
| + "compression scenarios at zlib-level and better " |
| + "compression ratios. The zstd compression library " |
| + "provides in-memory compression and decompression " |
| + "functions.", |
| + .output = "\x28\xb5\x2f\xfd\x00\x50\x75\x04\x00\x42\x4b\x1e\x17" |
| + "\x90\x81\x31\x00\xf2\x2f\xe4\x36\xc9\xef\x92\x88\x32" |
| + "\xc9\xf2\x24\x94\xd8\x68\x9a\x0f\x00\x0c\xc4\x31\x6f" |
| + "\x0d\x0c\x38\xac\x5c\x48\x03\xcd\x63\x67\xc0\xf3\xad" |
| + "\x4e\x90\xaa\x78\xa0\xa4\xc5\x99\xda\x2f\xb6\x24\x60" |
| + "\xe2\x79\x4b\xaa\xb6\x6b\x85\x0b\xc9\xc6\x04\x66\x86" |
| + "\xe2\xcc\xe2\x25\x3f\x4f\x09\xcd\xb8\x9d\xdb\xc1\x90" |
| + "\xa9\x11\xbc\x35\x44\x69\x2d\x9c\x64\x4f\x13\x31\x64" |
| + "\xcc\xfb\x4d\x95\x93\x86\x7f\x33\x7f\x1a\xef\xe9\x30" |
| + "\xf9\x67\xa1\x94\x0a\x69\x0f\x60\xcd\xc3\xab\x99\xdc" |
| + "\x42\xed\x97\x05\x00\x33\xc3\x15\x95\x3a\x06\xa0\x0e" |
| + "\x20\xa9\x0e\x82\xb9\x43\x45\x01", |
| + }, |
| +}; |
| + |
| +static const struct comp_testvec zstd_decomp_tv_template[] = { |
| + { |
| + .inlen = 43, |
| + .outlen = 68, |
| + .input = "\x28\xb5\x2f\xfd\x04\x50\xf5\x00\x00\xb8\x54\x68\x65" |
| + "\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x20\x69\x73" |
| + "\x20\x7a\x73\x74\x64\x2e\x20\x01\x00\x55\x73\x36\x01" |
| + "\x6b\xf4\x13\x35", |
| + .output = "The algorithm is zstd. " |
| + "The algorithm is zstd. " |
| + "The algorithm is zstd.", |
| + }, |
| + { |
| + .inlen = 155, |
| + .outlen = 244, |
| + .input = "\x28\xb5\x2f\xfd\x04\x50\x75\x04\x00\x42\x4b\x1e\x17" |
| + "\x90\x81\x31\x00\xf2\x2f\xe4\x36\xc9\xef\x92\x88\x32" |
| + "\xc9\xf2\x24\x94\xd8\x68\x9a\x0f\x00\x0c\xc4\x31\x6f" |
| + "\x0d\x0c\x38\xac\x5c\x48\x03\xcd\x63\x67\xc0\xf3\xad" |
| + "\x4e\x90\xaa\x78\xa0\xa4\xc5\x99\xda\x2f\xb6\x24\x60" |
| + "\xe2\x79\x4b\xaa\xb6\x6b\x85\x0b\xc9\xc6\x04\x66\x86" |
| + "\xe2\xcc\xe2\x25\x3f\x4f\x09\xcd\xb8\x9d\xdb\xc1\x90" |
| + "\xa9\x11\xbc\x35\x44\x69\x2d\x9c\x64\x4f\x13\x31\x64" |
| + "\xcc\xfb\x4d\x95\x93\x86\x7f\x33\x7f\x1a\xef\xe9\x30" |
| + "\xf9\x67\xa1\x94\x0a\x69\x0f\x60\xcd\xc3\xab\x99\xdc" |
| + "\x42\xed\x97\x05\x00\x33\xc3\x15\x95\x3a\x06\xa0\x0e" |
| + "\x20\xa9\x0e\x82\xb9\x43\x45\x01\xaa\x6d\xda\x0d", |
| + .output = "zstd, short for Zstandard, is a fast lossless " |
| + "compression algorithm, targeting real-time " |
| + "compression scenarios at zlib-level and better " |
| + "compression ratios. The zstd compression library " |
| + "provides in-memory compression and decompression " |
| + "functions.", |
| + }, |
| +}; |
| #endif /* _CRYPTO_TESTMGR_H */ |
| diff --git a/crypto/zstd.c b/crypto/zstd.c |
| new file mode 100644 |
| index 0000000..9a76b3e |
| --- /dev/null |
| +++ b/crypto/zstd.c |
| @@ -0,0 +1,265 @@ |
| +/* |
| + * Cryptographic API. |
| + * |
| + * Copyright (c) 2017-present, Facebook, Inc. |
| + * |
| + * This program is free software; you can redistribute it and/or modify it |
| + * under the terms of the GNU General Public License version 2 as published by |
| + * the Free Software Foundation. |
| + * |
| + * This program is distributed in the hope that it will be useful, but WITHOUT |
| + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| + * more details. |
| + */ |
| +#include <linux/crypto.h> |
| +#include <linux/init.h> |
| +#include <linux/interrupt.h> |
| +#include <linux/mm.h> |
| +#include <linux/module.h> |
| +#include <linux/net.h> |
| +#include <linux/vmalloc.h> |
| +#include <linux/zstd.h> |
| +#include <crypto/internal/scompress.h> |
| + |
| + |
| +#define ZSTD_DEF_LEVEL 3 |
| + |
| +struct zstd_ctx { |
| + ZSTD_CCtx *cctx; |
| + ZSTD_DCtx *dctx; |
| + void *cwksp; |
| + void *dwksp; |
| +}; |
| + |
| +static ZSTD_parameters zstd_params(void) |
| +{ |
| + return ZSTD_getParams(ZSTD_DEF_LEVEL, 0, 0); |
| +} |
| + |
| +static int zstd_comp_init(struct zstd_ctx *ctx) |
| +{ |
| + int ret = 0; |
| + const ZSTD_parameters params = zstd_params(); |
| + const size_t wksp_size = ZSTD_CCtxWorkspaceBound(params.cParams); |
| + |
| + ctx->cwksp = vzalloc(wksp_size); |
| + if (!ctx->cwksp) { |
| + ret = -ENOMEM; |
| + goto out; |
| + } |
| + |
| + ctx->cctx = ZSTD_initCCtx(ctx->cwksp, wksp_size); |
| + if (!ctx->cctx) { |
| + ret = -EINVAL; |
| + goto out_free; |
| + } |
| +out: |
| + return ret; |
| +out_free: |
| + vfree(ctx->cwksp); |
| + goto out; |
| +} |
| + |
| +static int zstd_decomp_init(struct zstd_ctx *ctx) |
| +{ |
| + int ret = 0; |
| + const size_t wksp_size = ZSTD_DCtxWorkspaceBound(); |
| + |
| + ctx->dwksp = vzalloc(wksp_size); |
| + if (!ctx->dwksp) { |
| + ret = -ENOMEM; |
| + goto out; |
| + } |
| + |
| + ctx->dctx = ZSTD_initDCtx(ctx->dwksp, wksp_size); |
| + if (!ctx->dctx) { |
| + ret = -EINVAL; |
| + goto out_free; |
| + } |
| +out: |
| + return ret; |
| +out_free: |
| + vfree(ctx->dwksp); |
| + goto out; |
| +} |
| + |
| +static void zstd_comp_exit(struct zstd_ctx *ctx) |
| +{ |
| + vfree(ctx->cwksp); |
| + ctx->cwksp = NULL; |
| + ctx->cctx = NULL; |
| +} |
| + |
| +static void zstd_decomp_exit(struct zstd_ctx *ctx) |
| +{ |
| + vfree(ctx->dwksp); |
| + ctx->dwksp = NULL; |
| + ctx->dctx = NULL; |
| +} |
| + |
| +static int __zstd_init(void *ctx) |
| +{ |
| + int ret; |
| + |
| + ret = zstd_comp_init(ctx); |
| + if (ret) |
| + return ret; |
| + ret = zstd_decomp_init(ctx); |
| + if (ret) |
| + zstd_comp_exit(ctx); |
| + return ret; |
| +} |
| + |
| +static void *zstd_alloc_ctx(struct crypto_scomp *tfm) |
| +{ |
| + int ret; |
| + struct zstd_ctx *ctx; |
| + |
| + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
| + if (!ctx) |
| + return ERR_PTR(-ENOMEM); |
| + |
| + ret = __zstd_init(ctx); |
| + if (ret) { |
| + kfree(ctx); |
| + return ERR_PTR(ret); |
| + } |
| + |
| + return ctx; |
| +} |
| + |
| +static int zstd_init(struct crypto_tfm *tfm) |
| +{ |
| + struct zstd_ctx *ctx = crypto_tfm_ctx(tfm); |
| + |
| + return __zstd_init(ctx); |
| +} |
| + |
| +static void __zstd_exit(void *ctx) |
| +{ |
| + zstd_comp_exit(ctx); |
| + zstd_decomp_exit(ctx); |
| +} |
| + |
| +static void zstd_free_ctx(struct crypto_scomp *tfm, void *ctx) |
| +{ |
| + __zstd_exit(ctx); |
| + kzfree(ctx); |
| +} |
| + |
| +static void zstd_exit(struct crypto_tfm *tfm) |
| +{ |
| + struct zstd_ctx *ctx = crypto_tfm_ctx(tfm); |
| + |
| + __zstd_exit(ctx); |
| +} |
| + |
| +static int __zstd_compress(const u8 *src, unsigned int slen, |
| + u8 *dst, unsigned int *dlen, void *ctx) |
| +{ |
| + size_t out_len; |
| + struct zstd_ctx *zctx = ctx; |
| + const ZSTD_parameters params = zstd_params(); |
| + |
| + out_len = ZSTD_compressCCtx(zctx->cctx, dst, *dlen, src, slen, params); |
| + if (ZSTD_isError(out_len)) |
| + return -EINVAL; |
| + *dlen = out_len; |
| + return 0; |
| +} |
| + |
| +static int zstd_compress(struct crypto_tfm *tfm, const u8 *src, |
| + unsigned int slen, u8 *dst, unsigned int *dlen) |
| +{ |
| + struct zstd_ctx *ctx = crypto_tfm_ctx(tfm); |
| + |
| + return __zstd_compress(src, slen, dst, dlen, ctx); |
| +} |
| + |
| +static int zstd_scompress(struct crypto_scomp *tfm, const u8 *src, |
| + unsigned int slen, u8 *dst, unsigned int *dlen, |
| + void *ctx) |
| +{ |
| + return __zstd_compress(src, slen, dst, dlen, ctx); |
| +} |
| + |
| +static int __zstd_decompress(const u8 *src, unsigned int slen, |
| + u8 *dst, unsigned int *dlen, void *ctx) |
| +{ |
| + size_t out_len; |
| + struct zstd_ctx *zctx = ctx; |
| + |
| + out_len = ZSTD_decompressDCtx(zctx->dctx, dst, *dlen, src, slen); |
| + if (ZSTD_isError(out_len)) |
| + return -EINVAL; |
| + *dlen = out_len; |
| + return 0; |
| +} |
| + |
| +static int zstd_decompress(struct crypto_tfm *tfm, const u8 *src, |
| + unsigned int slen, u8 *dst, unsigned int *dlen) |
| +{ |
| + struct zstd_ctx *ctx = crypto_tfm_ctx(tfm); |
| + |
| + return __zstd_decompress(src, slen, dst, dlen, ctx); |
| +} |
| + |
| +static int zstd_sdecompress(struct crypto_scomp *tfm, const u8 *src, |
| + unsigned int slen, u8 *dst, unsigned int *dlen, |
| + void *ctx) |
| +{ |
| + return __zstd_decompress(src, slen, dst, dlen, ctx); |
| +} |
| + |
| +static struct crypto_alg alg = { |
| + .cra_name = "zstd", |
| + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, |
| + .cra_ctxsize = sizeof(struct zstd_ctx), |
| + .cra_module = THIS_MODULE, |
| + .cra_init = zstd_init, |
| + .cra_exit = zstd_exit, |
| + .cra_u = { .compress = { |
| + .coa_compress = zstd_compress, |
| + .coa_decompress = zstd_decompress } } |
| +}; |
| + |
| +static struct scomp_alg scomp = { |
| + .alloc_ctx = zstd_alloc_ctx, |
| + .free_ctx = zstd_free_ctx, |
| + .compress = zstd_scompress, |
| + .decompress = zstd_sdecompress, |
| + .base = { |
| + .cra_name = "zstd", |
| + .cra_driver_name = "zstd-scomp", |
| + .cra_module = THIS_MODULE, |
| + } |
| +}; |
| + |
| +static int __init zstd_mod_init(void) |
| +{ |
| + int ret; |
| + |
| + ret = crypto_register_alg(&alg); |
| + if (ret) |
| + return ret; |
| + |
| + ret = crypto_register_scomp(&scomp); |
| + if (ret) |
| + crypto_unregister_alg(&alg); |
| + |
| + return ret; |
| +} |
| + |
| +static void __exit zstd_mod_fini(void) |
| +{ |
| + crypto_unregister_alg(&alg); |
| + crypto_unregister_scomp(&scomp); |
| +} |
| + |
| +module_init(zstd_mod_init); |
| +module_exit(zstd_mod_fini); |
| + |
| +MODULE_LICENSE("GPL"); |
| +MODULE_DESCRIPTION("Zstd Compression Algorithm"); |
| +MODULE_ALIAS_CRYPTO("zstd"); |
| -- |
| 2.9.3 |