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