1321936Shselasky// SPDX-License-Identifier: GPL-2.0-only 2321936Shselasky/* 3321936Shselasky * Cryptographic API. 4321936Shselasky * 5321936Shselasky * Copyright (c) 2017-present, Facebook, Inc. 6321936Shselasky */ 7321936Shselasky#include <linux/crypto.h> 8321936Shselasky#include <linux/init.h> 9321936Shselasky#include <linux/interrupt.h> 10321936Shselasky#include <linux/mm.h> 11321936Shselasky#include <linux/module.h> 12321936Shselasky#include <linux/net.h> 13321936Shselasky#include <linux/vmalloc.h> 14321936Shselasky#include <linux/zstd.h> 15321936Shselasky#include <crypto/internal/scompress.h> 16321936Shselasky 17321936Shselasky 18321936Shselasky#define ZSTD_DEF_LEVEL 3 19321936Shselasky 20321936Shselaskystruct zstd_ctx { 21321936Shselasky zstd_cctx *cctx; 22321936Shselasky zstd_dctx *dctx; 23321936Shselasky void *cwksp; 24321936Shselasky void *dwksp; 25321936Shselasky}; 26321936Shselasky 27321936Shselaskystatic zstd_parameters zstd_params(void) 28321936Shselasky{ 29321936Shselasky return zstd_get_params(ZSTD_DEF_LEVEL, 0); 30321936Shselasky} 31321936Shselasky 32321936Shselaskystatic int zstd_comp_init(struct zstd_ctx *ctx) 33321936Shselasky{ 34321936Shselasky int ret = 0; 35321936Shselasky const zstd_parameters params = zstd_params(); 36321936Shselasky const size_t wksp_size = zstd_cctx_workspace_bound(¶ms.cParams); 37321936Shselasky 38321936Shselasky ctx->cwksp = vzalloc(wksp_size); 39321936Shselasky if (!ctx->cwksp) { 40321936Shselasky ret = -ENOMEM; 41321936Shselasky goto out; 42321936Shselasky } 43321936Shselasky 44321936Shselasky ctx->cctx = zstd_init_cctx(ctx->cwksp, wksp_size); 45321936Shselasky if (!ctx->cctx) { 46321936Shselasky ret = -EINVAL; 47321936Shselasky goto out_free; 48321936Shselasky } 49321936Shselaskyout: 50321936Shselasky return ret; 51321936Shselaskyout_free: 52321936Shselasky vfree(ctx->cwksp); 53321936Shselasky goto out; 54321936Shselasky} 55321936Shselasky 56321936Shselaskystatic int zstd_decomp_init(struct zstd_ctx *ctx) 57321936Shselasky{ 58321936Shselasky int ret = 0; 59321936Shselasky const size_t wksp_size = zstd_dctx_workspace_bound(); 60321936Shselasky 61321936Shselasky ctx->dwksp = vzalloc(wksp_size); 62321936Shselasky if (!ctx->dwksp) { 63321936Shselasky ret = -ENOMEM; 64321936Shselasky goto out; 65321936Shselasky } 66321936Shselasky 67321936Shselasky ctx->dctx = zstd_init_dctx(ctx->dwksp, wksp_size); 68321936Shselasky if (!ctx->dctx) { 69321936Shselasky ret = -EINVAL; 70321936Shselasky goto out_free; 71321936Shselasky } 72321936Shselaskyout: 73321936Shselasky return ret; 74321936Shselaskyout_free: 75321936Shselasky vfree(ctx->dwksp); 76321936Shselasky goto out; 77321936Shselasky} 78321936Shselasky 79321936Shselaskystatic void zstd_comp_exit(struct zstd_ctx *ctx) 80321936Shselasky{ 81321936Shselasky vfree(ctx->cwksp); 82321936Shselasky ctx->cwksp = NULL; 83321936Shselasky ctx->cctx = NULL; 84321936Shselasky} 85321936Shselasky 86321936Shselaskystatic void zstd_decomp_exit(struct zstd_ctx *ctx) 87321936Shselasky{ 88321936Shselasky vfree(ctx->dwksp); 89321936Shselasky ctx->dwksp = NULL; 90321936Shselasky ctx->dctx = NULL; 91321936Shselasky} 92321936Shselasky 93321936Shselaskystatic int __zstd_init(void *ctx) 94321936Shselasky{ 95321936Shselasky int ret; 96321936Shselasky 97321936Shselasky ret = zstd_comp_init(ctx); 98321936Shselasky if (ret) 99321936Shselasky return ret; 100321936Shselasky ret = zstd_decomp_init(ctx); 101321936Shselasky if (ret) 102321936Shselasky zstd_comp_exit(ctx); 103321936Shselasky return ret; 104321936Shselasky} 105321936Shselasky 106321936Shselaskystatic void *zstd_alloc_ctx(struct crypto_scomp *tfm) 107321936Shselasky{ 108321936Shselasky int ret; 109321936Shselasky struct zstd_ctx *ctx; 110321936Shselasky 111321936Shselasky ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 112321936Shselasky if (!ctx) 113321936Shselasky return ERR_PTR(-ENOMEM); 114321936Shselasky 115321936Shselasky ret = __zstd_init(ctx); 116321936Shselasky if (ret) { 117321936Shselasky kfree(ctx); 118321936Shselasky return ERR_PTR(ret); 119321936Shselasky } 120321936Shselasky 121321936Shselasky return ctx; 122321936Shselasky} 123321936Shselasky 124321936Shselaskystatic int zstd_init(struct crypto_tfm *tfm) 125321936Shselasky{ 126321936Shselasky struct zstd_ctx *ctx = crypto_tfm_ctx(tfm); 127321936Shselasky 128321936Shselasky return __zstd_init(ctx); 129321936Shselasky} 130321936Shselasky 131321936Shselaskystatic void __zstd_exit(void *ctx) 132321936Shselasky{ 133321936Shselasky zstd_comp_exit(ctx); 134321936Shselasky zstd_decomp_exit(ctx); 135321936Shselasky} 136321936Shselasky 137321936Shselaskystatic void zstd_free_ctx(struct crypto_scomp *tfm, void *ctx) 138321936Shselasky{ 139321936Shselasky __zstd_exit(ctx); 140321936Shselasky kfree_sensitive(ctx); 141321936Shselasky} 142321936Shselasky 143321936Shselaskystatic void zstd_exit(struct crypto_tfm *tfm) 144321936Shselasky{ 145321936Shselasky struct zstd_ctx *ctx = crypto_tfm_ctx(tfm); 146321936Shselasky 147321936Shselasky __zstd_exit(ctx); 148321936Shselasky} 149321936Shselasky 150321936Shselaskystatic int __zstd_compress(const u8 *src, unsigned int slen, 151321936Shselasky u8 *dst, unsigned int *dlen, void *ctx) 152321936Shselasky{ 153321936Shselasky size_t out_len; 154321936Shselasky struct zstd_ctx *zctx = ctx; 155321936Shselasky const zstd_parameters params = zstd_params(); 156321936Shselasky 157321936Shselasky out_len = zstd_compress_cctx(zctx->cctx, dst, *dlen, src, slen, ¶ms); 158321936Shselasky if (zstd_is_error(out_len)) 159321936Shselasky return -EINVAL; 160321936Shselasky *dlen = out_len; 161321936Shselasky return 0; 162321936Shselasky} 163321936Shselasky 164321936Shselaskystatic int zstd_compress(struct crypto_tfm *tfm, const u8 *src, 165321936Shselasky unsigned int slen, u8 *dst, unsigned int *dlen) 166321936Shselasky{ 167321936Shselasky struct zstd_ctx *ctx = crypto_tfm_ctx(tfm); 168321936Shselasky 169321936Shselasky return __zstd_compress(src, slen, dst, dlen, ctx); 170321936Shselasky} 171321936Shselasky 172321936Shselaskystatic int zstd_scompress(struct crypto_scomp *tfm, const u8 *src, 173321936Shselasky unsigned int slen, u8 *dst, unsigned int *dlen, 174321936Shselasky void *ctx) 175321936Shselasky{ 176321936Shselasky return __zstd_compress(src, slen, dst, dlen, ctx); 177321936Shselasky} 178321936Shselasky 179321936Shselaskystatic int __zstd_decompress(const u8 *src, unsigned int slen, 180321936Shselasky u8 *dst, unsigned int *dlen, void *ctx) 181321936Shselasky{ 182321936Shselasky size_t out_len; 183321936Shselasky struct zstd_ctx *zctx = ctx; 184321936Shselasky 185321936Shselasky out_len = zstd_decompress_dctx(zctx->dctx, dst, *dlen, src, slen); 186321936Shselasky if (zstd_is_error(out_len)) 187321936Shselasky return -EINVAL; 188321936Shselasky *dlen = out_len; 189321936Shselasky return 0; 190321936Shselasky} 191321936Shselasky 192321936Shselaskystatic int zstd_decompress(struct crypto_tfm *tfm, const u8 *src, 193321936Shselasky unsigned int slen, u8 *dst, unsigned int *dlen) 194321936Shselasky{ 195321936Shselasky struct zstd_ctx *ctx = crypto_tfm_ctx(tfm); 196321936Shselasky 197321936Shselasky return __zstd_decompress(src, slen, dst, dlen, ctx); 198321936Shselasky} 199321936Shselasky 200321936Shselaskystatic int zstd_sdecompress(struct crypto_scomp *tfm, const u8 *src, 201321936Shselasky unsigned int slen, u8 *dst, unsigned int *dlen, 202321936Shselasky void *ctx) 203321936Shselasky{ 204321936Shselasky return __zstd_decompress(src, slen, dst, dlen, ctx); 205321936Shselasky} 206321936Shselasky 207321936Shselaskystatic struct crypto_alg alg = { 208321936Shselasky .cra_name = "zstd", 209321936Shselasky .cra_driver_name = "zstd-generic", 210321936Shselasky .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, 211321936Shselasky .cra_ctxsize = sizeof(struct zstd_ctx), 212321936Shselasky .cra_module = THIS_MODULE, 213321936Shselasky .cra_init = zstd_init, 214321936Shselasky .cra_exit = zstd_exit, 215321936Shselasky .cra_u = { .compress = { 216321936Shselasky .coa_compress = zstd_compress, 217321936Shselasky .coa_decompress = zstd_decompress } } 218321936Shselasky}; 219321936Shselasky 220321936Shselaskystatic struct scomp_alg scomp = { 221321936Shselasky .alloc_ctx = zstd_alloc_ctx, 222321936Shselasky .free_ctx = zstd_free_ctx, 223321936Shselasky .compress = zstd_scompress, 224321936Shselasky .decompress = zstd_sdecompress, 225321936Shselasky .base = { 226321936Shselasky .cra_name = "zstd", 227321936Shselasky .cra_driver_name = "zstd-scomp", 228321936Shselasky .cra_module = THIS_MODULE, 229321936Shselasky } 230321936Shselasky}; 231321936Shselasky 232321936Shselaskystatic int __init zstd_mod_init(void) 233321936Shselasky{ 234321936Shselasky int ret; 235321936Shselasky 236321936Shselasky ret = crypto_register_alg(&alg); 237321936Shselasky if (ret) 238321936Shselasky return ret; 239321936Shselasky 240321936Shselasky ret = crypto_register_scomp(&scomp); 241321936Shselasky if (ret) 242321936Shselasky crypto_unregister_alg(&alg); 243321936Shselasky 244321936Shselasky return ret; 245321936Shselasky} 246321936Shselasky 247321936Shselaskystatic void __exit zstd_mod_fini(void) 248321936Shselasky{ 249321936Shselasky crypto_unregister_alg(&alg); 250321936Shselasky crypto_unregister_scomp(&scomp); 251321936Shselasky} 252321936Shselasky 253321936Shselaskysubsys_initcall(zstd_mod_init); 254321936Shselaskymodule_exit(zstd_mod_fini); 255321936Shselasky 256321936ShselaskyMODULE_LICENSE("GPL"); 257321936ShselaskyMODULE_DESCRIPTION("Zstd Compression Algorithm"); 258321936ShselaskyMODULE_ALIAS_CRYPTO("zstd"); 259321936Shselasky