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
);
116 if (unlikely(!data
)) {
117 dprintk(1, KERN_ERR
, "Error getting free page.\n");
121 bufsize
= PAGE_SIZE
< nbytes
? PAGE_SIZE
: nbytes
;
127 size_t current_len
= nbytes
> bufsize
? bufsize
: nbytes
;
129 if (unlikely(copy_from_user(data
, src
, current_len
))) {
130 dprintk(1, KERN_ERR
, "Error copying %d bytes from user address %p.\n", (int)current_len
, src
);
135 sg_init_one(&sg
, data
, current_len
);
137 ret
= hash_n_crypt(ses_ptr
, cop
, &sg
, &sg
, current_len
);
140 dprintk(1, KERN_ERR
, "hash_n_crypt failed.\n");
144 if (ses_ptr
->cdata
.init
!= 0) {
145 if (unlikely(copy_to_user(dst
, data
, current_len
))) {
146 dprintk(1, KERN_ERR
, "could not copy to user.\n");
153 nbytes
-= current_len
;
157 free_page((unsigned long)data
);
163 /* This is the main crypto function - zero-copy edition */
165 __crypto_run_zc(struct csession
*ses_ptr
, struct kernel_crypt_op
*kcop
)
167 struct scatterlist
*src_sg
, *dst_sg
;
168 struct crypt_op
*cop
= &kcop
->cop
;
171 ret
= get_userbuf(ses_ptr
, cop
->src
, cop
->len
, cop
->dst
, cop
->len
,
172 kcop
->task
, kcop
->mm
, &src_sg
, &dst_sg
);
174 dprintk(1, KERN_ERR
, "Error getting user pages. "
175 "Falling back to non zero copy.\n");
176 return __crypto_run_std(ses_ptr
, cop
);
179 ret
= hash_n_crypt(ses_ptr
, cop
, src_sg
, dst_sg
, cop
->len
);
181 release_user_pages(ses_ptr
);
185 int crypto_run(struct fcrypt
*fcr
, struct kernel_crypt_op
*kcop
)
187 struct csession
*ses_ptr
;
188 struct crypt_op
*cop
= &kcop
->cop
;
191 if (unlikely(cop
->op
!= COP_ENCRYPT
&& cop
->op
!= COP_DECRYPT
)) {
192 dprintk(1, KERN_DEBUG
, "invalid operation op=%u\n", cop
->op
);
196 /* this also enters ses_ptr->sem */
197 ses_ptr
= crypto_get_session_by_sid(fcr
, cop
->ses
);
198 if (unlikely(!ses_ptr
)) {
199 dprintk(1, KERN_ERR
, "invalid session ID=0x%08X\n", cop
->ses
);
203 if (ses_ptr
->hdata
.init
!= 0 && (cop
->flags
== 0 || cop
->flags
& COP_FLAG_RESET
)) {
204 ret
= cryptodev_hash_reset(&ses_ptr
->hdata
);
207 "error in cryptodev_hash_reset()\n");
212 if (ses_ptr
->cdata
.init
!= 0) {
213 int blocksize
= ses_ptr
->cdata
.blocksize
;
215 if (unlikely(cop
->len
% blocksize
)) {
217 "data size (%u) isn't a multiple "
218 "of block size (%u)\n",
219 cop
->len
, blocksize
);
224 cryptodev_cipher_set_iv(&ses_ptr
->cdata
, kcop
->iv
,
225 min(ses_ptr
->cdata
.ivsize
, kcop
->ivlen
));
228 if (likely(cop
->len
)) {
229 if (cop
->flags
& COP_FLAG_NO_ZC
)
230 ret
= __crypto_run_std(ses_ptr
, &kcop
->cop
);
232 ret
= __crypto_run_zc(ses_ptr
, kcop
);
237 if (ses_ptr
->cdata
.init
!= 0) {
238 cryptodev_cipher_get_iv(&ses_ptr
->cdata
, kcop
->iv
,
239 min(ses_ptr
->cdata
.ivsize
, kcop
->ivlen
));
242 if (ses_ptr
->hdata
.init
!= 0 &&
243 ((cop
->flags
& COP_FLAG_FINAL
) ||
244 (!(cop
->flags
& COP_FLAG_UPDATE
) || cop
->len
== 0))) {
246 ret
= cryptodev_hash_final(&ses_ptr
->hdata
, kcop
->hash_output
);
248 dprintk(0, KERN_ERR
, "CryptoAPI failure: %d\n", ret
);
251 kcop
->digestsize
= ses_ptr
->hdata
.digestsize
;
255 crypto_put_session(ses_ptr
);