Merge tag 'char-misc-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-2.6-block.git] / drivers / staging / lustre / lustre / libcfs / linux / linux-crypto.c
CommitLineData
d7e09d03
PT
1/* GPL HEADER START
2 *
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 only,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License version 2 for more details (a copy is included
13 * in the LICENSE file that accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License
16 * version 2 along with this program; If not, see http://www.gnu.org/licenses
17 *
18 * Please visit http://www.xyratex.com/contact if you need additional
19 * information or have any questions.
20 *
21 * GPL HEADER END
22 */
23
24/*
25 * Copyright 2012 Xyratex Technology Limited
26 *
27 * Copyright (c) 2012, Intel Corporation.
28 */
29
6dae1000 30#include <crypto/hash.h>
d7e09d03 31#include <linux/scatterlist.h>
9fdaf8c0 32#include "../../../include/linux/libcfs/libcfs.h"
13636be4 33#include "linux-crypto.h"
d7e09d03
PT
34/**
35 * Array of hash algorithm speed in MByte per second
36 */
37static int cfs_crypto_hash_speeds[CFS_HASH_ALG_MAX];
38
d7e09d03
PT
39static int cfs_crypto_hash_alloc(unsigned char alg_id,
40 const struct cfs_crypto_hash_type **type,
6dae1000
HX
41 struct ahash_request **req,
42 unsigned char *key,
d7e09d03
PT
43 unsigned int key_len)
44{
6dae1000 45 struct crypto_ahash *tfm;
d7e09d03
PT
46 int err = 0;
47
48 *type = cfs_crypto_hash_type(alg_id);
49
50 if (*type == NULL) {
51 CWARN("Unsupported hash algorithm id = %d, max id is %d\n",
52 alg_id, CFS_HASH_ALG_MAX);
53 return -EINVAL;
54 }
6dae1000 55 tfm = crypto_alloc_ahash((*type)->cht_name, 0, CRYPTO_ALG_ASYNC);
d7e09d03 56
6dae1000 57 if (IS_ERR(tfm)) {
d7e09d03
PT
58 CDEBUG(D_INFO, "Failed to alloc crypto hash %s\n",
59 (*type)->cht_name);
6dae1000
HX
60 return PTR_ERR(tfm);
61 }
62
63 *req = ahash_request_alloc(tfm, GFP_KERNEL);
64 if (!*req) {
65 CDEBUG(D_INFO, "Failed to alloc ahash_request for %s\n",
66 (*type)->cht_name);
67 crypto_free_ahash(tfm);
68 return -ENOMEM;
d7e09d03
PT
69 }
70
6dae1000 71 ahash_request_set_callback(*req, 0, NULL, NULL);
d7e09d03
PT
72
73 /** Shash have different logic for initialization then digest
74 * shash: crypto_hash_setkey, crypto_hash_init
75 * digest: crypto_digest_init, crypto_digest_setkey
76 * Skip this function for digest, because we use shash logic at
77 * cfs_crypto_hash_alloc.
78 */
bd2909f7 79 if (key != NULL)
6dae1000 80 err = crypto_ahash_setkey(tfm, key, key_len);
bd2909f7 81 else if ((*type)->cht_key != 0)
6dae1000 82 err = crypto_ahash_setkey(tfm,
d7e09d03
PT
83 (unsigned char *)&((*type)->cht_key),
84 (*type)->cht_size);
d7e09d03
PT
85
86 if (err != 0) {
6dae1000 87 crypto_free_ahash(tfm);
d7e09d03
PT
88 return err;
89 }
90
91 CDEBUG(D_INFO, "Using crypto hash: %s (%s) speed %d MB/s\n",
6dae1000 92 crypto_ahash_alg_name(tfm), crypto_ahash_driver_name(tfm),
d7e09d03
PT
93 cfs_crypto_hash_speeds[alg_id]);
94
6dae1000
HX
95 err = crypto_ahash_init(*req);
96 if (err) {
97 ahash_request_free(*req);
98 crypto_free_ahash(tfm);
99 }
100 return err;
d7e09d03
PT
101}
102
103int cfs_crypto_hash_digest(unsigned char alg_id,
104 const void *buf, unsigned int buf_len,
105 unsigned char *key, unsigned int key_len,
106 unsigned char *hash, unsigned int *hash_len)
107{
108 struct scatterlist sl;
6dae1000 109 struct ahash_request *req;
d7e09d03
PT
110 int err;
111 const struct cfs_crypto_hash_type *type;
112
113 if (buf == NULL || buf_len == 0 || hash_len == NULL)
114 return -EINVAL;
115
6dae1000 116 err = cfs_crypto_hash_alloc(alg_id, &type, &req, key, key_len);
d7e09d03
PT
117 if (err != 0)
118 return err;
119
120 if (hash == NULL || *hash_len < type->cht_size) {
121 *hash_len = type->cht_size;
6dae1000
HX
122 crypto_free_ahash(crypto_ahash_reqtfm(req));
123 ahash_request_free(req);
d7e09d03
PT
124 return -ENOSPC;
125 }
0d749519 126 sg_init_one(&sl, buf, buf_len);
d7e09d03 127
6dae1000
HX
128 ahash_request_set_crypt(req, &sl, hash, sl.length);
129 err = crypto_ahash_digest(req);
130 crypto_free_ahash(crypto_ahash_reqtfm(req));
131 ahash_request_free(req);
d7e09d03
PT
132
133 return err;
134}
135EXPORT_SYMBOL(cfs_crypto_hash_digest);
136
137struct cfs_crypto_hash_desc *
138 cfs_crypto_hash_init(unsigned char alg_id,
139 unsigned char *key, unsigned int key_len)
140{
6dae1000 141 struct ahash_request *req;
d7e09d03
PT
142 int err;
143 const struct cfs_crypto_hash_type *type;
144
6dae1000 145 err = cfs_crypto_hash_alloc(alg_id, &type, &req, key, key_len);
d7e09d03 146
6dae1000 147 if (err)
d7e09d03 148 return ERR_PTR(err);
6dae1000 149 return (struct cfs_crypto_hash_desc *)req;
d7e09d03
PT
150}
151EXPORT_SYMBOL(cfs_crypto_hash_init);
152
153int cfs_crypto_hash_update_page(struct cfs_crypto_hash_desc *hdesc,
154 struct page *page, unsigned int offset,
155 unsigned int len)
156{
6dae1000 157 struct ahash_request *req = (void *)hdesc;
d7e09d03
PT
158 struct scatterlist sl;
159
160 sg_init_table(&sl, 1);
161 sg_set_page(&sl, page, len, offset & ~CFS_PAGE_MASK);
162
6dae1000
HX
163 ahash_request_set_crypt(req, &sl, NULL, sl.length);
164 return crypto_ahash_update(req);
d7e09d03
PT
165}
166EXPORT_SYMBOL(cfs_crypto_hash_update_page);
167
168int cfs_crypto_hash_update(struct cfs_crypto_hash_desc *hdesc,
169 const void *buf, unsigned int buf_len)
170{
6dae1000 171 struct ahash_request *req = (void *)hdesc;
d7e09d03
PT
172 struct scatterlist sl;
173
0d749519 174 sg_init_one(&sl, buf, buf_len);
d7e09d03 175
6dae1000
HX
176 ahash_request_set_crypt(req, &sl, NULL, sl.length);
177 return crypto_ahash_update(req);
d7e09d03
PT
178}
179EXPORT_SYMBOL(cfs_crypto_hash_update);
180
181/* If hash_len pointer is NULL - destroy descriptor. */
182int cfs_crypto_hash_final(struct cfs_crypto_hash_desc *hdesc,
183 unsigned char *hash, unsigned int *hash_len)
184{
185 int err;
6dae1000
HX
186 struct ahash_request *req = (void *)hdesc;
187 int size = crypto_ahash_digestsize(crypto_ahash_reqtfm(req));
d7e09d03
PT
188
189 if (hash_len == NULL) {
6dae1000
HX
190 crypto_free_ahash(crypto_ahash_reqtfm(req));
191 ahash_request_free(req);
d7e09d03
PT
192 return 0;
193 }
194 if (hash == NULL || *hash_len < size) {
195 *hash_len = size;
196 return -ENOSPC;
197 }
6dae1000
HX
198 ahash_request_set_crypt(req, NULL, hash, 0);
199 err = crypto_ahash_final(req);
d7e09d03
PT
200
201 if (err < 0) {
202 /* May be caller can fix error */
203 return err;
204 }
6dae1000
HX
205 crypto_free_ahash(crypto_ahash_reqtfm(req));
206 ahash_request_free(req);
d7e09d03
PT
207 return err;
208}
209EXPORT_SYMBOL(cfs_crypto_hash_final);
210
211static void cfs_crypto_performance_test(unsigned char alg_id,
212 const unsigned char *buf,
213 unsigned int buf_len)
214{
215 unsigned long start, end;
216 int bcount, err = 0;
217 int sec = 1; /* do test only 1 sec */
218 unsigned char hash[64];
219 unsigned int hash_len = 64;
220
221 for (start = jiffies, end = start + sec * HZ, bcount = 0;
222 time_before(jiffies, end); bcount++) {
223 err = cfs_crypto_hash_digest(alg_id, buf, buf_len, NULL, 0,
224 hash, &hash_len);
225 if (err)
226 break;
227
228 }
229 end = jiffies;
230
231 if (err) {
232 cfs_crypto_hash_speeds[alg_id] = -1;
233 CDEBUG(D_INFO, "Crypto hash algorithm %s, err = %d\n",
234 cfs_crypto_hash_name(alg_id), err);
235 } else {
236 unsigned long tmp;
50ffcb7e 237
d7e09d03
PT
238 tmp = ((bcount * buf_len / jiffies_to_msecs(end - start)) *
239 1000) / (1024 * 1024);
240 cfs_crypto_hash_speeds[alg_id] = (int)tmp;
241 }
242 CDEBUG(D_INFO, "Crypto hash algorithm %s speed = %d MB/s\n",
243 cfs_crypto_hash_name(alg_id), cfs_crypto_hash_speeds[alg_id]);
244}
245
246int cfs_crypto_hash_speed(unsigned char hash_alg)
247{
248 if (hash_alg < CFS_HASH_ALG_MAX)
249 return cfs_crypto_hash_speeds[hash_alg];
250 else
251 return -1;
252}
253EXPORT_SYMBOL(cfs_crypto_hash_speed);
254
255/**
256 * Do performance test for all hash algorithms.
257 */
258static int cfs_crypto_test_hashes(void)
259{
260 unsigned char i;
261 unsigned char *data;
262 unsigned int j;
263 /* Data block size for testing hash. Maximum
264 * kmalloc size for 2.6.18 kernel is 128K */
265 unsigned int data_len = 1 * 128 * 1024;
266
267 data = kmalloc(data_len, 0);
268 if (data == NULL) {
269 CERROR("Failed to allocate mem\n");
270 return -ENOMEM;
271 }
272
273 for (j = 0; j < data_len; j++)
274 data[j] = j & 0xff;
275
276 for (i = 0; i < CFS_HASH_ALG_MAX; i++)
277 cfs_crypto_performance_test(i, data, data_len);
278
279 kfree(data);
280 return 0;
281}
282
9c782da4 283static int adler32;
d7e09d03
PT
284
285int cfs_crypto_register(void)
286{
7045b388
AB
287 request_module("crc32c");
288
d7e09d03
PT
289 adler32 = cfs_crypto_adler32_register();
290
d7e09d03
PT
291 /* check all algorithms and do performance test */
292 cfs_crypto_test_hashes();
293 return 0;
294}
c9f6bb96 295
d7e09d03
PT
296void cfs_crypto_unregister(void)
297{
d7e09d03
PT
298 if (adler32 == 0)
299 cfs_crypto_adler32_unregister();
300
d7e09d03
PT
301 return;
302}