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>
22 #include <linux/file.h>
23 #include <linux/fdtable.h>
24 #include <linux/miscdevice.h>
25 #include <linux/crypto.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");
54 /* ====== Debug helpers ====== */
56 #define PFX "cryptodev: "
57 #define dprintk(level,severity,format,a...) \
59 if (level <= verbosity) \
60 printk(severity PFX "%s[%u]: " format, \
61 current->comm, current->pid, \
65 /* ====== CryptoAPI ====== */
67 #define FILL_SG(sg,ptr,len) \
69 (sg)->page = virt_to_page(ptr); \
70 (sg)->offset = offset_in_page(ptr); \
72 (sg)->dma_address = 0; \
76 struct list_head entry
;
78 struct crypto_blkcipher
*tfm
;
79 struct crypto_hash
*hash_tfm
;
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!
85 unsigned long long stat
[2];
86 size_t stat_max_size
, stat_count
;
91 struct list_head list
;
95 /* Prepare session for future use. */
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
;
103 const char *alg_name
=NULL
;
104 const char *hash_name
=NULL
;
105 struct blkcipher_alg
* blkalg
;
108 /* Does the request make sense? */
109 if (!sop
->cipher
&& !sop
->mac
) {
110 dprintk(1,KERN_DEBUG
,"Both 'cipher' and 'mac' unset.\n");
114 switch (sop
->cipher
) {
118 alg_name
= "cbc(des)";
120 case CRYPTO_3DES_CBC
:
121 alg_name
= "cbc(3des_ede)";
124 alg_name
= "cbc(blowfish)";
127 alg_name
= "cbc(aes)";
129 case CRYPTO_CAMELLIA_CBC
:
130 alg_name
= "cbc(camelia)";
133 dprintk(1,KERN_DEBUG
,"%s: bad cipher: %d\n", __func__
, sop
->cipher
);
140 case CRYPTO_MD5_HMAC
:
141 hash_name
= "hmac(md5)";
143 case CRYPTO_RIPEMD160_HMAC
:
144 hash_name
= "hmac(rmd160)";
146 case CRYPTO_SHA1_HMAC
:
147 hash_name
= "hmac(sha1)";
149 case CRYPTO_SHA2_256_HMAC
:
150 hash_name
= "hmac(sha256)";
152 case CRYPTO_SHA2_384_HMAC
:
153 hash_name
= "hmac(sha384)";
155 case CRYPTO_SHA2_512_HMAC
:
156 hash_name
= "hmac(sha512)";
164 case CRYPTO_RIPEMD160
:
165 hash_name
= "rmd160";
172 case CRYPTO_SHA2_256
:
173 hash_name
= "sha256";
176 case CRYPTO_SHA2_384
:
177 hash_name
= "sha384";
180 case CRYPTO_SHA2_512
:
181 hash_name
= "sha512";
186 dprintk(1,KERN_DEBUG
,"%s: bad mac: %d\n", __func__
, sop
->mac
);
190 /* Set-up crypto transform. */
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__
,
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
);
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);
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
);
225 dprintk(0,KERN_DEBUG
,"Setting key failed for %s-%zu.\n",
226 alg_name
, sop
->keylen
*8);
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__
,
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);
252 copy_from_user(hkeyp
, sop
->mackey
, sop
->mackeylen
);
253 ret
= crypto_hash_setkey(hash_tfm
, hkeyp
, sop
->mackeylen
);
255 dprintk(0,KERN_DEBUG
,"Setting hmac key failed for %s-%zu.\n",
256 hash_name
, sop
->mackeylen
*8);
264 /* Create a session and put it to the list. */
265 ses_new
= kmalloc(sizeof(*ses_new
), GFP_KERNEL
);
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
);
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... ;-) */
289 list_add(&ses_new
->entry
, &fcr
->list
);
292 /* Fill in some values for the user. */
293 sop
->ses
= ses_new
->sid
;
299 crypto_free_blkcipher(blk_tfm
);
301 crypto_free_hash(hash_tfm
);
307 /* Everything that needs to be done when remowing a session. */
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",
316 dprintk(2, KERN_DEBUG
, "Removed session 0x%08X\n", ses_ptr
->sid
);
317 #if defined(CRYPTODEV_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
);
329 crypto_free_blkcipher(ses_ptr
->tfm
);
332 if (ses_ptr
->hash_tfm
) {
333 crypto_free_hash(ses_ptr
->hash_tfm
);
334 ses_ptr
->hash_tfm
= NULL
;
340 /* Look up a session by ID and remove. */
342 crypto_finish_session(struct fcrypt
*fcr
, uint32_t sid
)
344 struct csession
*tmp
, *ses_ptr
;
345 struct list_head
*head
;
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
);
359 dprintk(1, KERN_ERR
, "Session with sid=0x%08X not found!\n", sid
);
367 /* Remove all sessions when closing the file */
369 crypto_finish_all_sessions(struct fcrypt
*fcr
)
371 struct csession
*tmp
, *ses_ptr
;
372 struct list_head
*head
;
377 list_for_each_entry_safe(ses_ptr
, tmp
, head
, entry
) {
378 list_del(&ses_ptr
->entry
);
379 crypto_destroy_session(ses_ptr
);
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
;
393 list_for_each_entry(ses_ptr
, &fcr
->list
, entry
) {
394 if(ses_ptr
->sid
== sid
) {
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
;
413 uint8_t hash_output
[HASH_MAX_LEN
];
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
);
428 ses_ptr
= crypto_get_session_by_sid(fcr
, copv
->ses
);
430 dprintk(1, KERN_ERR
, "invalid session ID=0x%08X\n", copv
->ses
);
434 data
= (char*)__get_free_page(GFP_KERNEL
);
436 if (unlikely(!data
)) {
441 bdesc
.tfm
= ses_ptr
->tfm
;
442 hdesc
.tfm
= ses_ptr
->hash_tfm
;
445 ret
= crypto_hash_init(&hdesc
);
448 "error in crypto_hash_init()\n");
454 blocksize
= crypto_blkcipher_blocksize(ses_ptr
->tfm
);
455 ivsize
= crypto_blkcipher_ivsize(ses_ptr
->tfm
);
458 copy_from_user(ivp
, copv
->iv
, ivsize
);
459 crypto_blkcipher_set_iv(ses_ptr
->tfm
, ivp
, ivsize
);
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
))) {
470 "data size (%zu) isn't a multiple of block size (%u)\n",
471 nbytes
, crypto_blkcipher_blocksize(ses_ptr
->tfm
));
476 bufsize
= PAGE_SIZE
< nbytes
? PAGE_SIZE
: nbytes
;
478 src
= copv
->iovec
[i
].src
;
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
);
494 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n",ret
);
498 if (bdesc
.tfm
&& (copv
->iovec
[i
].op_flags
& IOP_CIPHER
)) {
499 ret
= crypto_blkcipher_encrypt(&bdesc
, &sg
, &sg
, current_len
);
502 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n",ret
);
505 copy_to_user(dst
, data
, current_len
);
509 if (bdesc
.tfm
&& (copv
->iovec
[i
].op_flags
& IOP_CIPHER
)) {
510 ret
= crypto_blkcipher_decrypt(&bdesc
, &sg
, &sg
, current_len
);
513 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n",ret
);
516 copy_to_user(dst
, data
, current_len
);
521 if (hdesc
.tfm
&& (copv
->iovec
[i
].op_flags
& IOP_HASH
)) {
522 ret
= crypto_hash_update(&hdesc
, &sg
, current_len
);
524 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n",ret
);
530 nbytes
-= current_len
;
534 #if defined(CRYPTODEV_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
++;
547 ret
= crypto_hash_final(&hdesc
, hash_output
);
549 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n",ret
);
553 copy_to_user(copv
->mac
, hash_output
, crypto_hash_digestsize(ses_ptr
->hash_tfm
));
557 free_page((unsigned long)data
);
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
;
578 copv
.flags
= cop
->flags
;
586 return crypto_runv(fcr
, &copv
);
592 /* ====== /dev/crypto ====== */
595 cryptodev_open(struct inode
*inode
, struct file
*filp
)
599 fcr
= kmalloc(sizeof(*fcr
), GFP_KERNEL
);
603 memset(fcr
, 0, sizeof(*fcr
));
604 init_MUTEX(&fcr
->sem
);
605 INIT_LIST_HEAD(&fcr
->list
);
606 filp
->private_data
= fcr
;
612 cryptodev_release(struct inode
*inode
, struct file
*filp
)
614 struct fcrypt
*fcr
= filp
->private_data
;
617 crypto_finish_all_sessions(fcr
);
619 filp
->private_data
= NULL
;
626 clonefd(struct file
*filp
)
628 struct fdtable
*fdt
= files_fdtable(current
->files
);
630 ret
= get_unused_fd();
633 FD_SET(ret
, fdt
->open_fds
);
634 fd_install(ret
, filp
);
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
;
647 struct crypt_opv copv
;
648 struct fcrypt
*fcr
= filp
->private_data
;
665 copy_from_user(&sop
, (void*)arg
, sizeof(sop
));
666 ret
= crypto_create_session(fcr
, &sop
);
669 copy_to_user((void*)arg
, &sop
, sizeof(sop
));
673 get_user(ses
, (uint32_t*)arg
);
674 ret
= crypto_finish_session(fcr
, ses
);
678 copy_from_user(&cop
, (void*)arg
, sizeof(cop
));
679 ret
= crypto_run(fcr
, &cop
);
680 copy_to_user((void*)arg
, &cop
, sizeof(cop
));
684 copy_from_user(&cop
, (void*)arg
, sizeof(copv
));
685 ret
= crypto_runv(fcr
, &copv
);
686 copy_to_user((void*)arg
, &copv
, sizeof(copv
));
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
,
704 .fops
= &cryptodev_fops
,
708 cryptodev_register(void)
712 rc
= misc_register (&cryptodev
);
714 printk(KERN_ERR PFX
"registeration of /dev/crypto failed\n");
722 cryptodev_deregister(void)
724 misc_deregister(&cryptodev
);
727 /* ====== Module init/exit ====== */
729 int __init
init_cryptodev(void)
733 rc
= cryptodev_register();
737 printk(KERN_INFO PFX
"driver loaded.\n");
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
);