2 * Shared crypto simd helpers
4 * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
5 * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au>
7 * Based on aesni-intel_glue.c by:
8 * Copyright (C) 2008, Intel Corp.
9 * Author: Huang Ying <ying.huang@intel.com>
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.
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.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include <crypto/cryptd.h>
27 #include <crypto/internal/simd.h>
28 #include <crypto/internal/skcipher.h>
29 #include <linux/kernel.h>
30 #include <linux/module.h>
31 #include <linux/preempt.h>
34 struct simd_skcipher_alg
{
35 const char *ialg_name
;
36 struct skcipher_alg alg
;
39 struct simd_skcipher_ctx
{
40 struct cryptd_skcipher
*cryptd_tfm
;
43 static int simd_skcipher_setkey(struct crypto_skcipher
*tfm
, const u8
*key
,
46 struct simd_skcipher_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
47 struct crypto_skcipher
*child
= &ctx
->cryptd_tfm
->base
;
50 crypto_skcipher_clear_flags(child
, CRYPTO_TFM_REQ_MASK
);
51 crypto_skcipher_set_flags(child
, crypto_skcipher_get_flags(tfm
) &
53 err
= crypto_skcipher_setkey(child
, key
, key_len
);
54 crypto_skcipher_set_flags(tfm
, crypto_skcipher_get_flags(child
) &
59 static int simd_skcipher_encrypt(struct skcipher_request
*req
)
61 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
62 struct simd_skcipher_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
63 struct skcipher_request
*subreq
;
64 struct crypto_skcipher
*child
;
66 subreq
= skcipher_request_ctx(req
);
69 if (!may_use_simd() ||
70 (in_atomic() && cryptd_skcipher_queued(ctx
->cryptd_tfm
)))
71 child
= &ctx
->cryptd_tfm
->base
;
73 child
= cryptd_skcipher_child(ctx
->cryptd_tfm
);
75 skcipher_request_set_tfm(subreq
, child
);
77 return crypto_skcipher_encrypt(subreq
);
80 static int simd_skcipher_decrypt(struct skcipher_request
*req
)
82 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
83 struct simd_skcipher_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
84 struct skcipher_request
*subreq
;
85 struct crypto_skcipher
*child
;
87 subreq
= skcipher_request_ctx(req
);
90 if (!may_use_simd() ||
91 (in_atomic() && cryptd_skcipher_queued(ctx
->cryptd_tfm
)))
92 child
= &ctx
->cryptd_tfm
->base
;
94 child
= cryptd_skcipher_child(ctx
->cryptd_tfm
);
96 skcipher_request_set_tfm(subreq
, child
);
98 return crypto_skcipher_decrypt(subreq
);
101 static void simd_skcipher_exit(struct crypto_skcipher
*tfm
)
103 struct simd_skcipher_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
105 cryptd_free_skcipher(ctx
->cryptd_tfm
);
108 static int simd_skcipher_init(struct crypto_skcipher
*tfm
)
110 struct simd_skcipher_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
111 struct cryptd_skcipher
*cryptd_tfm
;
112 struct simd_skcipher_alg
*salg
;
113 struct skcipher_alg
*alg
;
116 alg
= crypto_skcipher_alg(tfm
);
117 salg
= container_of(alg
, struct simd_skcipher_alg
, alg
);
119 cryptd_tfm
= cryptd_alloc_skcipher(salg
->ialg_name
,
121 CRYPTO_ALG_INTERNAL
);
122 if (IS_ERR(cryptd_tfm
))
123 return PTR_ERR(cryptd_tfm
);
125 ctx
->cryptd_tfm
= cryptd_tfm
;
127 reqsize
= sizeof(struct skcipher_request
);
128 reqsize
+= crypto_skcipher_reqsize(&cryptd_tfm
->base
);
130 crypto_skcipher_set_reqsize(tfm
, reqsize
);
135 struct simd_skcipher_alg
*simd_skcipher_create_compat(const char *algname
,
137 const char *basename
)
139 struct simd_skcipher_alg
*salg
;
140 struct crypto_skcipher
*tfm
;
141 struct skcipher_alg
*ialg
;
142 struct skcipher_alg
*alg
;
145 tfm
= crypto_alloc_skcipher(basename
, CRYPTO_ALG_INTERNAL
,
146 CRYPTO_ALG_INTERNAL
| CRYPTO_ALG_ASYNC
);
148 return ERR_CAST(tfm
);
150 ialg
= crypto_skcipher_alg(tfm
);
152 salg
= kzalloc(sizeof(*salg
), GFP_KERNEL
);
154 salg
= ERR_PTR(-ENOMEM
);
158 salg
->ialg_name
= basename
;
162 if (snprintf(alg
->base
.cra_name
, CRYPTO_MAX_ALG_NAME
, "%s", algname
) >=
166 if (snprintf(alg
->base
.cra_driver_name
, CRYPTO_MAX_ALG_NAME
, "%s",
167 drvname
) >= CRYPTO_MAX_ALG_NAME
)
170 alg
->base
.cra_flags
= CRYPTO_ALG_ASYNC
;
171 alg
->base
.cra_priority
= ialg
->base
.cra_priority
;
172 alg
->base
.cra_blocksize
= ialg
->base
.cra_blocksize
;
173 alg
->base
.cra_alignmask
= ialg
->base
.cra_alignmask
;
174 alg
->base
.cra_module
= ialg
->base
.cra_module
;
175 alg
->base
.cra_ctxsize
= sizeof(struct simd_skcipher_ctx
);
177 alg
->ivsize
= ialg
->ivsize
;
178 alg
->chunksize
= ialg
->chunksize
;
179 alg
->min_keysize
= ialg
->min_keysize
;
180 alg
->max_keysize
= ialg
->max_keysize
;
182 alg
->init
= simd_skcipher_init
;
183 alg
->exit
= simd_skcipher_exit
;
185 alg
->setkey
= simd_skcipher_setkey
;
186 alg
->encrypt
= simd_skcipher_encrypt
;
187 alg
->decrypt
= simd_skcipher_decrypt
;
189 err
= crypto_register_skcipher(alg
);
194 crypto_free_skcipher(tfm
);
202 EXPORT_SYMBOL_GPL(simd_skcipher_create_compat
);
204 struct simd_skcipher_alg
*simd_skcipher_create(const char *algname
,
205 const char *basename
)
207 char drvname
[CRYPTO_MAX_ALG_NAME
];
209 if (snprintf(drvname
, CRYPTO_MAX_ALG_NAME
, "simd-%s", basename
) >=
211 return ERR_PTR(-ENAMETOOLONG
);
213 return simd_skcipher_create_compat(algname
, drvname
, basename
);
215 EXPORT_SYMBOL_GPL(simd_skcipher_create
);
217 void simd_skcipher_free(struct simd_skcipher_alg
*salg
)
219 crypto_unregister_skcipher(&salg
->alg
);
222 EXPORT_SYMBOL_GPL(simd_skcipher_free
);
224 int simd_register_skciphers_compat(struct skcipher_alg
*algs
, int count
,
225 struct simd_skcipher_alg
**simd_algs
)
231 const char *basename
;
232 struct simd_skcipher_alg
*simd
;
234 err
= crypto_register_skciphers(algs
, count
);
238 for (i
= 0; i
< count
; i
++) {
239 WARN_ON(strncmp(algs
[i
].base
.cra_name
, "__", 2));
240 WARN_ON(strncmp(algs
[i
].base
.cra_driver_name
, "__", 2));
241 algname
= algs
[i
].base
.cra_name
+ 2;
242 drvname
= algs
[i
].base
.cra_driver_name
+ 2;
243 basename
= algs
[i
].base
.cra_driver_name
;
244 simd
= simd_skcipher_create_compat(algname
, drvname
, basename
);
253 simd_unregister_skciphers(algs
, count
, simd_algs
);
256 EXPORT_SYMBOL_GPL(simd_register_skciphers_compat
);
258 void simd_unregister_skciphers(struct skcipher_alg
*algs
, int count
,
259 struct simd_skcipher_alg
**simd_algs
)
263 crypto_unregister_skciphers(algs
, count
);
265 for (i
= 0; i
< count
; i
++) {
267 simd_skcipher_free(simd_algs
[i
]);
272 EXPORT_SYMBOL_GPL(simd_unregister_skciphers
);
274 MODULE_LICENSE("GPL");