2 * Driver for /dev/crypto device (aka CryptoDev)
4 * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
6 * This file is part of linux cryptodev.
8 * cryptodev is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * cryptodev is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <linux/crypto.h>
24 #include <linux/highmem.h>
25 #include <linux/random.h>
26 #include <asm/uaccess.h>
27 #include <asm/ioctl.h>
28 #include <linux/scatterlist.h>
29 #include <crypto/algapi.h>
30 #include <crypto/hash.h>
31 #include "cryptodev.h"
32 #include "cryptodev_int.h"
35 struct cryptodev_result
{
36 struct completion completion
;
40 static void cryptodev_complete(struct crypto_async_request
*req
, int err
)
42 struct cryptodev_result
*res
= req
->data
;
44 if (err
== -EINPROGRESS
)
48 complete(&res
->completion
);
51 int cryptodev_cipher_init(struct cipher_data
* out
, const char* alg_name
, uint8_t __user
* key
, size_t keylen
)
53 uint8_t keyp
[CRYPTO_CIPHER_MAX_KEY_LEN
];
54 struct ablkcipher_alg
* alg
;
57 memset(out
, 0, sizeof(*out
));
61 if (unlikely(keylen
> CRYPTO_CIPHER_MAX_KEY_LEN
)) {
62 dprintk(1,KERN_DEBUG
,"Setting key failed for %s-%zu.\n",
66 /* Copy the key from user and set to TFM. */
67 if (unlikely(copy_from_user(keyp
, key
, keylen
))) {
68 dprintk(1, KERN_DEBUG
, "copy_from_user() failed for key\n");
72 out
->async
.s
= crypto_alloc_ablkcipher(alg_name
, 0, 0);
73 if (unlikely(IS_ERR(out
->async
.s
))) {
74 dprintk(1,KERN_DEBUG
,"%s: Failed to load cipher %s\n", __func__
,
79 alg
= crypto_ablkcipher_alg(out
->async
.s
);
82 /* Was correct key length supplied? */
83 if (alg
->max_keysize
> 0 && unlikely((keylen
< alg
->min_keysize
) ||
84 (keylen
> alg
->max_keysize
))) {
85 dprintk(1,KERN_DEBUG
,"Wrong keylen '%zu' for algorithm '%s'. Use %u to %u.\n",
86 keylen
, alg_name
, alg
->min_keysize
,
93 ret
= crypto_ablkcipher_setkey(out
->async
.s
, keyp
, keylen
);
95 dprintk(1,KERN_DEBUG
,"Setting key failed for %s-%zu.\n",
101 out
->blocksize
= crypto_ablkcipher_blocksize(out
->async
.s
);
102 out
->ivsize
= crypto_ablkcipher_ivsize(out
->async
.s
);
104 out
->async
.result
= kmalloc(sizeof(*out
->async
.result
), GFP_KERNEL
);
105 if (unlikely(!out
->async
.result
)) {
110 memset(out
->async
.result
, 0, sizeof(*out
->async
.result
));
111 init_completion(&out
->async
.result
->completion
);
113 out
->async
.request
= ablkcipher_request_alloc(out
->async
.s
, GFP_KERNEL
);
114 if (unlikely(!out
->async
.request
)) {
115 dprintk(1,KERN_ERR
,"error allocating async crypto request\n");
120 ablkcipher_request_set_callback(out
->async
.request
, CRYPTO_TFM_REQ_MAY_BACKLOG
,
121 cryptodev_complete
, out
->async
.result
);
125 crypto_free_ablkcipher(out
->async
.s
);
126 kfree(out
->async
.result
);
127 ablkcipher_request_free(out
->async
.request
);
132 void cryptodev_cipher_deinit(struct cipher_data
* cdata
)
134 crypto_free_ablkcipher(cdata
->async
.s
);
135 kfree(cdata
->async
.result
);
136 ablkcipher_request_free(cdata
->async
.request
);
141 int cryptodev_cipher_set_iv(struct cipher_data
* cdata
, void __user
* iv
, size_t iv_size
)
143 return copy_from_user(cdata
->async
.iv
, iv
, min(iv_size
,sizeof(cdata
->async
.iv
)));
146 static inline int waitfor (struct cryptodev_result
* cr
, ssize_t ret
)
153 wait_for_completion(&cr
->completion
);
154 /* At this point we known for sure the request has finished,
155 * because wait_for_completion above was not interruptible.
156 * This is important because otherwise hardware or driver
157 * might try to access memory which will be freed or reused for
158 * another request. */
160 if (unlikely(cr
->err
)) {
161 dprintk(0,KERN_ERR
,"error from async request: %zd \n", ret
);
173 ssize_t
cryptodev_cipher_encrypt( struct cipher_data
* cdata
, struct scatterlist
*sg1
, struct scatterlist
*sg2
, size_t len
)
177 INIT_COMPLETION(cdata
->async
.result
->completion
);
178 ablkcipher_request_set_crypt(cdata
->async
.request
, sg1
, sg2
,
179 len
, cdata
->async
.iv
);
180 ret
= crypto_ablkcipher_encrypt(cdata
->async
.request
);
182 return waitfor(cdata
->async
.result
,ret
);
185 ssize_t
cryptodev_cipher_decrypt( struct cipher_data
* cdata
, struct scatterlist
*sg1
, struct scatterlist
*sg2
, size_t len
)
189 INIT_COMPLETION(cdata
->async
.result
->completion
);
190 ablkcipher_request_set_crypt(cdata
->async
.request
, sg1
, sg2
,
191 len
, cdata
->async
.iv
);
192 ret
= crypto_ablkcipher_decrypt(cdata
->async
.request
);
194 return waitfor(cdata
->async
.result
, ret
);
199 int cryptodev_hash_init( struct hash_data
* hdata
, const char* alg_name
, int hmac_mode
, void __user
* mackey
, size_t mackeylen
)
202 uint8_t hkeyp
[CRYPTO_HMAC_MAX_KEY_LEN
];
206 if (unlikely(mackeylen
> CRYPTO_HMAC_MAX_KEY_LEN
)) {
207 dprintk(1,KERN_DEBUG
,"Setting hmac key failed for %s-%zu.\n",
208 alg_name
, mackeylen
*8);
211 if (unlikely(copy_from_user(hkeyp
, mackey
, mackeylen
))) {
212 dprintk(1, KERN_DEBUG
, "copy_from_user() failed for mackey\n");
216 hdata
->async
.s
= crypto_alloc_ahash(alg_name
, 0, 0);
217 if (unlikely(IS_ERR(hdata
->async
.s
))) {
218 dprintk(1,KERN_DEBUG
,"%s: Failed to load transform for %s\n", __func__
,
223 /* Copy the key from user and set to TFM. */
224 if (hmac_mode
!= 0) {
226 ret
= crypto_ahash_setkey(hdata
->async
.s
, hkeyp
, mackeylen
);
228 dprintk(1,KERN_DEBUG
,"Setting hmac key failed for %s-%zu.\n",
229 alg_name
, mackeylen
*8);
235 hdata
->digestsize
= crypto_ahash_digestsize(hdata
->async
.s
);
237 hdata
->async
.result
= kmalloc(sizeof(*hdata
->async
.result
), GFP_KERNEL
);
238 if (unlikely(!hdata
->async
.result
)) {
243 memset(hdata
->async
.result
, 0, sizeof(*hdata
->async
.result
));
244 init_completion(&hdata
->async
.result
->completion
);
246 hdata
->async
.request
= ahash_request_alloc(hdata
->async
.s
, GFP_KERNEL
);
247 if (unlikely(!hdata
->async
.request
)) {
248 dprintk(0,KERN_ERR
,"error allocating async crypto request\n");
253 ahash_request_set_callback(hdata
->async
.request
, CRYPTO_TFM_REQ_MAY_BACKLOG
,
254 cryptodev_complete
, hdata
->async
.result
);
260 crypto_free_ahash(hdata
->async
.s
);
264 void cryptodev_hash_deinit(struct hash_data
* hdata
)
266 crypto_free_ahash(hdata
->async
.s
);
270 int cryptodev_hash_reset( struct hash_data
* hdata
)
273 ret
= crypto_ahash_init(hdata
->async
.request
);
276 "error in crypto_hash_init()\n");
284 ssize_t
cryptodev_hash_update( struct hash_data
* hdata
, struct scatterlist
*sg
, size_t len
)
288 INIT_COMPLETION(hdata
->async
.result
->completion
);
289 ahash_request_set_crypt(hdata
->async
.request
, sg
, NULL
,
292 ret
= crypto_ahash_update(hdata
->async
.request
);
294 return waitfor(hdata
->async
.result
,ret
);
298 int cryptodev_hash_final( struct hash_data
* hdata
, void* output
)
302 INIT_COMPLETION(hdata
->async
.result
->completion
);
303 ahash_request_set_crypt(hdata
->async
.request
, NULL
, output
, 0);
305 ret
= crypto_ahash_final(hdata
->async
.request
);
307 return waitfor(hdata
->async
.result
,ret
);