Back to home page

LXR

 
 

    


0001 /*
0002  * Shared crypto simd helpers
0003  *
0004  * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
0005  * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au>
0006  *
0007  * Based on aesni-intel_glue.c by:
0008  *  Copyright (C) 2008, Intel Corp.
0009  *    Author: Huang Ying <ying.huang@intel.com>
0010  *
0011  * This program is free software; you can redistribute it and/or modify
0012  * it under the terms of the GNU General Public License as published by
0013  * the Free Software Foundation; either version 2 of the License, or
0014  * (at your option) any later version.
0015  *
0016  * This program is distributed in the hope that it will be useful,
0017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0019  * GNU General Public License for more details.
0020  *
0021  * You should have received a copy of the GNU General Public License
0022  * along with this program; if not, write to the Free Software
0023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
0024  * USA
0025  *
0026  */
0027 
0028 #include <crypto/cryptd.h>
0029 #include <crypto/internal/simd.h>
0030 #include <crypto/internal/skcipher.h>
0031 #include <linux/kernel.h>
0032 #include <linux/module.h>
0033 #include <linux/preempt.h>
0034 #include <asm/simd.h>
0035 
0036 struct simd_skcipher_alg {
0037     const char *ialg_name;
0038     struct skcipher_alg alg;
0039 };
0040 
0041 struct simd_skcipher_ctx {
0042     struct cryptd_skcipher *cryptd_tfm;
0043 };
0044 
0045 static int simd_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key,
0046                 unsigned int key_len)
0047 {
0048     struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
0049     struct crypto_skcipher *child = &ctx->cryptd_tfm->base;
0050     int err;
0051 
0052     crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
0053     crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(tfm) &
0054                      CRYPTO_TFM_REQ_MASK);
0055     err = crypto_skcipher_setkey(child, key, key_len);
0056     crypto_skcipher_set_flags(tfm, crypto_skcipher_get_flags(child) &
0057                        CRYPTO_TFM_RES_MASK);
0058     return err;
0059 }
0060 
0061 static int simd_skcipher_encrypt(struct skcipher_request *req)
0062 {
0063     struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
0064     struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
0065     struct skcipher_request *subreq;
0066     struct crypto_skcipher *child;
0067 
0068     subreq = skcipher_request_ctx(req);
0069     *subreq = *req;
0070 
0071     if (!may_use_simd() ||
0072         (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm)))
0073         child = &ctx->cryptd_tfm->base;
0074     else
0075         child = cryptd_skcipher_child(ctx->cryptd_tfm);
0076 
0077     skcipher_request_set_tfm(subreq, child);
0078 
0079     return crypto_skcipher_encrypt(subreq);
0080 }
0081 
0082 static int simd_skcipher_decrypt(struct skcipher_request *req)
0083 {
0084     struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
0085     struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
0086     struct skcipher_request *subreq;
0087     struct crypto_skcipher *child;
0088 
0089     subreq = skcipher_request_ctx(req);
0090     *subreq = *req;
0091 
0092     if (!may_use_simd() ||
0093         (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm)))
0094         child = &ctx->cryptd_tfm->base;
0095     else
0096         child = cryptd_skcipher_child(ctx->cryptd_tfm);
0097 
0098     skcipher_request_set_tfm(subreq, child);
0099 
0100     return crypto_skcipher_decrypt(subreq);
0101 }
0102 
0103 static void simd_skcipher_exit(struct crypto_skcipher *tfm)
0104 {
0105     struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
0106 
0107     cryptd_free_skcipher(ctx->cryptd_tfm);
0108 }
0109 
0110 static int simd_skcipher_init(struct crypto_skcipher *tfm)
0111 {
0112     struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
0113     struct cryptd_skcipher *cryptd_tfm;
0114     struct simd_skcipher_alg *salg;
0115     struct skcipher_alg *alg;
0116     unsigned reqsize;
0117 
0118     alg = crypto_skcipher_alg(tfm);
0119     salg = container_of(alg, struct simd_skcipher_alg, alg);
0120 
0121     cryptd_tfm = cryptd_alloc_skcipher(salg->ialg_name,
0122                        CRYPTO_ALG_INTERNAL,
0123                        CRYPTO_ALG_INTERNAL);
0124     if (IS_ERR(cryptd_tfm))
0125         return PTR_ERR(cryptd_tfm);
0126 
0127     ctx->cryptd_tfm = cryptd_tfm;
0128 
0129     reqsize = sizeof(struct skcipher_request);
0130     reqsize += crypto_skcipher_reqsize(&cryptd_tfm->base);
0131 
0132     crypto_skcipher_set_reqsize(tfm, reqsize);
0133 
0134     return 0;
0135 }
0136 
0137 struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname,
0138                               const char *drvname,
0139                               const char *basename)
0140 {
0141     struct simd_skcipher_alg *salg;
0142     struct crypto_skcipher *tfm;
0143     struct skcipher_alg *ialg;
0144     struct skcipher_alg *alg;
0145     int err;
0146 
0147     tfm = crypto_alloc_skcipher(basename, CRYPTO_ALG_INTERNAL,
0148                     CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC);
0149     if (IS_ERR(tfm))
0150         return ERR_CAST(tfm);
0151 
0152     ialg = crypto_skcipher_alg(tfm);
0153 
0154     salg = kzalloc(sizeof(*salg), GFP_KERNEL);
0155     if (!salg) {
0156         salg = ERR_PTR(-ENOMEM);
0157         goto out_put_tfm;
0158     }
0159 
0160     salg->ialg_name = basename;
0161     alg = &salg->alg;
0162 
0163     err = -ENAMETOOLONG;
0164     if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", algname) >=
0165         CRYPTO_MAX_ALG_NAME)
0166         goto out_free_salg;
0167 
0168     if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
0169              drvname) >= CRYPTO_MAX_ALG_NAME)
0170         goto out_free_salg;
0171 
0172     alg->base.cra_flags = CRYPTO_ALG_ASYNC;
0173     alg->base.cra_priority = ialg->base.cra_priority;
0174     alg->base.cra_blocksize = ialg->base.cra_blocksize;
0175     alg->base.cra_alignmask = ialg->base.cra_alignmask;
0176     alg->base.cra_module = ialg->base.cra_module;
0177     alg->base.cra_ctxsize = sizeof(struct simd_skcipher_ctx);
0178 
0179     alg->ivsize = ialg->ivsize;
0180     alg->chunksize = ialg->chunksize;
0181     alg->min_keysize = ialg->min_keysize;
0182     alg->max_keysize = ialg->max_keysize;
0183 
0184     alg->init = simd_skcipher_init;
0185     alg->exit = simd_skcipher_exit;
0186 
0187     alg->setkey = simd_skcipher_setkey;
0188     alg->encrypt = simd_skcipher_encrypt;
0189     alg->decrypt = simd_skcipher_decrypt;
0190 
0191     err = crypto_register_skcipher(alg);
0192     if (err)
0193         goto out_free_salg;
0194 
0195 out_put_tfm:
0196     crypto_free_skcipher(tfm);
0197     return salg;
0198 
0199 out_free_salg:
0200     kfree(salg);
0201     salg = ERR_PTR(err);
0202     goto out_put_tfm;
0203 }
0204 EXPORT_SYMBOL_GPL(simd_skcipher_create_compat);
0205 
0206 struct simd_skcipher_alg *simd_skcipher_create(const char *algname,
0207                            const char *basename)
0208 {
0209     char drvname[CRYPTO_MAX_ALG_NAME];
0210 
0211     if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >=
0212         CRYPTO_MAX_ALG_NAME)
0213         return ERR_PTR(-ENAMETOOLONG);
0214 
0215     return simd_skcipher_create_compat(algname, drvname, basename);
0216 }
0217 EXPORT_SYMBOL_GPL(simd_skcipher_create);
0218 
0219 void simd_skcipher_free(struct simd_skcipher_alg *salg)
0220 {
0221     crypto_unregister_skcipher(&salg->alg);
0222     kfree(salg);
0223 }
0224 EXPORT_SYMBOL_GPL(simd_skcipher_free);
0225 
0226 MODULE_LICENSE("GPL");