0001
0002
0003
0004
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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");