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 {
21cf30f6a5SNick Terrell zstd_cctx *cctx;
22cf30f6a5SNick Terrell zstd_dctx *dctx;
23d28fc3dbSNick Terrell void *cwksp;
24d28fc3dbSNick Terrell void *dwksp;
25d28fc3dbSNick Terrell };
26d28fc3dbSNick Terrell
zstd_params(void)27cf30f6a5SNick Terrell static zstd_parameters zstd_params(void)
28d28fc3dbSNick Terrell {
29cf30f6a5SNick 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;
35cf30f6a5SNick Terrell const zstd_parameters params = zstd_params();
36cf30f6a5SNick 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
44cf30f6a5SNick 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;
59cf30f6a5SNick 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
67cf30f6a5SNick 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(void)1060af7304cSHerbert Xu static void *zstd_alloc_ctx(void)
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_exit(void * ctx)124d28fc3dbSNick Terrell static void __zstd_exit(void *ctx)
125d28fc3dbSNick Terrell {
126d28fc3dbSNick Terrell zstd_comp_exit(ctx);
127d28fc3dbSNick Terrell zstd_decomp_exit(ctx);
128d28fc3dbSNick Terrell }
129d28fc3dbSNick Terrell
zstd_free_ctx(void * ctx)1300af7304cSHerbert Xu static void zstd_free_ctx(void *ctx)
131d28fc3dbSNick Terrell {
132d28fc3dbSNick Terrell __zstd_exit(ctx);
133453431a5SWaiman Long kfree_sensitive(ctx);
134d28fc3dbSNick Terrell }
135d28fc3dbSNick Terrell
__zstd_compress(const u8 * src,unsigned int slen,u8 * dst,unsigned int * dlen,void * ctx)136d28fc3dbSNick Terrell static int __zstd_compress(const u8 *src, unsigned int slen,
137d28fc3dbSNick Terrell u8 *dst, unsigned int *dlen, void *ctx)
138d28fc3dbSNick Terrell {
139d28fc3dbSNick Terrell size_t out_len;
140d28fc3dbSNick Terrell struct zstd_ctx *zctx = ctx;
141cf30f6a5SNick Terrell const zstd_parameters params = zstd_params();
142d28fc3dbSNick Terrell
143cf30f6a5SNick Terrell out_len = zstd_compress_cctx(zctx->cctx, dst, *dlen, src, slen, ¶ms);
144cf30f6a5SNick Terrell if (zstd_is_error(out_len))
145d28fc3dbSNick Terrell return -EINVAL;
146d28fc3dbSNick Terrell *dlen = out_len;
147d28fc3dbSNick Terrell return 0;
148d28fc3dbSNick Terrell }
149d28fc3dbSNick Terrell
zstd_scompress(struct crypto_scomp * tfm,const u8 * src,unsigned int slen,u8 * dst,unsigned int * dlen,void * ctx)150d28fc3dbSNick Terrell static int zstd_scompress(struct crypto_scomp *tfm, const u8 *src,
151d28fc3dbSNick Terrell unsigned int slen, u8 *dst, unsigned int *dlen,
152d28fc3dbSNick Terrell void *ctx)
153d28fc3dbSNick Terrell {
154d28fc3dbSNick Terrell return __zstd_compress(src, slen, dst, dlen, ctx);
155d28fc3dbSNick Terrell }
156d28fc3dbSNick Terrell
__zstd_decompress(const u8 * src,unsigned int slen,u8 * dst,unsigned int * dlen,void * ctx)157d28fc3dbSNick Terrell static int __zstd_decompress(const u8 *src, unsigned int slen,
158d28fc3dbSNick Terrell u8 *dst, unsigned int *dlen, void *ctx)
159d28fc3dbSNick Terrell {
160d28fc3dbSNick Terrell size_t out_len;
161d28fc3dbSNick Terrell struct zstd_ctx *zctx = ctx;
162d28fc3dbSNick Terrell
163cf30f6a5SNick Terrell out_len = zstd_decompress_dctx(zctx->dctx, dst, *dlen, src, slen);
164cf30f6a5SNick Terrell if (zstd_is_error(out_len))
165d28fc3dbSNick Terrell return -EINVAL;
166d28fc3dbSNick Terrell *dlen = out_len;
167d28fc3dbSNick Terrell return 0;
168d28fc3dbSNick Terrell }
169d28fc3dbSNick Terrell
zstd_sdecompress(struct crypto_scomp * tfm,const u8 * src,unsigned int slen,u8 * dst,unsigned int * dlen,void * ctx)170d28fc3dbSNick Terrell static int zstd_sdecompress(struct crypto_scomp *tfm, const u8 *src,
171d28fc3dbSNick Terrell unsigned int slen, u8 *dst, unsigned int *dlen,
172d28fc3dbSNick Terrell void *ctx)
173d28fc3dbSNick Terrell {
174d28fc3dbSNick Terrell return __zstd_decompress(src, slen, dst, dlen, ctx);
175d28fc3dbSNick Terrell }
176d28fc3dbSNick Terrell
177d28fc3dbSNick Terrell static struct scomp_alg scomp = {
178d28fc3dbSNick Terrell .alloc_ctx = zstd_alloc_ctx,
179d28fc3dbSNick Terrell .free_ctx = zstd_free_ctx,
180d28fc3dbSNick Terrell .compress = zstd_scompress,
181d28fc3dbSNick Terrell .decompress = zstd_sdecompress,
182d28fc3dbSNick Terrell .base = {
183d28fc3dbSNick Terrell .cra_name = "zstd",
184d28fc3dbSNick Terrell .cra_driver_name = "zstd-scomp",
185d28fc3dbSNick Terrell .cra_module = THIS_MODULE,
186d28fc3dbSNick Terrell }
187d28fc3dbSNick Terrell };
188d28fc3dbSNick Terrell
zstd_mod_init(void)189d28fc3dbSNick Terrell static int __init zstd_mod_init(void)
190d28fc3dbSNick Terrell {
191*8beb4045SArd Biesheuvel return crypto_register_scomp(&scomp);
192d28fc3dbSNick Terrell }
193d28fc3dbSNick Terrell
zstd_mod_fini(void)194d28fc3dbSNick Terrell static void __exit zstd_mod_fini(void)
195d28fc3dbSNick Terrell {
196d28fc3dbSNick Terrell crypto_unregister_scomp(&scomp);
197d28fc3dbSNick Terrell }
198d28fc3dbSNick Terrell
199c4741b23SEric Biggers subsys_initcall(zstd_mod_init);
200d28fc3dbSNick Terrell module_exit(zstd_mod_fini);
201d28fc3dbSNick Terrell
202d28fc3dbSNick Terrell MODULE_LICENSE("GPL");
203d28fc3dbSNick Terrell MODULE_DESCRIPTION("Zstd Compression Algorithm");
204d28fc3dbSNick Terrell MODULE_ALIAS_CRYPTO("zstd");
205