Only check that size is multiple of blocksize on ciphers.
[cryptodev-linux.git] / cryptodev.c
blobf09a38d5aadb39e61415abc14281b1f1306c531f
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 Nikos Mavrogiannopoulos <nmav@gennetsa.com>, Gennet S.A.
7 * Device /dev/crypto provides an interface for
8 * accessing kernel CryptoAPI algorithms (ciphers,
9 * hashes) from userspace programs.
11 * /dev/crypto interface was originally introduced in
12 * OpenBSD and this module attempts to keep the API,
13 * although a bit extended.
17 #include <linux/module.h>
18 #include <linux/moduleparam.h>
19 #include <linux/init.h>
20 #include <linux/sched.h>
21 #include <linux/fs.h>
22 #include <linux/file.h>
23 #include <linux/fdtable.h>
24 #include <linux/miscdevice.h>
25 #include <linux/crypto.h>
26 #include <linux/mm.h>
27 #include <linux/highmem.h>
28 #include <linux/random.h>
29 #include "cryptodev.h"
30 #include <asm/uaccess.h>
31 #include <asm/ioctl.h>
32 #include <linux/scatterlist.h>
34 MODULE_AUTHOR("Michal Ludvig <mludvig@logix.net.nz>");
35 MODULE_DESCRIPTION("CryptoDev driver");
36 MODULE_LICENSE("Dual BSD/GPL");
38 /* ====== Compile-time config ====== */
40 #define CRYPTODEV_STATS
42 /* ====== Module parameters ====== */
44 static int verbosity = 0;
45 module_param(verbosity, int, 0644);
46 MODULE_PARM_DESC(verbosity, "0: normal, 1: verbose, 2: debug");
48 #ifdef CRYPTODEV_STATS
49 static int enable_stats = 0;
50 module_param(enable_stats, int, 0644);
51 MODULE_PARM_DESC(enable_stats, "collect statictics about cryptodev usage");
52 #endif
54 /* ====== Debug helpers ====== */
56 #define PFX "cryptodev: "
57 #define dprintk(level,severity,format,a...) \
58 do { \
59 if (level <= verbosity) \
60 printk(severity PFX "%s[%u]: " format, \
61 current->comm, current->pid, \
62 ##a); \
63 } while (0)
65 /* ====== CryptoAPI ====== */
67 #define FILL_SG(sg,ptr,len) \
68 do { \
69 (sg)->page = virt_to_page(ptr); \
70 (sg)->offset = offset_in_page(ptr); \
71 (sg)->length = len; \
72 (sg)->dma_address = 0; \
73 } while (0)
75 struct csession {
76 struct list_head entry;
77 struct semaphore sem;
78 struct crypto_blkcipher *tfm;
79 struct crypto_hash *hash_tfm;
80 uint32_t sid;
81 #ifdef CRYPTODEV_STATS
82 #if ! ((COP_ENCRYPT < 2) && (COP_DECRYPT < 2))
83 #error Struct csession.stat uses COP_{ENCRYPT,DECRYPT} as indices. Do something!
84 #endif
85 unsigned long long stat[2];
86 size_t stat_max_size, stat_count;
87 #endif
90 struct fcrypt {
91 struct list_head list;
92 struct semaphore sem;
95 /* Prepare session for future use. */
96 static int
97 crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
99 struct csession *ses_new, *ses_ptr;
100 struct crypto_blkcipher *blk_tfm=NULL;
101 struct crypto_hash *hash_tfm=NULL;
102 int ret = 0;
103 const char *alg_name=NULL;
104 const char *hash_name=NULL;
105 struct blkcipher_alg* blkalg;
106 int hmac_mode = 1;
108 /* Does the request make sense? */
109 if (!sop->cipher && !sop->mac) {
110 dprintk(1,KERN_DEBUG,"Both 'cipher' and 'mac' unset.\n");
111 return -EINVAL;
114 switch (sop->cipher) {
115 case 0:
116 break;
117 case CRYPTO_DES_CBC:
118 alg_name = "cbc(des)";
119 break;
120 case CRYPTO_3DES_CBC:
121 alg_name = "cbc(3des_ede)";
122 break;
123 case CRYPTO_BLF_CBC:
124 alg_name = "cbc(blowfish)";
125 break;
126 case CRYPTO_AES_CBC:
127 alg_name = "cbc(aes)";
128 break;
129 case CRYPTO_CAMELLIA_CBC:
130 alg_name = "cbc(camelia)";
131 break;
132 default:
133 dprintk(1,KERN_DEBUG,"%s: bad cipher: %d\n", __func__, sop->cipher);
134 return -EINVAL;
137 switch (sop->mac) {
138 case 0:
139 break;
140 case CRYPTO_MD5_HMAC:
141 hash_name = "hmac(md5)";
142 break;
143 case CRYPTO_RIPEMD160_HMAC:
144 hash_name = "hmac(rmd160)";
145 break;
146 case CRYPTO_SHA1_HMAC:
147 hash_name = "hmac(sha1)";
148 break;
149 case CRYPTO_SHA2_256_HMAC:
150 hash_name = "hmac(sha256)";
151 break;
152 case CRYPTO_SHA2_384_HMAC:
153 hash_name = "hmac(sha384)";
154 break;
155 case CRYPTO_SHA2_512_HMAC:
156 hash_name = "hmac(sha512)";
157 break;
159 /* non-hmac cases */
160 case CRYPTO_MD5:
161 hash_name = "md5";
162 hmac_mode = 0;
163 break;
164 case CRYPTO_RIPEMD160:
165 hash_name = "rmd160";
166 hmac_mode = 0;
167 break;
168 case CRYPTO_SHA1:
169 hash_name = "sha1";
170 hmac_mode = 0;
171 break;
172 case CRYPTO_SHA2_256:
173 hash_name = "sha256";
174 hmac_mode = 0;
175 break;
176 case CRYPTO_SHA2_384:
177 hash_name = "sha384";
178 hmac_mode = 0;
179 break;
180 case CRYPTO_SHA2_512:
181 hash_name = "sha512";
182 hmac_mode = 0;
183 break;
185 default:
186 dprintk(1,KERN_DEBUG,"%s: bad mac: %d\n", __func__, sop->mac);
187 return -EINVAL;
190 /* Set-up crypto transform. */
191 if (alg_name) {
192 uint8_t keyp[CRYPTO_CIPHER_MAX_KEY_LEN];
194 blk_tfm = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC);
195 if (IS_ERR(blk_tfm)) {
196 dprintk(1,KERN_DEBUG,"%s: Failed to load transform for %s\n", __func__,
197 alg_name);
198 return -EINVAL;
201 blkalg = crypto_blkcipher_alg(blk_tfm);
202 if (blkalg != NULL) {
203 /* Was correct key length supplied? */
204 if ((sop->keylen < blkalg->min_keysize) ||
205 (sop->keylen > blkalg->max_keysize)) {
206 dprintk(0,KERN_DEBUG,"Wrong keylen '%zu' for algorithm '%s'. Use %u to %u.\n",
207 sop->keylen, alg_name, blkalg->min_keysize,
208 blkalg->max_keysize);
209 ret = -EINVAL;
210 goto error;
214 if (sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN) {
215 dprintk(0,KERN_DEBUG,"Setting key failed for %s-%zu.\n",
216 alg_name, sop->keylen*8);
217 ret = -EINVAL;
218 goto error;
221 /* Copy the key from user and set to TFM. */
222 copy_from_user(keyp, sop->key, sop->keylen);
223 ret = crypto_blkcipher_setkey(blk_tfm, keyp, sop->keylen);
224 if (ret) {
225 dprintk(0,KERN_DEBUG,"Setting key failed for %s-%zu.\n",
226 alg_name, sop->keylen*8);
227 ret = -EINVAL;
228 goto error;
233 if (hash_name) {
234 hash_tfm = crypto_alloc_hash(hash_name, 0, CRYPTO_ALG_ASYNC);
235 if (IS_ERR(hash_tfm)) {
236 dprintk(1,KERN_DEBUG,"%s: Failed to load transform for %s\n", __func__,
237 hash_name);
238 return -EINVAL;
241 /* Copy the key from user and set to TFM. */
242 if (hmac_mode != 0) {
243 uint8_t hkeyp[CRYPTO_HMAC_MAX_KEY_LEN];
245 if (sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN) {
246 dprintk(0,KERN_DEBUG,"Setting hmac key failed for %s-%zu.\n",
247 hash_name, sop->mackeylen*8);
248 ret = -EINVAL;
249 goto error;
252 copy_from_user(hkeyp, sop->mackey, sop->mackeylen);
253 ret = crypto_hash_setkey(hash_tfm, hkeyp, sop->mackeylen);
254 if (ret) {
255 dprintk(0,KERN_DEBUG,"Setting hmac key failed for %s-%zu.\n",
256 hash_name, sop->mackeylen*8);
257 ret = -EINVAL;
258 goto error;
264 /* Create a session and put it to the list. */
265 ses_new = kmalloc(sizeof(*ses_new), GFP_KERNEL);
266 if(!ses_new) {
267 ret = -ENOMEM;
268 goto error;
271 memset(ses_new, 0, sizeof(*ses_new));
272 get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
273 ses_new->tfm = blk_tfm;
274 ses_new->hash_tfm = hash_tfm;
275 init_MUTEX(&ses_new->sem);
277 down(&fcr->sem);
278 restart:
279 list_for_each_entry(ses_ptr, &fcr->list, entry) {
280 /* Check for duplicate SID */
281 if (unlikely(ses_new->sid == ses_ptr->sid)) {
282 get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
283 /* Unless we have a broken RNG this
284 shouldn't loop forever... ;-) */
285 goto restart;
289 list_add(&ses_new->entry, &fcr->list);
290 up(&fcr->sem);
292 /* Fill in some values for the user. */
293 sop->ses = ses_new->sid;
295 return 0;
297 error:
298 if (blk_tfm)
299 crypto_free_blkcipher(blk_tfm);
300 if (hash_tfm)
301 crypto_free_hash(hash_tfm);
303 return ret;
307 /* Everything that needs to be done when remowing a session. */
308 static inline void
309 crypto_destroy_session(struct csession *ses_ptr)
311 if(down_trylock(&ses_ptr->sem)) {
312 dprintk(2, KERN_DEBUG, "Waiting for semaphore of sid=0x%08X\n",
313 ses_ptr->sid);
314 down(&ses_ptr->sem);
316 dprintk(2, KERN_DEBUG, "Removed session 0x%08X\n", ses_ptr->sid);
317 #if defined(CRYPTODEV_STATS)
318 if(enable_stats)
319 dprintk(2, KERN_DEBUG,
320 "Usage in Bytes: enc=%llu, dec=%llu, max=%zu, avg=%lu, cnt=%zu\n",
321 ses_ptr->stat[COP_ENCRYPT], ses_ptr->stat[COP_DECRYPT],
322 ses_ptr->stat_max_size, ses_ptr->stat_count > 0
323 ? ((unsigned long)(ses_ptr->stat[COP_ENCRYPT]+
324 ses_ptr->stat[COP_DECRYPT]) /
325 ses_ptr->stat_count) : 0,
326 ses_ptr->stat_count);
327 #endif
328 if (ses_ptr->tfm) {
329 crypto_free_blkcipher(ses_ptr->tfm);
330 ses_ptr->tfm = NULL;
332 if (ses_ptr->hash_tfm) {
333 crypto_free_hash(ses_ptr->hash_tfm);
334 ses_ptr->hash_tfm = NULL;
336 up(&ses_ptr->sem);
337 kfree(ses_ptr);
340 /* Look up a session by ID and remove. */
341 static int
342 crypto_finish_session(struct fcrypt *fcr, uint32_t sid)
344 struct csession *tmp, *ses_ptr;
345 struct list_head *head;
346 int ret = 0;
348 down(&fcr->sem);
349 head = &fcr->list;
350 list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
351 if(ses_ptr->sid == sid) {
352 list_del(&ses_ptr->entry);
353 crypto_destroy_session(ses_ptr);
354 break;
358 if (!ses_ptr) {
359 dprintk(1, KERN_ERR, "Session with sid=0x%08X not found!\n", sid);
360 ret = -ENOENT;
362 up(&fcr->sem);
364 return ret;
367 /* Remove all sessions when closing the file */
368 static int
369 crypto_finish_all_sessions(struct fcrypt *fcr)
371 struct csession *tmp, *ses_ptr;
372 struct list_head *head;
374 down(&fcr->sem);
376 head = &fcr->list;
377 list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
378 list_del(&ses_ptr->entry);
379 crypto_destroy_session(ses_ptr);
381 up(&fcr->sem);
383 return 0;
386 /* Look up session by session ID. The returned session is locked. */
387 static struct csession *
388 crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid)
390 struct csession *ses_ptr;
392 down(&fcr->sem);
393 list_for_each_entry(ses_ptr, &fcr->list, entry) {
394 if(ses_ptr->sid == sid) {
395 down(&ses_ptr->sem);
396 break;
399 up(&fcr->sem);
401 return ses_ptr;
404 static int crypto_runv(struct fcrypt *fcr, struct crypt_opv *copv)
406 char *data, ivp[EALG_MAX_BLOCK_LEN];
407 char __user *src, __user *dst;
408 struct scatterlist sg;
409 struct csession *ses_ptr;
410 unsigned int ivsize=0;
411 size_t nbytes, bufsize;
412 int ret = 0;
413 uint8_t hash_output[HASH_MAX_LEN];
414 int blocksize=1, i;
415 struct blkcipher_desc bdesc = {
416 .flags = CRYPTO_TFM_REQ_MAY_SLEEP,
418 struct hash_desc hdesc = {
419 .flags = CRYPTO_TFM_REQ_MAY_SLEEP,
423 if (unlikely(copv->op != COP_ENCRYPT && copv->op != COP_DECRYPT)) {
424 dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", copv->op);
425 return -EINVAL;
428 ses_ptr = crypto_get_session_by_sid(fcr, copv->ses);
429 if (!ses_ptr) {
430 dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", copv->ses);
431 return -EINVAL;
434 data = (char*)__get_free_page(GFP_KERNEL);
436 if (unlikely(!data)) {
437 ret = -ENOMEM;
438 goto out_unlock;
441 bdesc.tfm = ses_ptr->tfm;
442 hdesc.tfm = ses_ptr->hash_tfm;
444 if (hdesc.tfm) {
445 ret = crypto_hash_init(&hdesc);
446 if (unlikely(ret)) {
447 dprintk(1, KERN_ERR,
448 "error in crypto_hash_init()\n");
449 goto out_unlock;
453 if (ses_ptr->tfm) {
454 blocksize = crypto_blkcipher_blocksize(ses_ptr->tfm);
455 ivsize = crypto_blkcipher_ivsize(ses_ptr->tfm);
457 if (copv->iv) {
458 copy_from_user(ivp, copv->iv, ivsize);
459 crypto_blkcipher_set_iv(ses_ptr->tfm, ivp, ivsize);
463 dst = copv->dst;
465 for (i=0;i<copv->iovec_cnt;i++) {
466 nbytes = copv->iovec[i].len;
468 if (unlikely(bdesc.tfm && (copv->iovec[i].op_flags & IOP_CIPHER) && (nbytes % blocksize))) {
469 dprintk(1, KERN_ERR,
470 "data size (%zu) isn't a multiple of block size (%u)\n",
471 nbytes, crypto_blkcipher_blocksize(ses_ptr->tfm));
472 ret = -EINVAL;
473 goto out_unlock;
476 bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes;
478 src = copv->iovec[i].src;
480 while(nbytes > 0) {
481 size_t current_len = nbytes > bufsize ? bufsize : nbytes;
483 copy_from_user(data, src, current_len);
485 sg_set_buf(&sg, data, current_len);
487 /* Always hash before encryption and after decryption. Maybe
488 * we should introduce a flag to switch... TBD later on.
490 if (copv->op == COP_ENCRYPT) {
491 if (hdesc.tfm && (copv->iovec[i].op_flags & IOP_HASH)) {
492 ret = crypto_hash_update(&hdesc, &sg, current_len);
493 if (unlikely(ret)) {
494 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
495 goto out;
498 if (bdesc.tfm && (copv->iovec[i].op_flags & IOP_CIPHER)) {
499 ret = crypto_blkcipher_encrypt(&bdesc, &sg, &sg, current_len);
501 if (unlikely(ret)) {
502 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
503 goto out;
505 copy_to_user(dst, data, current_len);
506 dst += current_len;
508 } else {
509 if (bdesc.tfm && (copv->iovec[i].op_flags & IOP_CIPHER)) {
510 ret = crypto_blkcipher_decrypt(&bdesc, &sg, &sg, current_len);
512 if (unlikely(ret)) {
513 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
514 goto out;
516 copy_to_user(dst, data, current_len);
517 dst += current_len;
521 if (hdesc.tfm && (copv->iovec[i].op_flags & IOP_HASH)) {
522 ret = crypto_hash_update(&hdesc, &sg, current_len);
523 if (unlikely(ret)) {
524 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
525 goto out;
530 nbytes -= current_len;
531 src += current_len;
534 #if defined(CRYPTODEV_STATS)
535 if (enable_stats) {
536 /* this is safe - we check cop->op at the function entry */
537 ses_ptr->stat[copv->op] += copv->iovec[i].len;
538 if (ses_ptr->stat_max_size < copv->iovec[i].len)
539 ses_ptr->stat_max_size = copv->iovec[i].len;
540 ses_ptr->stat_count++;
542 #endif
546 if (hdesc.tfm) {
547 ret = crypto_hash_final(&hdesc, hash_output);
548 if (unlikely(ret)) {
549 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
550 goto out;
553 copy_to_user(copv->mac, hash_output, crypto_hash_digestsize(ses_ptr->hash_tfm));
556 out:
557 free_page((unsigned long)data);
559 out_unlock:
560 up(&ses_ptr->sem);
562 return ret;
565 /* This is the main crypto function - feed it with plaintext
566 and get a ciphertext (or vice versa :-) */
567 static int crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
569 struct crypt_opv copv;
570 struct crypt_iovec iovec;
572 iovec.src = cop->src;
573 iovec.len = cop->len;
574 iovec.op_flags = IOP_CIPHER|IOP_HASH;
576 copv.op = cop->op;
577 copv.ses = cop->ses;
578 copv.flags = cop->flags;
579 copv.iovec = &iovec;
580 copv.iovec_cnt = 1;
582 copv.dst = cop->dst;
583 copv.mac = cop->mac;
584 copv.iv = cop->iv;
586 return crypto_runv(fcr, &copv);
592 /* ====== /dev/crypto ====== */
594 static int
595 cryptodev_open(struct inode *inode, struct file *filp)
597 struct fcrypt *fcr;
599 fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
600 if(!fcr)
601 return -ENOMEM;
603 memset(fcr, 0, sizeof(*fcr));
604 init_MUTEX(&fcr->sem);
605 INIT_LIST_HEAD(&fcr->list);
606 filp->private_data = fcr;
608 return 0;
611 static int
612 cryptodev_release(struct inode *inode, struct file *filp)
614 struct fcrypt *fcr = filp->private_data;
616 if(fcr) {
617 crypto_finish_all_sessions(fcr);
618 kfree(fcr);
619 filp->private_data = NULL;
622 return 0;
625 static int
626 clonefd(struct file *filp)
628 struct fdtable *fdt = files_fdtable(current->files);
629 int ret;
630 ret = get_unused_fd();
631 if (ret >= 0) {
632 get_file(filp);
633 FD_SET(ret, fdt->open_fds);
634 fd_install(ret, filp);
637 return ret;
640 static int
641 cryptodev_ioctl(struct inode *inode, struct file *filp,
642 unsigned int cmd, unsigned long arg)
644 int __user *p = (void __user *)arg;
645 struct session_op sop;
646 struct crypt_op cop;
647 struct crypt_opv copv;
648 struct fcrypt *fcr = filp->private_data;
649 uint32_t ses;
650 int ret, fd;
652 if (!fcr)
653 BUG();
655 switch (cmd) {
656 case CIOCASYMFEAT:
657 put_user(0, p);
658 return 0;
659 case CRIOGET:
660 fd = clonefd(filp);
661 put_user(fd, p);
662 return 0;
664 case CIOCGSESSION:
665 copy_from_user(&sop, (void*)arg, sizeof(sop));
666 ret = crypto_create_session(fcr, &sop);
667 if (ret)
668 return ret;
669 copy_to_user((void*)arg, &sop, sizeof(sop));
670 return 0;
672 case CIOCFSESSION:
673 get_user(ses, (uint32_t*)arg);
674 ret = crypto_finish_session(fcr, ses);
675 return ret;
677 case CIOCCRYPT:
678 copy_from_user(&cop, (void*)arg, sizeof(cop));
679 ret = crypto_run(fcr, &cop);
680 copy_to_user((void*)arg, &cop, sizeof(cop));
681 return ret;
683 case CIOCCRYPTV:
684 copy_from_user(&cop, (void*)arg, sizeof(copv));
685 ret = crypto_runv(fcr, &copv);
686 copy_to_user((void*)arg, &copv, sizeof(copv));
687 return ret;
689 default:
690 return -EINVAL;
694 struct file_operations cryptodev_fops = {
695 .owner = THIS_MODULE,
696 .open = cryptodev_open,
697 .release = cryptodev_release,
698 .ioctl = cryptodev_ioctl,
701 struct miscdevice cryptodev = {
702 .minor = CRYPTODEV_MINOR,
703 .name = "crypto",
704 .fops = &cryptodev_fops,
707 static int
708 cryptodev_register(void)
710 int rc;
712 rc = misc_register (&cryptodev);
713 if (rc) {
714 printk(KERN_ERR PFX "registeration of /dev/crypto failed\n");
715 return rc;
718 return 0;
721 static void
722 cryptodev_deregister(void)
724 misc_deregister(&cryptodev);
727 /* ====== Module init/exit ====== */
729 int __init init_cryptodev(void)
731 int rc;
733 rc = cryptodev_register();
734 if (rc)
735 return rc;
737 printk(KERN_INFO PFX "driver loaded.\n");
739 return 0;
742 void __exit exit_cryptodev(void)
744 cryptodev_deregister();
745 printk(KERN_INFO PFX "driver unloaded.\n");
748 module_init(init_cryptodev);
749 module_exit(exit_cryptodev);