cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

test-cipher.c (8754B)


      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
     39static unsigned int data_size __read_mostly = 256;
     40static unsigned int debug __read_mostly = 0;
     41
     42/* tie all skcipher structures together */
     43struct 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 */
     51static 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 */
    101static 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 */
    126static 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
    228out:
    229	if (skcipher)
    230		crypto_free_skcipher(skcipher);
    231	if (req)
    232		skcipher_request_free(req);
    233	return ret;
    234}
    235
    236static 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
    344out:
    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
    357static void __exit chacha_s390_test_exit(void)
    358{
    359	pr_info("s390 ChaCha20 test module exit\n");
    360}
    361
    362module_param_named(size, data_size, uint, 0660);
    363module_param(debug, int, 0660);
    364MODULE_PARM_DESC(size, "Size of a plaintext");
    365MODULE_PARM_DESC(debug, "Debug level (0=off,1=on)");
    366
    367module_init(chacha_s390_test_init);
    368module_exit(chacha_s390_test_exit);
    369
    370MODULE_DESCRIPTION("s390 ChaCha20 self-test");
    371MODULE_AUTHOR("Vladis Dronov <vdronoff@gmail.com>");
    372MODULE_LICENSE("GPL v2");