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 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program 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, write to the Free Software
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 * Device /dev/crypto provides an interface for
27 * accessing kernel CryptoAPI algorithms (ciphers,
28 * hashes) from userspace programs.
30 * /dev/crypto interface was originally introduced in
31 * OpenBSD and this module attempts to keep the API.
34 #include <crypto/hash.h>
35 #include <linux/crypto.h>
37 #include <linux/highmem.h>
38 #include <linux/ioctl.h>
39 #include <linux/random.h>
40 #include <linux/syscalls.h>
41 #include <linux/pagemap.h>
42 #include <linux/poll.h>
43 #include <linux/uaccess.h>
44 #include <crypto/cryptodev.h>
45 #include <crypto/scatterwalk.h>
46 #include <linux/scatterlist.h>
47 #include "cryptodev_int.h"
52 /* This file contains the traditional operations of encryption
53 * and hashing of /dev/crypto.
57 hash_n_crypt(struct csession
*ses_ptr
, struct crypt_op
*cop
,
58 struct scatterlist
*src_sg
, struct scatterlist
*dst_sg
,
63 /* Always hash before encryption and after decryption. Maybe
64 * we should introduce a flag to switch... TBD later on.
66 if (cop
->op
== COP_ENCRYPT
) {
67 if (ses_ptr
->hdata
.init
!= 0) {
68 ret
= cryptodev_hash_update(&ses_ptr
->hdata
,
73 if (ses_ptr
->cdata
.init
!= 0) {
74 ret
= cryptodev_cipher_encrypt(&ses_ptr
->cdata
,
81 if (ses_ptr
->cdata
.init
!= 0) {
82 ret
= cryptodev_cipher_decrypt(&ses_ptr
->cdata
,
89 if (ses_ptr
->hdata
.init
!= 0) {
90 ret
= cryptodev_hash_update(&ses_ptr
->hdata
,
98 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n", ret
);
102 /* This is the main crypto function - feed it with plaintext
103 and get a ciphertext (or vice versa :-) */
105 __crypto_run_std(struct csession
*ses_ptr
, struct crypt_op
*cop
)
108 char __user
*src
, *dst
;
109 struct scatterlist sg
;
110 size_t nbytes
, bufsize
;
114 data
= (char *)__get_free_page(GFP_KERNEL
);
119 bufsize
= PAGE_SIZE
< nbytes
? PAGE_SIZE
: nbytes
;
125 size_t current_len
= nbytes
> bufsize
? bufsize
: nbytes
;
127 if (unlikely(copy_from_user(data
, src
, current_len
))) {
132 sg_init_one(&sg
, data
, current_len
);
134 ret
= hash_n_crypt(ses_ptr
, cop
, &sg
, &sg
, current_len
);
139 if (ses_ptr
->cdata
.init
!= 0) {
140 if (unlikely(copy_to_user(dst
, data
, current_len
))) {
147 nbytes
-= current_len
;
151 free_page((unsigned long)data
);
157 /* This is the main crypto function - zero-copy edition */
159 __crypto_run_zc(struct csession
*ses_ptr
, struct kernel_crypt_op
*kcop
)
161 struct scatterlist
*src_sg
, *dst_sg
;
162 struct crypt_op
*cop
= &kcop
->cop
;
163 int ret
= 0, pagecount
;
165 ret
= get_userbuf(ses_ptr
, cop
->src
, cop
->len
, cop
->dst
, cop
->len
,
166 kcop
->task
, kcop
->mm
, &src_sg
, &dst_sg
, &pagecount
);
168 dprintk(1, KERN_ERR
, "Error getting user pages. "
169 "Falling back to non zero copy.\n");
170 return __crypto_run_std(ses_ptr
, cop
);
173 ret
= hash_n_crypt(ses_ptr
, cop
, src_sg
, dst_sg
, cop
->len
);
175 release_user_pages(ses_ptr
->pages
, pagecount
);
179 int crypto_run(struct fcrypt
*fcr
, struct kernel_crypt_op
*kcop
)
181 struct csession
*ses_ptr
;
182 struct crypt_op
*cop
= &kcop
->cop
;
185 if (unlikely(cop
->op
!= COP_ENCRYPT
&& cop
->op
!= COP_DECRYPT
)) {
186 dprintk(1, KERN_DEBUG
, "invalid operation op=%u\n", cop
->op
);
190 /* this also enters ses_ptr->sem */
191 ses_ptr
= crypto_get_session_by_sid(fcr
, cop
->ses
);
192 if (unlikely(!ses_ptr
)) {
193 dprintk(1, KERN_ERR
, "invalid session ID=0x%08X\n", cop
->ses
);
197 if (ses_ptr
->hdata
.init
!= 0 && !(cop
->flags
& (COP_FLAG_UPDATE
| COP_FLAG_FINAL
))) {
198 ret
= cryptodev_hash_reset(&ses_ptr
->hdata
);
201 "error in cryptodev_hash_reset()\n");
206 if (ses_ptr
->cdata
.init
!= 0) {
207 int blocksize
= ses_ptr
->cdata
.blocksize
;
209 if (unlikely(cop
->len
% blocksize
)) {
211 "data size (%u) isn't a multiple "
212 "of block size (%u)\n",
213 cop
->len
, blocksize
);
218 cryptodev_cipher_set_iv(&ses_ptr
->cdata
, kcop
->iv
,
219 min(ses_ptr
->cdata
.ivsize
, kcop
->ivlen
));
222 if (likely(cop
->len
)) {
223 if (cop
->flags
& COP_FLAG_NO_ZC
)
224 ret
= __crypto_run_std(ses_ptr
, &kcop
->cop
);
226 ret
= __crypto_run_zc(ses_ptr
, kcop
);
231 if (ses_ptr
->cdata
.init
!= 0) {
232 cryptodev_cipher_get_iv(&ses_ptr
->cdata
, kcop
->iv
,
233 min(ses_ptr
->cdata
.ivsize
, kcop
->ivlen
));
236 if (ses_ptr
->hdata
.init
!= 0 &&
237 ((cop
->flags
& COP_FLAG_FINAL
) ||
238 (!(cop
->flags
& COP_FLAG_UPDATE
) || cop
->len
== 0))) {
240 ret
= cryptodev_hash_final(&ses_ptr
->hdata
, kcop
->hash_output
);
242 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n", ret
);
245 kcop
->digestsize
= ses_ptr
->hdata
.digestsize
;
249 crypto_put_session(ses_ptr
);