xref: /linux/tools/testing/crypto/chacha20-s390/test-cipher.c (revision 056a5087d87ead77dedbe9cf5bde53b7cd4b4651)
1 /* SPDX-License-Identifier: GPL-2.0
2  *
3  * Copyright (C) 2022 Red Hat, Inc.
4  * Author: Vladis Dronov <vdronoff@gmail.com>
5  */
6 
7 #include <asm/elf.h>
8 #include <asm/uaccess.h>
9 #include <asm/smp.h>
10 #include <crypto/skcipher.h>
11 #include <crypto/akcipher.h>
12 #include <crypto/acompress.h>
13 #include <crypto/rng.h>
14 #include <crypto/kpp.h>
15 #include <crypto/internal/simd.h>
16 #include <crypto/chacha.h>
17 #include <crypto/aead.h>
18 #include <crypto/hash.h>
19 #include <linux/crypto.h>
20 #include <linux/debugfs.h>
21 #include <linux/delay.h>
22 #include <linux/err.h>
23 #include <linux/fs.h>
24 #include <linux/fips.h>
25 #include <linux/kernel.h>
26 #include <linux/kthread.h>
27 #include <linux/module.h>
28 #include <linux/sched.h>
29 #include <linux/scatterlist.h>
30 #include <linux/time.h>
31 #include <linux/vmalloc.h>
32 #include <linux/zlib.h>
33 #include <linux/once.h>
34 #include <linux/random.h>
35 #include <linux/slab.h>
36 #include <linux/string.h>
37 
38 static unsigned int data_size __read_mostly = 256;
39 static unsigned int debug __read_mostly = 0;
40 
41 /* tie all skcipher structures together */
42 struct skcipher_def {
43 	struct scatterlist sginp, sgout;
44 	struct crypto_skcipher *tfm;
45 	struct skcipher_request *req;
46 	struct crypto_wait wait;
47 };
48 
49 /* Perform cipher operations with the chacha lib */
50 static int test_lib_chacha(u8 *revert, u8 *cipher, u8 *plain)
51 {
52 	struct chacha_state chacha_state;
53 	u8 iv[16], key[32];
54 	u64 start, end;
55 
56 	memset(key, 'X', sizeof(key));
57 	memset(iv, 'I', sizeof(iv));
58 
59 	if (debug) {
60 		print_hex_dump(KERN_INFO, "key: ", DUMP_PREFIX_OFFSET,
61 			       16, 1, key, 32, 1);
62 
63 		print_hex_dump(KERN_INFO, "iv:  ", DUMP_PREFIX_OFFSET,
64 			       16, 1, iv, 16, 1);
65 	}
66 
67 	/* Encrypt */
68 	chacha_init(&chacha_state, (u32 *)key, iv);
69 
70 	start = ktime_get_ns();
71 	chacha_crypt_arch(&chacha_state, cipher, plain, data_size, 20);
72 	end = ktime_get_ns();
73 
74 
75 	if (debug)
76 		print_hex_dump(KERN_INFO, "encr:", DUMP_PREFIX_OFFSET,
77 			       16, 1, cipher,
78 			       (data_size > 64 ? 64 : data_size), 1);
79 
80 	pr_info("lib encryption took: %lld nsec", end - start);
81 
82 	/* Decrypt */
83 	chacha_init(&chacha_state, (u32 *)key, iv);
84 
85 	start = ktime_get_ns();
86 	chacha_crypt_arch(&chacha_state, revert, cipher, data_size, 20);
87 	end = ktime_get_ns();
88 
89 	if (debug)
90 		print_hex_dump(KERN_INFO, "decr:", DUMP_PREFIX_OFFSET,
91 			       16, 1, revert,
92 			       (data_size > 64 ? 64 : data_size), 1);
93 
94 	pr_info("lib decryption took: %lld nsec", end - start);
95 
96 	return 0;
97 }
98 
99 /* Perform cipher operations with skcipher */
100 static unsigned int test_skcipher_encdec(struct skcipher_def *sk,
101 					 int enc)
102 {
103 	int rc;
104 
105 	if (enc) {
106 		rc = crypto_wait_req(crypto_skcipher_encrypt(sk->req),
107 				     &sk->wait);
108 		if (rc)
109 			pr_info("skcipher encrypt returned with result"
110 				"%d\n", rc);
111 	}
112 	else
113 	{
114 		rc = crypto_wait_req(crypto_skcipher_decrypt(sk->req),
115 				     &sk->wait);
116 		if (rc)
117 			pr_info("skcipher decrypt returned with result"
118 				"%d\n", rc);
119 	}
120 
121 	return rc;
122 }
123 
124 /* Initialize and trigger cipher operations */
125 static int test_skcipher(char *name, u8 *revert, u8 *cipher, u8 *plain)
126 {
127 	struct skcipher_def sk;
128 	struct crypto_skcipher *skcipher = NULL;
129 	struct skcipher_request *req = NULL;
130 	u8 iv[16], key[32];
131 	u64 start, end;
132 	int ret = -EFAULT;
133 
134 	skcipher = crypto_alloc_skcipher(name, 0, 0);
135 	if (IS_ERR(skcipher)) {
136 		pr_info("could not allocate skcipher %s handle\n", name);
137 		return PTR_ERR(skcipher);
138 	}
139 
140 	req = skcipher_request_alloc(skcipher, GFP_KERNEL);
141 	if (!req) {
142 		pr_info("could not allocate skcipher request\n");
143 		ret = -ENOMEM;
144 		goto out;
145 	}
146 
147 	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
148 					  crypto_req_done,
149 					  &sk.wait);
150 
151 	memset(key, 'X', sizeof(key));
152 	memset(iv, 'I', sizeof(iv));
153 
154 	if (crypto_skcipher_setkey(skcipher, key, 32)) {
155 		pr_info("key could not be set\n");
156 		ret = -EAGAIN;
157 		goto out;
158 	}
159 
160 	if (debug) {
161 		print_hex_dump(KERN_INFO, "key: ", DUMP_PREFIX_OFFSET,
162 			       16, 1, key, 32, 1);
163 
164 		print_hex_dump(KERN_INFO, "iv:  ", DUMP_PREFIX_OFFSET,
165 			       16, 1, iv, 16, 1);
166 	}
167 
168 	sk.tfm = skcipher;
169 	sk.req = req;
170 
171 	/* Encrypt in one pass */
172 	sg_init_one(&sk.sginp, plain, data_size);
173 	sg_init_one(&sk.sgout, cipher, data_size);
174 	skcipher_request_set_crypt(req, &sk.sginp, &sk.sgout,
175 				   data_size, iv);
176 	crypto_init_wait(&sk.wait);
177 
178 	/* Encrypt data */
179 	start = ktime_get_ns();
180 	ret = test_skcipher_encdec(&sk, 1);
181 	end = ktime_get_ns();
182 
183 	if (ret)
184 		goto out;
185 
186 	pr_info("%s tfm encryption successful, took %lld nsec\n", name, end - start);
187 
188 	if (debug)
189 		print_hex_dump(KERN_INFO, "encr:", DUMP_PREFIX_OFFSET,
190 			       16, 1, cipher,
191 			       (data_size > 64 ? 64 : data_size), 1);
192 
193 	/* Prepare for decryption */
194 	memset(iv, 'I', sizeof(iv));
195 
196 	sg_init_one(&sk.sginp, cipher, data_size);
197 	sg_init_one(&sk.sgout, revert, data_size);
198 	skcipher_request_set_crypt(req, &sk.sginp, &sk.sgout,
199 				   data_size, iv);
200 	crypto_init_wait(&sk.wait);
201 
202 	/* Decrypt data */
203 	start = ktime_get_ns();
204 	ret = test_skcipher_encdec(&sk, 0);
205 	end = ktime_get_ns();
206 
207 	if (ret)
208 		goto out;
209 
210 	pr_info("%s tfm decryption successful, took %lld nsec\n", name, end - start);
211 
212 	if (debug)
213 		print_hex_dump(KERN_INFO, "decr:", DUMP_PREFIX_OFFSET,
214 			       16, 1, revert,
215 			       (data_size > 64 ? 64 : data_size), 1);
216 
217 	/* Dump some internal skcipher data */
218 	if (debug)
219 		pr_info("skcipher %s: cryptlen %d blksize %d stride %d "
220 			"ivsize %d alignmask 0x%x\n",
221 			name, sk.req->cryptlen,
222 			crypto_skcipher_blocksize(sk.tfm),
223 			crypto_skcipher_alg(sk.tfm)->walksize,
224 			crypto_skcipher_ivsize(sk.tfm),
225 			crypto_skcipher_alignmask(sk.tfm));
226 
227 out:
228 	if (skcipher)
229 		crypto_free_skcipher(skcipher);
230 	if (req)
231 		skcipher_request_free(req);
232 	return ret;
233 }
234 
235 static int __init chacha_s390_test_init(void)
236 {
237 	u8 *plain = NULL, *revert = NULL;
238 	u8 *cipher_generic = NULL, *cipher_s390 = NULL;
239 	int ret = -1;
240 
241 	pr_info("s390 ChaCha20 test module: size=%d debug=%d\n",
242 		data_size, debug);
243 
244 	/* Allocate and fill buffers */
245 	plain = vmalloc(data_size);
246 	if (!plain) {
247 		pr_info("could not allocate plain buffer\n");
248 		ret = -2;
249 		goto out;
250 	}
251 	memset(plain, 'a', data_size);
252 	get_random_bytes(plain, (data_size > 256 ? 256 : data_size));
253 
254 	cipher_generic = vzalloc(data_size);
255 	if (!cipher_generic) {
256 		pr_info("could not allocate cipher_generic buffer\n");
257 		ret = -2;
258 		goto out;
259 	}
260 
261 	cipher_s390 = vzalloc(data_size);
262 	if (!cipher_s390) {
263 		pr_info("could not allocate cipher_s390 buffer\n");
264 		ret = -2;
265 		goto out;
266 	}
267 
268 	revert = vzalloc(data_size);
269 	if (!revert) {
270 		pr_info("could not allocate revert buffer\n");
271 		ret = -2;
272 		goto out;
273 	}
274 
275 	if (debug)
276 		print_hex_dump(KERN_INFO, "src: ", DUMP_PREFIX_OFFSET,
277 			       16, 1, plain,
278 			       (data_size > 64 ? 64 : data_size), 1);
279 
280 	/* Use chacha20 generic */
281 	ret = test_skcipher("chacha20-generic", revert, cipher_generic, plain);
282 	if (ret)
283 		goto out;
284 
285 	if (memcmp(plain, revert, data_size)) {
286 		pr_info("generic en/decryption check FAILED\n");
287 		ret = -2;
288 		goto out;
289 	}
290 	else
291 		pr_info("generic en/decryption check OK\n");
292 
293 	memset(revert, 0, data_size);
294 
295 	/* Use chacha20 s390 */
296 	ret = test_skcipher("chacha20-s390", revert, cipher_s390, plain);
297 	if (ret)
298 		goto out;
299 
300 	if (memcmp(plain, revert, data_size)) {
301 		pr_info("s390 en/decryption check FAILED\n");
302 		ret = -2;
303 		goto out;
304 	}
305 	else
306 		pr_info("s390 en/decryption check OK\n");
307 
308 	if (memcmp(cipher_generic, cipher_s390, data_size)) {
309 		pr_info("s390 vs generic check FAILED\n");
310 		ret = -2;
311 		goto out;
312 	}
313 	else
314 		pr_info("s390 vs generic check OK\n");
315 
316 	memset(cipher_s390, 0, data_size);
317 	memset(revert, 0, data_size);
318 
319 	/* Use chacha20 lib */
320 	test_lib_chacha(revert, cipher_s390, plain);
321 
322 	if (memcmp(plain, revert, data_size)) {
323 		pr_info("lib en/decryption check FAILED\n");
324 		ret = -2;
325 		goto out;
326 	}
327 	else
328 		pr_info("lib en/decryption check OK\n");
329 
330 	if (memcmp(cipher_generic, cipher_s390, data_size)) {
331 		pr_info("lib vs generic check FAILED\n");
332 		ret = -2;
333 		goto out;
334 	}
335 	else
336 		pr_info("lib vs generic check OK\n");
337 
338 	pr_info("--- chacha20 s390 test end ---\n");
339 
340 out:
341 	if (plain)
342 		vfree(plain);
343 	if (cipher_generic)
344 		vfree(cipher_generic);
345 	if (cipher_s390)
346 		vfree(cipher_s390);
347 	if (revert)
348 		vfree(revert);
349 
350 	return -1;
351 }
352 
353 static void __exit chacha_s390_test_exit(void)
354 {
355 	pr_info("s390 ChaCha20 test module exit\n");
356 }
357 
358 module_param_named(size, data_size, uint, 0660);
359 module_param(debug, int, 0660);
360 MODULE_PARM_DESC(size, "Size of a plaintext");
361 MODULE_PARM_DESC(debug, "Debug level (0=off,1=on)");
362 
363 module_init(chacha_s390_test_init);
364 module_exit(chacha_s390_test_exit);
365 
366 MODULE_DESCRIPTION("s390 ChaCha20 self-test");
367 MODULE_AUTHOR("Vladis Dronov <vdronoff@gmail.com>");
368 MODULE_LICENSE("GPL v2");
369