xref: /linux/crypto/zstd.c (revision d28fc3db)
1*d28fc3dbSNick Terrell /*
2*d28fc3dbSNick Terrell  * Cryptographic API.
3*d28fc3dbSNick Terrell  *
4*d28fc3dbSNick Terrell  * Copyright (c) 2017-present, Facebook, Inc.
5*d28fc3dbSNick Terrell  *
6*d28fc3dbSNick Terrell  * This program is free software; you can redistribute it and/or modify it
7*d28fc3dbSNick Terrell  * under the terms of the GNU General Public License version 2 as published by
8*d28fc3dbSNick Terrell  * the Free Software Foundation.
9*d28fc3dbSNick Terrell  *
10*d28fc3dbSNick Terrell  * This program is distributed in the hope that it will be useful, but WITHOUT
11*d28fc3dbSNick Terrell  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12*d28fc3dbSNick Terrell  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13*d28fc3dbSNick Terrell  * more details.
14*d28fc3dbSNick Terrell  */
15*d28fc3dbSNick Terrell #include <linux/crypto.h>
16*d28fc3dbSNick Terrell #include <linux/init.h>
17*d28fc3dbSNick Terrell #include <linux/interrupt.h>
18*d28fc3dbSNick Terrell #include <linux/mm.h>
19*d28fc3dbSNick Terrell #include <linux/module.h>
20*d28fc3dbSNick Terrell #include <linux/net.h>
21*d28fc3dbSNick Terrell #include <linux/vmalloc.h>
22*d28fc3dbSNick Terrell #include <linux/zstd.h>
23*d28fc3dbSNick Terrell #include <crypto/internal/scompress.h>
24*d28fc3dbSNick Terrell 
25*d28fc3dbSNick Terrell 
26*d28fc3dbSNick Terrell #define ZSTD_DEF_LEVEL	3
27*d28fc3dbSNick Terrell 
28*d28fc3dbSNick Terrell struct zstd_ctx {
29*d28fc3dbSNick Terrell 	ZSTD_CCtx *cctx;
30*d28fc3dbSNick Terrell 	ZSTD_DCtx *dctx;
31*d28fc3dbSNick Terrell 	void *cwksp;
32*d28fc3dbSNick Terrell 	void *dwksp;
33*d28fc3dbSNick Terrell };
34*d28fc3dbSNick Terrell 
35*d28fc3dbSNick Terrell static ZSTD_parameters zstd_params(void)
36*d28fc3dbSNick Terrell {
37*d28fc3dbSNick Terrell 	return ZSTD_getParams(ZSTD_DEF_LEVEL, 0, 0);
38*d28fc3dbSNick Terrell }
39*d28fc3dbSNick Terrell 
40*d28fc3dbSNick Terrell static int zstd_comp_init(struct zstd_ctx *ctx)
41*d28fc3dbSNick Terrell {
42*d28fc3dbSNick Terrell 	int ret = 0;
43*d28fc3dbSNick Terrell 	const ZSTD_parameters params = zstd_params();
44*d28fc3dbSNick Terrell 	const size_t wksp_size = ZSTD_CCtxWorkspaceBound(params.cParams);
45*d28fc3dbSNick Terrell 
46*d28fc3dbSNick Terrell 	ctx->cwksp = vzalloc(wksp_size);
47*d28fc3dbSNick Terrell 	if (!ctx->cwksp) {
48*d28fc3dbSNick Terrell 		ret = -ENOMEM;
49*d28fc3dbSNick Terrell 		goto out;
50*d28fc3dbSNick Terrell 	}
51*d28fc3dbSNick Terrell 
52*d28fc3dbSNick Terrell 	ctx->cctx = ZSTD_initCCtx(ctx->cwksp, wksp_size);
53*d28fc3dbSNick Terrell 	if (!ctx->cctx) {
54*d28fc3dbSNick Terrell 		ret = -EINVAL;
55*d28fc3dbSNick Terrell 		goto out_free;
56*d28fc3dbSNick Terrell 	}
57*d28fc3dbSNick Terrell out:
58*d28fc3dbSNick Terrell 	return ret;
59*d28fc3dbSNick Terrell out_free:
60*d28fc3dbSNick Terrell 	vfree(ctx->cwksp);
61*d28fc3dbSNick Terrell 	goto out;
62*d28fc3dbSNick Terrell }
63*d28fc3dbSNick Terrell 
64*d28fc3dbSNick Terrell static int zstd_decomp_init(struct zstd_ctx *ctx)
65*d28fc3dbSNick Terrell {
66*d28fc3dbSNick Terrell 	int ret = 0;
67*d28fc3dbSNick Terrell 	const size_t wksp_size = ZSTD_DCtxWorkspaceBound();
68*d28fc3dbSNick Terrell 
69*d28fc3dbSNick Terrell 	ctx->dwksp = vzalloc(wksp_size);
70*d28fc3dbSNick Terrell 	if (!ctx->dwksp) {
71*d28fc3dbSNick Terrell 		ret = -ENOMEM;
72*d28fc3dbSNick Terrell 		goto out;
73*d28fc3dbSNick Terrell 	}
74*d28fc3dbSNick Terrell 
75*d28fc3dbSNick Terrell 	ctx->dctx = ZSTD_initDCtx(ctx->dwksp, wksp_size);
76*d28fc3dbSNick Terrell 	if (!ctx->dctx) {
77*d28fc3dbSNick Terrell 		ret = -EINVAL;
78*d28fc3dbSNick Terrell 		goto out_free;
79*d28fc3dbSNick Terrell 	}
80*d28fc3dbSNick Terrell out:
81*d28fc3dbSNick Terrell 	return ret;
82*d28fc3dbSNick Terrell out_free:
83*d28fc3dbSNick Terrell 	vfree(ctx->dwksp);
84*d28fc3dbSNick Terrell 	goto out;
85*d28fc3dbSNick Terrell }
86*d28fc3dbSNick Terrell 
87*d28fc3dbSNick Terrell static void zstd_comp_exit(struct zstd_ctx *ctx)
88*d28fc3dbSNick Terrell {
89*d28fc3dbSNick Terrell 	vfree(ctx->cwksp);
90*d28fc3dbSNick Terrell 	ctx->cwksp = NULL;
91*d28fc3dbSNick Terrell 	ctx->cctx = NULL;
92*d28fc3dbSNick Terrell }
93*d28fc3dbSNick Terrell 
94*d28fc3dbSNick Terrell static void zstd_decomp_exit(struct zstd_ctx *ctx)
95*d28fc3dbSNick Terrell {
96*d28fc3dbSNick Terrell 	vfree(ctx->dwksp);
97*d28fc3dbSNick Terrell 	ctx->dwksp = NULL;
98*d28fc3dbSNick Terrell 	ctx->dctx = NULL;
99*d28fc3dbSNick Terrell }
100*d28fc3dbSNick Terrell 
101*d28fc3dbSNick Terrell static int __zstd_init(void *ctx)
102*d28fc3dbSNick Terrell {
103*d28fc3dbSNick Terrell 	int ret;
104*d28fc3dbSNick Terrell 
105*d28fc3dbSNick Terrell 	ret = zstd_comp_init(ctx);
106*d28fc3dbSNick Terrell 	if (ret)
107*d28fc3dbSNick Terrell 		return ret;
108*d28fc3dbSNick Terrell 	ret = zstd_decomp_init(ctx);
109*d28fc3dbSNick Terrell 	if (ret)
110*d28fc3dbSNick Terrell 		zstd_comp_exit(ctx);
111*d28fc3dbSNick Terrell 	return ret;
112*d28fc3dbSNick Terrell }
113*d28fc3dbSNick Terrell 
114*d28fc3dbSNick Terrell static void *zstd_alloc_ctx(struct crypto_scomp *tfm)
115*d28fc3dbSNick Terrell {
116*d28fc3dbSNick Terrell 	int ret;
117*d28fc3dbSNick Terrell 	struct zstd_ctx *ctx;
118*d28fc3dbSNick Terrell 
119*d28fc3dbSNick Terrell 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
120*d28fc3dbSNick Terrell 	if (!ctx)
121*d28fc3dbSNick Terrell 		return ERR_PTR(-ENOMEM);
122*d28fc3dbSNick Terrell 
123*d28fc3dbSNick Terrell 	ret = __zstd_init(ctx);
124*d28fc3dbSNick Terrell 	if (ret) {
125*d28fc3dbSNick Terrell 		kfree(ctx);
126*d28fc3dbSNick Terrell 		return ERR_PTR(ret);
127*d28fc3dbSNick Terrell 	}
128*d28fc3dbSNick Terrell 
129*d28fc3dbSNick Terrell 	return ctx;
130*d28fc3dbSNick Terrell }
131*d28fc3dbSNick Terrell 
132*d28fc3dbSNick Terrell static int zstd_init(struct crypto_tfm *tfm)
133*d28fc3dbSNick Terrell {
134*d28fc3dbSNick Terrell 	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
135*d28fc3dbSNick Terrell 
136*d28fc3dbSNick Terrell 	return __zstd_init(ctx);
137*d28fc3dbSNick Terrell }
138*d28fc3dbSNick Terrell 
139*d28fc3dbSNick Terrell static void __zstd_exit(void *ctx)
140*d28fc3dbSNick Terrell {
141*d28fc3dbSNick Terrell 	zstd_comp_exit(ctx);
142*d28fc3dbSNick Terrell 	zstd_decomp_exit(ctx);
143*d28fc3dbSNick Terrell }
144*d28fc3dbSNick Terrell 
145*d28fc3dbSNick Terrell static void zstd_free_ctx(struct crypto_scomp *tfm, void *ctx)
146*d28fc3dbSNick Terrell {
147*d28fc3dbSNick Terrell 	__zstd_exit(ctx);
148*d28fc3dbSNick Terrell 	kzfree(ctx);
149*d28fc3dbSNick Terrell }
150*d28fc3dbSNick Terrell 
151*d28fc3dbSNick Terrell static void zstd_exit(struct crypto_tfm *tfm)
152*d28fc3dbSNick Terrell {
153*d28fc3dbSNick Terrell 	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
154*d28fc3dbSNick Terrell 
155*d28fc3dbSNick Terrell 	__zstd_exit(ctx);
156*d28fc3dbSNick Terrell }
157*d28fc3dbSNick Terrell 
158*d28fc3dbSNick Terrell static int __zstd_compress(const u8 *src, unsigned int slen,
159*d28fc3dbSNick Terrell 			   u8 *dst, unsigned int *dlen, void *ctx)
160*d28fc3dbSNick Terrell {
161*d28fc3dbSNick Terrell 	size_t out_len;
162*d28fc3dbSNick Terrell 	struct zstd_ctx *zctx = ctx;
163*d28fc3dbSNick Terrell 	const ZSTD_parameters params = zstd_params();
164*d28fc3dbSNick Terrell 
165*d28fc3dbSNick Terrell 	out_len = ZSTD_compressCCtx(zctx->cctx, dst, *dlen, src, slen, params);
166*d28fc3dbSNick Terrell 	if (ZSTD_isError(out_len))
167*d28fc3dbSNick Terrell 		return -EINVAL;
168*d28fc3dbSNick Terrell 	*dlen = out_len;
169*d28fc3dbSNick Terrell 	return 0;
170*d28fc3dbSNick Terrell }
171*d28fc3dbSNick Terrell 
172*d28fc3dbSNick Terrell static int zstd_compress(struct crypto_tfm *tfm, const u8 *src,
173*d28fc3dbSNick Terrell 			 unsigned int slen, u8 *dst, unsigned int *dlen)
174*d28fc3dbSNick Terrell {
175*d28fc3dbSNick Terrell 	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
176*d28fc3dbSNick Terrell 
177*d28fc3dbSNick Terrell 	return __zstd_compress(src, slen, dst, dlen, ctx);
178*d28fc3dbSNick Terrell }
179*d28fc3dbSNick Terrell 
180*d28fc3dbSNick Terrell static int zstd_scompress(struct crypto_scomp *tfm, const u8 *src,
181*d28fc3dbSNick Terrell 			  unsigned int slen, u8 *dst, unsigned int *dlen,
182*d28fc3dbSNick Terrell 			  void *ctx)
183*d28fc3dbSNick Terrell {
184*d28fc3dbSNick Terrell 	return __zstd_compress(src, slen, dst, dlen, ctx);
185*d28fc3dbSNick Terrell }
186*d28fc3dbSNick Terrell 
187*d28fc3dbSNick Terrell static int __zstd_decompress(const u8 *src, unsigned int slen,
188*d28fc3dbSNick Terrell 			     u8 *dst, unsigned int *dlen, void *ctx)
189*d28fc3dbSNick Terrell {
190*d28fc3dbSNick Terrell 	size_t out_len;
191*d28fc3dbSNick Terrell 	struct zstd_ctx *zctx = ctx;
192*d28fc3dbSNick Terrell 
193*d28fc3dbSNick Terrell 	out_len = ZSTD_decompressDCtx(zctx->dctx, dst, *dlen, src, slen);
194*d28fc3dbSNick Terrell 	if (ZSTD_isError(out_len))
195*d28fc3dbSNick Terrell 		return -EINVAL;
196*d28fc3dbSNick Terrell 	*dlen = out_len;
197*d28fc3dbSNick Terrell 	return 0;
198*d28fc3dbSNick Terrell }
199*d28fc3dbSNick Terrell 
200*d28fc3dbSNick Terrell static int zstd_decompress(struct crypto_tfm *tfm, const u8 *src,
201*d28fc3dbSNick Terrell 			   unsigned int slen, u8 *dst, unsigned int *dlen)
202*d28fc3dbSNick Terrell {
203*d28fc3dbSNick Terrell 	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
204*d28fc3dbSNick Terrell 
205*d28fc3dbSNick Terrell 	return __zstd_decompress(src, slen, dst, dlen, ctx);
206*d28fc3dbSNick Terrell }
207*d28fc3dbSNick Terrell 
208*d28fc3dbSNick Terrell static int zstd_sdecompress(struct crypto_scomp *tfm, const u8 *src,
209*d28fc3dbSNick Terrell 			    unsigned int slen, u8 *dst, unsigned int *dlen,
210*d28fc3dbSNick Terrell 			    void *ctx)
211*d28fc3dbSNick Terrell {
212*d28fc3dbSNick Terrell 	return __zstd_decompress(src, slen, dst, dlen, ctx);
213*d28fc3dbSNick Terrell }
214*d28fc3dbSNick Terrell 
215*d28fc3dbSNick Terrell static struct crypto_alg alg = {
216*d28fc3dbSNick Terrell 	.cra_name		= "zstd",
217*d28fc3dbSNick Terrell 	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
218*d28fc3dbSNick Terrell 	.cra_ctxsize		= sizeof(struct zstd_ctx),
219*d28fc3dbSNick Terrell 	.cra_module		= THIS_MODULE,
220*d28fc3dbSNick Terrell 	.cra_init		= zstd_init,
221*d28fc3dbSNick Terrell 	.cra_exit		= zstd_exit,
222*d28fc3dbSNick Terrell 	.cra_u			= { .compress = {
223*d28fc3dbSNick Terrell 	.coa_compress		= zstd_compress,
224*d28fc3dbSNick Terrell 	.coa_decompress		= zstd_decompress } }
225*d28fc3dbSNick Terrell };
226*d28fc3dbSNick Terrell 
227*d28fc3dbSNick Terrell static struct scomp_alg scomp = {
228*d28fc3dbSNick Terrell 	.alloc_ctx		= zstd_alloc_ctx,
229*d28fc3dbSNick Terrell 	.free_ctx		= zstd_free_ctx,
230*d28fc3dbSNick Terrell 	.compress		= zstd_scompress,
231*d28fc3dbSNick Terrell 	.decompress		= zstd_sdecompress,
232*d28fc3dbSNick Terrell 	.base			= {
233*d28fc3dbSNick Terrell 		.cra_name	= "zstd",
234*d28fc3dbSNick Terrell 		.cra_driver_name = "zstd-scomp",
235*d28fc3dbSNick Terrell 		.cra_module	 = THIS_MODULE,
236*d28fc3dbSNick Terrell 	}
237*d28fc3dbSNick Terrell };
238*d28fc3dbSNick Terrell 
239*d28fc3dbSNick Terrell static int __init zstd_mod_init(void)
240*d28fc3dbSNick Terrell {
241*d28fc3dbSNick Terrell 	int ret;
242*d28fc3dbSNick Terrell 
243*d28fc3dbSNick Terrell 	ret = crypto_register_alg(&alg);
244*d28fc3dbSNick Terrell 	if (ret)
245*d28fc3dbSNick Terrell 		return ret;
246*d28fc3dbSNick Terrell 
247*d28fc3dbSNick Terrell 	ret = crypto_register_scomp(&scomp);
248*d28fc3dbSNick Terrell 	if (ret)
249*d28fc3dbSNick Terrell 		crypto_unregister_alg(&alg);
250*d28fc3dbSNick Terrell 
251*d28fc3dbSNick Terrell 	return ret;
252*d28fc3dbSNick Terrell }
253*d28fc3dbSNick Terrell 
254*d28fc3dbSNick Terrell static void __exit zstd_mod_fini(void)
255*d28fc3dbSNick Terrell {
256*d28fc3dbSNick Terrell 	crypto_unregister_alg(&alg);
257*d28fc3dbSNick Terrell 	crypto_unregister_scomp(&scomp);
258*d28fc3dbSNick Terrell }
259*d28fc3dbSNick Terrell 
260*d28fc3dbSNick Terrell module_init(zstd_mod_init);
261*d28fc3dbSNick Terrell module_exit(zstd_mod_fini);
262*d28fc3dbSNick Terrell 
263*d28fc3dbSNick Terrell MODULE_LICENSE("GPL");
264*d28fc3dbSNick Terrell MODULE_DESCRIPTION("Zstd Compression Algorithm");
265*d28fc3dbSNick Terrell MODULE_ALIAS_CRYPTO("zstd");
266