Corrected copyright statements and other minir fixes.
[cryptodev-linux.git] / cryptodev.c
blob5d195f3c87c4b52c8d9246697c1cdc4f8e64ae3d
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,
30 * although a bit extended.
34 #include <linux/module.h>
35 #include <linux/moduleparam.h>
36 #include <linux/init.h>
37 #include <linux/sched.h>
38 #include <linux/fs.h>
39 #include <linux/file.h>
40 #include <linux/fdtable.h>
41 #include <linux/miscdevice.h>
42 #include <linux/crypto.h>
43 #include <linux/mm.h>
44 #include <linux/highmem.h>
45 #include <linux/random.h>
46 #include "cryptodev.h"
47 #include <asm/uaccess.h>
48 #include <asm/ioctl.h>
49 #include <linux/scatterlist.h>
51 MODULE_AUTHOR("Michal Ludvig <mludvig@logix.net.nz>");
52 MODULE_DESCRIPTION("CryptoDev driver");
53 MODULE_LICENSE("GPL");
55 /* ====== Compile-time config ====== */
57 #define CRYPTODEV_STATS
59 /* ====== Module parameters ====== */
61 static int verbosity = 0;
62 module_param(verbosity, int, 0644);
63 MODULE_PARM_DESC(verbosity, "0: normal, 1: verbose, 2: debug");
65 #ifdef CRYPTODEV_STATS
66 static int enable_stats = 0;
67 module_param(enable_stats, int, 0644);
68 MODULE_PARM_DESC(enable_stats, "collect statictics about cryptodev usage");
69 #endif
71 /* ====== Debug helpers ====== */
73 #define PFX "cryptodev: "
74 #define dprintk(level,severity,format,a...) \
75 do { \
76 if (level <= verbosity) \
77 printk(severity PFX "%s[%u]: " format, \
78 current->comm, current->pid, \
79 ##a); \
80 } while (0)
82 /* ====== CryptoAPI ====== */
84 #define FILL_SG(sg,ptr,len) \
85 do { \
86 (sg)->page = virt_to_page(ptr); \
87 (sg)->offset = offset_in_page(ptr); \
88 (sg)->length = len; \
89 (sg)->dma_address = 0; \
90 } while (0)
92 struct csession {
93 struct list_head entry;
94 struct semaphore sem;
95 struct crypto_blkcipher *tfm;
96 struct crypto_hash *hash_tfm;
97 uint32_t sid;
98 #ifdef CRYPTODEV_STATS
99 #if ! ((COP_ENCRYPT < 2) && (COP_DECRYPT < 2))
100 #error Struct csession.stat uses COP_{ENCRYPT,DECRYPT} as indices. Do something!
101 #endif
102 unsigned long long stat[2];
103 size_t stat_max_size, stat_count;
104 #endif
107 struct fcrypt {
108 struct list_head list;
109 struct semaphore sem;
112 /* Prepare session for future use. */
113 static int
114 crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
116 struct csession *ses_new, *ses_ptr;
117 struct crypto_blkcipher *blk_tfm=NULL;
118 struct crypto_hash *hash_tfm=NULL;
119 int ret = 0;
120 const char *alg_name=NULL;
121 const char *hash_name=NULL;
122 struct blkcipher_alg* blkalg;
123 int hmac_mode = 1;
125 /* Does the request make sense? */
126 if (!sop->cipher && !sop->mac) {
127 dprintk(1,KERN_DEBUG,"Both 'cipher' and 'mac' unset.\n");
128 return -EINVAL;
131 switch (sop->cipher) {
132 case 0:
133 break;
134 case CRYPTO_DES_CBC:
135 alg_name = "cbc(des)";
136 break;
137 case CRYPTO_3DES_CBC:
138 alg_name = "cbc(3des_ede)";
139 break;
140 case CRYPTO_BLF_CBC:
141 alg_name = "cbc(blowfish)";
142 break;
143 case CRYPTO_AES_CBC:
144 alg_name = "cbc(aes)";
145 break;
146 case CRYPTO_CAMELLIA_CBC:
147 alg_name = "cbc(camelia)";
148 break;
149 default:
150 dprintk(1,KERN_DEBUG,"%s: bad cipher: %d\n", __func__, sop->cipher);
151 return -EINVAL;
154 switch (sop->mac) {
155 case 0:
156 break;
157 case CRYPTO_MD5_HMAC:
158 hash_name = "hmac(md5)";
159 break;
160 case CRYPTO_RIPEMD160_HMAC:
161 hash_name = "hmac(rmd160)";
162 break;
163 case CRYPTO_SHA1_HMAC:
164 hash_name = "hmac(sha1)";
165 break;
166 case CRYPTO_SHA2_256_HMAC:
167 hash_name = "hmac(sha256)";
168 break;
169 case CRYPTO_SHA2_384_HMAC:
170 hash_name = "hmac(sha384)";
171 break;
172 case CRYPTO_SHA2_512_HMAC:
173 hash_name = "hmac(sha512)";
174 break;
176 /* non-hmac cases */
177 case CRYPTO_MD5:
178 hash_name = "md5";
179 hmac_mode = 0;
180 break;
181 case CRYPTO_RIPEMD160:
182 hash_name = "rmd160";
183 hmac_mode = 0;
184 break;
185 case CRYPTO_SHA1:
186 hash_name = "sha1";
187 hmac_mode = 0;
188 break;
189 case CRYPTO_SHA2_256:
190 hash_name = "sha256";
191 hmac_mode = 0;
192 break;
193 case CRYPTO_SHA2_384:
194 hash_name = "sha384";
195 hmac_mode = 0;
196 break;
197 case CRYPTO_SHA2_512:
198 hash_name = "sha512";
199 hmac_mode = 0;
200 break;
202 default:
203 dprintk(1,KERN_DEBUG,"%s: bad mac: %d\n", __func__, sop->mac);
204 return -EINVAL;
207 /* Set-up crypto transform. */
208 if (alg_name) {
209 uint8_t keyp[CRYPTO_CIPHER_MAX_KEY_LEN];
211 blk_tfm = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC);
212 if (IS_ERR(blk_tfm)) {
213 dprintk(1,KERN_DEBUG,"%s: Failed to load transform for %s\n", __func__,
214 alg_name);
215 return -EINVAL;
218 blkalg = crypto_blkcipher_alg(blk_tfm);
219 if (blkalg != NULL) {
220 /* Was correct key length supplied? */
221 if ((sop->keylen < blkalg->min_keysize) ||
222 (sop->keylen > blkalg->max_keysize)) {
223 dprintk(0,KERN_DEBUG,"Wrong keylen '%zu' for algorithm '%s'. Use %u to %u.\n",
224 sop->keylen, alg_name, blkalg->min_keysize,
225 blkalg->max_keysize);
226 ret = -EINVAL;
227 goto error;
231 if (sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN) {
232 dprintk(0,KERN_DEBUG,"Setting key failed for %s-%zu.\n",
233 alg_name, sop->keylen*8);
234 ret = -EINVAL;
235 goto error;
238 /* Copy the key from user and set to TFM. */
239 copy_from_user(keyp, sop->key, sop->keylen);
240 ret = crypto_blkcipher_setkey(blk_tfm, keyp, sop->keylen);
241 if (ret) {
242 dprintk(0,KERN_DEBUG,"Setting key failed for %s-%zu.\n",
243 alg_name, sop->keylen*8);
244 ret = -EINVAL;
245 goto error;
250 if (hash_name) {
251 hash_tfm = crypto_alloc_hash(hash_name, 0, CRYPTO_ALG_ASYNC);
252 if (IS_ERR(hash_tfm)) {
253 dprintk(1,KERN_DEBUG,"%s: Failed to load transform for %s\n", __func__,
254 hash_name);
255 return -EINVAL;
258 /* Copy the key from user and set to TFM. */
259 if (hmac_mode != 0) {
260 uint8_t hkeyp[CRYPTO_HMAC_MAX_KEY_LEN];
262 if (sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN) {
263 dprintk(0,KERN_DEBUG,"Setting hmac key failed for %s-%zu.\n",
264 hash_name, sop->mackeylen*8);
265 ret = -EINVAL;
266 goto error;
269 copy_from_user(hkeyp, sop->mackey, sop->mackeylen);
270 ret = crypto_hash_setkey(hash_tfm, hkeyp, sop->mackeylen);
271 if (ret) {
272 dprintk(0,KERN_DEBUG,"Setting hmac key failed for %s-%zu.\n",
273 hash_name, sop->mackeylen*8);
274 ret = -EINVAL;
275 goto error;
281 /* Create a session and put it to the list. */
282 ses_new = kmalloc(sizeof(*ses_new), GFP_KERNEL);
283 if(!ses_new) {
284 ret = -ENOMEM;
285 goto error;
288 memset(ses_new, 0, sizeof(*ses_new));
289 get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
290 ses_new->tfm = blk_tfm;
291 ses_new->hash_tfm = hash_tfm;
292 init_MUTEX(&ses_new->sem);
294 down(&fcr->sem);
295 restart:
296 list_for_each_entry(ses_ptr, &fcr->list, entry) {
297 /* Check for duplicate SID */
298 if (unlikely(ses_new->sid == ses_ptr->sid)) {
299 get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
300 /* Unless we have a broken RNG this
301 shouldn't loop forever... ;-) */
302 goto restart;
306 list_add(&ses_new->entry, &fcr->list);
307 up(&fcr->sem);
309 /* Fill in some values for the user. */
310 sop->ses = ses_new->sid;
312 return 0;
314 error:
315 if (blk_tfm)
316 crypto_free_blkcipher(blk_tfm);
317 if (hash_tfm)
318 crypto_free_hash(hash_tfm);
320 return ret;
324 /* Everything that needs to be done when remowing a session. */
325 static inline void
326 crypto_destroy_session(struct csession *ses_ptr)
328 if(down_trylock(&ses_ptr->sem)) {
329 dprintk(2, KERN_DEBUG, "Waiting for semaphore of sid=0x%08X\n",
330 ses_ptr->sid);
331 down(&ses_ptr->sem);
333 dprintk(2, KERN_DEBUG, "Removed session 0x%08X\n", ses_ptr->sid);
334 #if defined(CRYPTODEV_STATS)
335 if(enable_stats)
336 dprintk(2, KERN_DEBUG,
337 "Usage in Bytes: enc=%llu, dec=%llu, max=%zu, avg=%lu, cnt=%zu\n",
338 ses_ptr->stat[COP_ENCRYPT], ses_ptr->stat[COP_DECRYPT],
339 ses_ptr->stat_max_size, ses_ptr->stat_count > 0
340 ? ((unsigned long)(ses_ptr->stat[COP_ENCRYPT]+
341 ses_ptr->stat[COP_DECRYPT]) /
342 ses_ptr->stat_count) : 0,
343 ses_ptr->stat_count);
344 #endif
345 if (ses_ptr->tfm) {
346 crypto_free_blkcipher(ses_ptr->tfm);
347 ses_ptr->tfm = NULL;
349 if (ses_ptr->hash_tfm) {
350 crypto_free_hash(ses_ptr->hash_tfm);
351 ses_ptr->hash_tfm = NULL;
353 up(&ses_ptr->sem);
354 kfree(ses_ptr);
357 /* Look up a session by ID and remove. */
358 static int
359 crypto_finish_session(struct fcrypt *fcr, uint32_t sid)
361 struct csession *tmp, *ses_ptr;
362 struct list_head *head;
363 int ret = 0;
365 down(&fcr->sem);
366 head = &fcr->list;
367 list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
368 if(ses_ptr->sid == sid) {
369 list_del(&ses_ptr->entry);
370 crypto_destroy_session(ses_ptr);
371 break;
375 if (!ses_ptr) {
376 dprintk(1, KERN_ERR, "Session with sid=0x%08X not found!\n", sid);
377 ret = -ENOENT;
379 up(&fcr->sem);
381 return ret;
384 /* Remove all sessions when closing the file */
385 static int
386 crypto_finish_all_sessions(struct fcrypt *fcr)
388 struct csession *tmp, *ses_ptr;
389 struct list_head *head;
391 down(&fcr->sem);
393 head = &fcr->list;
394 list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
395 list_del(&ses_ptr->entry);
396 crypto_destroy_session(ses_ptr);
398 up(&fcr->sem);
400 return 0;
403 /* Look up session by session ID. The returned session is locked. */
404 static struct csession *
405 crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid)
407 struct csession *ses_ptr;
409 down(&fcr->sem);
410 list_for_each_entry(ses_ptr, &fcr->list, entry) {
411 if(ses_ptr->sid == sid) {
412 down(&ses_ptr->sem);
413 break;
416 up(&fcr->sem);
418 return ses_ptr;
421 /* This is the main crypto function - feed it with plaintext
422 and get a ciphertext (or vice versa :-) */
423 static int
424 crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
426 char *data, ivp[EALG_MAX_BLOCK_LEN];
427 char __user *src, __user *dst;
428 struct scatterlist sg;
429 struct csession *ses_ptr;
430 unsigned int ivsize=0;
431 size_t nbytes, bufsize;
432 int ret = 0;
433 uint8_t hash_output[HASH_MAX_LEN];
434 struct blkcipher_desc bdesc = {
435 .flags = CRYPTO_TFM_REQ_MAY_SLEEP,
437 struct hash_desc hdesc = {
438 .flags = CRYPTO_TFM_REQ_MAY_SLEEP,
442 if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) {
443 dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", cop->op);
444 return -EINVAL;
447 ses_ptr = crypto_get_session_by_sid(fcr, cop->ses);
448 if (!ses_ptr) {
449 dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", cop->ses);
450 return -EINVAL;
453 nbytes = cop->len;
454 data = (char*)__get_free_page(GFP_KERNEL);
456 if (unlikely(!data)) {
457 ret = -ENOMEM;
458 goto out_unlock;
460 bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes;
462 nbytes = cop->len;
463 bdesc.tfm = ses_ptr->tfm;
464 hdesc.tfm = ses_ptr->hash_tfm;
465 if (hdesc.tfm) {
466 ret = crypto_hash_init(&hdesc);
467 if (unlikely(ret)) {
468 dprintk(1, KERN_ERR,
469 "error in crypto_hash_init()\n");
470 goto out_unlock;
474 if (bdesc.tfm) {
475 int blocksize = crypto_blkcipher_blocksize(bdesc.tfm);
477 if (unlikely(nbytes % blocksize)) {
478 dprintk(1, KERN_ERR,
479 "data size (%zu) isn't a multiple of block size (%u)\n",
480 nbytes, blocksize);
481 ret = -EINVAL;
482 goto out_unlock;
485 ivsize = crypto_blkcipher_ivsize(bdesc.tfm);
487 if (cop->iv) {
488 copy_from_user(ivp, cop->iv, ivsize);
489 crypto_blkcipher_set_iv(bdesc.tfm, ivp, ivsize);
493 src = cop->src;
494 dst = cop->dst;
497 while(nbytes > 0) {
498 size_t current_len = nbytes > bufsize ? bufsize : nbytes;
500 copy_from_user(data, src, current_len);
502 sg_set_buf(&sg, data, current_len);
504 /* Always hash before encryption and after decryption. Maybe
505 * we should introduce a flag to switch... TBD later on.
507 if (cop->op == COP_ENCRYPT) {
508 if (hdesc.tfm) {
509 ret = crypto_hash_update(&hdesc, &sg, current_len);
510 if (unlikely(ret)) {
511 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
512 goto out;
515 if (bdesc.tfm) {
516 ret = crypto_blkcipher_encrypt(&bdesc, &sg, &sg, current_len);
518 if (unlikely(ret)) {
519 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
520 goto out;
522 copy_to_user(dst, data, current_len);
523 dst += current_len;
525 } else {
526 if (bdesc.tfm) {
527 ret = crypto_blkcipher_decrypt(&bdesc, &sg, &sg, current_len);
529 if (unlikely(ret)) {
530 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
531 goto out;
533 copy_to_user(dst, data, current_len);
534 dst += current_len;
538 if (hdesc.tfm) {
539 ret = crypto_hash_update(&hdesc, &sg, current_len);
540 if (unlikely(ret)) {
541 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
542 goto out;
547 nbytes -= current_len;
548 src += current_len;
551 if (hdesc.tfm) {
552 ret = crypto_hash_final(&hdesc, hash_output);
553 if (unlikely(ret)) {
554 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
555 goto out;
558 copy_to_user(cop->mac, hash_output, crypto_hash_digestsize(ses_ptr->hash_tfm));
561 #if defined(CRYPTODEV_STATS)
562 if (enable_stats) {
563 /* this is safe - we check cop->op at the function entry */
564 ses_ptr->stat[cop->op] += cop->len;
565 if (ses_ptr->stat_max_size < cop->len)
566 ses_ptr->stat_max_size = cop->len;
567 ses_ptr->stat_count++;
569 #endif
571 out:
572 free_page((unsigned long)data);
574 out_unlock:
575 up(&ses_ptr->sem);
577 return ret;
580 /* ====== /dev/crypto ====== */
582 static int
583 cryptodev_open(struct inode *inode, struct file *filp)
585 struct fcrypt *fcr;
587 fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
588 if(!fcr)
589 return -ENOMEM;
591 memset(fcr, 0, sizeof(*fcr));
592 init_MUTEX(&fcr->sem);
593 INIT_LIST_HEAD(&fcr->list);
594 filp->private_data = fcr;
596 return 0;
599 static int
600 cryptodev_release(struct inode *inode, struct file *filp)
602 struct fcrypt *fcr = filp->private_data;
604 if(fcr) {
605 crypto_finish_all_sessions(fcr);
606 kfree(fcr);
607 filp->private_data = NULL;
610 return 0;
613 static int
614 clonefd(struct file *filp)
616 struct fdtable *fdt = files_fdtable(current->files);
617 int ret;
618 ret = get_unused_fd();
619 if (ret >= 0) {
620 get_file(filp);
621 FD_SET(ret, fdt->open_fds);
622 fd_install(ret, filp);
625 return ret;
628 static int
629 cryptodev_ioctl(struct inode *inode, struct file *filp,
630 unsigned int cmd, unsigned long arg)
632 int __user *p = (void __user *)arg;
633 struct session_op sop;
634 struct crypt_op cop;
635 struct fcrypt *fcr = filp->private_data;
636 uint32_t ses;
637 int ret, fd;
639 if (!fcr)
640 BUG();
642 switch (cmd) {
643 case CIOCASYMFEAT:
644 put_user(0, p);
645 return 0;
646 case CRIOGET:
647 fd = clonefd(filp);
648 put_user(fd, p);
649 return 0;
651 case CIOCGSESSION:
652 copy_from_user(&sop, (void*)arg, sizeof(sop));
653 ret = crypto_create_session(fcr, &sop);
654 if (ret)
655 return ret;
656 copy_to_user((void*)arg, &sop, sizeof(sop));
657 return 0;
659 case CIOCFSESSION:
660 get_user(ses, (uint32_t*)arg);
661 ret = crypto_finish_session(fcr, ses);
662 return ret;
664 case CIOCCRYPT:
665 copy_from_user(&cop, (void*)arg, sizeof(cop));
666 ret = crypto_run(fcr, &cop);
667 copy_to_user((void*)arg, &cop, sizeof(cop));
668 return ret;
670 default:
671 return -EINVAL;
675 struct file_operations cryptodev_fops = {
676 .owner = THIS_MODULE,
677 .open = cryptodev_open,
678 .release = cryptodev_release,
679 .ioctl = cryptodev_ioctl,
682 struct miscdevice cryptodev = {
683 .minor = CRYPTODEV_MINOR,
684 .name = "crypto",
685 .fops = &cryptodev_fops,
688 static int
689 cryptodev_register(void)
691 int rc;
693 rc = misc_register (&cryptodev);
694 if (rc) {
695 printk(KERN_ERR PFX "registeration of /dev/crypto failed\n");
696 return rc;
699 return 0;
702 static void
703 cryptodev_deregister(void)
705 misc_deregister(&cryptodev);
708 /* ====== Module init/exit ====== */
710 int __init init_cryptodev(void)
712 int rc;
714 rc = cryptodev_register();
715 if (rc)
716 return rc;
718 printk(KERN_INFO PFX "driver loaded.\n");
720 return 0;
723 void __exit exit_cryptodev(void)
725 cryptodev_deregister();
726 printk(KERN_INFO PFX "driver unloaded.\n");
729 module_init(init_cryptodev);
730 module_exit(exit_cryptodev);