bumped version
[cryptodev-linux.git] / main.c
blobfe6d3909c1424293cf2e4ef3c575e735a41d521f
1 /*
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
21 * Foundation, Inc.,
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>
36 #include <linux/mm.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"
48 #include "zc.h"
49 #include "cryptlib.h"
50 #include "version.h"
52 /* This file contains the traditional operations of encryption
53 * and hashing of /dev/crypto.
56 static int
57 hash_n_crypt(struct csession *ses_ptr, struct crypt_op *cop,
58 struct scatterlist *src_sg, struct scatterlist *dst_sg,
59 uint32_t len)
61 int ret;
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,
69 src_sg, len);
70 if (unlikely(ret))
71 goto out_err;
73 if (ses_ptr->cdata.init != 0) {
74 ret = cryptodev_cipher_encrypt(&ses_ptr->cdata,
75 src_sg, dst_sg, len);
77 if (unlikely(ret))
78 goto out_err;
80 } else {
81 if (ses_ptr->cdata.init != 0) {
82 ret = cryptodev_cipher_decrypt(&ses_ptr->cdata,
83 src_sg, dst_sg, len);
85 if (unlikely(ret))
86 goto out_err;
89 if (ses_ptr->hdata.init != 0) {
90 ret = cryptodev_hash_update(&ses_ptr->hdata,
91 dst_sg, len);
92 if (unlikely(ret))
93 goto out_err;
96 return 0;
97 out_err:
98 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n", ret);
99 return ret;
102 /* This is the main crypto function - feed it with plaintext
103 and get a ciphertext (or vice versa :-) */
104 static int
105 __crypto_run_std(struct csession *ses_ptr, struct crypt_op *cop)
107 char *data;
108 char __user *src, *dst;
109 struct scatterlist sg;
110 size_t nbytes, bufsize;
111 int ret = 0;
113 nbytes = cop->len;
114 data = (char *)__get_free_page(GFP_KERNEL);
116 if (unlikely(!data)) {
117 dprintk(1, KERN_ERR, "Error getting free page.\n");
118 return -ENOMEM;
121 bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes;
123 src = cop->src;
124 dst = cop->dst;
126 while (nbytes > 0) {
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);
131 ret = -EFAULT;
132 break;
135 sg_init_one(&sg, data, current_len);
137 ret = hash_n_crypt(ses_ptr, cop, &sg, &sg, current_len);
139 if (unlikely(ret)) {
140 dprintk(1, KERN_ERR, "hash_n_crypt failed.\n");
141 break;
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");
147 ret = -EFAULT;
148 break;
152 dst += current_len;
153 nbytes -= current_len;
154 src += current_len;
157 free_page((unsigned long)data);
158 return ret;
163 /* This is the main crypto function - zero-copy edition */
164 static int
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;
169 int ret = 0;
171 ret = get_userbuf(ses_ptr, cop->src, cop->len, cop->dst, cop->len,
172 kcop->task, kcop->mm, &src_sg, &dst_sg);
173 if (unlikely(ret)) {
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);
182 return ret;
185 int crypto_run(struct fcrypt *fcr, struct kernel_crypt_op *kcop)
187 struct csession *ses_ptr;
188 struct crypt_op *cop = &kcop->cop;
189 int ret;
191 if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) {
192 dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", cop->op);
193 return -EINVAL;
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);
200 return -EINVAL;
203 if (ses_ptr->hdata.init != 0 && (cop->flags == 0 || cop->flags & COP_FLAG_RESET)) {
204 ret = cryptodev_hash_reset(&ses_ptr->hdata);
205 if (unlikely(ret)) {
206 dprintk(1, KERN_ERR,
207 "error in cryptodev_hash_reset()\n");
208 goto out_unlock;
212 if (ses_ptr->cdata.init != 0) {
213 int blocksize = ses_ptr->cdata.blocksize;
215 if (unlikely(cop->len % blocksize)) {
216 dprintk(1, KERN_ERR,
217 "data size (%u) isn't a multiple "
218 "of block size (%u)\n",
219 cop->len, blocksize);
220 ret = -EINVAL;
221 goto out_unlock;
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);
231 else
232 ret = __crypto_run_zc(ses_ptr, kcop);
233 if (unlikely(ret))
234 goto out_unlock;
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);
247 if (unlikely(ret)) {
248 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n", ret);
249 goto out_unlock;
251 kcop->digestsize = ses_ptr->hdata.digestsize;
254 out_unlock:
255 crypto_put_session(ses_ptr);
256 return ret;