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>
39 #include <linux/file.h>
40 #include <linux/fdtable.h>
41 #include <linux/miscdevice.h>
42 #include <linux/crypto.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");
71 /* ====== Debug helpers ====== */
73 #define PFX "cryptodev: "
74 #define dprintk(level,severity,format,a...) \
76 if (level <= verbosity) \
77 printk(severity PFX "%s[%u]: " format, \
78 current->comm, current->pid, \
82 /* ====== CryptoAPI ====== */
84 #define FILL_SG(sg,ptr,len) \
86 (sg)->page = virt_to_page(ptr); \
87 (sg)->offset = offset_in_page(ptr); \
89 (sg)->dma_address = 0; \
93 struct list_head entry
;
95 struct crypto_blkcipher
*tfm
;
96 struct crypto_hash
*hash_tfm
;
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!
102 unsigned long long stat
[2];
103 size_t stat_max_size
, stat_count
;
108 struct list_head list
;
109 struct semaphore sem
;
112 /* Prepare session for future use. */
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
;
120 const char *alg_name
=NULL
;
121 const char *hash_name
=NULL
;
122 struct blkcipher_alg
* blkalg
;
125 /* Does the request make sense? */
126 if (!sop
->cipher
&& !sop
->mac
) {
127 dprintk(1,KERN_DEBUG
,"Both 'cipher' and 'mac' unset.\n");
131 switch (sop
->cipher
) {
135 alg_name
= "cbc(des)";
137 case CRYPTO_3DES_CBC
:
138 alg_name
= "cbc(3des_ede)";
141 alg_name
= "cbc(blowfish)";
144 alg_name
= "cbc(aes)";
146 case CRYPTO_CAMELLIA_CBC
:
147 alg_name
= "cbc(camelia)";
150 dprintk(1,KERN_DEBUG
,"%s: bad cipher: %d\n", __func__
, sop
->cipher
);
157 case CRYPTO_MD5_HMAC
:
158 hash_name
= "hmac(md5)";
160 case CRYPTO_RIPEMD160_HMAC
:
161 hash_name
= "hmac(rmd160)";
163 case CRYPTO_SHA1_HMAC
:
164 hash_name
= "hmac(sha1)";
166 case CRYPTO_SHA2_256_HMAC
:
167 hash_name
= "hmac(sha256)";
169 case CRYPTO_SHA2_384_HMAC
:
170 hash_name
= "hmac(sha384)";
172 case CRYPTO_SHA2_512_HMAC
:
173 hash_name
= "hmac(sha512)";
181 case CRYPTO_RIPEMD160
:
182 hash_name
= "rmd160";
189 case CRYPTO_SHA2_256
:
190 hash_name
= "sha256";
193 case CRYPTO_SHA2_384
:
194 hash_name
= "sha384";
197 case CRYPTO_SHA2_512
:
198 hash_name
= "sha512";
203 dprintk(1,KERN_DEBUG
,"%s: bad mac: %d\n", __func__
, sop
->mac
);
207 /* Set-up crypto transform. */
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__
,
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
);
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);
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
);
242 dprintk(0,KERN_DEBUG
,"Setting key failed for %s-%zu.\n",
243 alg_name
, sop
->keylen
*8);
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__
,
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);
269 copy_from_user(hkeyp
, sop
->mackey
, sop
->mackeylen
);
270 ret
= crypto_hash_setkey(hash_tfm
, hkeyp
, sop
->mackeylen
);
272 dprintk(0,KERN_DEBUG
,"Setting hmac key failed for %s-%zu.\n",
273 hash_name
, sop
->mackeylen
*8);
281 /* Create a session and put it to the list. */
282 ses_new
= kmalloc(sizeof(*ses_new
), GFP_KERNEL
);
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
);
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... ;-) */
306 list_add(&ses_new
->entry
, &fcr
->list
);
309 /* Fill in some values for the user. */
310 sop
->ses
= ses_new
->sid
;
316 crypto_free_blkcipher(blk_tfm
);
318 crypto_free_hash(hash_tfm
);
324 /* Everything that needs to be done when remowing a session. */
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",
333 dprintk(2, KERN_DEBUG
, "Removed session 0x%08X\n", ses_ptr
->sid
);
334 #if defined(CRYPTODEV_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
);
346 crypto_free_blkcipher(ses_ptr
->tfm
);
349 if (ses_ptr
->hash_tfm
) {
350 crypto_free_hash(ses_ptr
->hash_tfm
);
351 ses_ptr
->hash_tfm
= NULL
;
357 /* Look up a session by ID and remove. */
359 crypto_finish_session(struct fcrypt
*fcr
, uint32_t sid
)
361 struct csession
*tmp
, *ses_ptr
;
362 struct list_head
*head
;
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
);
376 dprintk(1, KERN_ERR
, "Session with sid=0x%08X not found!\n", sid
);
384 /* Remove all sessions when closing the file */
386 crypto_finish_all_sessions(struct fcrypt
*fcr
)
388 struct csession
*tmp
, *ses_ptr
;
389 struct list_head
*head
;
394 list_for_each_entry_safe(ses_ptr
, tmp
, head
, entry
) {
395 list_del(&ses_ptr
->entry
);
396 crypto_destroy_session(ses_ptr
);
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
;
410 list_for_each_entry(ses_ptr
, &fcr
->list
, entry
) {
411 if(ses_ptr
->sid
== sid
) {
421 /* This is the main crypto function - feed it with plaintext
422 and get a ciphertext (or vice versa :-) */
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
;
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
);
447 ses_ptr
= crypto_get_session_by_sid(fcr
, cop
->ses
);
449 dprintk(1, KERN_ERR
, "invalid session ID=0x%08X\n", cop
->ses
);
454 data
= (char*)__get_free_page(GFP_KERNEL
);
456 if (unlikely(!data
)) {
460 bufsize
= PAGE_SIZE
< nbytes
? PAGE_SIZE
: nbytes
;
463 bdesc
.tfm
= ses_ptr
->tfm
;
464 hdesc
.tfm
= ses_ptr
->hash_tfm
;
466 ret
= crypto_hash_init(&hdesc
);
469 "error in crypto_hash_init()\n");
475 int blocksize
= crypto_blkcipher_blocksize(bdesc
.tfm
);
477 if (unlikely(nbytes
% blocksize
)) {
479 "data size (%zu) isn't a multiple of block size (%u)\n",
485 ivsize
= crypto_blkcipher_ivsize(bdesc
.tfm
);
488 copy_from_user(ivp
, cop
->iv
, ivsize
);
489 crypto_blkcipher_set_iv(bdesc
.tfm
, ivp
, ivsize
);
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
) {
509 ret
= crypto_hash_update(&hdesc
, &sg
, current_len
);
511 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n",ret
);
516 ret
= crypto_blkcipher_encrypt(&bdesc
, &sg
, &sg
, current_len
);
519 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n",ret
);
522 copy_to_user(dst
, data
, current_len
);
527 ret
= crypto_blkcipher_decrypt(&bdesc
, &sg
, &sg
, current_len
);
530 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n",ret
);
533 copy_to_user(dst
, data
, current_len
);
539 ret
= crypto_hash_update(&hdesc
, &sg
, current_len
);
541 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n",ret
);
547 nbytes
-= current_len
;
552 ret
= crypto_hash_final(&hdesc
, hash_output
);
554 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n",ret
);
558 copy_to_user(cop
->mac
, hash_output
, crypto_hash_digestsize(ses_ptr
->hash_tfm
));
561 #if defined(CRYPTODEV_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
++;
572 free_page((unsigned long)data
);
580 /* ====== /dev/crypto ====== */
583 cryptodev_open(struct inode
*inode
, struct file
*filp
)
587 fcr
= kmalloc(sizeof(*fcr
), GFP_KERNEL
);
591 memset(fcr
, 0, sizeof(*fcr
));
592 init_MUTEX(&fcr
->sem
);
593 INIT_LIST_HEAD(&fcr
->list
);
594 filp
->private_data
= fcr
;
600 cryptodev_release(struct inode
*inode
, struct file
*filp
)
602 struct fcrypt
*fcr
= filp
->private_data
;
605 crypto_finish_all_sessions(fcr
);
607 filp
->private_data
= NULL
;
614 clonefd(struct file
*filp
)
616 struct fdtable
*fdt
= files_fdtable(current
->files
);
618 ret
= get_unused_fd();
621 FD_SET(ret
, fdt
->open_fds
);
622 fd_install(ret
, filp
);
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
;
635 struct fcrypt
*fcr
= filp
->private_data
;
652 copy_from_user(&sop
, (void*)arg
, sizeof(sop
));
653 ret
= crypto_create_session(fcr
, &sop
);
656 copy_to_user((void*)arg
, &sop
, sizeof(sop
));
660 get_user(ses
, (uint32_t*)arg
);
661 ret
= crypto_finish_session(fcr
, ses
);
665 copy_from_user(&cop
, (void*)arg
, sizeof(cop
));
666 ret
= crypto_run(fcr
, &cop
);
667 copy_to_user((void*)arg
, &cop
, sizeof(cop
));
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
,
685 .fops
= &cryptodev_fops
,
689 cryptodev_register(void)
693 rc
= misc_register (&cryptodev
);
695 printk(KERN_ERR PFX
"registeration of /dev/crypto failed\n");
703 cryptodev_deregister(void)
705 misc_deregister(&cryptodev
);
708 /* ====== Module init/exit ====== */
710 int __init
init_cryptodev(void)
714 rc
= cryptodev_register();
718 printk(KERN_INFO PFX
"driver loaded.\n");
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
);