1 /* 2 * Shared crypto simd helpers 3 * 4 * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> 5 * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au> 6 * 7 * Based on aesni-intel_glue.c by: 8 * Copyright (C) 2008, Intel Corp. 9 * Author: Huang Ying <ying.huang@intel.com> 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 24 * USA 25 * 26 */ 27 28 #include <crypto/cryptd.h> 29 #include <crypto/internal/simd.h> 30 #include <crypto/internal/skcipher.h> 31 #include <linux/kernel.h> 32 #include <linux/module.h> 33 #include <linux/preempt.h> 34 #include <asm/simd.h> 35 36 struct simd_skcipher_alg { 37 const char *ialg_name; 38 struct skcipher_alg alg; 39 }; 40 41 struct simd_skcipher_ctx { 42 struct cryptd_skcipher *cryptd_tfm; 43 }; 44 45 static int simd_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, 46 unsigned int key_len) 47 { 48 struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 49 struct crypto_skcipher *child = &ctx->cryptd_tfm->base; 50 int err; 51 52 crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); 53 crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(tfm) & 54 CRYPTO_TFM_REQ_MASK); 55 err = crypto_skcipher_setkey(child, key, key_len); 56 crypto_skcipher_set_flags(tfm, crypto_skcipher_get_flags(child) & 57 CRYPTO_TFM_RES_MASK); 58 return err; 59 } 60 61 static int simd_skcipher_encrypt(struct skcipher_request *req) 62 { 63 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 64 struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 65 struct skcipher_request *subreq; 66 struct crypto_skcipher *child; 67 68 subreq = skcipher_request_ctx(req); 69 *subreq = *req; 70 71 if (!may_use_simd() || 72 (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm))) 73 child = &ctx->cryptd_tfm->base; 74 else 75 child = cryptd_skcipher_child(ctx->cryptd_tfm); 76 77 skcipher_request_set_tfm(subreq, child); 78 79 return crypto_skcipher_encrypt(subreq); 80 } 81 82 static int simd_skcipher_decrypt(struct skcipher_request *req) 83 { 84 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 85 struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 86 struct skcipher_request *subreq; 87 struct crypto_skcipher *child; 88 89 subreq = skcipher_request_ctx(req); 90 *subreq = *req; 91 92 if (!may_use_simd() || 93 (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm))) 94 child = &ctx->cryptd_tfm->base; 95 else 96 child = cryptd_skcipher_child(ctx->cryptd_tfm); 97 98 skcipher_request_set_tfm(subreq, child); 99 100 return crypto_skcipher_decrypt(subreq); 101 } 102 103 static void simd_skcipher_exit(struct crypto_skcipher *tfm) 104 { 105 struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 106 107 cryptd_free_skcipher(ctx->cryptd_tfm); 108 } 109 110 static int simd_skcipher_init(struct crypto_skcipher *tfm) 111 { 112 struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 113 struct cryptd_skcipher *cryptd_tfm; 114 struct simd_skcipher_alg *salg; 115 struct skcipher_alg *alg; 116 unsigned reqsize; 117 118 alg = crypto_skcipher_alg(tfm); 119 salg = container_of(alg, struct simd_skcipher_alg, alg); 120 121 cryptd_tfm = cryptd_alloc_skcipher(salg->ialg_name, 122 CRYPTO_ALG_INTERNAL, 123 CRYPTO_ALG_INTERNAL); 124 if (IS_ERR(cryptd_tfm)) 125 return PTR_ERR(cryptd_tfm); 126 127 ctx->cryptd_tfm = cryptd_tfm; 128 129 reqsize = sizeof(struct skcipher_request); 130 reqsize += crypto_skcipher_reqsize(&cryptd_tfm->base); 131 132 crypto_skcipher_set_reqsize(tfm, reqsize); 133 134 return 0; 135 } 136 137 struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname, 138 const char *drvname, 139 const char *basename) 140 { 141 struct simd_skcipher_alg *salg; 142 struct crypto_skcipher *tfm; 143 struct skcipher_alg *ialg; 144 struct skcipher_alg *alg; 145 int err; 146 147 tfm = crypto_alloc_skcipher(basename, CRYPTO_ALG_INTERNAL, 148 CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC); 149 if (IS_ERR(tfm)) 150 return ERR_CAST(tfm); 151 152 ialg = crypto_skcipher_alg(tfm); 153 154 salg = kzalloc(sizeof(*salg), GFP_KERNEL); 155 if (!salg) { 156 salg = ERR_PTR(-ENOMEM); 157 goto out_put_tfm; 158 } 159 160 salg->ialg_name = basename; 161 alg = &salg->alg; 162 163 err = -ENAMETOOLONG; 164 if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", algname) >= 165 CRYPTO_MAX_ALG_NAME) 166 goto out_free_salg; 167 168 if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", 169 drvname) >= CRYPTO_MAX_ALG_NAME) 170 goto out_free_salg; 171 172 alg->base.cra_flags = CRYPTO_ALG_ASYNC; 173 alg->base.cra_priority = ialg->base.cra_priority; 174 alg->base.cra_blocksize = ialg->base.cra_blocksize; 175 alg->base.cra_alignmask = ialg->base.cra_alignmask; 176 alg->base.cra_module = ialg->base.cra_module; 177 alg->base.cra_ctxsize = sizeof(struct simd_skcipher_ctx); 178 179 alg->ivsize = ialg->ivsize; 180 alg->chunksize = ialg->chunksize; 181 alg->min_keysize = ialg->min_keysize; 182 alg->max_keysize = ialg->max_keysize; 183 184 alg->init = simd_skcipher_init; 185 alg->exit = simd_skcipher_exit; 186 187 alg->setkey = simd_skcipher_setkey; 188 alg->encrypt = simd_skcipher_encrypt; 189 alg->decrypt = simd_skcipher_decrypt; 190 191 err = crypto_register_skcipher(alg); 192 if (err) 193 goto out_free_salg; 194 195 out_put_tfm: 196 crypto_free_skcipher(tfm); 197 return salg; 198 199 out_free_salg: 200 kfree(salg); 201 salg = ERR_PTR(err); 202 goto out_put_tfm; 203 } 204 EXPORT_SYMBOL_GPL(simd_skcipher_create_compat); 205 206 struct simd_skcipher_alg *simd_skcipher_create(const char *algname, 207 const char *basename) 208 { 209 char drvname[CRYPTO_MAX_ALG_NAME]; 210 211 if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >= 212 CRYPTO_MAX_ALG_NAME) 213 return ERR_PTR(-ENAMETOOLONG); 214 215 return simd_skcipher_create_compat(algname, drvname, basename); 216 } 217 EXPORT_SYMBOL_GPL(simd_skcipher_create); 218 219 void simd_skcipher_free(struct simd_skcipher_alg *salg) 220 { 221 crypto_unregister_skcipher(&salg->alg); 222 kfree(salg); 223 } 224 EXPORT_SYMBOL_GPL(simd_skcipher_free); 225 226 MODULE_LICENSE("GPL"); 227