1 /* SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2022 Red Hat, Inc.
4 * Author: Vladis Dronov <vdronoff@gmail.com>
8 #include <asm/uaccess.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>
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>
39 static unsigned int data_size __read_mostly = 256;
40 static unsigned int debug __read_mostly = 0;
42 /* tie all skcipher structures together */
44 struct scatterlist sginp, sgout;
45 struct crypto_skcipher *tfm;
46 struct skcipher_request *req;
47 struct crypto_wait wait;
50 /* Perform cipher operations with the chacha lib */
51 static int test_lib_chacha(u8 *revert, u8 *cipher, u8 *plain)
53 u32 chacha_state[CHACHA_STATE_WORDS];
57 memset(key, 'X', sizeof(key));
58 memset(iv, 'I', sizeof(iv));
61 print_hex_dump(KERN_INFO, "key: ", DUMP_PREFIX_OFFSET,
64 print_hex_dump(KERN_INFO, "iv: ", DUMP_PREFIX_OFFSET,
69 chacha_init_arch(chacha_state, (u32*)key, iv);
71 start = ktime_get_ns();
72 chacha_crypt_arch(chacha_state, cipher, plain, data_size, 20);
77 print_hex_dump(KERN_INFO, "encr:", DUMP_PREFIX_OFFSET,
79 (data_size > 64 ? 64 : data_size), 1);
81 pr_info("lib encryption took: %lld nsec", end - start);
84 chacha_init_arch(chacha_state, (u32 *)key, iv);
86 start = ktime_get_ns();
87 chacha_crypt_arch(chacha_state, revert, cipher, data_size, 20);
91 print_hex_dump(KERN_INFO, "decr:", DUMP_PREFIX_OFFSET,
93 (data_size > 64 ? 64 : data_size), 1);
95 pr_info("lib decryption took: %lld nsec", end - start);
100 /* Perform cipher operations with skcipher */
101 static unsigned int test_skcipher_encdec(struct skcipher_def *sk,
107 rc = crypto_wait_req(crypto_skcipher_encrypt(sk->req),
110 pr_info("skcipher encrypt returned with result"
115 rc = crypto_wait_req(crypto_skcipher_decrypt(sk->req),
118 pr_info("skcipher decrypt returned with result"
125 /* Initialize and trigger cipher operations */
126 static int test_skcipher(char *name, u8 *revert, u8 *cipher, u8 *plain)
128 struct skcipher_def sk;
129 struct crypto_skcipher *skcipher = NULL;
130 struct skcipher_request *req = NULL;
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);
141 req = skcipher_request_alloc(skcipher, GFP_KERNEL);
143 pr_info("could not allocate skcipher request\n");
148 skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
152 memset(key, 'X', sizeof(key));
153 memset(iv, 'I', sizeof(iv));
155 if (crypto_skcipher_setkey(skcipher, key, 32)) {
156 pr_info("key could not be set\n");
162 print_hex_dump(KERN_INFO, "key: ", DUMP_PREFIX_OFFSET,
165 print_hex_dump(KERN_INFO, "iv: ", DUMP_PREFIX_OFFSET,
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,
177 crypto_init_wait(&sk.wait);
180 start = ktime_get_ns();
181 ret = test_skcipher_encdec(&sk, 1);
182 end = ktime_get_ns();
187 pr_info("%s tfm encryption successful, took %lld nsec\n", name, end - start);
190 print_hex_dump(KERN_INFO, "encr:", DUMP_PREFIX_OFFSET,
192 (data_size > 64 ? 64 : data_size), 1);
194 /* Prepare for decryption */
195 memset(iv, 'I', sizeof(iv));
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,
201 crypto_init_wait(&sk.wait);
204 start = ktime_get_ns();
205 ret = test_skcipher_encdec(&sk, 0);
206 end = ktime_get_ns();
211 pr_info("%s tfm decryption successful, took %lld nsec\n", name, end - start);
214 print_hex_dump(KERN_INFO, "decr:", DUMP_PREFIX_OFFSET,
216 (data_size > 64 ? 64 : data_size), 1);
218 /* Dump some internal skcipher data */
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));
230 crypto_free_skcipher(skcipher);
232 skcipher_request_free(req);
236 static int __init chacha_s390_test_init(void)
238 u8 *plain = NULL, *revert = NULL;
239 u8 *cipher_generic = NULL, *cipher_s390 = NULL;
242 pr_info("s390 ChaCha20 test module: size=%d debug=%d\n",
245 /* Allocate and fill buffers */
246 plain = vmalloc(data_size);
248 pr_info("could not allocate plain buffer\n");
252 memset(plain, 'a', data_size);
253 get_random_bytes(plain, (data_size > 256 ? 256 : data_size));
255 cipher_generic = vmalloc(data_size);
256 if (!cipher_generic) {
257 pr_info("could not allocate cipher_generic buffer\n");
261 memset(cipher_generic, 0, data_size);
263 cipher_s390 = vmalloc(data_size);
265 pr_info("could not allocate cipher_s390 buffer\n");
269 memset(cipher_s390, 0, data_size);
271 revert = vmalloc(data_size);
273 pr_info("could not allocate revert buffer\n");
277 memset(revert, 0, data_size);
280 print_hex_dump(KERN_INFO, "src: ", DUMP_PREFIX_OFFSET,
282 (data_size > 64 ? 64 : data_size), 1);
284 /* Use chacha20 generic */
285 ret = test_skcipher("chacha20-generic", revert, cipher_generic, plain);
289 if (memcmp(plain, revert, data_size)) {
290 pr_info("generic en/decryption check FAILED\n");
295 pr_info("generic en/decryption check OK\n");
297 memset(revert, 0, data_size);
299 /* Use chacha20 s390 */
300 ret = test_skcipher("chacha20-s390", revert, cipher_s390, plain);
304 if (memcmp(plain, revert, data_size)) {
305 pr_info("s390 en/decryption check FAILED\n");
310 pr_info("s390 en/decryption check OK\n");
312 if (memcmp(cipher_generic, cipher_s390, data_size)) {
313 pr_info("s390 vs generic check FAILED\n");
318 pr_info("s390 vs generic check OK\n");
320 memset(cipher_s390, 0, data_size);
321 memset(revert, 0, data_size);
323 /* Use chacha20 lib */
324 test_lib_chacha(revert, cipher_s390, plain);
326 if (memcmp(plain, revert, data_size)) {
327 pr_info("lib en/decryption check FAILED\n");
332 pr_info("lib en/decryption check OK\n");
334 if (memcmp(cipher_generic, cipher_s390, data_size)) {
335 pr_info("lib vs generic check FAILED\n");
340 pr_info("lib vs generic check OK\n");
342 pr_info("--- chacha20 s390 test end ---\n");
348 vfree(cipher_generic);
357 static void __exit chacha_s390_test_exit(void)
359 pr_info("s390 ChaCha20 test module exit\n");
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)");
367 module_init(chacha_s390_test_init);
368 module_exit(chacha_s390_test_exit);
370 MODULE_DESCRIPTION("s390 ChaCha20 self-test");
371 MODULE_AUTHOR("Vladis Dronov <vdronoff@gmail.com>");
372 MODULE_LICENSE("GPL v2");