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"
51 /* This file contains the traditional operations of encryption
52 * and hashing of /dev/crypto.
56 hash_n_crypt(struct csession
*ses_ptr
, struct crypt_op
*cop
,
57 struct scatterlist
*src_sg
, struct scatterlist
*dst_sg
,
62 /* Always hash before encryption and after decryption. Maybe
63 * we should introduce a flag to switch... TBD later on.
65 if (cop
->op
== COP_ENCRYPT
) {
66 if (ses_ptr
->hdata
.init
!= 0) {
67 ret
= cryptodev_hash_update(&ses_ptr
->hdata
,
72 if (ses_ptr
->cdata
.init
!= 0) {
73 ret
= cryptodev_cipher_encrypt(&ses_ptr
->cdata
,
80 if (ses_ptr
->cdata
.init
!= 0) {
81 ret
= cryptodev_cipher_decrypt(&ses_ptr
->cdata
,
88 if (ses_ptr
->hdata
.init
!= 0) {
89 ret
= cryptodev_hash_update(&ses_ptr
->hdata
,
97 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n", ret
);
101 /* This is the main crypto function - feed it with plaintext
102 and get a ciphertext (or vice versa :-) */
104 __crypto_run_std(struct csession
*ses_ptr
, struct crypt_op
*cop
)
107 char __user
*src
, *dst
;
108 struct scatterlist sg
;
109 size_t nbytes
, bufsize
;
113 data
= (char *)__get_free_page(GFP_KERNEL
);
118 bufsize
= PAGE_SIZE
< nbytes
? PAGE_SIZE
: nbytes
;
124 size_t current_len
= nbytes
> bufsize
? bufsize
: nbytes
;
126 if (unlikely(copy_from_user(data
, src
, current_len
))) {
131 sg_init_one(&sg
, data
, current_len
);
133 ret
= hash_n_crypt(ses_ptr
, cop
, &sg
, &sg
, current_len
);
138 if (ses_ptr
->cdata
.init
!= 0) {
139 if (unlikely(copy_to_user(dst
, data
, current_len
))) {
146 nbytes
-= current_len
;
150 free_page((unsigned long)data
);
154 /* make cop->src and cop->dst available in scatterlists */
155 static int get_userbuf(struct csession
*ses
, struct kernel_crypt_op
*kcop
,
156 struct scatterlist
**src_sg
, struct scatterlist
**dst_sg
,
159 int src_pagecount
, dst_pagecount
= 0, pagecount
, write_src
= 1;
160 struct crypt_op
*cop
= &kcop
->cop
;
163 if (cop
->src
== NULL
)
166 if (ses
->alignmask
&& !IS_ALIGNED((unsigned long)cop
->src
, ses
->alignmask
)) {
167 dprintk(2, KERN_WARNING
, "%s: careful - source address %lx is not %d byte aligned\n",
168 __func__
, (unsigned long)cop
->src
, ses
->alignmask
+ 1);
171 src_pagecount
= PAGECOUNT(cop
->src
, cop
->len
);
172 if (!ses
->cdata
.init
) { /* hashing only */
174 } else if (cop
->src
!= cop
->dst
) { /* non-in-situ transformation */
175 if (cop
->dst
== NULL
)
178 dst_pagecount
= PAGECOUNT(cop
->dst
, cop
->len
);
181 if (ses
->alignmask
&& !IS_ALIGNED((unsigned long)cop
->dst
, ses
->alignmask
)) {
182 dprintk(2, KERN_WARNING
, "%s: careful - destination address %lx is not %d byte aligned\n",
183 __func__
, (unsigned long)cop
->dst
, ses
->alignmask
+ 1);
187 (*tot_pages
) = pagecount
= src_pagecount
+ dst_pagecount
;
189 if (pagecount
> ses
->array_size
) {
190 rc
= adjust_sg_array(ses
, pagecount
);
195 rc
= __get_userbuf(cop
->src
, cop
->len
, write_src
, src_pagecount
,
196 ses
->pages
, ses
->sg
, kcop
->task
, kcop
->mm
);
199 "failed to get user pages for data input\n");
202 (*src_sg
) = (*dst_sg
) = ses
->sg
;
207 (*dst_sg
) = ses
->sg
+ src_pagecount
;
209 rc
= __get_userbuf(cop
->dst
, cop
->len
, 1, dst_pagecount
,
210 ses
->pages
+ src_pagecount
, *dst_sg
,
211 kcop
->task
, kcop
->mm
);
214 "failed to get user pages for data output\n");
215 release_user_pages(ses
->pages
, src_pagecount
);
222 /* This is the main crypto function - zero-copy edition */
224 __crypto_run_zc(struct csession
*ses_ptr
, struct kernel_crypt_op
*kcop
)
226 struct scatterlist
*src_sg
, *dst_sg
;
227 struct crypt_op
*cop
= &kcop
->cop
;
228 int ret
= 0, pagecount
;
230 ret
= get_userbuf(ses_ptr
, kcop
, &src_sg
, &dst_sg
, &pagecount
);
232 dprintk(1, KERN_ERR
, "Error getting user pages. "
233 "Falling back to non zero copy.\n");
234 return __crypto_run_std(ses_ptr
, cop
);
237 ret
= hash_n_crypt(ses_ptr
, cop
, src_sg
, dst_sg
, cop
->len
);
239 release_user_pages(ses_ptr
->pages
, pagecount
);
243 int crypto_run(struct fcrypt
*fcr
, struct kernel_crypt_op
*kcop
)
245 struct csession
*ses_ptr
;
246 struct crypt_op
*cop
= &kcop
->cop
;
249 if (unlikely(cop
->op
!= COP_ENCRYPT
&& cop
->op
!= COP_DECRYPT
)) {
250 dprintk(1, KERN_DEBUG
, "invalid operation op=%u\n", cop
->op
);
254 /* this also enters ses_ptr->sem */
255 ses_ptr
= crypto_get_session_by_sid(fcr
, cop
->ses
);
256 if (unlikely(!ses_ptr
)) {
257 dprintk(1, KERN_ERR
, "invalid session ID=0x%08X\n", cop
->ses
);
261 if (ses_ptr
->hdata
.init
!= 0 && !(cop
->flags
& (COP_FLAG_UPDATE
| COP_FLAG_FINAL
))) {
262 ret
= cryptodev_hash_reset(&ses_ptr
->hdata
);
265 "error in cryptodev_hash_reset()\n");
270 if (ses_ptr
->cdata
.init
!= 0) {
271 int blocksize
= ses_ptr
->cdata
.blocksize
;
273 if (unlikely(cop
->len
% blocksize
)) {
275 "data size (%u) isn't a multiple "
276 "of block size (%u)\n",
277 cop
->len
, blocksize
);
282 cryptodev_cipher_set_iv(&ses_ptr
->cdata
, kcop
->iv
,
283 min(ses_ptr
->cdata
.ivsize
, kcop
->ivlen
));
286 if (likely(cop
->len
)) {
287 if (cop
->flags
& COP_FLAG_NO_ZC
)
288 ret
= __crypto_run_std(ses_ptr
, &kcop
->cop
);
290 ret
= __crypto_run_zc(ses_ptr
, kcop
);
295 if (ses_ptr
->cdata
.init
!= 0) {
296 cryptodev_cipher_get_iv(&ses_ptr
->cdata
, kcop
->iv
,
297 min(ses_ptr
->cdata
.ivsize
, kcop
->ivlen
));
300 if (ses_ptr
->hdata
.init
!= 0 &&
301 ((cop
->flags
& COP_FLAG_FINAL
) ||
302 (!(cop
->flags
& COP_FLAG_UPDATE
) || cop
->len
== 0))) {
304 ret
= cryptodev_hash_final(&ses_ptr
->hdata
, kcop
->hash_output
);
306 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n", ret
);
309 kcop
->digestsize
= ses_ptr
->hdata
.digestsize
;
313 crypto_put_session(ses_ptr
);