xref: /linux/crypto/zstd.c (revision cf30f6a5)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d28fc3dbSNick Terrell /*
3d28fc3dbSNick Terrell  * Cryptographic API.
4d28fc3dbSNick Terrell  *
5d28fc3dbSNick Terrell  * Copyright (c) 2017-present, Facebook, Inc.
6d28fc3dbSNick Terrell  */
7d28fc3dbSNick Terrell #include <linux/crypto.h>
8d28fc3dbSNick Terrell #include <linux/init.h>
9d28fc3dbSNick Terrell #include <linux/interrupt.h>
10d28fc3dbSNick Terrell #include <linux/mm.h>
11d28fc3dbSNick Terrell #include <linux/module.h>
12d28fc3dbSNick Terrell #include <linux/net.h>
13d28fc3dbSNick Terrell #include <linux/vmalloc.h>
14d28fc3dbSNick Terrell #include <linux/zstd.h>
15d28fc3dbSNick Terrell #include <crypto/internal/scompress.h>
16d28fc3dbSNick Terrell 
17d28fc3dbSNick Terrell 
18d28fc3dbSNick Terrell #define ZSTD_DEF_LEVEL	3
19d28fc3dbSNick Terrell 
20d28fc3dbSNick Terrell struct zstd_ctx {
21*cf30f6a5SNick Terrell 	zstd_cctx *cctx;
22*cf30f6a5SNick Terrell 	zstd_dctx *dctx;
23d28fc3dbSNick Terrell 	void *cwksp;
24d28fc3dbSNick Terrell 	void *dwksp;
25d28fc3dbSNick Terrell };
26d28fc3dbSNick Terrell 
zstd_params(void)27*cf30f6a5SNick Terrell static zstd_parameters zstd_params(void)
28d28fc3dbSNick Terrell {
29*cf30f6a5SNick Terrell 	return zstd_get_params(ZSTD_DEF_LEVEL, 0);
30d28fc3dbSNick Terrell }
31d28fc3dbSNick Terrell 
zstd_comp_init(struct zstd_ctx * ctx)32d28fc3dbSNick Terrell static int zstd_comp_init(struct zstd_ctx *ctx)
33d28fc3dbSNick Terrell {
34d28fc3dbSNick Terrell 	int ret = 0;
35*cf30f6a5SNick Terrell 	const zstd_parameters params = zstd_params();
36*cf30f6a5SNick Terrell 	const size_t wksp_size = zstd_cctx_workspace_bound(&params.cParams);
37d28fc3dbSNick Terrell 
38d28fc3dbSNick Terrell 	ctx->cwksp = vzalloc(wksp_size);
39d28fc3dbSNick Terrell 	if (!ctx->cwksp) {
40d28fc3dbSNick Terrell 		ret = -ENOMEM;
41d28fc3dbSNick Terrell 		goto out;
42d28fc3dbSNick Terrell 	}
43d28fc3dbSNick Terrell 
44*cf30f6a5SNick Terrell 	ctx->cctx = zstd_init_cctx(ctx->cwksp, wksp_size);
45d28fc3dbSNick Terrell 	if (!ctx->cctx) {
46d28fc3dbSNick Terrell 		ret = -EINVAL;
47d28fc3dbSNick Terrell 		goto out_free;
48d28fc3dbSNick Terrell 	}
49d28fc3dbSNick Terrell out:
50d28fc3dbSNick Terrell 	return ret;
51d28fc3dbSNick Terrell out_free:
52d28fc3dbSNick Terrell 	vfree(ctx->cwksp);
53d28fc3dbSNick Terrell 	goto out;
54d28fc3dbSNick Terrell }
55d28fc3dbSNick Terrell 
zstd_decomp_init(struct zstd_ctx * ctx)56d28fc3dbSNick Terrell static int zstd_decomp_init(struct zstd_ctx *ctx)
57d28fc3dbSNick Terrell {
58d28fc3dbSNick Terrell 	int ret = 0;
59*cf30f6a5SNick Terrell 	const size_t wksp_size = zstd_dctx_workspace_bound();
60d28fc3dbSNick Terrell 
61d28fc3dbSNick Terrell 	ctx->dwksp = vzalloc(wksp_size);
62d28fc3dbSNick Terrell 	if (!ctx->dwksp) {
63d28fc3dbSNick Terrell 		ret = -ENOMEM;
64d28fc3dbSNick Terrell 		goto out;
65d28fc3dbSNick Terrell 	}
66d28fc3dbSNick Terrell 
67*cf30f6a5SNick Terrell 	ctx->dctx = zstd_init_dctx(ctx->dwksp, wksp_size);
68d28fc3dbSNick Terrell 	if (!ctx->dctx) {
69d28fc3dbSNick Terrell 		ret = -EINVAL;
70d28fc3dbSNick Terrell 		goto out_free;
71d28fc3dbSNick Terrell 	}
72d28fc3dbSNick Terrell out:
73d28fc3dbSNick Terrell 	return ret;
74d28fc3dbSNick Terrell out_free:
75d28fc3dbSNick Terrell 	vfree(ctx->dwksp);
76d28fc3dbSNick Terrell 	goto out;
77d28fc3dbSNick Terrell }
78d28fc3dbSNick Terrell 
zstd_comp_exit(struct zstd_ctx * ctx)79d28fc3dbSNick Terrell static void zstd_comp_exit(struct zstd_ctx *ctx)
80d28fc3dbSNick Terrell {
81d28fc3dbSNick Terrell 	vfree(ctx->cwksp);
82d28fc3dbSNick Terrell 	ctx->cwksp = NULL;
83d28fc3dbSNick Terrell 	ctx->cctx = NULL;
84d28fc3dbSNick Terrell }
85d28fc3dbSNick Terrell 
zstd_decomp_exit(struct zstd_ctx * ctx)86d28fc3dbSNick Terrell static void zstd_decomp_exit(struct zstd_ctx *ctx)
87d28fc3dbSNick Terrell {
88d28fc3dbSNick Terrell 	vfree(ctx->dwksp);
89d28fc3dbSNick Terrell 	ctx->dwksp = NULL;
90d28fc3dbSNick Terrell 	ctx->dctx = NULL;
91d28fc3dbSNick Terrell }
92d28fc3dbSNick Terrell 
__zstd_init(void * ctx)93d28fc3dbSNick Terrell static int __zstd_init(void *ctx)
94d28fc3dbSNick Terrell {
95d28fc3dbSNick Terrell 	int ret;
96d28fc3dbSNick Terrell 
97d28fc3dbSNick Terrell 	ret = zstd_comp_init(ctx);
98d28fc3dbSNick Terrell 	if (ret)
99d28fc3dbSNick Terrell 		return ret;
100d28fc3dbSNick Terrell 	ret = zstd_decomp_init(ctx);
101d28fc3dbSNick Terrell 	if (ret)
102d28fc3dbSNick Terrell 		zstd_comp_exit(ctx);
103d28fc3dbSNick Terrell 	return ret;
104d28fc3dbSNick Terrell }
105d28fc3dbSNick Terrell 
zstd_alloc_ctx(struct crypto_scomp * tfm)106d28fc3dbSNick Terrell static void *zstd_alloc_ctx(struct crypto_scomp *tfm)
107d28fc3dbSNick Terrell {
108d28fc3dbSNick Terrell 	int ret;
109d28fc3dbSNick Terrell 	struct zstd_ctx *ctx;
110d28fc3dbSNick Terrell 
111d28fc3dbSNick Terrell 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
112d28fc3dbSNick Terrell 	if (!ctx)
113d28fc3dbSNick Terrell 		return ERR_PTR(-ENOMEM);
114d28fc3dbSNick Terrell 
115d28fc3dbSNick Terrell 	ret = __zstd_init(ctx);
116d28fc3dbSNick Terrell 	if (ret) {
117d28fc3dbSNick Terrell 		kfree(ctx);
118d28fc3dbSNick Terrell 		return ERR_PTR(ret);
119d28fc3dbSNick Terrell 	}
120d28fc3dbSNick Terrell 
121d28fc3dbSNick Terrell 	return ctx;
122d28fc3dbSNick Terrell }
123d28fc3dbSNick Terrell 
zstd_init(struct crypto_tfm * tfm)124d28fc3dbSNick Terrell static int zstd_init(struct crypto_tfm *tfm)
125d28fc3dbSNick Terrell {
126d28fc3dbSNick Terrell 	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
127d28fc3dbSNick Terrell 
128d28fc3dbSNick Terrell 	return __zstd_init(ctx);
129d28fc3dbSNick Terrell }
130d28fc3dbSNick Terrell 
__zstd_exit(void * ctx)131d28fc3dbSNick Terrell static void __zstd_exit(void *ctx)
132d28fc3dbSNick Terrell {
133d28fc3dbSNick Terrell 	zstd_comp_exit(ctx);
134d28fc3dbSNick Terrell 	zstd_decomp_exit(ctx);
135d28fc3dbSNick Terrell }
136d28fc3dbSNick Terrell 
zstd_free_ctx(struct crypto_scomp * tfm,void * ctx)137d28fc3dbSNick Terrell static void zstd_free_ctx(struct crypto_scomp *tfm, void *ctx)
138d28fc3dbSNick Terrell {
139d28fc3dbSNick Terrell 	__zstd_exit(ctx);
140453431a5SWaiman Long 	kfree_sensitive(ctx);
141d28fc3dbSNick Terrell }
142d28fc3dbSNick Terrell 
zstd_exit(struct crypto_tfm * tfm)143d28fc3dbSNick Terrell static void zstd_exit(struct crypto_tfm *tfm)
144d28fc3dbSNick Terrell {
145d28fc3dbSNick Terrell 	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
146d28fc3dbSNick Terrell 
147d28fc3dbSNick Terrell 	__zstd_exit(ctx);
148d28fc3dbSNick Terrell }
149d28fc3dbSNick Terrell 
__zstd_compress(const u8 * src,unsigned int slen,u8 * dst,unsigned int * dlen,void * ctx)150d28fc3dbSNick Terrell static int __zstd_compress(const u8 *src, unsigned int slen,
151d28fc3dbSNick Terrell 			   u8 *dst, unsigned int *dlen, void *ctx)
152d28fc3dbSNick Terrell {
153d28fc3dbSNick Terrell 	size_t out_len;
154d28fc3dbSNick Terrell 	struct zstd_ctx *zctx = ctx;
155*cf30f6a5SNick Terrell 	const zstd_parameters params = zstd_params();
156d28fc3dbSNick Terrell 
157*cf30f6a5SNick Terrell 	out_len = zstd_compress_cctx(zctx->cctx, dst, *dlen, src, slen, &params);
158*cf30f6a5SNick Terrell 	if (zstd_is_error(out_len))
159d28fc3dbSNick Terrell 		return -EINVAL;
160d28fc3dbSNick Terrell 	*dlen = out_len;
161d28fc3dbSNick Terrell 	return 0;
162d28fc3dbSNick Terrell }
163d28fc3dbSNick Terrell 
zstd_compress(struct crypto_tfm * tfm,const u8 * src,unsigned int slen,u8 * dst,unsigned int * dlen)164d28fc3dbSNick Terrell static int zstd_compress(struct crypto_tfm *tfm, const u8 *src,
165d28fc3dbSNick Terrell 			 unsigned int slen, u8 *dst, unsigned int *dlen)
166d28fc3dbSNick Terrell {
167d28fc3dbSNick Terrell 	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
168d28fc3dbSNick Terrell 
169d28fc3dbSNick Terrell 	return __zstd_compress(src, slen, dst, dlen, ctx);
170d28fc3dbSNick Terrell }
171d28fc3dbSNick Terrell 
zstd_scompress(struct crypto_scomp * tfm,const u8 * src,unsigned int slen,u8 * dst,unsigned int * dlen,void * ctx)172d28fc3dbSNick Terrell static int zstd_scompress(struct crypto_scomp *tfm, const u8 *src,
173d28fc3dbSNick Terrell 			  unsigned int slen, u8 *dst, unsigned int *dlen,
174d28fc3dbSNick Terrell 			  void *ctx)
175d28fc3dbSNick Terrell {
176d28fc3dbSNick Terrell 	return __zstd_compress(src, slen, dst, dlen, ctx);
177d28fc3dbSNick Terrell }
178d28fc3dbSNick Terrell 
__zstd_decompress(const u8 * src,unsigned int slen,u8 * dst,unsigned int * dlen,void * ctx)179d28fc3dbSNick Terrell static int __zstd_decompress(const u8 *src, unsigned int slen,
180d28fc3dbSNick Terrell 			     u8 *dst, unsigned int *dlen, void *ctx)
181d28fc3dbSNick Terrell {
182d28fc3dbSNick Terrell 	size_t out_len;
183d28fc3dbSNick Terrell 	struct zstd_ctx *zctx = ctx;
184d28fc3dbSNick Terrell 
185*cf30f6a5SNick Terrell 	out_len = zstd_decompress_dctx(zctx->dctx, dst, *dlen, src, slen);
186*cf30f6a5SNick Terrell 	if (zstd_is_error(out_len))
187d28fc3dbSNick Terrell 		return -EINVAL;
188d28fc3dbSNick Terrell 	*dlen = out_len;
189d28fc3dbSNick Terrell 	return 0;
190d28fc3dbSNick Terrell }
191d28fc3dbSNick Terrell 
zstd_decompress(struct crypto_tfm * tfm,const u8 * src,unsigned int slen,u8 * dst,unsigned int * dlen)192d28fc3dbSNick Terrell static int zstd_decompress(struct crypto_tfm *tfm, const u8 *src,
193d28fc3dbSNick Terrell 			   unsigned int slen, u8 *dst, unsigned int *dlen)
194d28fc3dbSNick Terrell {
195d28fc3dbSNick Terrell 	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
196d28fc3dbSNick Terrell 
197d28fc3dbSNick Terrell 	return __zstd_decompress(src, slen, dst, dlen, ctx);
198d28fc3dbSNick Terrell }
199d28fc3dbSNick Terrell 
zstd_sdecompress(struct crypto_scomp * tfm,const u8 * src,unsigned int slen,u8 * dst,unsigned int * dlen,void * ctx)200d28fc3dbSNick Terrell static int zstd_sdecompress(struct crypto_scomp *tfm, const u8 *src,
201d28fc3dbSNick Terrell 			    unsigned int slen, u8 *dst, unsigned int *dlen,
202d28fc3dbSNick Terrell 			    void *ctx)
203d28fc3dbSNick Terrell {
204d28fc3dbSNick Terrell 	return __zstd_decompress(src, slen, dst, dlen, ctx);
205d28fc3dbSNick Terrell }
206d28fc3dbSNick Terrell 
207d28fc3dbSNick Terrell static struct crypto_alg alg = {
208d28fc3dbSNick Terrell 	.cra_name		= "zstd",
209d6ebf528SEric Biggers 	.cra_driver_name	= "zstd-generic",
210d28fc3dbSNick Terrell 	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
211d28fc3dbSNick Terrell 	.cra_ctxsize		= sizeof(struct zstd_ctx),
212d28fc3dbSNick Terrell 	.cra_module		= THIS_MODULE,
213d28fc3dbSNick Terrell 	.cra_init		= zstd_init,
214d28fc3dbSNick Terrell 	.cra_exit		= zstd_exit,
215d28fc3dbSNick Terrell 	.cra_u			= { .compress = {
216d28fc3dbSNick Terrell 	.coa_compress		= zstd_compress,
217d28fc3dbSNick Terrell 	.coa_decompress		= zstd_decompress } }
218d28fc3dbSNick Terrell };
219d28fc3dbSNick Terrell 
220d28fc3dbSNick Terrell static struct scomp_alg scomp = {
221d28fc3dbSNick Terrell 	.alloc_ctx		= zstd_alloc_ctx,
222d28fc3dbSNick Terrell 	.free_ctx		= zstd_free_ctx,
223d28fc3dbSNick Terrell 	.compress		= zstd_scompress,
224d28fc3dbSNick Terrell 	.decompress		= zstd_sdecompress,
225d28fc3dbSNick Terrell 	.base			= {
226d28fc3dbSNick Terrell 		.cra_name	= "zstd",
227d28fc3dbSNick Terrell 		.cra_driver_name = "zstd-scomp",
228d28fc3dbSNick Terrell 		.cra_module	 = THIS_MODULE,
229d28fc3dbSNick Terrell 	}
230d28fc3dbSNick Terrell };
231d28fc3dbSNick Terrell 
zstd_mod_init(void)232d28fc3dbSNick Terrell static int __init zstd_mod_init(void)
233d28fc3dbSNick Terrell {
234d28fc3dbSNick Terrell 	int ret;
235d28fc3dbSNick Terrell 
236d28fc3dbSNick Terrell 	ret = crypto_register_alg(&alg);
237d28fc3dbSNick Terrell 	if (ret)
238d28fc3dbSNick Terrell 		return ret;
239d28fc3dbSNick Terrell 
240d28fc3dbSNick Terrell 	ret = crypto_register_scomp(&scomp);
241d28fc3dbSNick Terrell 	if (ret)
242d28fc3dbSNick Terrell 		crypto_unregister_alg(&alg);
243d28fc3dbSNick Terrell 
244d28fc3dbSNick Terrell 	return ret;
245d28fc3dbSNick Terrell }
246d28fc3dbSNick Terrell 
zstd_mod_fini(void)247d28fc3dbSNick Terrell static void __exit zstd_mod_fini(void)
248d28fc3dbSNick Terrell {
249d28fc3dbSNick Terrell 	crypto_unregister_alg(&alg);
250d28fc3dbSNick Terrell 	crypto_unregister_scomp(&scomp);
251d28fc3dbSNick Terrell }
252d28fc3dbSNick Terrell 
253c4741b23SEric Biggers subsys_initcall(zstd_mod_init);
254d28fc3dbSNick Terrell module_exit(zstd_mod_fini);
255d28fc3dbSNick Terrell 
256d28fc3dbSNick Terrell MODULE_LICENSE("GPL");
257d28fc3dbSNick Terrell MODULE_DESCRIPTION("Zstd Compression Algorithm");
258d28fc3dbSNick Terrell MODULE_ALIAS_CRYPTO("zstd");
259