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