test-cipher.c 8.4 KB

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