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(¶ms.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, ¶ms);
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