1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Shared crypto simd helpers 4 * 5 * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> 6 * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au> 7 * Copyright (c) 2019 Google LLC 8 * 9 * Based on aesni-intel_glue.c by: 10 * Copyright (C) 2008, Intel Corp. 11 * Author: Huang Ying <ying.huang@intel.com> 12 */ 13 14 /* 15 * Shared crypto SIMD helpers. These functions dynamically create and register 16 * an AEAD algorithm that wraps another, internal algorithm. The wrapper 17 * ensures that the internal algorithm is only executed in a context where SIMD 18 * instructions are usable, i.e. where may_use_simd() returns true. If SIMD is 19 * already usable, the wrapper directly calls the internal algorithm. Otherwise 20 * it defers execution to a workqueue via cryptd. 21 * 22 * This is an alternative to the internal algorithm implementing a fallback for 23 * the !may_use_simd() case itself. 24 * 25 * Note that the wrapper algorithm is asynchronous, i.e. it has the 26 * CRYPTO_ALG_ASYNC flag set. Therefore it won't be found by users who 27 * explicitly allocate a synchronous algorithm. 28 */ 29 30 #include <crypto/cryptd.h> 31 #include <crypto/internal/aead.h> 32 #include <crypto/internal/simd.h> 33 #include <linux/kernel.h> 34 #include <linux/module.h> 35 #include <linux/preempt.h> 36 #include <asm/simd.h> 37 38 struct simd_aead_alg { 39 const char *ialg_name; 40 struct aead_alg alg; 41 }; 42 43 struct simd_aead_ctx { 44 struct cryptd_aead *cryptd_tfm; 45 }; 46 47 static int simd_aead_setkey(struct crypto_aead *tfm, const u8 *key, 48 unsigned int key_len) 49 { 50 struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); 51 struct crypto_aead *child = &ctx->cryptd_tfm->base; 52 53 crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK); 54 crypto_aead_set_flags(child, crypto_aead_get_flags(tfm) & 55 CRYPTO_TFM_REQ_MASK); 56 return crypto_aead_setkey(child, key, key_len); 57 } 58 59 static int simd_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) 60 { 61 struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); 62 struct crypto_aead *child = &ctx->cryptd_tfm->base; 63 64 return crypto_aead_setauthsize(child, authsize); 65 } 66 67 static int simd_aead_encrypt(struct aead_request *req) 68 { 69 struct crypto_aead *tfm = crypto_aead_reqtfm(req); 70 struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); 71 struct aead_request *subreq; 72 struct crypto_aead *child; 73 74 subreq = aead_request_ctx(req); 75 *subreq = *req; 76 77 if (!crypto_simd_usable() || 78 (in_atomic() && cryptd_aead_queued(ctx->cryptd_tfm))) 79 child = &ctx->cryptd_tfm->base; 80 else 81 child = cryptd_aead_child(ctx->cryptd_tfm); 82 83 aead_request_set_tfm(subreq, child); 84 85 return crypto_aead_encrypt(subreq); 86 } 87 88 static int simd_aead_decrypt(struct aead_request *req) 89 { 90 struct crypto_aead *tfm = crypto_aead_reqtfm(req); 91 struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); 92 struct aead_request *subreq; 93 struct crypto_aead *child; 94 95 subreq = aead_request_ctx(req); 96 *subreq = *req; 97 98 if (!crypto_simd_usable() || 99 (in_atomic() && cryptd_aead_queued(ctx->cryptd_tfm))) 100 child = &ctx->cryptd_tfm->base; 101 else 102 child = cryptd_aead_child(ctx->cryptd_tfm); 103 104 aead_request_set_tfm(subreq, child); 105 106 return crypto_aead_decrypt(subreq); 107 } 108 109 static void simd_aead_exit(struct crypto_aead *tfm) 110 { 111 struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); 112 113 cryptd_free_aead(ctx->cryptd_tfm); 114 } 115 116 static int simd_aead_init(struct crypto_aead *tfm) 117 { 118 struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); 119 struct cryptd_aead *cryptd_tfm; 120 struct simd_aead_alg *salg; 121 struct aead_alg *alg; 122 unsigned reqsize; 123 124 alg = crypto_aead_alg(tfm); 125 salg = container_of(alg, struct simd_aead_alg, alg); 126 127 cryptd_tfm = cryptd_alloc_aead(salg->ialg_name, CRYPTO_ALG_INTERNAL, 128 CRYPTO_ALG_INTERNAL); 129 if (IS_ERR(cryptd_tfm)) 130 return PTR_ERR(cryptd_tfm); 131 132 ctx->cryptd_tfm = cryptd_tfm; 133 134 reqsize = max(crypto_aead_reqsize(cryptd_aead_child(cryptd_tfm)), 135 crypto_aead_reqsize(&cryptd_tfm->base)); 136 reqsize += sizeof(struct aead_request); 137 138 crypto_aead_set_reqsize(tfm, reqsize); 139 140 return 0; 141 } 142 143 static struct simd_aead_alg *simd_aead_create_compat(struct aead_alg *ialg, 144 const char *algname, 145 const char *drvname, 146 const char *basename) 147 { 148 struct simd_aead_alg *salg; 149 struct aead_alg *alg; 150 int err; 151 152 salg = kzalloc_obj(*salg); 153 if (!salg) { 154 salg = ERR_PTR(-ENOMEM); 155 goto out; 156 } 157 158 salg->ialg_name = basename; 159 alg = &salg->alg; 160 161 err = -ENAMETOOLONG; 162 if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", algname) >= 163 CRYPTO_MAX_ALG_NAME) 164 goto out_free_salg; 165 166 if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", 167 drvname) >= CRYPTO_MAX_ALG_NAME) 168 goto out_free_salg; 169 170 alg->base.cra_flags = CRYPTO_ALG_ASYNC | 171 (ialg->base.cra_flags & CRYPTO_ALG_INHERITED_FLAGS); 172 alg->base.cra_priority = ialg->base.cra_priority; 173 alg->base.cra_blocksize = ialg->base.cra_blocksize; 174 alg->base.cra_alignmask = ialg->base.cra_alignmask; 175 alg->base.cra_module = ialg->base.cra_module; 176 alg->base.cra_ctxsize = sizeof(struct simd_aead_ctx); 177 178 alg->ivsize = ialg->ivsize; 179 alg->maxauthsize = ialg->maxauthsize; 180 alg->chunksize = ialg->chunksize; 181 182 alg->init = simd_aead_init; 183 alg->exit = simd_aead_exit; 184 185 alg->setkey = simd_aead_setkey; 186 alg->setauthsize = simd_aead_setauthsize; 187 alg->encrypt = simd_aead_encrypt; 188 alg->decrypt = simd_aead_decrypt; 189 190 err = crypto_register_aead(alg); 191 if (err) 192 goto out_free_salg; 193 194 out: 195 return salg; 196 197 out_free_salg: 198 kfree(salg); 199 salg = ERR_PTR(err); 200 goto out; 201 } 202 203 static void simd_aead_free(struct simd_aead_alg *salg) 204 { 205 crypto_unregister_aead(&salg->alg); 206 kfree(salg); 207 } 208 209 int simd_register_aeads_compat(struct aead_alg *algs, int count, 210 struct simd_aead_alg **simd_algs) 211 { 212 int err; 213 int i; 214 const char *algname; 215 const char *drvname; 216 const char *basename; 217 struct simd_aead_alg *simd; 218 219 for (i = 0; i < count; i++) { 220 if (WARN_ON(strncmp(algs[i].base.cra_name, "__", 2) || 221 strncmp(algs[i].base.cra_driver_name, "__", 2))) 222 return -EINVAL; 223 } 224 225 err = crypto_register_aeads(algs, count); 226 if (err) 227 return err; 228 229 for (i = 0; i < count; i++) { 230 algname = algs[i].base.cra_name + 2; 231 drvname = algs[i].base.cra_driver_name + 2; 232 basename = algs[i].base.cra_driver_name; 233 simd = simd_aead_create_compat(algs + i, algname, drvname, basename); 234 err = PTR_ERR(simd); 235 if (IS_ERR(simd)) 236 goto err_unregister; 237 simd_algs[i] = simd; 238 } 239 return 0; 240 241 err_unregister: 242 simd_unregister_aeads(algs, count, simd_algs); 243 return err; 244 } 245 EXPORT_SYMBOL_GPL(simd_register_aeads_compat); 246 247 void simd_unregister_aeads(struct aead_alg *algs, int count, 248 struct simd_aead_alg **simd_algs) 249 { 250 int i; 251 252 crypto_unregister_aeads(algs, count); 253 254 for (i = 0; i < count; i++) { 255 if (simd_algs[i]) { 256 simd_aead_free(simd_algs[i]); 257 simd_algs[i] = NULL; 258 } 259 } 260 } 261 EXPORT_SYMBOL_GPL(simd_unregister_aeads); 262 263 MODULE_DESCRIPTION("Shared crypto SIMD helpers"); 264 MODULE_LICENSE("GPL"); 265