cryptodev initialises its sg with sg_set_buf. Although I'm not
[cryptodev-linux.git] / cryptodev_main.c
blob63ce16239e0e097183f34c30e65078f5b3a752a7
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/crypto.h>
35 #include <linux/mm.h>
36 #include <linux/highmem.h>
37 #include <linux/random.h>
38 #include "cryptodev.h"
39 #include <asm/uaccess.h>
40 #include <asm/ioctl.h>
41 #include <linux/scatterlist.h>
42 #include "cryptodev_int.h"
44 MODULE_AUTHOR("Nikos Mavrogiannopoulos <nmav@gnutls.org>");
45 MODULE_DESCRIPTION("CryptoDev driver");
46 MODULE_LICENSE("GPL");
48 /* ====== Compile-time config ====== */
50 #define CRYPTODEV_STATS
52 /* ====== Module parameters ====== */
54 int cryptodev_verbosity = 0;
55 module_param(cryptodev_verbosity, int, 0644);
56 MODULE_PARM_DESC(cryptodev_verbosity, "0: normal, 1: verbose, 2: debug");
58 #ifdef CRYPTODEV_STATS
59 static int enable_stats = 0;
60 module_param(enable_stats, int, 0644);
61 MODULE_PARM_DESC(enable_stats, "collect statictics about cryptodev usage");
62 #endif
64 /* ====== CryptoAPI ====== */
66 #define FILL_SG(sg,ptr,len) \
67 do { \
68 (sg)->page = virt_to_page(ptr); \
69 (sg)->offset = offset_in_page(ptr); \
70 (sg)->length = len; \
71 (sg)->dma_address = 0; \
72 } while (0)
74 struct csession {
75 struct list_head entry;
76 struct semaphore sem;
77 struct cipher_data cdata;
78 struct hash_data hdata;
79 uint32_t sid;
80 #ifdef CRYPTODEV_STATS
81 #if ! ((COP_ENCRYPT < 2) && (COP_DECRYPT < 2))
82 #error Struct csession.stat uses COP_{ENCRYPT,DECRYPT} as indices. Do something!
83 #endif
84 unsigned long long stat[2];
85 size_t stat_max_size, stat_count;
86 #endif
89 struct fcrypt {
90 struct list_head list;
91 struct semaphore sem;
94 /* Prepare session for future use. */
95 static int
96 crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
98 struct csession *ses_new, *ses_ptr;
99 int ret = 0;
100 const char *alg_name=NULL;
101 const char *hash_name=NULL;
102 int hmac_mode = 1;
104 /* Does the request make sense? */
105 if (!sop->cipher && !sop->mac) {
106 dprintk(1,KERN_DEBUG,"Both 'cipher' and 'mac' unset.\n");
107 return -EINVAL;
110 switch (sop->cipher) {
111 case 0:
112 break;
113 case CRYPTO_DES_CBC:
114 alg_name = "cbc(des)";
115 break;
116 case CRYPTO_3DES_CBC:
117 alg_name = "cbc(des3_ede)";
118 break;
119 case CRYPTO_BLF_CBC:
120 alg_name = "cbc(blowfish)";
121 break;
122 case CRYPTO_AES_CBC:
123 alg_name = "cbc(aes)";
124 break;
125 case CRYPTO_CAMELLIA_CBC:
126 alg_name = "cbc(camelia)";
127 break;
128 default:
129 dprintk(1,KERN_DEBUG,"%s: bad cipher: %d\n", __func__, sop->cipher);
130 return -EINVAL;
133 switch (sop->mac) {
134 case 0:
135 break;
136 case CRYPTO_MD5_HMAC:
137 hash_name = "hmac(md5)";
138 break;
139 case CRYPTO_RIPEMD160_HMAC:
140 hash_name = "hmac(rmd160)";
141 break;
142 case CRYPTO_SHA1_HMAC:
143 hash_name = "hmac(sha1)";
144 break;
145 case CRYPTO_SHA2_256_HMAC:
146 hash_name = "hmac(sha256)";
147 break;
148 case CRYPTO_SHA2_384_HMAC:
149 hash_name = "hmac(sha384)";
150 break;
151 case CRYPTO_SHA2_512_HMAC:
152 hash_name = "hmac(sha512)";
153 break;
155 /* non-hmac cases */
156 case CRYPTO_MD5:
157 hash_name = "md5";
158 hmac_mode = 0;
159 break;
160 case CRYPTO_RIPEMD160:
161 hash_name = "rmd160";
162 hmac_mode = 0;
163 break;
164 case CRYPTO_SHA1:
165 hash_name = "sha1";
166 hmac_mode = 0;
167 break;
168 case CRYPTO_SHA2_256:
169 hash_name = "sha256";
170 hmac_mode = 0;
171 break;
172 case CRYPTO_SHA2_384:
173 hash_name = "sha384";
174 hmac_mode = 0;
175 break;
176 case CRYPTO_SHA2_512:
177 hash_name = "sha512";
178 hmac_mode = 0;
179 break;
181 default:
182 dprintk(1,KERN_DEBUG,"%s: bad mac: %d\n", __func__, sop->mac);
183 return -EINVAL;
186 /* Create a session and put it to the list. */
187 ses_new = kmalloc(sizeof(*ses_new), GFP_KERNEL);
188 if(!ses_new) {
189 ret = -ENOMEM;
190 goto error;
193 memset(ses_new, 0, sizeof(*ses_new));
195 /* Set-up crypto transform. */
196 if (alg_name) {
198 ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, sop->key, sop->keylen);
199 if (ret < 0) {
200 return ret;
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 transform for %s\n", __func__,
208 hash_name);
209 return -EINVAL;
213 /* put the new session to the list */
214 get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
215 init_MUTEX(&ses_new->sem);
217 down(&fcr->sem);
218 restart:
219 list_for_each_entry(ses_ptr, &fcr->list, entry) {
220 /* Check for duplicate SID */
221 if (unlikely(ses_new->sid == ses_ptr->sid)) {
222 get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
223 /* Unless we have a broken RNG this
224 shouldn't loop forever... ;-) */
225 goto restart;
229 list_add(&ses_new->entry, &fcr->list);
230 up(&fcr->sem);
232 /* Fill in some values for the user. */
233 sop->ses = ses_new->sid;
235 return 0;
237 error:
238 cryptodev_cipher_deinit( &ses_new->cdata);
239 cryptodev_hash_deinit( &ses_new->hdata);
241 return ret;
245 /* Everything that needs to be done when remowing a session. */
246 static inline void
247 crypto_destroy_session(struct csession *ses_ptr)
249 if(down_trylock(&ses_ptr->sem)) {
250 dprintk(2, KERN_DEBUG, "Waiting for semaphore of sid=0x%08X\n",
251 ses_ptr->sid);
252 down(&ses_ptr->sem);
254 dprintk(2, KERN_DEBUG, "Removed session 0x%08X\n", ses_ptr->sid);
255 #if defined(CRYPTODEV_STATS)
256 if(enable_stats)
257 dprintk(2, KERN_DEBUG,
258 "Usage in Bytes: enc=%llu, dec=%llu, max=%zu, avg=%lu, cnt=%zu\n",
259 ses_ptr->stat[COP_ENCRYPT], ses_ptr->stat[COP_DECRYPT],
260 ses_ptr->stat_max_size, ses_ptr->stat_count > 0
261 ? ((unsigned long)(ses_ptr->stat[COP_ENCRYPT]+
262 ses_ptr->stat[COP_DECRYPT]) /
263 ses_ptr->stat_count) : 0,
264 ses_ptr->stat_count);
265 #endif
266 cryptodev_cipher_deinit(&ses_ptr->cdata);
267 cryptodev_hash_deinit(&ses_ptr->hdata);
268 up(&ses_ptr->sem);
269 kfree(ses_ptr);
272 /* Look up a session by ID and remove. */
273 static int
274 crypto_finish_session(struct fcrypt *fcr, uint32_t sid)
276 struct csession *tmp, *ses_ptr;
277 struct list_head *head;
278 int ret = 0;
280 down(&fcr->sem);
281 head = &fcr->list;
282 list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
283 if(ses_ptr->sid == sid) {
284 list_del(&ses_ptr->entry);
285 crypto_destroy_session(ses_ptr);
286 break;
290 if (!ses_ptr) {
291 dprintk(1, KERN_ERR, "Session with sid=0x%08X not found!\n", sid);
292 ret = -ENOENT;
294 up(&fcr->sem);
296 return ret;
299 /* Remove all sessions when closing the file */
300 static int
301 crypto_finish_all_sessions(struct fcrypt *fcr)
303 struct csession *tmp, *ses_ptr;
304 struct list_head *head;
306 down(&fcr->sem);
308 head = &fcr->list;
309 list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
310 list_del(&ses_ptr->entry);
311 crypto_destroy_session(ses_ptr);
313 up(&fcr->sem);
315 return 0;
318 /* Look up session by session ID. The returned session is locked. */
319 static struct csession *
320 crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid)
322 struct csession *ses_ptr;
324 down(&fcr->sem);
325 list_for_each_entry(ses_ptr, &fcr->list, entry) {
326 if(ses_ptr->sid == sid) {
327 down(&ses_ptr->sem);
328 break;
331 up(&fcr->sem);
333 return ses_ptr;
336 /* This is the main crypto function - feed it with plaintext
337 and get a ciphertext (or vice versa :-) */
338 static int
339 crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
341 char *data;
342 char __user *src, __user *dst;
343 struct scatterlist sg;
344 struct csession *ses_ptr;
345 unsigned int ivsize=0;
346 size_t nbytes, bufsize;
347 int ret = 0;
348 uint8_t hash_output[AALG_MAX_RESULT_LEN];
350 if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) {
351 dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", cop->op);
352 return -EINVAL;
355 ses_ptr = crypto_get_session_by_sid(fcr, cop->ses);
356 if (!ses_ptr) {
357 dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", cop->ses);
358 return -EINVAL;
361 nbytes = cop->len;
362 data = (char*)__get_free_page(GFP_KERNEL);
364 if (unlikely(!data)) {
365 ret = -ENOMEM;
366 goto out_unlock;
368 bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes;
370 nbytes = cop->len;
372 if (ses_ptr->hdata.init != 0) {
373 ret = cryptodev_hash_reset(&ses_ptr->hdata);
374 if (unlikely(ret)) {
375 dprintk(1, KERN_ERR,
376 "error in cryptodev_hash_reset()\n");
377 goto out_unlock;
381 if (ses_ptr->cdata.init != 0) {
382 int blocksize = ses_ptr->cdata.blocksize;
384 if (unlikely(nbytes % blocksize)) {
385 dprintk(1, KERN_ERR,
386 "data size (%zu) isn't a multiple of block size (%u)\n",
387 nbytes, blocksize);
388 ret = -EINVAL;
389 goto out_unlock;
392 ivsize = ses_ptr->cdata.ivsize;
394 if (cop->iv) {
395 cryptodev_cipher_set_iv(&ses_ptr->cdata, cop->iv, ivsize);
399 src = cop->src;
400 dst = cop->dst;
403 while(nbytes > 0) {
404 size_t current_len = nbytes > bufsize ? bufsize : nbytes;
406 copy_from_user(data, src, current_len);
408 sg_init_one(&sg, data, current_len);
410 /* Always hash before encryption and after decryption. Maybe
411 * we should introduce a flag to switch... TBD later on.
413 if (cop->op == COP_ENCRYPT) {
414 if (ses_ptr->hdata.init != 0) {
415 ret = cryptodev_hash_update(&ses_ptr->hdata, &sg, current_len);
416 if (unlikely(ret)) {
417 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
418 goto out;
421 if (ses_ptr->cdata.init != 0) {
422 ret = cryptodev_cipher_encrypt( &ses_ptr->cdata, &sg, &sg, current_len);
424 if (unlikely(ret)) {
425 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
426 goto out;
428 copy_to_user(dst, data, current_len);
429 dst += current_len;
431 } else {
432 if (ses_ptr->cdata.init != 0) {
433 ret = cryptodev_cipher_decrypt( &ses_ptr->cdata, &sg, &sg, current_len);
435 if (unlikely(ret)) {
436 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
437 goto out;
439 copy_to_user(dst, data, current_len);
440 dst += current_len;
444 if (ses_ptr->hdata.init != 0) {
445 ret = cryptodev_hash_update(&ses_ptr->hdata, &sg, current_len);
446 if (unlikely(ret)) {
447 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
448 goto out;
453 nbytes -= current_len;
454 src += current_len;
457 if (ses_ptr->hdata.init != 0) {
458 ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output);
459 if (unlikely(ret)) {
460 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
461 goto out;
464 copy_to_user(cop->mac, hash_output, ses_ptr->hdata.digestsize);
467 #if defined(CRYPTODEV_STATS)
468 if (enable_stats) {
469 /* this is safe - we check cop->op at the function entry */
470 ses_ptr->stat[cop->op] += cop->len;
471 if (ses_ptr->stat_max_size < cop->len)
472 ses_ptr->stat_max_size = cop->len;
473 ses_ptr->stat_count++;
475 #endif
477 out:
478 free_page((unsigned long)data);
480 out_unlock:
481 up(&ses_ptr->sem);
483 return ret;
486 /* ====== /dev/crypto ====== */
488 static int
489 cryptodev_open(struct inode *inode, struct file *filp)
491 struct fcrypt *fcr;
493 fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
494 if(!fcr)
495 return -ENOMEM;
497 memset(fcr, 0, sizeof(*fcr));
498 init_MUTEX(&fcr->sem);
499 INIT_LIST_HEAD(&fcr->list);
500 filp->private_data = fcr;
502 return 0;
505 static int
506 cryptodev_release(struct inode *inode, struct file *filp)
508 struct fcrypt *fcr = filp->private_data;
510 if(fcr) {
511 crypto_finish_all_sessions(fcr);
512 kfree(fcr);
513 filp->private_data = NULL;
516 return 0;
519 static int
520 clonefd(struct file *filp)
522 struct fdtable *fdt = files_fdtable(current->files);
523 int ret;
524 ret = get_unused_fd();
525 if (ret >= 0) {
526 get_file(filp);
527 FD_SET(ret, fdt->open_fds);
528 fd_install(ret, filp);
531 return ret;
534 static int
535 cryptodev_ioctl(struct inode *inode, struct file *filp,
536 unsigned int cmd, unsigned long arg)
538 int __user *p = (void __user *)arg;
539 struct session_op sop;
540 struct crypt_op cop;
541 struct fcrypt *fcr = filp->private_data;
542 uint32_t ses;
543 int ret, fd;
545 if (!fcr)
546 BUG();
548 switch (cmd) {
549 case CIOCASYMFEAT:
550 put_user(0, p);
551 return 0;
552 case CRIOGET:
553 fd = clonefd(filp);
554 put_user(fd, p);
555 return 0;
557 case CIOCGSESSION:
558 copy_from_user(&sop, (void*)arg, sizeof(sop));
559 ret = crypto_create_session(fcr, &sop);
560 if (ret)
561 return ret;
562 copy_to_user((void*)arg, &sop, sizeof(sop));
563 return 0;
565 case CIOCFSESSION:
566 get_user(ses, (uint32_t*)arg);
567 ret = crypto_finish_session(fcr, ses);
568 return ret;
570 case CIOCCRYPT:
571 copy_from_user(&cop, (void*)arg, sizeof(cop));
572 ret = crypto_run(fcr, &cop);
573 copy_to_user((void*)arg, &cop, sizeof(cop));
574 return ret;
576 default:
577 return -EINVAL;
581 struct file_operations cryptodev_fops = {
582 .owner = THIS_MODULE,
583 .open = cryptodev_open,
584 .release = cryptodev_release,
585 .ioctl = cryptodev_ioctl,
588 struct miscdevice cryptodev = {
589 .minor = MISC_DYNAMIC_MINOR,
590 .name = "crypto",
591 .fops = &cryptodev_fops,
594 static int
595 cryptodev_register(void)
597 int rc;
599 rc = misc_register (&cryptodev);
600 if (rc) {
601 printk(KERN_ERR PFX "registeration of /dev/crypto failed\n");
602 return rc;
605 return 0;
608 static void
609 cryptodev_deregister(void)
611 misc_deregister(&cryptodev);
614 /* ====== Module init/exit ====== */
616 int __init init_cryptodev(void)
618 int rc;
620 rc = cryptodev_register();
621 if (rc)
622 return rc;
624 printk(KERN_INFO PFX "driver loaded.\n");
626 return 0;
629 void __exit exit_cryptodev(void)
631 cryptodev_deregister();
632 printk(KERN_INFO PFX "driver unloaded.\n");
635 module_init(init_cryptodev);
636 module_exit(exit_cryptodev);