crypto_op_to_*: fix typo into the correct direction
[cryptodev-linux.git] / cryptodev_main.c
blobd016931c39a4d9c64c93bc2d0f52d5d5a9242924
1 /*
2 * Driver for /dev/crypto device (aka CryptoDev)
4 * Copyright (c) 2004 Michal Ludvig <mludvig@logix.net.nz>, SuSE Labs
5 * Copyright (c) 2009,2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
7 * This file is part of linux cryptodev.
9 * cryptodev is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * cryptodev is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * Device /dev/crypto provides an interface for
25 * accessing kernel CryptoAPI algorithms (ciphers,
26 * hashes) from userspace programs.
28 * /dev/crypto interface was originally introduced in
29 * OpenBSD and this module attempts to keep the API.
33 #include <linux/crypto.h>
34 #include <linux/mm.h>
35 #include <linux/highmem.h>
36 #include <linux/random.h>
37 #include "cryptodev.h"
38 #include <asm/uaccess.h>
39 #include <asm/ioctl.h>
40 #include <linux/scatterlist.h>
41 #include "cryptodev_int.h"
43 MODULE_AUTHOR("Nikos Mavrogiannopoulos <nmav@gnutls.org>");
44 MODULE_DESCRIPTION("CryptoDev driver");
45 MODULE_LICENSE("GPL");
47 /* ====== Compile-time config ====== */
49 #define CRYPTODEV_STATS
51 /* ====== Module parameters ====== */
53 int cryptodev_verbosity = 0;
54 module_param(cryptodev_verbosity, int, 0644);
55 MODULE_PARM_DESC(cryptodev_verbosity, "0: normal, 1: verbose, 2: debug");
57 #ifdef CRYPTODEV_STATS
58 static int enable_stats = 0;
59 module_param(enable_stats, int, 0644);
60 MODULE_PARM_DESC(enable_stats, "collect statictics about cryptodev usage");
61 #endif
63 /* ====== CryptoAPI ====== */
65 #define FILL_SG(sg,ptr,len) \
66 do { \
67 (sg)->page = virt_to_page(ptr); \
68 (sg)->offset = offset_in_page(ptr); \
69 (sg)->length = len; \
70 (sg)->dma_address = 0; \
71 } while (0)
73 struct csession {
74 struct list_head entry;
75 struct semaphore sem;
76 struct cipher_data cdata;
77 struct hash_data hdata;
78 uint32_t sid;
79 #ifdef CRYPTODEV_STATS
80 #if ! ((COP_ENCRYPT < 2) && (COP_DECRYPT < 2))
81 #error Struct csession.stat uses COP_{ENCRYPT,DECRYPT} as indices. Do something!
82 #endif
83 unsigned long long stat[2];
84 size_t stat_max_size, stat_count;
85 #endif
88 struct fcrypt {
89 struct list_head list;
90 struct semaphore sem;
93 /* Prepare session for future use. */
94 static int
95 crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
97 struct csession *ses_new = NULL, *ses_ptr;
98 int ret = 0;
99 const char *alg_name=NULL;
100 const char *hash_name=NULL;
101 int hmac_mode = 1;
103 /* Does the request make sense? */
104 if (unlikely(!sop->cipher && !sop->mac)) {
105 dprintk(1,KERN_DEBUG,"Both 'cipher' and 'mac' unset.\n");
106 return -EINVAL;
109 switch (sop->cipher) {
110 case 0:
111 break;
112 case CRYPTO_DES_CBC:
113 alg_name = "cbc(des)";
114 break;
115 case CRYPTO_3DES_CBC:
116 alg_name = "cbc(des3_ede)";
117 break;
118 case CRYPTO_BLF_CBC:
119 alg_name = "cbc(blowfish)";
120 break;
121 case CRYPTO_AES_CBC:
122 alg_name = "cbc(aes)";
123 break;
124 case CRYPTO_CAMELLIA_CBC:
125 alg_name = "cbc(camelia)";
126 break;
127 default:
128 dprintk(1,KERN_DEBUG,"%s: bad cipher: %d\n", __func__, sop->cipher);
129 return -EINVAL;
132 switch (sop->mac) {
133 case 0:
134 break;
135 case CRYPTO_MD5_HMAC:
136 hash_name = "hmac(md5)";
137 break;
138 case CRYPTO_RIPEMD160_HMAC:
139 hash_name = "hmac(rmd160)";
140 break;
141 case CRYPTO_SHA1_HMAC:
142 hash_name = "hmac(sha1)";
143 break;
144 case CRYPTO_SHA2_256_HMAC:
145 hash_name = "hmac(sha256)";
146 break;
147 case CRYPTO_SHA2_384_HMAC:
148 hash_name = "hmac(sha384)";
149 break;
150 case CRYPTO_SHA2_512_HMAC:
151 hash_name = "hmac(sha512)";
152 break;
154 /* non-hmac cases */
155 case CRYPTO_MD5:
156 hash_name = "md5";
157 hmac_mode = 0;
158 break;
159 case CRYPTO_RIPEMD160:
160 hash_name = "rmd160";
161 hmac_mode = 0;
162 break;
163 case CRYPTO_SHA1:
164 hash_name = "sha1";
165 hmac_mode = 0;
166 break;
167 case CRYPTO_SHA2_256:
168 hash_name = "sha256";
169 hmac_mode = 0;
170 break;
171 case CRYPTO_SHA2_384:
172 hash_name = "sha384";
173 hmac_mode = 0;
174 break;
175 case CRYPTO_SHA2_512:
176 hash_name = "sha512";
177 hmac_mode = 0;
178 break;
180 default:
181 dprintk(1,KERN_DEBUG,"%s: bad mac: %d\n", __func__, sop->mac);
182 return -EINVAL;
185 /* Create a session and put it to the list. */
186 ses_new = kmalloc(sizeof(*ses_new), GFP_KERNEL);
187 if(!ses_new) {
188 return -ENOMEM;
191 memset(ses_new, 0, sizeof(*ses_new));
193 /* Set-up crypto transform. */
194 if (alg_name) {
195 ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, sop->key, sop->keylen);
196 if (ret < 0) {
197 dprintk(1,KERN_DEBUG,"%s: Failed to load cipher for %s\n", __func__,
198 alg_name);
199 ret = -EINVAL;
200 goto error;
204 if (hash_name) {
205 ret = cryptodev_hash_init(&ses_new->hdata, hash_name, hmac_mode, sop->mackey, sop->mackeylen);
206 if (ret != 0) {
207 dprintk(1,KERN_DEBUG,"%s: Failed to load hash for %s\n", __func__,
208 hash_name);
209 ret = -EINVAL;
210 goto error;
214 /* put the new session to the list */
215 get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
216 init_MUTEX(&ses_new->sem);
218 down(&fcr->sem);
219 restart:
220 list_for_each_entry(ses_ptr, &fcr->list, entry) {
221 /* Check for duplicate SID */
222 if (unlikely(ses_new->sid == ses_ptr->sid)) {
223 get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
224 /* Unless we have a broken RNG this
225 shouldn't loop forever... ;-) */
226 goto restart;
230 list_add(&ses_new->entry, &fcr->list);
231 up(&fcr->sem);
233 /* Fill in some values for the user. */
234 sop->ses = ses_new->sid;
236 return 0;
238 error:
239 cryptodev_cipher_deinit( &ses_new->cdata);
240 cryptodev_hash_deinit( &ses_new->hdata);
241 if (ses_new) kfree(ses_new);
243 return ret;
247 /* Everything that needs to be done when remowing a session. */
248 static inline void
249 crypto_destroy_session(struct csession *ses_ptr)
251 if(down_trylock(&ses_ptr->sem)) {
252 dprintk(2, KERN_DEBUG, "Waiting for semaphore of sid=0x%08X\n",
253 ses_ptr->sid);
254 down(&ses_ptr->sem);
256 dprintk(2, KERN_DEBUG, "Removed session 0x%08X\n", ses_ptr->sid);
257 #if defined(CRYPTODEV_STATS)
258 if(enable_stats)
259 dprintk(2, KERN_DEBUG,
260 "Usage in Bytes: enc=%llu, dec=%llu, max=%zu, avg=%lu, cnt=%zu\n",
261 ses_ptr->stat[COP_ENCRYPT], ses_ptr->stat[COP_DECRYPT],
262 ses_ptr->stat_max_size, ses_ptr->stat_count > 0
263 ? ((unsigned long)(ses_ptr->stat[COP_ENCRYPT]+
264 ses_ptr->stat[COP_DECRYPT]) /
265 ses_ptr->stat_count) : 0,
266 ses_ptr->stat_count);
267 #endif
268 cryptodev_cipher_deinit(&ses_ptr->cdata);
269 cryptodev_hash_deinit(&ses_ptr->hdata);
270 up(&ses_ptr->sem);
271 kfree(ses_ptr);
274 /* Look up a session by ID and remove. */
275 static int
276 crypto_finish_session(struct fcrypt *fcr, uint32_t sid)
278 struct csession *tmp, *ses_ptr;
279 struct list_head *head;
280 int ret = 0;
282 down(&fcr->sem);
283 head = &fcr->list;
284 list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
285 if(ses_ptr->sid == sid) {
286 list_del(&ses_ptr->entry);
287 crypto_destroy_session(ses_ptr);
288 break;
292 if (unlikely(!ses_ptr)) {
293 dprintk(1, KERN_ERR, "Session with sid=0x%08X not found!\n", sid);
294 ret = -ENOENT;
296 up(&fcr->sem);
298 return ret;
301 /* Remove all sessions when closing the file */
302 static int
303 crypto_finish_all_sessions(struct fcrypt *fcr)
305 struct csession *tmp, *ses_ptr;
306 struct list_head *head;
308 down(&fcr->sem);
310 head = &fcr->list;
311 list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
312 list_del(&ses_ptr->entry);
313 crypto_destroy_session(ses_ptr);
315 up(&fcr->sem);
317 return 0;
320 /* Look up session by session ID. The returned session is locked. */
321 static struct csession *
322 crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid)
324 struct csession *ses_ptr;
326 down(&fcr->sem);
327 list_for_each_entry(ses_ptr, &fcr->list, entry) {
328 if(ses_ptr->sid == sid) {
329 down(&ses_ptr->sem);
330 break;
333 up(&fcr->sem);
335 return ses_ptr;
338 /* This is the main crypto function - feed it with plaintext
339 and get a ciphertext (or vice versa :-) */
340 static int
341 crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
343 char *data;
344 char __user *src, __user *dst;
345 struct scatterlist sg;
346 struct csession *ses_ptr;
347 unsigned int ivsize=0;
348 size_t nbytes, bufsize;
349 int ret = 0;
350 uint8_t hash_output[AALG_MAX_RESULT_LEN];
352 if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) {
353 dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", cop->op);
354 return -EINVAL;
357 ses_ptr = crypto_get_session_by_sid(fcr, cop->ses);
358 if (unlikely(!ses_ptr)) {
359 dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", cop->ses);
360 return -EINVAL;
363 nbytes = cop->len;
364 data = (char*)__get_free_page(GFP_KERNEL);
366 if (unlikely(!data)) {
367 ret = -ENOMEM;
368 goto out_unlock;
370 bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes;
372 nbytes = cop->len;
374 if (ses_ptr->hdata.init != 0) {
375 ret = cryptodev_hash_reset(&ses_ptr->hdata);
376 if (unlikely(ret)) {
377 dprintk(1, KERN_ERR,
378 "error in cryptodev_hash_reset()\n");
379 goto out_unlock;
383 if (ses_ptr->cdata.init != 0) {
384 int blocksize = ses_ptr->cdata.blocksize;
386 if (unlikely(nbytes % blocksize)) {
387 dprintk(1, KERN_ERR,
388 "data size (%zu) isn't a multiple of block size (%u)\n",
389 nbytes, blocksize);
390 ret = -EINVAL;
391 goto out_unlock;
394 ivsize = ses_ptr->cdata.ivsize;
396 if (cop->iv) {
397 cryptodev_cipher_set_iv(&ses_ptr->cdata, cop->iv, ivsize);
401 src = cop->src;
402 dst = cop->dst;
405 while(nbytes > 0) {
406 size_t current_len = nbytes > bufsize ? bufsize : nbytes;
408 copy_from_user(data, src, current_len);
410 sg_init_one(&sg, data, current_len);
412 /* Always hash before encryption and after decryption. Maybe
413 * we should introduce a flag to switch... TBD later on.
415 if (cop->op == COP_ENCRYPT) {
416 if (ses_ptr->hdata.init != 0) {
417 ret = cryptodev_hash_update(&ses_ptr->hdata, &sg, current_len);
418 if (unlikely(ret)) {
419 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
420 goto out;
423 if (ses_ptr->cdata.init != 0) {
424 ret = cryptodev_cipher_encrypt( &ses_ptr->cdata, &sg, &sg, current_len);
426 if (unlikely(ret)) {
427 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
428 goto out;
430 copy_to_user(dst, data, current_len);
431 dst += current_len;
433 } else {
434 if (ses_ptr->cdata.init != 0) {
435 ret = cryptodev_cipher_decrypt( &ses_ptr->cdata, &sg, &sg, current_len);
437 if (unlikely(ret)) {
438 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
439 goto out;
441 copy_to_user(dst, data, current_len);
442 dst += current_len;
446 if (ses_ptr->hdata.init != 0) {
447 ret = cryptodev_hash_update(&ses_ptr->hdata, &sg, current_len);
448 if (unlikely(ret)) {
449 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
450 goto out;
455 nbytes -= current_len;
456 src += current_len;
459 if (ses_ptr->hdata.init != 0) {
460 ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output);
461 if (unlikely(ret)) {
462 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
463 goto out;
466 copy_to_user(cop->mac, hash_output, ses_ptr->hdata.digestsize);
469 #if defined(CRYPTODEV_STATS)
470 if (enable_stats) {
471 /* this is safe - we check cop->op at the function entry */
472 ses_ptr->stat[cop->op] += cop->len;
473 if (ses_ptr->stat_max_size < cop->len)
474 ses_ptr->stat_max_size = cop->len;
475 ses_ptr->stat_count++;
477 #endif
479 out:
480 free_page((unsigned long)data);
482 out_unlock:
483 up(&ses_ptr->sem);
485 return ret;
488 /* ====== /dev/crypto ====== */
490 static int
491 cryptodev_open(struct inode *inode, struct file *filp)
493 struct fcrypt *fcr;
495 fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
496 if(!fcr)
497 return -ENOMEM;
499 memset(fcr, 0, sizeof(*fcr));
500 init_MUTEX(&fcr->sem);
501 INIT_LIST_HEAD(&fcr->list);
502 filp->private_data = fcr;
504 return 0;
507 static int
508 cryptodev_release(struct inode *inode, struct file *filp)
510 struct fcrypt *fcr = filp->private_data;
512 if(fcr) {
513 crypto_finish_all_sessions(fcr);
514 kfree(fcr);
515 filp->private_data = NULL;
518 return 0;
521 static int
522 clonefd(struct file *filp)
524 struct fdtable *fdt = files_fdtable(current->files);
525 int ret;
526 ret = get_unused_fd();
527 if (ret >= 0) {
528 get_file(filp);
529 FD_SET(ret, fdt->open_fds);
530 fd_install(ret, filp);
533 return ret;
536 static int
537 cryptodev_ioctl(struct inode *inode, struct file *filp,
538 unsigned int cmd, unsigned long arg)
540 int __user *p = (void __user *)arg;
541 struct session_op sop;
542 struct crypt_op cop;
543 struct fcrypt *fcr = filp->private_data;
544 uint32_t ses;
545 int ret, fd;
547 if (unlikely(!fcr))
548 BUG();
550 switch (cmd) {
551 case CIOCASYMFEAT:
552 put_user(0, p);
553 return 0;
554 case CRIOGET:
555 fd = clonefd(filp);
556 put_user(fd, p);
557 return 0;
559 case CIOCGSESSION:
560 copy_from_user(&sop, (void*)arg, sizeof(sop));
561 ret = crypto_create_session(fcr, &sop);
562 if (unlikely(ret))
563 return ret;
564 copy_to_user((void*)arg, &sop, sizeof(sop));
565 return 0;
567 case CIOCFSESSION:
568 get_user(ses, (uint32_t*)arg);
569 ret = crypto_finish_session(fcr, ses);
570 return ret;
572 case CIOCCRYPT:
573 copy_from_user(&cop, (void*)arg, sizeof(cop));
574 ret = crypto_run(fcr, &cop);
575 if (unlikely(ret))
576 return ret;
577 copy_to_user((void*)arg, &cop, sizeof(cop));
578 return 0;
580 default:
581 return -EINVAL;
585 static inline void
586 compat_to_session_op(struct compat_session_op *compat, struct session_op *sop)
588 memcpy(sop, compat, sizeof(uint32_t) * 3);
589 sop->key = (uint8_t *)(unsigned long)compat->key;
590 sop->mackeylen = compat->mackeylen;
591 sop->mackey = (uint8_t *)(unsigned long)compat->mackey;
592 sop->ses = compat->ses;
595 static inline void
596 session_op_to_compat(struct session_op *sop, struct compat_session_op *compat)
598 memcpy(compat, sop, sizeof(uint32_t) * 3);
599 compat->key = (unsigned long)sop->key;
600 compat->mackeylen = sop->mackeylen;
601 compat->mackey = (unsigned long)sop->mackey;
602 compat->ses = sop->ses;
605 static inline void
606 compat_to_crypt_op(struct compat_crypt_op *compat, struct crypt_op *cop)
608 memcpy(cop, compat, sizeof(uint32_t) * 2 + sizeof(uint16_t) * 2);
609 cop->src = (uint8_t *)(unsigned long)compat->src;
610 cop->dst = (uint8_t *)(unsigned long)compat->dst;
611 cop->mac = (uint8_t *)(unsigned long)compat->mac;
612 cop->iv = (uint8_t *)(unsigned long)compat->iv;
615 static inline void
616 crypt_op_to_compat(struct crypt_op *cop, struct compat_crypt_op *compat)
618 memcpy(compat, cop, sizeof(uint32_t) * 2 + sizeof(uint16_t) * 2);
619 compat->src = (unsigned long)cop->src;
620 compat->dst = (unsigned long)cop->dst;
621 compat->mac = (unsigned long)cop->mac;
622 compat->iv = (unsigned long)cop->iv;
625 static long
626 cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
628 struct fcrypt *fcr = file->private_data;
629 struct session_op sop;
630 struct compat_session_op compat_sop;
631 struct crypt_op cop;
632 struct compat_crypt_op compat_cop;
633 int ret;
635 if (unlikely(!fcr))
636 BUG();
638 switch (cmd) {
639 case CIOCASYMFEAT:
640 case CRIOGET:
641 case CIOCFSESSION:
642 return cryptodev_ioctl(NULL, file, cmd, arg);
644 case COMPAT_CIOCGSESSION:
645 copy_from_user(&compat_sop, (void *)arg,
646 sizeof(compat_sop));
647 compat_to_session_op(&compat_sop, &sop);
649 ret = crypto_create_session(fcr, &sop);
650 if (unlikely(ret))
651 return ret;
653 session_op_to_compat(&sop, &compat_sop);
654 copy_to_user((void*)arg, &compat_sop,
655 sizeof(compat_sop));
656 return 0;
658 case COMPAT_CIOCCRYPT:
659 copy_from_user(&compat_cop, (void*)arg,
660 sizeof(compat_cop));
661 compat_to_crypt_op(&compat_cop, &cop);
663 ret = crypto_run(fcr, &cop);
664 if (unlikely(ret))
665 return ret;
667 crypt_op_to_compat(&cop, &compat_cop);
668 copy_to_user((void*)arg, &compat_cop,
669 sizeof(compat_cop));
670 return 0;
672 default:
673 return -EINVAL;
677 struct file_operations cryptodev_fops = {
678 .owner = THIS_MODULE,
679 .open = cryptodev_open,
680 .release = cryptodev_release,
681 .ioctl = cryptodev_ioctl,
682 .compat_ioctl = cryptodev_compat_ioctl,
685 struct miscdevice cryptodev = {
686 .minor = MISC_DYNAMIC_MINOR,
687 .name = "crypto",
688 .fops = &cryptodev_fops,
691 static int
692 cryptodev_register(void)
694 int rc;
696 rc = misc_register (&cryptodev);
697 if (unlikely(rc)) {
698 printk(KERN_ERR PFX "registeration of /dev/crypto failed\n");
699 return rc;
702 return 0;
705 static void
706 cryptodev_deregister(void)
708 misc_deregister(&cryptodev);
711 /* ====== Module init/exit ====== */
713 int __init init_cryptodev(void)
715 int rc;
717 rc = cryptodev_register();
718 if (unlikely(rc))
719 return rc;
721 printk(KERN_INFO PFX "driver loaded.\n");
723 return 0;
726 void __exit exit_cryptodev(void)
728 cryptodev_deregister();
729 printk(KERN_INFO PFX "driver unloaded.\n");
732 module_init(init_cryptodev);
733 module_exit(exit_cryptodev);