1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* Algorithms supported by virtio crypto device |
3 | * |
4 | * Authors: Gonglei <arei.gonglei@huawei.com> |
5 | * |
6 | * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD. |
7 | */ |
8 | |
9 | #include <crypto/engine.h> |
10 | #include <crypto/internal/skcipher.h> |
11 | #include <crypto/scatterwalk.h> |
12 | #include <linux/err.h> |
13 | #include <linux/scatterlist.h> |
14 | #include <uapi/linux/virtio_crypto.h> |
15 | #include "virtio_crypto_common.h" |
16 | |
17 | |
18 | struct virtio_crypto_skcipher_ctx { |
19 | struct virtio_crypto *vcrypto; |
20 | struct crypto_skcipher *tfm; |
21 | |
22 | struct virtio_crypto_sym_session_info enc_sess_info; |
23 | struct virtio_crypto_sym_session_info dec_sess_info; |
24 | }; |
25 | |
26 | struct virtio_crypto_sym_request { |
27 | struct virtio_crypto_request base; |
28 | |
29 | /* Cipher or aead */ |
30 | uint32_t type; |
31 | struct virtio_crypto_skcipher_ctx *skcipher_ctx; |
32 | struct skcipher_request *skcipher_req; |
33 | uint8_t *iv; |
34 | /* Encryption? */ |
35 | bool encrypt; |
36 | }; |
37 | |
38 | struct virtio_crypto_algo { |
39 | uint32_t algonum; |
40 | uint32_t service; |
41 | unsigned int active_devs; |
42 | struct skcipher_engine_alg algo; |
43 | }; |
44 | |
45 | /* |
46 | * The algs_lock protects the below global virtio_crypto_active_devs |
47 | * and crypto algorithms registion. |
48 | */ |
49 | static DEFINE_MUTEX(algs_lock); |
50 | static void virtio_crypto_skcipher_finalize_req( |
51 | struct virtio_crypto_sym_request *vc_sym_req, |
52 | struct skcipher_request *req, |
53 | int err); |
54 | |
55 | static void virtio_crypto_dataq_sym_callback |
56 | (struct virtio_crypto_request *vc_req, int len) |
57 | { |
58 | struct virtio_crypto_sym_request *vc_sym_req = |
59 | container_of(vc_req, struct virtio_crypto_sym_request, base); |
60 | struct skcipher_request *ablk_req; |
61 | int error; |
62 | |
63 | /* Finish the encrypt or decrypt process */ |
64 | if (vc_sym_req->type == VIRTIO_CRYPTO_SYM_OP_CIPHER) { |
65 | switch (vc_req->status) { |
66 | case VIRTIO_CRYPTO_OK: |
67 | error = 0; |
68 | break; |
69 | case VIRTIO_CRYPTO_INVSESS: |
70 | case VIRTIO_CRYPTO_ERR: |
71 | error = -EINVAL; |
72 | break; |
73 | case VIRTIO_CRYPTO_BADMSG: |
74 | error = -EBADMSG; |
75 | break; |
76 | default: |
77 | error = -EIO; |
78 | break; |
79 | } |
80 | ablk_req = vc_sym_req->skcipher_req; |
81 | virtio_crypto_skcipher_finalize_req(vc_sym_req, |
82 | req: ablk_req, err: error); |
83 | } |
84 | } |
85 | |
86 | static u64 virtio_crypto_alg_sg_nents_length(struct scatterlist *sg) |
87 | { |
88 | u64 total = 0; |
89 | |
90 | for (total = 0; sg; sg = sg_next(sg)) |
91 | total += sg->length; |
92 | |
93 | return total; |
94 | } |
95 | |
96 | static int |
97 | virtio_crypto_alg_validate_key(int key_len, uint32_t *alg) |
98 | { |
99 | switch (key_len) { |
100 | case AES_KEYSIZE_128: |
101 | case AES_KEYSIZE_192: |
102 | case AES_KEYSIZE_256: |
103 | *alg = VIRTIO_CRYPTO_CIPHER_AES_CBC; |
104 | break; |
105 | default: |
106 | return -EINVAL; |
107 | } |
108 | return 0; |
109 | } |
110 | |
111 | static int virtio_crypto_alg_skcipher_init_session( |
112 | struct virtio_crypto_skcipher_ctx *ctx, |
113 | uint32_t alg, const uint8_t *key, |
114 | unsigned int keylen, |
115 | int encrypt) |
116 | { |
117 | struct scatterlist outhdr, key_sg, inhdr, *sgs[3]; |
118 | struct virtio_crypto *vcrypto = ctx->vcrypto; |
119 | int op = encrypt ? VIRTIO_CRYPTO_OP_ENCRYPT : VIRTIO_CRYPTO_OP_DECRYPT; |
120 | int err; |
121 | unsigned int num_out = 0, num_in = 0; |
122 | struct virtio_crypto_op_ctrl_req *ctrl; |
123 | struct virtio_crypto_session_input *input; |
124 | struct virtio_crypto_sym_create_session_req *sym_create_session; |
125 | struct virtio_crypto_ctrl_request *vc_ctrl_req; |
126 | |
127 | /* |
128 | * Avoid to do DMA from the stack, switch to using |
129 | * dynamically-allocated for the key |
130 | */ |
131 | uint8_t *cipher_key = kmemdup(p: key, size: keylen, GFP_ATOMIC); |
132 | |
133 | if (!cipher_key) |
134 | return -ENOMEM; |
135 | |
136 | vc_ctrl_req = kzalloc(size: sizeof(*vc_ctrl_req), GFP_KERNEL); |
137 | if (!vc_ctrl_req) { |
138 | err = -ENOMEM; |
139 | goto out; |
140 | } |
141 | |
142 | /* Pad ctrl header */ |
143 | ctrl = &vc_ctrl_req->ctrl; |
144 | ctrl->header.opcode = cpu_to_le32(VIRTIO_CRYPTO_CIPHER_CREATE_SESSION); |
145 | ctrl->header.algo = cpu_to_le32(alg); |
146 | /* Set the default dataqueue id to 0 */ |
147 | ctrl->header.queue_id = 0; |
148 | |
149 | input = &vc_ctrl_req->input; |
150 | input->status = cpu_to_le32(VIRTIO_CRYPTO_ERR); |
151 | /* Pad cipher's parameters */ |
152 | sym_create_session = &ctrl->u.sym_create_session; |
153 | sym_create_session->op_type = cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER); |
154 | sym_create_session->u.cipher.para.algo = ctrl->header.algo; |
155 | sym_create_session->u.cipher.para.keylen = cpu_to_le32(keylen); |
156 | sym_create_session->u.cipher.para.op = cpu_to_le32(op); |
157 | |
158 | sg_init_one(&outhdr, ctrl, sizeof(*ctrl)); |
159 | sgs[num_out++] = &outhdr; |
160 | |
161 | /* Set key */ |
162 | sg_init_one(&key_sg, cipher_key, keylen); |
163 | sgs[num_out++] = &key_sg; |
164 | |
165 | /* Return status and session id back */ |
166 | sg_init_one(&inhdr, input, sizeof(*input)); |
167 | sgs[num_out + num_in++] = &inhdr; |
168 | |
169 | err = virtio_crypto_ctrl_vq_request(vcrypto, sgs, out_sgs: num_out, in_sgs: num_in, vc_ctrl_req); |
170 | if (err < 0) |
171 | goto out; |
172 | |
173 | if (le32_to_cpu(input->status) != VIRTIO_CRYPTO_OK) { |
174 | pr_err("virtio_crypto: Create session failed status: %u\n" , |
175 | le32_to_cpu(input->status)); |
176 | err = -EINVAL; |
177 | goto out; |
178 | } |
179 | |
180 | if (encrypt) |
181 | ctx->enc_sess_info.session_id = le64_to_cpu(input->session_id); |
182 | else |
183 | ctx->dec_sess_info.session_id = le64_to_cpu(input->session_id); |
184 | |
185 | err = 0; |
186 | out: |
187 | kfree(objp: vc_ctrl_req); |
188 | kfree_sensitive(objp: cipher_key); |
189 | return err; |
190 | } |
191 | |
192 | static int virtio_crypto_alg_skcipher_close_session( |
193 | struct virtio_crypto_skcipher_ctx *ctx, |
194 | int encrypt) |
195 | { |
196 | struct scatterlist outhdr, status_sg, *sgs[2]; |
197 | struct virtio_crypto_destroy_session_req *destroy_session; |
198 | struct virtio_crypto *vcrypto = ctx->vcrypto; |
199 | int err; |
200 | unsigned int num_out = 0, num_in = 0; |
201 | struct virtio_crypto_op_ctrl_req *ctrl; |
202 | struct virtio_crypto_inhdr *ctrl_status; |
203 | struct virtio_crypto_ctrl_request *vc_ctrl_req; |
204 | |
205 | vc_ctrl_req = kzalloc(size: sizeof(*vc_ctrl_req), GFP_KERNEL); |
206 | if (!vc_ctrl_req) |
207 | return -ENOMEM; |
208 | |
209 | ctrl_status = &vc_ctrl_req->ctrl_status; |
210 | ctrl_status->status = VIRTIO_CRYPTO_ERR; |
211 | /* Pad ctrl header */ |
212 | ctrl = &vc_ctrl_req->ctrl; |
213 | ctrl->header.opcode = cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION); |
214 | /* Set the default virtqueue id to 0 */ |
215 | ctrl->header.queue_id = 0; |
216 | |
217 | destroy_session = &ctrl->u.destroy_session; |
218 | |
219 | if (encrypt) |
220 | destroy_session->session_id = cpu_to_le64(ctx->enc_sess_info.session_id); |
221 | else |
222 | destroy_session->session_id = cpu_to_le64(ctx->dec_sess_info.session_id); |
223 | |
224 | sg_init_one(&outhdr, ctrl, sizeof(*ctrl)); |
225 | sgs[num_out++] = &outhdr; |
226 | |
227 | /* Return status and session id back */ |
228 | sg_init_one(&status_sg, &ctrl_status->status, sizeof(ctrl_status->status)); |
229 | sgs[num_out + num_in++] = &status_sg; |
230 | |
231 | err = virtio_crypto_ctrl_vq_request(vcrypto, sgs, out_sgs: num_out, in_sgs: num_in, vc_ctrl_req); |
232 | if (err < 0) |
233 | goto out; |
234 | |
235 | if (ctrl_status->status != VIRTIO_CRYPTO_OK) { |
236 | pr_err("virtio_crypto: Close session failed status: %u, session_id: 0x%llx\n" , |
237 | ctrl_status->status, destroy_session->session_id); |
238 | |
239 | err = -EINVAL; |
240 | goto out; |
241 | } |
242 | |
243 | err = 0; |
244 | out: |
245 | kfree(objp: vc_ctrl_req); |
246 | return err; |
247 | } |
248 | |
249 | static int virtio_crypto_alg_skcipher_init_sessions( |
250 | struct virtio_crypto_skcipher_ctx *ctx, |
251 | const uint8_t *key, unsigned int keylen) |
252 | { |
253 | uint32_t alg; |
254 | int ret; |
255 | struct virtio_crypto *vcrypto = ctx->vcrypto; |
256 | |
257 | if (keylen > vcrypto->max_cipher_key_len) { |
258 | pr_err("virtio_crypto: the key is too long\n" ); |
259 | return -EINVAL; |
260 | } |
261 | |
262 | if (virtio_crypto_alg_validate_key(key_len: keylen, alg: &alg)) |
263 | return -EINVAL; |
264 | |
265 | /* Create encryption session */ |
266 | ret = virtio_crypto_alg_skcipher_init_session(ctx, |
267 | alg, key, keylen, encrypt: 1); |
268 | if (ret) |
269 | return ret; |
270 | /* Create decryption session */ |
271 | ret = virtio_crypto_alg_skcipher_init_session(ctx, |
272 | alg, key, keylen, encrypt: 0); |
273 | if (ret) { |
274 | virtio_crypto_alg_skcipher_close_session(ctx, encrypt: 1); |
275 | return ret; |
276 | } |
277 | return 0; |
278 | } |
279 | |
280 | /* Note: kernel crypto API realization */ |
281 | static int virtio_crypto_skcipher_setkey(struct crypto_skcipher *tfm, |
282 | const uint8_t *key, |
283 | unsigned int keylen) |
284 | { |
285 | struct virtio_crypto_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); |
286 | uint32_t alg; |
287 | int ret; |
288 | |
289 | ret = virtio_crypto_alg_validate_key(key_len: keylen, alg: &alg); |
290 | if (ret) |
291 | return ret; |
292 | |
293 | if (!ctx->vcrypto) { |
294 | /* New key */ |
295 | int node = virtio_crypto_get_current_node(); |
296 | struct virtio_crypto *vcrypto = |
297 | virtcrypto_get_dev_node(node, |
298 | VIRTIO_CRYPTO_SERVICE_CIPHER, algo: alg); |
299 | if (!vcrypto) { |
300 | pr_err("virtio_crypto: Could not find a virtio device in the system or unsupported algo\n" ); |
301 | return -ENODEV; |
302 | } |
303 | |
304 | ctx->vcrypto = vcrypto; |
305 | } else { |
306 | /* Rekeying, we should close the created sessions previously */ |
307 | virtio_crypto_alg_skcipher_close_session(ctx, encrypt: 1); |
308 | virtio_crypto_alg_skcipher_close_session(ctx, encrypt: 0); |
309 | } |
310 | |
311 | ret = virtio_crypto_alg_skcipher_init_sessions(ctx, key, keylen); |
312 | if (ret) { |
313 | virtcrypto_dev_put(vcrypto_dev: ctx->vcrypto); |
314 | ctx->vcrypto = NULL; |
315 | |
316 | return ret; |
317 | } |
318 | |
319 | return 0; |
320 | } |
321 | |
322 | static int |
323 | __virtio_crypto_skcipher_do_req(struct virtio_crypto_sym_request *vc_sym_req, |
324 | struct skcipher_request *req, |
325 | struct data_queue *data_vq) |
326 | { |
327 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); |
328 | struct virtio_crypto_skcipher_ctx *ctx = vc_sym_req->skcipher_ctx; |
329 | struct virtio_crypto_request *vc_req = &vc_sym_req->base; |
330 | unsigned int ivsize = crypto_skcipher_ivsize(tfm); |
331 | struct virtio_crypto *vcrypto = ctx->vcrypto; |
332 | struct virtio_crypto_op_data_req *req_data; |
333 | int src_nents, dst_nents; |
334 | int err; |
335 | unsigned long flags; |
336 | struct scatterlist outhdr, iv_sg, status_sg, **sgs; |
337 | u64 dst_len; |
338 | unsigned int num_out = 0, num_in = 0; |
339 | int sg_total; |
340 | uint8_t *iv; |
341 | struct scatterlist *sg; |
342 | |
343 | src_nents = sg_nents_for_len(sg: req->src, len: req->cryptlen); |
344 | if (src_nents < 0) { |
345 | pr_err("Invalid number of src SG.\n" ); |
346 | return src_nents; |
347 | } |
348 | |
349 | dst_nents = sg_nents(sg: req->dst); |
350 | |
351 | pr_debug("virtio_crypto: Number of sgs (src_nents: %d, dst_nents: %d)\n" , |
352 | src_nents, dst_nents); |
353 | |
354 | /* Why 3? outhdr + iv + inhdr */ |
355 | sg_total = src_nents + dst_nents + 3; |
356 | sgs = kcalloc_node(n: sg_total, size: sizeof(*sgs), GFP_KERNEL, |
357 | node: dev_to_node(dev: &vcrypto->vdev->dev)); |
358 | if (!sgs) |
359 | return -ENOMEM; |
360 | |
361 | req_data = kzalloc_node(size: sizeof(*req_data), GFP_KERNEL, |
362 | node: dev_to_node(dev: &vcrypto->vdev->dev)); |
363 | if (!req_data) { |
364 | kfree(objp: sgs); |
365 | return -ENOMEM; |
366 | } |
367 | |
368 | vc_req->req_data = req_data; |
369 | vc_sym_req->type = VIRTIO_CRYPTO_SYM_OP_CIPHER; |
370 | /* Head of operation */ |
371 | if (vc_sym_req->encrypt) { |
372 | req_data->header.session_id = |
373 | cpu_to_le64(ctx->enc_sess_info.session_id); |
374 | req_data->header.opcode = |
375 | cpu_to_le32(VIRTIO_CRYPTO_CIPHER_ENCRYPT); |
376 | } else { |
377 | req_data->header.session_id = |
378 | cpu_to_le64(ctx->dec_sess_info.session_id); |
379 | req_data->header.opcode = |
380 | cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DECRYPT); |
381 | } |
382 | req_data->u.sym_req.op_type = cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER); |
383 | req_data->u.sym_req.u.cipher.para.iv_len = cpu_to_le32(ivsize); |
384 | req_data->u.sym_req.u.cipher.para.src_data_len = |
385 | cpu_to_le32(req->cryptlen); |
386 | |
387 | dst_len = virtio_crypto_alg_sg_nents_length(sg: req->dst); |
388 | if (unlikely(dst_len > U32_MAX)) { |
389 | pr_err("virtio_crypto: The dst_len is beyond U32_MAX\n" ); |
390 | err = -EINVAL; |
391 | goto free; |
392 | } |
393 | |
394 | dst_len = min_t(unsigned int, req->cryptlen, dst_len); |
395 | pr_debug("virtio_crypto: src_len: %u, dst_len: %llu\n" , |
396 | req->cryptlen, dst_len); |
397 | |
398 | if (unlikely(req->cryptlen + dst_len + ivsize + |
399 | sizeof(vc_req->status) > vcrypto->max_size)) { |
400 | pr_err("virtio_crypto: The length is too big\n" ); |
401 | err = -EINVAL; |
402 | goto free; |
403 | } |
404 | |
405 | req_data->u.sym_req.u.cipher.para.dst_data_len = |
406 | cpu_to_le32((uint32_t)dst_len); |
407 | |
408 | /* Outhdr */ |
409 | sg_init_one(&outhdr, req_data, sizeof(*req_data)); |
410 | sgs[num_out++] = &outhdr; |
411 | |
412 | /* IV */ |
413 | |
414 | /* |
415 | * Avoid to do DMA from the stack, switch to using |
416 | * dynamically-allocated for the IV |
417 | */ |
418 | iv = kzalloc_node(size: ivsize, GFP_ATOMIC, |
419 | node: dev_to_node(dev: &vcrypto->vdev->dev)); |
420 | if (!iv) { |
421 | err = -ENOMEM; |
422 | goto free; |
423 | } |
424 | memcpy(iv, req->iv, ivsize); |
425 | if (!vc_sym_req->encrypt) |
426 | scatterwalk_map_and_copy(buf: req->iv, sg: req->src, |
427 | start: req->cryptlen - AES_BLOCK_SIZE, |
428 | AES_BLOCK_SIZE, out: 0); |
429 | |
430 | sg_init_one(&iv_sg, iv, ivsize); |
431 | sgs[num_out++] = &iv_sg; |
432 | vc_sym_req->iv = iv; |
433 | |
434 | /* Source data */ |
435 | for (sg = req->src; src_nents; sg = sg_next(sg), src_nents--) |
436 | sgs[num_out++] = sg; |
437 | |
438 | /* Destination data */ |
439 | for (sg = req->dst; sg; sg = sg_next(sg)) |
440 | sgs[num_out + num_in++] = sg; |
441 | |
442 | /* Status */ |
443 | sg_init_one(&status_sg, &vc_req->status, sizeof(vc_req->status)); |
444 | sgs[num_out + num_in++] = &status_sg; |
445 | |
446 | vc_req->sgs = sgs; |
447 | |
448 | spin_lock_irqsave(&data_vq->lock, flags); |
449 | err = virtqueue_add_sgs(vq: data_vq->vq, sgs, out_sgs: num_out, |
450 | in_sgs: num_in, data: vc_req, GFP_ATOMIC); |
451 | virtqueue_kick(vq: data_vq->vq); |
452 | spin_unlock_irqrestore(lock: &data_vq->lock, flags); |
453 | if (unlikely(err < 0)) |
454 | goto free_iv; |
455 | |
456 | return 0; |
457 | |
458 | free_iv: |
459 | kfree_sensitive(objp: iv); |
460 | free: |
461 | kfree_sensitive(objp: req_data); |
462 | kfree(objp: sgs); |
463 | return err; |
464 | } |
465 | |
466 | static int virtio_crypto_skcipher_encrypt(struct skcipher_request *req) |
467 | { |
468 | struct crypto_skcipher *atfm = crypto_skcipher_reqtfm(req); |
469 | struct virtio_crypto_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm: atfm); |
470 | struct virtio_crypto_sym_request *vc_sym_req = |
471 | skcipher_request_ctx(req); |
472 | struct virtio_crypto_request *vc_req = &vc_sym_req->base; |
473 | struct virtio_crypto *vcrypto = ctx->vcrypto; |
474 | /* Use the first data virtqueue as default */ |
475 | struct data_queue *data_vq = &vcrypto->data_vq[0]; |
476 | |
477 | if (!req->cryptlen) |
478 | return 0; |
479 | if (req->cryptlen % AES_BLOCK_SIZE) |
480 | return -EINVAL; |
481 | |
482 | vc_req->dataq = data_vq; |
483 | vc_req->alg_cb = virtio_crypto_dataq_sym_callback; |
484 | vc_sym_req->skcipher_ctx = ctx; |
485 | vc_sym_req->skcipher_req = req; |
486 | vc_sym_req->encrypt = true; |
487 | |
488 | return crypto_transfer_skcipher_request_to_engine(engine: data_vq->engine, req); |
489 | } |
490 | |
491 | static int virtio_crypto_skcipher_decrypt(struct skcipher_request *req) |
492 | { |
493 | struct crypto_skcipher *atfm = crypto_skcipher_reqtfm(req); |
494 | struct virtio_crypto_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm: atfm); |
495 | struct virtio_crypto_sym_request *vc_sym_req = |
496 | skcipher_request_ctx(req); |
497 | struct virtio_crypto_request *vc_req = &vc_sym_req->base; |
498 | struct virtio_crypto *vcrypto = ctx->vcrypto; |
499 | /* Use the first data virtqueue as default */ |
500 | struct data_queue *data_vq = &vcrypto->data_vq[0]; |
501 | |
502 | if (!req->cryptlen) |
503 | return 0; |
504 | if (req->cryptlen % AES_BLOCK_SIZE) |
505 | return -EINVAL; |
506 | |
507 | vc_req->dataq = data_vq; |
508 | vc_req->alg_cb = virtio_crypto_dataq_sym_callback; |
509 | vc_sym_req->skcipher_ctx = ctx; |
510 | vc_sym_req->skcipher_req = req; |
511 | vc_sym_req->encrypt = false; |
512 | |
513 | return crypto_transfer_skcipher_request_to_engine(engine: data_vq->engine, req); |
514 | } |
515 | |
516 | static int virtio_crypto_skcipher_init(struct crypto_skcipher *tfm) |
517 | { |
518 | struct virtio_crypto_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); |
519 | |
520 | crypto_skcipher_set_reqsize(skcipher: tfm, reqsize: sizeof(struct virtio_crypto_sym_request)); |
521 | ctx->tfm = tfm; |
522 | |
523 | return 0; |
524 | } |
525 | |
526 | static void virtio_crypto_skcipher_exit(struct crypto_skcipher *tfm) |
527 | { |
528 | struct virtio_crypto_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); |
529 | |
530 | if (!ctx->vcrypto) |
531 | return; |
532 | |
533 | virtio_crypto_alg_skcipher_close_session(ctx, encrypt: 1); |
534 | virtio_crypto_alg_skcipher_close_session(ctx, encrypt: 0); |
535 | virtcrypto_dev_put(vcrypto_dev: ctx->vcrypto); |
536 | ctx->vcrypto = NULL; |
537 | } |
538 | |
539 | int virtio_crypto_skcipher_crypt_req( |
540 | struct crypto_engine *engine, void *vreq) |
541 | { |
542 | struct skcipher_request *req = container_of(vreq, struct skcipher_request, base); |
543 | struct virtio_crypto_sym_request *vc_sym_req = |
544 | skcipher_request_ctx(req); |
545 | struct virtio_crypto_request *vc_req = &vc_sym_req->base; |
546 | struct data_queue *data_vq = vc_req->dataq; |
547 | int ret; |
548 | |
549 | ret = __virtio_crypto_skcipher_do_req(vc_sym_req, req, data_vq); |
550 | if (ret < 0) |
551 | return ret; |
552 | |
553 | virtqueue_kick(vq: data_vq->vq); |
554 | |
555 | return 0; |
556 | } |
557 | |
558 | static void virtio_crypto_skcipher_finalize_req( |
559 | struct virtio_crypto_sym_request *vc_sym_req, |
560 | struct skcipher_request *req, |
561 | int err) |
562 | { |
563 | if (vc_sym_req->encrypt) |
564 | scatterwalk_map_and_copy(buf: req->iv, sg: req->dst, |
565 | start: req->cryptlen - AES_BLOCK_SIZE, |
566 | AES_BLOCK_SIZE, out: 0); |
567 | kfree_sensitive(objp: vc_sym_req->iv); |
568 | virtcrypto_clear_request(vc_req: &vc_sym_req->base); |
569 | |
570 | crypto_finalize_skcipher_request(engine: vc_sym_req->base.dataq->engine, |
571 | req, err); |
572 | } |
573 | |
574 | static struct virtio_crypto_algo virtio_crypto_algs[] = { { |
575 | .algonum = VIRTIO_CRYPTO_CIPHER_AES_CBC, |
576 | .service = VIRTIO_CRYPTO_SERVICE_CIPHER, |
577 | .algo.base = { |
578 | .base.cra_name = "cbc(aes)" , |
579 | .base.cra_driver_name = "virtio_crypto_aes_cbc" , |
580 | .base.cra_priority = 150, |
581 | .base.cra_flags = CRYPTO_ALG_ASYNC | |
582 | CRYPTO_ALG_ALLOCATES_MEMORY, |
583 | .base.cra_blocksize = AES_BLOCK_SIZE, |
584 | .base.cra_ctxsize = sizeof(struct virtio_crypto_skcipher_ctx), |
585 | .base.cra_module = THIS_MODULE, |
586 | .init = virtio_crypto_skcipher_init, |
587 | .exit = virtio_crypto_skcipher_exit, |
588 | .setkey = virtio_crypto_skcipher_setkey, |
589 | .decrypt = virtio_crypto_skcipher_decrypt, |
590 | .encrypt = virtio_crypto_skcipher_encrypt, |
591 | .min_keysize = AES_MIN_KEY_SIZE, |
592 | .max_keysize = AES_MAX_KEY_SIZE, |
593 | .ivsize = AES_BLOCK_SIZE, |
594 | }, |
595 | .algo.op = { |
596 | .do_one_request = virtio_crypto_skcipher_crypt_req, |
597 | }, |
598 | } }; |
599 | |
600 | int virtio_crypto_skcipher_algs_register(struct virtio_crypto *vcrypto) |
601 | { |
602 | int ret = 0; |
603 | int i = 0; |
604 | |
605 | mutex_lock(&algs_lock); |
606 | |
607 | for (i = 0; i < ARRAY_SIZE(virtio_crypto_algs); i++) { |
608 | |
609 | uint32_t service = virtio_crypto_algs[i].service; |
610 | uint32_t algonum = virtio_crypto_algs[i].algonum; |
611 | |
612 | if (!virtcrypto_algo_is_supported(vcrypto_dev: vcrypto, service, algo: algonum)) |
613 | continue; |
614 | |
615 | if (virtio_crypto_algs[i].active_devs == 0) { |
616 | ret = crypto_engine_register_skcipher(alg: &virtio_crypto_algs[i].algo); |
617 | if (ret) |
618 | goto unlock; |
619 | } |
620 | |
621 | virtio_crypto_algs[i].active_devs++; |
622 | dev_info(&vcrypto->vdev->dev, "Registered algo %s\n" , |
623 | virtio_crypto_algs[i].algo.base.base.cra_name); |
624 | } |
625 | |
626 | unlock: |
627 | mutex_unlock(lock: &algs_lock); |
628 | return ret; |
629 | } |
630 | |
631 | void virtio_crypto_skcipher_algs_unregister(struct virtio_crypto *vcrypto) |
632 | { |
633 | int i = 0; |
634 | |
635 | mutex_lock(&algs_lock); |
636 | |
637 | for (i = 0; i < ARRAY_SIZE(virtio_crypto_algs); i++) { |
638 | |
639 | uint32_t service = virtio_crypto_algs[i].service; |
640 | uint32_t algonum = virtio_crypto_algs[i].algonum; |
641 | |
642 | if (virtio_crypto_algs[i].active_devs == 0 || |
643 | !virtcrypto_algo_is_supported(vcrypto_dev: vcrypto, service, algo: algonum)) |
644 | continue; |
645 | |
646 | if (virtio_crypto_algs[i].active_devs == 1) |
647 | crypto_engine_unregister_skcipher(alg: &virtio_crypto_algs[i].algo); |
648 | |
649 | virtio_crypto_algs[i].active_devs--; |
650 | } |
651 | |
652 | mutex_unlock(lock: &algs_lock); |
653 | } |
654 | |