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