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
= crypto_skcipher_reqsize(cryptd_skcipher_child(cryptd_tfm
));
128 reqsize
= max(reqsize
, crypto_skcipher_reqsize(&cryptd_tfm
->base
));
129 reqsize
+= sizeof(struct skcipher_request
);
131 crypto_skcipher_set_reqsize(tfm
, reqsize
);
136 struct simd_skcipher_alg
*simd_skcipher_create_compat(const char *algname
,
138 const char *basename
)
140 struct simd_skcipher_alg
*salg
;
141 struct crypto_skcipher
*tfm
;
142 struct skcipher_alg
*ialg
;
143 struct skcipher_alg
*alg
;
146 tfm
= crypto_alloc_skcipher(basename
, CRYPTO_ALG_INTERNAL
,
147 CRYPTO_ALG_INTERNAL
| CRYPTO_ALG_ASYNC
);
149 return ERR_CAST(tfm
);
151 ialg
= crypto_skcipher_alg(tfm
);
153 salg
= kzalloc(sizeof(*salg
), GFP_KERNEL
);
155 salg
= ERR_PTR(-ENOMEM
);
159 salg
->ialg_name
= basename
;
163 if (snprintf(alg
->base
.cra_name
, CRYPTO_MAX_ALG_NAME
, "%s", algname
) >=
167 if (snprintf(alg
->base
.cra_driver_name
, CRYPTO_MAX_ALG_NAME
, "%s",
168 drvname
) >= CRYPTO_MAX_ALG_NAME
)
171 alg
->base
.cra_flags
= CRYPTO_ALG_ASYNC
;
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_skcipher_ctx
);
178 alg
->ivsize
= ialg
->ivsize
;
179 alg
->chunksize
= ialg
->chunksize
;
180 alg
->min_keysize
= ialg
->min_keysize
;
181 alg
->max_keysize
= ialg
->max_keysize
;
183 alg
->init
= simd_skcipher_init
;
184 alg
->exit
= simd_skcipher_exit
;
186 alg
->setkey
= simd_skcipher_setkey
;
187 alg
->encrypt
= simd_skcipher_encrypt
;
188 alg
->decrypt
= simd_skcipher_decrypt
;
190 err
= crypto_register_skcipher(alg
);
195 crypto_free_skcipher(tfm
);
203 EXPORT_SYMBOL_GPL(simd_skcipher_create_compat
);
205 struct simd_skcipher_alg
*simd_skcipher_create(const char *algname
,
206 const char *basename
)
208 char drvname
[CRYPTO_MAX_ALG_NAME
];
210 if (snprintf(drvname
, CRYPTO_MAX_ALG_NAME
, "simd-%s", basename
) >=
212 return ERR_PTR(-ENAMETOOLONG
);
214 return simd_skcipher_create_compat(algname
, drvname
, basename
);
216 EXPORT_SYMBOL_GPL(simd_skcipher_create
);
218 void simd_skcipher_free(struct simd_skcipher_alg
*salg
)
220 crypto_unregister_skcipher(&salg
->alg
);
223 EXPORT_SYMBOL_GPL(simd_skcipher_free
);
225 int simd_register_skciphers_compat(struct skcipher_alg
*algs
, int count
,
226 struct simd_skcipher_alg
**simd_algs
)
232 const char *basename
;
233 struct simd_skcipher_alg
*simd
;
235 err
= crypto_register_skciphers(algs
, count
);
239 for (i
= 0; i
< count
; i
++) {
240 WARN_ON(strncmp(algs
[i
].base
.cra_name
, "__", 2));
241 WARN_ON(strncmp(algs
[i
].base
.cra_driver_name
, "__", 2));
242 algname
= algs
[i
].base
.cra_name
+ 2;
243 drvname
= algs
[i
].base
.cra_driver_name
+ 2;
244 basename
= algs
[i
].base
.cra_driver_name
;
245 simd
= simd_skcipher_create_compat(algname
, drvname
, basename
);
254 simd_unregister_skciphers(algs
, count
, simd_algs
);
257 EXPORT_SYMBOL_GPL(simd_register_skciphers_compat
);
259 void simd_unregister_skciphers(struct skcipher_alg
*algs
, int count
,
260 struct simd_skcipher_alg
**simd_algs
)
264 crypto_unregister_skciphers(algs
, count
);
266 for (i
= 0; i
< count
; i
++) {
268 simd_skcipher_free(simd_algs
[i
]);
273 EXPORT_SYMBOL_GPL(simd_unregister_skciphers
);
275 MODULE_LICENSE("GPL");