Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0
0002  *
0003  * Copyright (C) 2022 Red Hat, Inc.
0004  * Author: Vladis Dronov <vdronoff@gmail.com>
0005  */
0006 
0007 #include <asm/elf.h>
0008 #include <asm/uaccess.h>
0009 #include <asm/smp.h>
0010 #include <crypto/skcipher.h>
0011 #include <crypto/akcipher.h>
0012 #include <crypto/acompress.h>
0013 #include <crypto/rng.h>
0014 #include <crypto/drbg.h>
0015 #include <crypto/kpp.h>
0016 #include <crypto/internal/simd.h>
0017 #include <crypto/chacha.h>
0018 #include <crypto/aead.h>
0019 #include <crypto/hash.h>
0020 #include <linux/crypto.h>
0021 #include <linux/debugfs.h>
0022 #include <linux/delay.h>
0023 #include <linux/err.h>
0024 #include <linux/fs.h>
0025 #include <linux/fips.h>
0026 #include <linux/kernel.h>
0027 #include <linux/kthread.h>
0028 #include <linux/module.h>
0029 #include <linux/sched.h>
0030 #include <linux/scatterlist.h>
0031 #include <linux/time.h>
0032 #include <linux/vmalloc.h>
0033 #include <linux/zlib.h>
0034 #include <linux/once.h>
0035 #include <linux/random.h>
0036 #include <linux/slab.h>
0037 #include <linux/string.h>
0038 
0039 static unsigned int data_size __read_mostly = 256;
0040 static unsigned int debug __read_mostly = 0;
0041 
0042 /* tie all skcipher structures together */
0043 struct skcipher_def {
0044     struct scatterlist sginp, sgout;
0045     struct crypto_skcipher *tfm;
0046     struct skcipher_request *req;
0047     struct crypto_wait wait;
0048 };
0049 
0050 /* Perform cipher operations with the chacha lib */
0051 static int test_lib_chacha(u8 *revert, u8 *cipher, u8 *plain)
0052 {
0053     u32 chacha_state[CHACHA_STATE_WORDS];
0054     u8 iv[16], key[32];
0055     u64 start, end;
0056 
0057     memset(key, 'X', sizeof(key));
0058     memset(iv, 'I', sizeof(iv));
0059 
0060     if (debug) {
0061         print_hex_dump(KERN_INFO, "key: ", DUMP_PREFIX_OFFSET,
0062                    16, 1, key, 32, 1);
0063 
0064         print_hex_dump(KERN_INFO, "iv:  ", DUMP_PREFIX_OFFSET,
0065                    16, 1, iv, 16, 1);
0066     }
0067 
0068     /* Encrypt */
0069     chacha_init_arch(chacha_state, (u32*)key, iv);
0070 
0071     start = ktime_get_ns();
0072     chacha_crypt_arch(chacha_state, cipher, plain, data_size, 20);
0073     end = ktime_get_ns();
0074 
0075 
0076     if (debug)
0077         print_hex_dump(KERN_INFO, "encr:", DUMP_PREFIX_OFFSET,
0078                    16, 1, cipher,
0079                    (data_size > 64 ? 64 : data_size), 1);
0080 
0081     pr_info("lib encryption took: %lld nsec", end - start);
0082 
0083     /* Decrypt */
0084     chacha_init_arch(chacha_state, (u32 *)key, iv);
0085 
0086     start = ktime_get_ns();
0087     chacha_crypt_arch(chacha_state, revert, cipher, data_size, 20);
0088     end = ktime_get_ns();
0089 
0090     if (debug)
0091         print_hex_dump(KERN_INFO, "decr:", DUMP_PREFIX_OFFSET,
0092                    16, 1, revert,
0093                    (data_size > 64 ? 64 : data_size), 1);
0094 
0095     pr_info("lib decryption took: %lld nsec", end - start);
0096 
0097     return 0;
0098 }
0099 
0100 /* Perform cipher operations with skcipher */
0101 static unsigned int test_skcipher_encdec(struct skcipher_def *sk,
0102                      int enc)
0103 {
0104     int rc;
0105 
0106     if (enc) {
0107         rc = crypto_wait_req(crypto_skcipher_encrypt(sk->req),
0108                      &sk->wait);
0109         if (rc)
0110             pr_info("skcipher encrypt returned with result"
0111                 "%d\n", rc);
0112     }
0113     else
0114     {
0115         rc = crypto_wait_req(crypto_skcipher_decrypt(sk->req),
0116                      &sk->wait);
0117         if (rc)
0118             pr_info("skcipher decrypt returned with result"
0119                 "%d\n", rc);
0120     }
0121 
0122     return rc;
0123 }
0124 
0125 /* Initialize and trigger cipher operations */
0126 static int test_skcipher(char *name, u8 *revert, u8 *cipher, u8 *plain)
0127 {
0128     struct skcipher_def sk;
0129     struct crypto_skcipher *skcipher = NULL;
0130     struct skcipher_request *req = NULL;
0131     u8 iv[16], key[32];
0132     u64 start, end;
0133     int ret = -EFAULT;
0134 
0135     skcipher = crypto_alloc_skcipher(name, 0, 0);
0136     if (IS_ERR(skcipher)) {
0137         pr_info("could not allocate skcipher %s handle\n", name);
0138         return PTR_ERR(skcipher);
0139     }
0140 
0141     req = skcipher_request_alloc(skcipher, GFP_KERNEL);
0142     if (!req) {
0143         pr_info("could not allocate skcipher request\n");
0144         ret = -ENOMEM;
0145         goto out;
0146     }
0147 
0148     skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
0149                       crypto_req_done,
0150                       &sk.wait);
0151 
0152     memset(key, 'X', sizeof(key));
0153     memset(iv, 'I', sizeof(iv));
0154 
0155     if (crypto_skcipher_setkey(skcipher, key, 32)) {
0156         pr_info("key could not be set\n");
0157         ret = -EAGAIN;
0158         goto out;
0159     }
0160 
0161     if (debug) {
0162         print_hex_dump(KERN_INFO, "key: ", DUMP_PREFIX_OFFSET,
0163                    16, 1, key, 32, 1);
0164 
0165         print_hex_dump(KERN_INFO, "iv:  ", DUMP_PREFIX_OFFSET,
0166                    16, 1, iv, 16, 1);
0167     }
0168 
0169     sk.tfm = skcipher;
0170     sk.req = req;
0171 
0172     /* Encrypt in one pass */
0173     sg_init_one(&sk.sginp, plain, data_size);
0174     sg_init_one(&sk.sgout, cipher, data_size);
0175     skcipher_request_set_crypt(req, &sk.sginp, &sk.sgout,
0176                    data_size, iv);
0177     crypto_init_wait(&sk.wait);
0178 
0179     /* Encrypt data */
0180     start = ktime_get_ns();
0181     ret = test_skcipher_encdec(&sk, 1);
0182     end = ktime_get_ns();
0183 
0184     if (ret)
0185         goto out;
0186 
0187     pr_info("%s tfm encryption successful, took %lld nsec\n", name, end - start);
0188 
0189     if (debug)
0190         print_hex_dump(KERN_INFO, "encr:", DUMP_PREFIX_OFFSET,
0191                    16, 1, cipher,
0192                    (data_size > 64 ? 64 : data_size), 1);
0193 
0194     /* Prepare for decryption */
0195     memset(iv, 'I', sizeof(iv));
0196 
0197     sg_init_one(&sk.sginp, cipher, data_size);
0198     sg_init_one(&sk.sgout, revert, data_size);
0199     skcipher_request_set_crypt(req, &sk.sginp, &sk.sgout,
0200                    data_size, iv);
0201     crypto_init_wait(&sk.wait);
0202 
0203     /* Decrypt data */
0204     start = ktime_get_ns();
0205     ret = test_skcipher_encdec(&sk, 0);
0206     end = ktime_get_ns();
0207 
0208     if (ret)
0209         goto out;
0210 
0211     pr_info("%s tfm decryption successful, took %lld nsec\n", name, end - start);
0212 
0213     if (debug)
0214         print_hex_dump(KERN_INFO, "decr:", DUMP_PREFIX_OFFSET,
0215                    16, 1, revert,
0216                    (data_size > 64 ? 64 : data_size), 1);
0217 
0218     /* Dump some internal skcipher data */
0219     if (debug)
0220         pr_info("skcipher %s: cryptlen %d blksize %d stride %d "
0221             "ivsize %d alignmask 0x%x\n",
0222             name, sk.req->cryptlen,
0223             crypto_skcipher_blocksize(sk.tfm),
0224             crypto_skcipher_alg(sk.tfm)->walksize,
0225             crypto_skcipher_ivsize(sk.tfm),
0226             crypto_skcipher_alignmask(sk.tfm));
0227 
0228 out:
0229     if (skcipher)
0230         crypto_free_skcipher(skcipher);
0231     if (req)
0232         skcipher_request_free(req);
0233     return ret;
0234 }
0235 
0236 static int __init chacha_s390_test_init(void)
0237 {
0238     u8 *plain = NULL, *revert = NULL;
0239     u8 *cipher_generic = NULL, *cipher_s390 = NULL;
0240     int ret = -1;
0241 
0242     pr_info("s390 ChaCha20 test module: size=%d debug=%d\n",
0243         data_size, debug);
0244 
0245     /* Allocate and fill buffers */
0246     plain = vmalloc(data_size);
0247     if (!plain) {
0248         pr_info("could not allocate plain buffer\n");
0249         ret = -2;
0250         goto out;
0251     }
0252     memset(plain, 'a', data_size);
0253     get_random_bytes(plain, (data_size > 256 ? 256 : data_size));
0254 
0255     cipher_generic = vzalloc(data_size);
0256     if (!cipher_generic) {
0257         pr_info("could not allocate cipher_generic buffer\n");
0258         ret = -2;
0259         goto out;
0260     }
0261 
0262     cipher_s390 = vzalloc(data_size);
0263     if (!cipher_s390) {
0264         pr_info("could not allocate cipher_s390 buffer\n");
0265         ret = -2;
0266         goto out;
0267     }
0268 
0269     revert = vzalloc(data_size);
0270     if (!revert) {
0271         pr_info("could not allocate revert buffer\n");
0272         ret = -2;
0273         goto out;
0274     }
0275 
0276     if (debug)
0277         print_hex_dump(KERN_INFO, "src: ", DUMP_PREFIX_OFFSET,
0278                    16, 1, plain,
0279                    (data_size > 64 ? 64 : data_size), 1);
0280 
0281     /* Use chacha20 generic */
0282     ret = test_skcipher("chacha20-generic", revert, cipher_generic, plain);
0283     if (ret)
0284         goto out;
0285 
0286     if (memcmp(plain, revert, data_size)) {
0287         pr_info("generic en/decryption check FAILED\n");
0288         ret = -2;
0289         goto out;
0290     }
0291     else
0292         pr_info("generic en/decryption check OK\n");
0293 
0294     memset(revert, 0, data_size);
0295 
0296     /* Use chacha20 s390 */
0297     ret = test_skcipher("chacha20-s390", revert, cipher_s390, plain);
0298     if (ret)
0299         goto out;
0300 
0301     if (memcmp(plain, revert, data_size)) {
0302         pr_info("s390 en/decryption check FAILED\n");
0303         ret = -2;
0304         goto out;
0305     }
0306     else
0307         pr_info("s390 en/decryption check OK\n");
0308 
0309     if (memcmp(cipher_generic, cipher_s390, data_size)) {
0310         pr_info("s390 vs generic check FAILED\n");
0311         ret = -2;
0312         goto out;
0313     }
0314     else
0315         pr_info("s390 vs generic check OK\n");
0316 
0317     memset(cipher_s390, 0, data_size);
0318     memset(revert, 0, data_size);
0319 
0320     /* Use chacha20 lib */
0321     test_lib_chacha(revert, cipher_s390, plain);
0322 
0323     if (memcmp(plain, revert, data_size)) {
0324         pr_info("lib en/decryption check FAILED\n");
0325         ret = -2;
0326         goto out;
0327     }
0328     else
0329         pr_info("lib en/decryption check OK\n");
0330 
0331     if (memcmp(cipher_generic, cipher_s390, data_size)) {
0332         pr_info("lib vs generic check FAILED\n");
0333         ret = -2;
0334         goto out;
0335     }
0336     else
0337         pr_info("lib vs generic check OK\n");
0338 
0339     pr_info("--- chacha20 s390 test end ---\n");
0340 
0341 out:
0342     if (plain)
0343         vfree(plain);
0344     if (cipher_generic)
0345         vfree(cipher_generic);
0346     if (cipher_s390)
0347         vfree(cipher_s390);
0348     if (revert)
0349         vfree(revert);
0350 
0351     return -1;
0352 }
0353 
0354 static void __exit chacha_s390_test_exit(void)
0355 {
0356     pr_info("s390 ChaCha20 test module exit\n");
0357 }
0358 
0359 module_param_named(size, data_size, uint, 0660);
0360 module_param(debug, int, 0660);
0361 MODULE_PARM_DESC(size, "Size of a plaintext");
0362 MODULE_PARM_DESC(debug, "Debug level (0=off,1=on)");
0363 
0364 module_init(chacha_s390_test_init);
0365 module_exit(chacha_s390_test_exit);
0366 
0367 MODULE_DESCRIPTION("s390 ChaCha20 self-test");
0368 MODULE_AUTHOR("Vladis Dronov <vdronoff@gmail.com>");
0369 MODULE_LICENSE("GPL v2");