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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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