aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-kernel/cryptodev/sdk_patches/0035-use-directly-crypto-API-digest-operation-for-CIOCHAS.patch
blob: 4745dc9065771de298de3226d68c2b3565b6c490 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
From f123f38532ae022e818312a9bc04cdb287e9623f Mon Sep 17 00:00:00 2001
From: Cristian Stoica <cristian.stoica@nxp.com>
Date: Thu, 17 Dec 2015 10:34:20 +0200
Subject: [PATCH 35/38] use directly crypto API 'digest' operation for CIOCHASH

Signed-off-by: Cristian Stoica <cristian.stoica@nxp.com>
---
 crypto/cryptodev.h |   2 +-
 cryptodev_int.h    |  10 ++++
 ioctl.c            | 158 ++++++++++++++++++++++++++++++++++++++++++++---------
 main.c             |  39 ++++++++++++-
 4 files changed, 179 insertions(+), 30 deletions(-)

diff --git a/crypto/cryptodev.h b/crypto/cryptodev.h
index c6083f7..9ade102 100644
--- a/crypto/cryptodev.h
+++ b/crypto/cryptodev.h
@@ -169,7 +169,7 @@ struct crypt_auth_op {
 
 /* data container for CIOCHASH operations */
 struct hash_op_data {
-	__u32	ses;		/* session identifier */
+	struct csession	*ses;	/* session identifier */
 	__u32	mac_op;		/* cryptodev_crypto_op_t */
 	__u8	*mackey;
 	__u32	mackeylen;
diff --git a/cryptodev_int.h b/cryptodev_int.h
index cb005d7..74c295a 100644
--- a/cryptodev_int.h
+++ b/cryptodev_int.h
@@ -164,6 +164,15 @@ struct kernel_crypt_op {
 	struct mm_struct *mm;
 };
 
+struct kernel_hash_op {
+	struct hash_op_data hash_op;
+
+	int digestsize;
+	uint8_t hash_output[AALG_MAX_RESULT_LEN];
+	struct task_struct *task;
+	struct mm_struct *mm;
+};
+
 struct kernel_crypt_auth_op {
 	struct crypt_auth_op caop;
 
@@ -192,6 +201,7 @@ int kcaop_to_user(struct kernel_crypt_auth_op *kcaop,
 		struct fcrypt *fcr, void __user *arg);
 int crypto_auth_run(struct fcrypt *fcr, struct kernel_crypt_auth_op *kcaop);
 int crypto_run(struct fcrypt *fcr, struct kernel_crypt_op *kcop);
+int hash_run(struct kernel_hash_op *khop);
 
 #include <cryptlib.h>
 
diff --git a/ioctl.c b/ioctl.c
index 3763954..a052614 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -397,7 +397,128 @@ session_error:
 	return ret;
 }
 
-/* Everything that needs to be done when removing a session. */
+static inline void hash_destroy_session(struct csession *ses_ptr)
+{
+	cryptodev_hash_deinit(&ses_ptr->hdata);
+	kfree(ses_ptr->pages);
+	kfree(ses_ptr->sg);
+	kfree(ses_ptr);
+}
+
+static int hash_create_session(struct hash_op_data *hash_op)
+{
+	struct csession	*ses;
+	int ret = 0;
+	const char *hash_name;
+	int hmac_mode = 1;
+	uint8_t mkey[CRYPTO_HMAC_MAX_KEY_LEN];
+
+	switch (hash_op->mac_op) {
+	case CRYPTO_MD5_HMAC:
+		hash_name = "hmac(md5)";
+		break;
+	case CRYPTO_RIPEMD160_HMAC:
+		hash_name = "hmac(rmd160)";
+		break;
+	case CRYPTO_SHA1_HMAC:
+		hash_name = "hmac(sha1)";
+		break;
+	case CRYPTO_SHA2_224_HMAC:
+		hash_name = "hmac(sha224)";
+		break;
+	case CRYPTO_SHA2_256_HMAC:
+		hash_name = "hmac(sha256)";
+		break;
+	case CRYPTO_SHA2_384_HMAC:
+		hash_name = "hmac(sha384)";
+		break;
+	case CRYPTO_SHA2_512_HMAC:
+		hash_name = "hmac(sha512)";
+		break;
+	/* non-hmac cases */
+	case CRYPTO_MD5:
+		hash_name = "md5";
+		hmac_mode = 0;
+		break;
+	case CRYPTO_RIPEMD160:
+		hash_name = "rmd160";
+		hmac_mode = 0;
+		break;
+	case CRYPTO_SHA1:
+		hash_name = "sha1";
+		hmac_mode = 0;
+		break;
+	case CRYPTO_SHA2_224:
+		hash_name = "sha224";
+		hmac_mode = 0;
+		break;
+	case CRYPTO_SHA2_256:
+		hash_name = "sha256";
+		hmac_mode = 0;
+		break;
+	case CRYPTO_SHA2_384:
+		hash_name = "sha384";
+		hmac_mode = 0;
+		break;
+	case CRYPTO_SHA2_512:
+		hash_name = "sha512";
+		hmac_mode = 0;
+		break;
+	default:
+		ddebug(1, "bad mac: %d", hash_op->mac_op);
+		return -EINVAL;
+	}
+
+	ses = kzalloc(sizeof(*ses), GFP_KERNEL);
+	if (!ses) {
+		return -ENOMEM;
+	}
+
+	if (unlikely(hash_op->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) {
+		ddebug(1, "Setting key failed for %s-%zu.", hash_name,
+		       (size_t)hash_op->mackeylen * 8);
+		ret = -EINVAL;
+		goto error_hash;
+	}
+
+	if (hash_op->mackey &&
+	    unlikely(copy_from_user(mkey, hash_op->mackey, hash_op->mackeylen))) {
+		ret = -EFAULT;
+		goto error_hash;
+	}
+
+	ret = cryptodev_hash_init(&ses->hdata, hash_name, hmac_mode,
+			mkey, hash_op->mackeylen);
+	if (ret != 0) {
+		ddebug(1, "Failed to load hash for %s", hash_name);
+		ret = -EINVAL;
+		goto error_hash;
+	}
+
+	ses->alignmask = ses->hdata.alignmask;
+	ddebug(2, "got alignmask %d", ses->alignmask);
+
+	ses->array_size = DEFAULT_PREALLOC_PAGES;
+	ddebug(2, "preallocating for %d user pages", ses->array_size);
+
+	ses->pages = kzalloc(ses->array_size * sizeof(struct page *), GFP_KERNEL);
+	ses->sg = kzalloc(ses->array_size * sizeof(struct scatterlist), GFP_KERNEL);
+	if (ses->sg == NULL || ses->pages == NULL) {
+		ddebug(0, "Memory error");
+		ret = -ENOMEM;
+		goto error_hash;
+	}
+
+	hash_op->ses = ses;
+	return 0;
+
+error_hash:
+	hash_destroy_session(ses);
+	return ret;
+}
+
+
+/* Everything that needs to be done when remowing a session. */
 static inline void
 crypto_destroy_session(struct csession *ses_ptr)
 {
@@ -960,7 +1081,7 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
 	void __user *arg = (void __user *)arg_;
 	int __user *p = arg;
 	struct session_op sop;
-	struct hash_op_data hash_op;
+	struct kernel_hash_op khop;
 	struct kernel_crypt_op kcop;
 	struct kernel_crypt_auth_op kcaop;
 	struct crypt_priv *pcr = filp->private_data;
@@ -1051,52 +1172,35 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
 
 		return kcop_to_user(&kcop, fcr, arg);
 	case CIOCHASH:
-		/* get session */
-		if (unlikely(copy_from_user(&hash_op, arg, sizeof(struct hash_op_data)))) {
+		if (unlikely(copy_from_user(&khop.hash_op, arg, sizeof(struct hash_op_data)))) {
 			pr_err("copy from user fault\n");
 			return -EFAULT;
 		}
+		khop.task = current;
+		khop.mm = current->mm;
 
-		sop.cipher = 0;
-		sop.mac = hash_op.mac_op;
-		sop.mackey = hash_op.mackey;
-		sop.mackeylen = hash_op.mackeylen;
-
-		/* writes sop.ses as a side-effect */
-		ret = crypto_create_session(fcr, &sop);
+		/* get session */
+		ret = hash_create_session(&khop.hash_op);
 		if (unlikely(ret)) {
 			pr_err("can't get session\n");
 			return ret;
 		}
 
 		/* do hashing */
-		kcop.cop.ses = sop.ses;
-		kcop.cop.flags = hash_op.flags;
-		kcop.cop.len = hash_op.len;
-		kcop.cop.src = hash_op.src;
-		kcop.cop.mac = hash_op.mac_result;
-		kcop.cop.dst = 0;
-		kcop.cop.op = 0;
-		kcop.cop.iv = 0;
-		kcop.ivlen = 0;
-		kcop.digestsize = 0; /* will be updated during operation */
-		kcop.task = current;
-		kcop.mm = current->mm;
-
-		ret = crypto_run(fcr, &kcop);
+		ret = hash_run(&khop);
 		if (unlikely(ret)) {
 			dwarning(1, "Error in hash run");
 			return ret;
 		}
 
-		ret = copy_to_user(kcop.cop.mac, kcop.hash_output, kcop.digestsize);
+		ret = copy_to_user(khop.hash_op.mac_result, khop.hash_output, khop.digestsize);
 		if (unlikely(ret)) {
 			dwarning(1, "Error in copy to user");
 			return ret;
 		}
 
 		/* put session */
-		ret = crypto_finish_session(fcr, sop.ses);
+		hash_destroy_session(khop.hash_op.ses);
 		return 0;
 	case CIOCAUTHCRYPT:
 		if (unlikely(ret = kcaop_from_user(&kcaop, fcr, arg))) {
diff --git a/main.c b/main.c
index ec11129..095aea5 100644
--- a/main.c
+++ b/main.c
@@ -159,8 +159,6 @@ __crypto_run_std(struct csession *ses_ptr, struct crypt_op *cop)
 	return ret;
 }
 
-
-
 /* This is the main crypto function - zero-copy edition */
 static int
 __crypto_run_zc(struct csession *ses_ptr, struct kernel_crypt_op *kcop)
@@ -841,3 +839,40 @@ out_unlock:
 	crypto_put_session(ses_ptr);
 	return ret;
 }
+
+int hash_run(struct kernel_hash_op *khop)
+{
+	struct hash_op_data *hash_op = &khop->hash_op;
+	struct csession *ses_ptr = hash_op->ses;
+	struct hash_data *hdata = &ses_ptr->hdata;
+	int ret;
+	struct scatterlist *src_sg;
+	struct scatterlist *dst_sg; /* required by get_userbuf but not used */
+
+	if (hash_op->len == 0) {
+		src_sg = NULL;
+	} else {
+		ret = get_userbuf(ses_ptr, hash_op->src, hash_op->len, NULL, 0,
+				khop->task, khop->mm, &src_sg, &dst_sg);
+		if (unlikely(ret)) {
+			derr(1, "Error getting user pages");
+			return ret;
+		}
+	}
+
+	ahash_request_set_crypt(hdata->async.request, src_sg, khop->hash_output, hash_op->len);
+
+	ret = crypto_ahash_digest(hdata->async.request);
+	if (ret == -EINPROGRESS || ret == -EBUSY) {
+		wait_for_completion(&hdata->async.result.completion);
+		ret = hdata->async.result.err;
+		if (ret != 0) {
+			derr(0, "CryptoAPI failure: %d", ret);
+		}
+	}
+
+	khop->digestsize = ses_ptr->hdata.digestsize;
+
+	release_user_pages(ses_ptr);
+	return ret;
+}
-- 
2.7.0