From: Vladis Dronov <[email protected]>
Implement a crypto library interface for the s390-native ChaCha20 cipher
algorithm. This allows us to stop to select CRYPTO_CHACHA20 and instead
select CRYPTO_ARCH_HAVE_LIB_CHACHA. This allows BIG_KEYS=y not to build
a whole ChaCha20 crypto infrastructure as a built-in, but build a smaller
CRYPTO_LIB_CHACHA instead.
Make CRYPTO_CHACHA_S390 config entry to look like similar ones on other
architectures. Remove CRYPTO_ALGAPI select as anyway it is selected by
CRYPTO_SKCIPHER.
Add a new test module and a test script for ChaCha20 cipher and its
interfaces. Here are test results on an idle z15 machine:
Data | Generic crypto TFM | s390 crypto TFM | s390 lib
size | enc dec | enc dec | enc dec
-----+--------------------+------------------+----------------
512b | 1545ns 1295ns | 604ns 446ns | 430ns 407ns
4k | 9536ns 9463ns | 2329ns 2174ns | 2170ns 2154ns
64k | 149.6us 149.3us | 34.4us 34.5us | 33.9us 33.1us
6M | 23.61ms 23.11ms | 4223us 4160us | 3951us 4008us
60M | 143.9ms 143.9ms | 33.5ms 33.2ms | 32.2ms 32.1ms
Signed-off-by: Vladis Dronov <[email protected]>
---
arch/s390/crypto/chacha-glue.c | 34 +-
drivers/crypto/Kconfig | 4 +-
tools/testing/crypto/chacha20-s390/Makefile | 12 +
.../testing/crypto/chacha20-s390/run-tests.sh | 34 ++
.../crypto/chacha20-s390/test-cipher.c | 372 ++++++++++++++++++
5 files changed, 452 insertions(+), 4 deletions(-)
create mode 100644 tools/testing/crypto/chacha20-s390/Makefile
create mode 100644 tools/testing/crypto/chacha20-s390/run-tests.sh
create mode 100644 tools/testing/crypto/chacha20-s390/test-cipher.c
diff --git a/arch/s390/crypto/chacha-glue.c b/arch/s390/crypto/chacha-glue.c
index ccfff73e2c93..2ec51f339cec 100644
--- a/arch/s390/crypto/chacha-glue.c
+++ b/arch/s390/crypto/chacha-glue.c
@@ -62,6 +62,34 @@ static int chacha20_s390(struct skcipher_request *req)
return rc;
}
+void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds)
+{
+ /* TODO: implement hchacha_block_arch() in assembly */
+ hchacha_block_generic(state, stream, nrounds);
+}
+EXPORT_SYMBOL(hchacha_block_arch);
+
+void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv)
+{
+ chacha_init_generic(state, key, iv);
+}
+EXPORT_SYMBOL(chacha_init_arch);
+
+void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src,
+ unsigned int bytes, int nrounds)
+{
+ /* s390 chacha20 implementation has 20 rounds hard-coded,
+ * it cannot handle a block of data or less, but otherwise
+ * it can handle data of arbitrary size
+ */
+ if (bytes <= CHACHA_BLOCK_SIZE || nrounds != 20)
+ chacha_crypt_generic(state, dst, src, bytes, nrounds);
+ else
+ chacha20_crypt_s390(state, dst, src, bytes,
+ &state[4], &state[12]);
+}
+EXPORT_SYMBOL(chacha_crypt_arch);
+
static struct skcipher_alg chacha_algs[] = {
{
.base.cra_name = "chacha20",
@@ -83,12 +111,14 @@ static struct skcipher_alg chacha_algs[] = {
static int __init chacha_mod_init(void)
{
- return crypto_register_skciphers(chacha_algs, ARRAY_SIZE(chacha_algs));
+ return IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER) ?
+ crypto_register_skciphers(chacha_algs, ARRAY_SIZE(chacha_algs)) : 0;
}
static void __exit chacha_mod_fini(void)
{
- crypto_unregister_skciphers(chacha_algs, ARRAY_SIZE(chacha_algs));
+ if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER))
+ crypto_unregister_skciphers(chacha_algs, ARRAY_SIZE(chacha_algs));
}
module_cpu_feature_match(VXRS, chacha_mod_init);
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 7b2d138bc83e..ee99c02c84e8 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -216,9 +216,9 @@ config CRYPTO_AES_S390
config CRYPTO_CHACHA_S390
tristate "ChaCha20 stream cipher"
depends on S390
- select CRYPTO_ALGAPI
select CRYPTO_SKCIPHER
- select CRYPTO_CHACHA20
+ select CRYPTO_LIB_CHACHA_GENERIC
+ select CRYPTO_ARCH_HAVE_LIB_CHACHA
help
This is the s390 SIMD implementation of the ChaCha20 stream
cipher (RFC 7539).
diff --git a/tools/testing/crypto/chacha20-s390/Makefile b/tools/testing/crypto/chacha20-s390/Makefile
new file mode 100644
index 000000000000..db81cd2fb9c5
--- /dev/null
+++ b/tools/testing/crypto/chacha20-s390/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2022 Red Hat, Inc.
+# Author: Vladis Dronov <[email protected]>
+
+obj-m += test_cipher.o
+test_cipher-y := test-cipher.o
+
+all:
+ make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
+clean:
+ make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
diff --git a/tools/testing/crypto/chacha20-s390/run-tests.sh b/tools/testing/crypto/chacha20-s390/run-tests.sh
new file mode 100644
index 000000000000..43108794b996
--- /dev/null
+++ b/tools/testing/crypto/chacha20-s390/run-tests.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2022 Red Hat, Inc.
+# Author: Vladis Dronov <[email protected]>
+#
+# This script runs (via instmod) test-cipher.ko module which invokes
+# generic and s390-native ChaCha20 encryprion algorithms with different
+# size of data. Check 'dmesg' for results.
+#
+# The insmod error is expected:
+# insmod: ERROR: could not insert module test_cipher.ko: Operation not permitted
+
+lsmod | grep chacha | cut -f1 -d' ' | xargs rmmod
+modprobe chacha_generic
+modprobe chacha_s390
+
+# run encryption for different data size, including whole block(s) +/- 1
+insmod test_cipher.ko size=63
+insmod test_cipher.ko size=64
+insmod test_cipher.ko size=65
+insmod test_cipher.ko size=127
+insmod test_cipher.ko size=128
+insmod test_cipher.ko size=129
+insmod test_cipher.ko size=511
+insmod test_cipher.ko size=512
+insmod test_cipher.ko size=513
+insmod test_cipher.ko size=4096
+insmod test_cipher.ko size=65611
+insmod test_cipher.ko size=6291456
+insmod test_cipher.ko size=62914560
+
+# print test logs
+dmesg | tail -170
diff --git a/tools/testing/crypto/chacha20-s390/test-cipher.c b/tools/testing/crypto/chacha20-s390/test-cipher.c
new file mode 100644
index 000000000000..34e8b855266f
--- /dev/null
+++ b/tools/testing/crypto/chacha20-s390/test-cipher.c
@@ -0,0 +1,372 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ * Author: Vladis Dronov <[email protected]>
+ */
+
+#include <asm/elf.h>
+#include <asm/uaccess.h>
+#include <asm/smp.h>
+#include <crypto/skcipher.h>
+#include <crypto/akcipher.h>
+#include <crypto/acompress.h>
+#include <crypto/rng.h>
+#include <crypto/drbg.h>
+#include <crypto/kpp.h>
+#include <crypto/internal/simd.h>
+#include <crypto/chacha.h>
+#include <crypto/aead.h>
+#include <crypto/hash.h>
+#include <linux/crypto.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/fips.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/scatterlist.h>
+#include <linux/time.h>
+#include <linux/vmalloc.h>
+#include <linux/zlib.h>
+#include <linux/once.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+static unsigned int data_size __read_mostly = 256;
+static unsigned int debug __read_mostly = 0;
+
+/* tie all skcipher structures together */
+struct skcipher_def {
+ struct scatterlist sginp, sgout;
+ struct crypto_skcipher *tfm;
+ struct skcipher_request *req;
+ struct crypto_wait wait;
+};
+
+/* Perform cipher operations with the chacha lib */
+static int test_lib_chacha(u8 *revert, u8 *cipher, u8 *plain)
+{
+ u32 chacha_state[CHACHA_STATE_WORDS];
+ u8 iv[16], key[32];
+ u64 start, end;
+
+ memset(key, 'X', sizeof(key));
+ memset(iv, 'I', sizeof(iv));
+
+ if (debug) {
+ print_hex_dump(KERN_INFO, "key: ", DUMP_PREFIX_OFFSET,
+ 16, 1, key, 32, 1);
+
+ print_hex_dump(KERN_INFO, "iv: ", DUMP_PREFIX_OFFSET,
+ 16, 1, iv, 16, 1);
+ }
+
+ /* Encrypt */
+ chacha_init_arch(chacha_state, (u32*)key, iv);
+
+ start = ktime_get_ns();
+ chacha_crypt_arch(chacha_state, cipher, plain, data_size, 20);
+ end = ktime_get_ns();
+
+
+ if (debug)
+ print_hex_dump(KERN_INFO, "encr:", DUMP_PREFIX_OFFSET,
+ 16, 1, cipher,
+ (data_size > 64 ? 64 : data_size), 1);
+
+ pr_info("lib encryption took: %lld nsec", end - start);
+
+ /* Decrypt */
+ chacha_init_arch(chacha_state, (u32 *)key, iv);
+
+ start = ktime_get_ns();
+ chacha_crypt_arch(chacha_state, revert, cipher, data_size, 20);
+ end = ktime_get_ns();
+
+ if (debug)
+ print_hex_dump(KERN_INFO, "decr:", DUMP_PREFIX_OFFSET,
+ 16, 1, revert,
+ (data_size > 64 ? 64 : data_size), 1);
+
+ pr_info("lib decryption took: %lld nsec", end - start);
+
+ return 0;
+}
+
+/* Perform cipher operations with skcipher */
+static unsigned int test_skcipher_encdec(struct skcipher_def *sk,
+ int enc)
+{
+ int rc;
+
+ if (enc) {
+ rc = crypto_wait_req(crypto_skcipher_encrypt(sk->req),
+ &sk->wait);
+ if (rc)
+ pr_info("skcipher encrypt returned with result"
+ "%d\n", rc);
+ }
+ else
+ {
+ rc = crypto_wait_req(crypto_skcipher_decrypt(sk->req),
+ &sk->wait);
+ if (rc)
+ pr_info("skcipher decrypt returned with result"
+ "%d\n", rc);
+ }
+
+ return rc;
+}
+
+/* Initialize and trigger cipher operations */
+static int test_skcipher(char *name, u8 *revert, u8 *cipher, u8 *plain)
+{
+ struct skcipher_def sk;
+ struct crypto_skcipher *skcipher = NULL;
+ struct skcipher_request *req = NULL;
+ u8 iv[16], key[32];
+ u64 start, end;
+ int ret = -EFAULT;
+
+ skcipher = crypto_alloc_skcipher(name, 0, 0);
+ if (IS_ERR(skcipher)) {
+ pr_info("could not allocate skcipher %s handle\n", name);
+ return PTR_ERR(skcipher);
+ }
+
+ req = skcipher_request_alloc(skcipher, GFP_KERNEL);
+ if (!req) {
+ pr_info("could not allocate skcipher request\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ crypto_req_done,
+ &sk.wait);
+
+ memset(key, 'X', sizeof(key));
+ memset(iv, 'I', sizeof(iv));
+
+ if (crypto_skcipher_setkey(skcipher, key, 32)) {
+ pr_info("key could not be set\n");
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ if (debug) {
+ print_hex_dump(KERN_INFO, "key: ", DUMP_PREFIX_OFFSET,
+ 16, 1, key, 32, 1);
+
+ print_hex_dump(KERN_INFO, "iv: ", DUMP_PREFIX_OFFSET,
+ 16, 1, iv, 16, 1);
+ }
+
+ sk.tfm = skcipher;
+ sk.req = req;
+
+ /* Encrypt in one pass */
+ sg_init_one(&sk.sginp, plain, data_size);
+ sg_init_one(&sk.sgout, cipher, data_size);
+ skcipher_request_set_crypt(req, &sk.sginp, &sk.sgout,
+ data_size, iv);
+ crypto_init_wait(&sk.wait);
+
+ /* Encrypt data */
+ start = ktime_get_ns();
+ ret = test_skcipher_encdec(&sk, 1);
+ end = ktime_get_ns();
+
+ if (ret)
+ goto out;
+
+ pr_info("%s tfm encryption successful, took %lld nsec\n", name, end - start);
+
+ if (debug)
+ print_hex_dump(KERN_INFO, "encr:", DUMP_PREFIX_OFFSET,
+ 16, 1, cipher,
+ (data_size > 64 ? 64 : data_size), 1);
+
+ /* Prepare for decryption */
+ memset(iv, 'I', sizeof(iv));
+
+ sg_init_one(&sk.sginp, cipher, data_size);
+ sg_init_one(&sk.sgout, revert, data_size);
+ skcipher_request_set_crypt(req, &sk.sginp, &sk.sgout,
+ data_size, iv);
+ crypto_init_wait(&sk.wait);
+
+ /* Decrypt data */
+ start = ktime_get_ns();
+ ret = test_skcipher_encdec(&sk, 0);
+ end = ktime_get_ns();
+
+ if (ret)
+ goto out;
+
+ pr_info("%s tfm decryption successful, took %lld nsec\n", name, end - start);
+
+ if (debug)
+ print_hex_dump(KERN_INFO, "decr:", DUMP_PREFIX_OFFSET,
+ 16, 1, revert,
+ (data_size > 64 ? 64 : data_size), 1);
+
+ /* Dump some internal skcipher data */
+ if (debug)
+ pr_info("skcipher %s: cryptlen %d blksize %d stride %d "
+ "ivsize %d alignmask 0x%x\n",
+ name, sk.req->cryptlen,
+ crypto_skcipher_blocksize(sk.tfm),
+ crypto_skcipher_alg(sk.tfm)->walksize,
+ crypto_skcipher_ivsize(sk.tfm),
+ crypto_skcipher_alignmask(sk.tfm));
+
+out:
+ if (skcipher)
+ crypto_free_skcipher(skcipher);
+ if (req)
+ skcipher_request_free(req);
+ return ret;
+}
+
+static int __init chacha_s390_test_init(void)
+{
+ u8 *plain = NULL, *revert = NULL;
+ u8 *cipher_generic = NULL, *cipher_s390 = NULL;
+ int ret = -1;
+
+ pr_info("s390 ChaCha20 test module: size=%d debug=%d\n",
+ data_size, debug);
+
+ /* Allocate and fill buffers */
+ plain = vmalloc(data_size);
+ if (!plain) {
+ pr_info("could not allocate plain buffer\n");
+ ret = -2;
+ goto out;
+ }
+ memset(plain, 'a', data_size);
+ get_random_bytes(plain, (data_size > 256 ? 256 : data_size));
+
+ cipher_generic = vmalloc(data_size);
+ if (!cipher_generic) {
+ pr_info("could not allocate cipher_generic buffer\n");
+ ret = -2;
+ goto out;
+ }
+ memset(cipher_generic, 0, data_size);
+
+ cipher_s390 = vmalloc(data_size);
+ if (!cipher_s390) {
+ pr_info("could not allocate cipher_s390 buffer\n");
+ ret = -2;
+ goto out;
+ }
+ memset(cipher_s390, 0, data_size);
+
+ revert = vmalloc(data_size);
+ if (!revert) {
+ pr_info("could not allocate revert buffer\n");
+ ret = -2;
+ goto out;
+ }
+ memset(revert, 0, data_size);
+
+ if (debug)
+ print_hex_dump(KERN_INFO, "src: ", DUMP_PREFIX_OFFSET,
+ 16, 1, plain,
+ (data_size > 64 ? 64 : data_size), 1);
+
+ /* Use chacha20 generic */
+ ret = test_skcipher("chacha20-generic", revert, cipher_generic, plain);
+ if (ret)
+ goto out;
+
+ if (memcmp(plain, revert, data_size)) {
+ pr_info("generic en/decryption check FAILED\n");
+ ret = -2;
+ goto out;
+ }
+ else
+ pr_info("generic en/decryption check OK\n");
+
+ memset(revert, 0, data_size);
+
+ /* Use chacha20 s390 */
+ ret = test_skcipher("chacha20-s390", revert, cipher_s390, plain);
+ if (ret)
+ goto out;
+
+ if (memcmp(plain, revert, data_size)) {
+ pr_info("s390 en/decryption check FAILED\n");
+ ret = -2;
+ goto out;
+ }
+ else
+ pr_info("s390 en/decryption check OK\n");
+
+ if (memcmp(cipher_generic, cipher_s390, data_size)) {
+ pr_info("s390 vs generic check FAILED\n");
+ ret = -2;
+ goto out;
+ }
+ else
+ pr_info("s390 vs generic check OK\n");
+
+ memset(cipher_s390, 0, data_size);
+ memset(revert, 0, data_size);
+
+ /* Use chacha20 lib */
+ test_lib_chacha(revert, cipher_s390, plain);
+
+ if (memcmp(plain, revert, data_size)) {
+ pr_info("lib en/decryption check FAILED\n");
+ ret = -2;
+ goto out;
+ }
+ else
+ pr_info("lib en/decryption check OK\n");
+
+ if (memcmp(cipher_generic, cipher_s390, data_size)) {
+ pr_info("lib vs generic check FAILED\n");
+ ret = -2;
+ goto out;
+ }
+ else
+ pr_info("lib vs generic check OK\n");
+
+ pr_info("--- chacha20 s390 test end ---\n");
+
+out:
+ if (plain)
+ vfree(plain);
+ if (cipher_generic)
+ vfree(cipher_generic);
+ if (cipher_s390)
+ vfree(cipher_s390);
+ if (revert)
+ vfree(revert);
+
+ return -1;
+}
+
+static void __exit chacha_s390_test_exit(void)
+{
+ pr_info("s390 ChaCha20 test module exit\n");
+}
+
+module_param_named(size, data_size, uint, 0660);
+module_param(debug, int, 0660);
+MODULE_PARM_DESC(size, "Size of a plaintext");
+MODULE_PARM_DESC(debug, "Debug level (0=off,1=on)");
+
+module_init(chacha_s390_test_init);
+module_exit(chacha_s390_test_exit);
+
+MODULE_DESCRIPTION("s390 ChaCha20 self-test");
+MODULE_AUTHOR("Vladis Dronov <[email protected]>");
+MODULE_LICENSE("GPL v2");
--
2.35.1
On 2022-05-08 15:09, Vladis Dronov wrote:
> From: Vladis Dronov <[email protected]>
>
> Implement a crypto library interface for the s390-native ChaCha20
> cipher
> algorithm. This allows us to stop to select CRYPTO_CHACHA20 and instead
> select CRYPTO_ARCH_HAVE_LIB_CHACHA. This allows BIG_KEYS=y not to build
> a whole ChaCha20 crypto infrastructure as a built-in, but build a
> smaller
> CRYPTO_LIB_CHACHA instead.
>
> Make CRYPTO_CHACHA_S390 config entry to look like similar ones on other
> architectures. Remove CRYPTO_ALGAPI select as anyway it is selected by
> CRYPTO_SKCIPHER.
>
> Add a new test module and a test script for ChaCha20 cipher and its
> interfaces. Here are test results on an idle z15 machine:
>
> Data | Generic crypto TFM | s390 crypto TFM | s390 lib
> size | enc dec | enc dec | enc dec
> -----+--------------------+------------------+----------------
> 512b | 1545ns 1295ns | 604ns 446ns | 430ns 407ns
> 4k | 9536ns 9463ns | 2329ns 2174ns | 2170ns 2154ns
> 64k | 149.6us 149.3us | 34.4us 34.5us | 33.9us 33.1us
> 6M | 23.61ms 23.11ms | 4223us 4160us | 3951us 4008us
> 60M | 143.9ms 143.9ms | 33.5ms 33.2ms | 32.2ms 32.1ms
>
> Signed-off-by: Vladis Dronov <[email protected]>
> ---
> arch/s390/crypto/chacha-glue.c | 34 +-
> drivers/crypto/Kconfig | 4 +-
> tools/testing/crypto/chacha20-s390/Makefile | 12 +
> .../testing/crypto/chacha20-s390/run-tests.sh | 34 ++
> .../crypto/chacha20-s390/test-cipher.c | 372 ++++++++++++++++++
> 5 files changed, 452 insertions(+), 4 deletions(-)
> create mode 100644 tools/testing/crypto/chacha20-s390/Makefile
> create mode 100644 tools/testing/crypto/chacha20-s390/run-tests.sh
> create mode 100644 tools/testing/crypto/chacha20-s390/test-cipher.c
>
> diff --git a/arch/s390/crypto/chacha-glue.c
> b/arch/s390/crypto/chacha-glue.c
> index ccfff73e2c93..2ec51f339cec 100644
> --- a/arch/s390/crypto/chacha-glue.c
> +++ b/arch/s390/crypto/chacha-glue.c
> @@ -62,6 +62,34 @@ static int chacha20_s390(struct skcipher_request
> *req)
> return rc;
> }
>
> +void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds)
> +{
> + /* TODO: implement hchacha_block_arch() in assembly */
> + hchacha_block_generic(state, stream, nrounds);
> +}
> +EXPORT_SYMBOL(hchacha_block_arch);
> +
> +void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv)
> +{
> + chacha_init_generic(state, key, iv);
> +}
> +EXPORT_SYMBOL(chacha_init_arch);
> +
> +void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src,
> + unsigned int bytes, int nrounds)
> +{
> + /* s390 chacha20 implementation has 20 rounds hard-coded,
> + * it cannot handle a block of data or less, but otherwise
> + * it can handle data of arbitrary size
> + */
> + if (bytes <= CHACHA_BLOCK_SIZE || nrounds != 20)
> + chacha_crypt_generic(state, dst, src, bytes, nrounds);
> + else
> + chacha20_crypt_s390(state, dst, src, bytes,
> + &state[4], &state[12]);
> +}
> +EXPORT_SYMBOL(chacha_crypt_arch);
> +
> static struct skcipher_alg chacha_algs[] = {
> {
> .base.cra_name = "chacha20",
> @@ -83,12 +111,14 @@ static struct skcipher_alg chacha_algs[] = {
>
> static int __init chacha_mod_init(void)
> {
> - return crypto_register_skciphers(chacha_algs,
> ARRAY_SIZE(chacha_algs));
> + return IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER) ?
> + crypto_register_skciphers(chacha_algs, ARRAY_SIZE(chacha_algs)) : 0;
> }
>
> static void __exit chacha_mod_fini(void)
> {
> - crypto_unregister_skciphers(chacha_algs, ARRAY_SIZE(chacha_algs));
> + if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER))
> + crypto_unregister_skciphers(chacha_algs, ARRAY_SIZE(chacha_algs));
> }
>
> module_cpu_feature_match(VXRS, chacha_mod_init);
> diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
> index 7b2d138bc83e..ee99c02c84e8 100644
> --- a/drivers/crypto/Kconfig
> +++ b/drivers/crypto/Kconfig
> @@ -216,9 +216,9 @@ config CRYPTO_AES_S390
> config CRYPTO_CHACHA_S390
> tristate "ChaCha20 stream cipher"
> depends on S390
> - select CRYPTO_ALGAPI
> select CRYPTO_SKCIPHER
> - select CRYPTO_CHACHA20
> + select CRYPTO_LIB_CHACHA_GENERIC
> + select CRYPTO_ARCH_HAVE_LIB_CHACHA
> help
> This is the s390 SIMD implementation of the ChaCha20 stream
> cipher (RFC 7539).
> diff --git a/tools/testing/crypto/chacha20-s390/Makefile
> b/tools/testing/crypto/chacha20-s390/Makefile
> new file mode 100644
> index 000000000000..db81cd2fb9c5
> --- /dev/null
> +++ b/tools/testing/crypto/chacha20-s390/Makefile
> @@ -0,0 +1,12 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Copyright (C) 2022 Red Hat, Inc.
> +# Author: Vladis Dronov <[email protected]>
> +
> +obj-m += test_cipher.o
> +test_cipher-y := test-cipher.o
> +
> +all:
> + make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
> +clean:
> + make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
> diff --git a/tools/testing/crypto/chacha20-s390/run-tests.sh
> b/tools/testing/crypto/chacha20-s390/run-tests.sh
> new file mode 100644
> index 000000000000..43108794b996
> --- /dev/null
> +++ b/tools/testing/crypto/chacha20-s390/run-tests.sh
> @@ -0,0 +1,34 @@
> +#!/bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Copyright (C) 2022 Red Hat, Inc.
> +# Author: Vladis Dronov <[email protected]>
> +#
> +# This script runs (via instmod) test-cipher.ko module which invokes
> +# generic and s390-native ChaCha20 encryprion algorithms with
> different
> +# size of data. Check 'dmesg' for results.
> +#
> +# The insmod error is expected:
> +# insmod: ERROR: could not insert module test_cipher.ko: Operation
> not permitted
> +
> +lsmod | grep chacha | cut -f1 -d' ' | xargs rmmod
> +modprobe chacha_generic
> +modprobe chacha_s390
> +
> +# run encryption for different data size, including whole block(s) +/-
> 1
> +insmod test_cipher.ko size=63
> +insmod test_cipher.ko size=64
> +insmod test_cipher.ko size=65
> +insmod test_cipher.ko size=127
> +insmod test_cipher.ko size=128
> +insmod test_cipher.ko size=129
> +insmod test_cipher.ko size=511
> +insmod test_cipher.ko size=512
> +insmod test_cipher.ko size=513
> +insmod test_cipher.ko size=4096
> +insmod test_cipher.ko size=65611
> +insmod test_cipher.ko size=6291456
> +insmod test_cipher.ko size=62914560
> +
> +# print test logs
> +dmesg | tail -170
> diff --git a/tools/testing/crypto/chacha20-s390/test-cipher.c
> b/tools/testing/crypto/chacha20-s390/test-cipher.c
> new file mode 100644
> index 000000000000..34e8b855266f
> --- /dev/null
> +++ b/tools/testing/crypto/chacha20-s390/test-cipher.c
> @@ -0,0 +1,372 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + *
> + * Copyright (C) 2022 Red Hat, Inc.
> + * Author: Vladis Dronov <[email protected]>
> + */
> +
> +#include <asm/elf.h>
> +#include <asm/uaccess.h>
> +#include <asm/smp.h>
> +#include <crypto/skcipher.h>
> +#include <crypto/akcipher.h>
> +#include <crypto/acompress.h>
> +#include <crypto/rng.h>
> +#include <crypto/drbg.h>
> +#include <crypto/kpp.h>
> +#include <crypto/internal/simd.h>
> +#include <crypto/chacha.h>
> +#include <crypto/aead.h>
> +#include <crypto/hash.h>
> +#include <linux/crypto.h>
> +#include <linux/debugfs.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/fs.h>
> +#include <linux/fips.h>
> +#include <linux/kernel.h>
> +#include <linux/kthread.h>
> +#include <linux/module.h>
> +#include <linux/sched.h>
> +#include <linux/scatterlist.h>
> +#include <linux/time.h>
> +#include <linux/vmalloc.h>
> +#include <linux/zlib.h>
> +#include <linux/once.h>
> +#include <linux/random.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +
> +static unsigned int data_size __read_mostly = 256;
> +static unsigned int debug __read_mostly = 0;
> +
> +/* tie all skcipher structures together */
> +struct skcipher_def {
> + struct scatterlist sginp, sgout;
> + struct crypto_skcipher *tfm;
> + struct skcipher_request *req;
> + struct crypto_wait wait;
> +};
> +
> +/* Perform cipher operations with the chacha lib */
> +static int test_lib_chacha(u8 *revert, u8 *cipher, u8 *plain)
> +{
> + u32 chacha_state[CHACHA_STATE_WORDS];
> + u8 iv[16], key[32];
> + u64 start, end;
> +
> + memset(key, 'X', sizeof(key));
> + memset(iv, 'I', sizeof(iv));
> +
> + if (debug) {
> + print_hex_dump(KERN_INFO, "key: ", DUMP_PREFIX_OFFSET,
> + 16, 1, key, 32, 1);
> +
> + print_hex_dump(KERN_INFO, "iv: ", DUMP_PREFIX_OFFSET,
> + 16, 1, iv, 16, 1);
> + }
> +
> + /* Encrypt */
> + chacha_init_arch(chacha_state, (u32*)key, iv);
> +
> + start = ktime_get_ns();
> + chacha_crypt_arch(chacha_state, cipher, plain, data_size, 20);
> + end = ktime_get_ns();
> +
> +
> + if (debug)
> + print_hex_dump(KERN_INFO, "encr:", DUMP_PREFIX_OFFSET,
> + 16, 1, cipher,
> + (data_size > 64 ? 64 : data_size), 1);
> +
> + pr_info("lib encryption took: %lld nsec", end - start);
> +
> + /* Decrypt */
> + chacha_init_arch(chacha_state, (u32 *)key, iv);
> +
> + start = ktime_get_ns();
> + chacha_crypt_arch(chacha_state, revert, cipher, data_size, 20);
> + end = ktime_get_ns();
> +
> + if (debug)
> + print_hex_dump(KERN_INFO, "decr:", DUMP_PREFIX_OFFSET,
> + 16, 1, revert,
> + (data_size > 64 ? 64 : data_size), 1);
> +
> + pr_info("lib decryption took: %lld nsec", end - start);
> +
> + return 0;
> +}
> +
> +/* Perform cipher operations with skcipher */
> +static unsigned int test_skcipher_encdec(struct skcipher_def *sk,
> + int enc)
> +{
> + int rc;
> +
> + if (enc) {
> + rc = crypto_wait_req(crypto_skcipher_encrypt(sk->req),
> + &sk->wait);
> + if (rc)
> + pr_info("skcipher encrypt returned with result"
> + "%d\n", rc);
> + }
> + else
> + {
> + rc = crypto_wait_req(crypto_skcipher_decrypt(sk->req),
> + &sk->wait);
> + if (rc)
> + pr_info("skcipher decrypt returned with result"
> + "%d\n", rc);
> + }
> +
> + return rc;
> +}
> +
> +/* Initialize and trigger cipher operations */
> +static int test_skcipher(char *name, u8 *revert, u8 *cipher, u8
> *plain)
> +{
> + struct skcipher_def sk;
> + struct crypto_skcipher *skcipher = NULL;
> + struct skcipher_request *req = NULL;
> + u8 iv[16], key[32];
> + u64 start, end;
> + int ret = -EFAULT;
> +
> + skcipher = crypto_alloc_skcipher(name, 0, 0);
> + if (IS_ERR(skcipher)) {
> + pr_info("could not allocate skcipher %s handle\n", name);
> + return PTR_ERR(skcipher);
> + }
> +
> + req = skcipher_request_alloc(skcipher, GFP_KERNEL);
> + if (!req) {
> + pr_info("could not allocate skcipher request\n");
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> + crypto_req_done,
> + &sk.wait);
> +
> + memset(key, 'X', sizeof(key));
> + memset(iv, 'I', sizeof(iv));
> +
> + if (crypto_skcipher_setkey(skcipher, key, 32)) {
> + pr_info("key could not be set\n");
> + ret = -EAGAIN;
> + goto out;
> + }
> +
> + if (debug) {
> + print_hex_dump(KERN_INFO, "key: ", DUMP_PREFIX_OFFSET,
> + 16, 1, key, 32, 1);
> +
> + print_hex_dump(KERN_INFO, "iv: ", DUMP_PREFIX_OFFSET,
> + 16, 1, iv, 16, 1);
> + }
> +
> + sk.tfm = skcipher;
> + sk.req = req;
> +
> + /* Encrypt in one pass */
> + sg_init_one(&sk.sginp, plain, data_size);
> + sg_init_one(&sk.sgout, cipher, data_size);
> + skcipher_request_set_crypt(req, &sk.sginp, &sk.sgout,
> + data_size, iv);
> + crypto_init_wait(&sk.wait);
> +
> + /* Encrypt data */
> + start = ktime_get_ns();
> + ret = test_skcipher_encdec(&sk, 1);
> + end = ktime_get_ns();
> +
> + if (ret)
> + goto out;
> +
> + pr_info("%s tfm encryption successful, took %lld nsec\n", name, end -
> start);
> +
> + if (debug)
> + print_hex_dump(KERN_INFO, "encr:", DUMP_PREFIX_OFFSET,
> + 16, 1, cipher,
> + (data_size > 64 ? 64 : data_size), 1);
> +
> + /* Prepare for decryption */
> + memset(iv, 'I', sizeof(iv));
> +
> + sg_init_one(&sk.sginp, cipher, data_size);
> + sg_init_one(&sk.sgout, revert, data_size);
> + skcipher_request_set_crypt(req, &sk.sginp, &sk.sgout,
> + data_size, iv);
> + crypto_init_wait(&sk.wait);
> +
> + /* Decrypt data */
> + start = ktime_get_ns();
> + ret = test_skcipher_encdec(&sk, 0);
> + end = ktime_get_ns();
> +
> + if (ret)
> + goto out;
> +
> + pr_info("%s tfm decryption successful, took %lld nsec\n", name, end -
> start);
> +
> + if (debug)
> + print_hex_dump(KERN_INFO, "decr:", DUMP_PREFIX_OFFSET,
> + 16, 1, revert,
> + (data_size > 64 ? 64 : data_size), 1);
> +
> + /* Dump some internal skcipher data */
> + if (debug)
> + pr_info("skcipher %s: cryptlen %d blksize %d stride %d "
> + "ivsize %d alignmask 0x%x\n",
> + name, sk.req->cryptlen,
> + crypto_skcipher_blocksize(sk.tfm),
> + crypto_skcipher_alg(sk.tfm)->walksize,
> + crypto_skcipher_ivsize(sk.tfm),
> + crypto_skcipher_alignmask(sk.tfm));
> +
> +out:
> + if (skcipher)
> + crypto_free_skcipher(skcipher);
> + if (req)
> + skcipher_request_free(req);
> + return ret;
> +}
> +
> +static int __init chacha_s390_test_init(void)
> +{
> + u8 *plain = NULL, *revert = NULL;
> + u8 *cipher_generic = NULL, *cipher_s390 = NULL;
> + int ret = -1;
> +
> + pr_info("s390 ChaCha20 test module: size=%d debug=%d\n",
> + data_size, debug);
> +
> + /* Allocate and fill buffers */
> + plain = vmalloc(data_size);
> + if (!plain) {
> + pr_info("could not allocate plain buffer\n");
> + ret = -2;
> + goto out;
> + }
> + memset(plain, 'a', data_size);
> + get_random_bytes(plain, (data_size > 256 ? 256 : data_size));
> +
> + cipher_generic = vmalloc(data_size);
> + if (!cipher_generic) {
> + pr_info("could not allocate cipher_generic buffer\n");
> + ret = -2;
> + goto out;
> + }
> + memset(cipher_generic, 0, data_size);
> +
> + cipher_s390 = vmalloc(data_size);
> + if (!cipher_s390) {
> + pr_info("could not allocate cipher_s390 buffer\n");
> + ret = -2;
> + goto out;
> + }
> + memset(cipher_s390, 0, data_size);
> +
> + revert = vmalloc(data_size);
> + if (!revert) {
> + pr_info("could not allocate revert buffer\n");
> + ret = -2;
> + goto out;
> + }
> + memset(revert, 0, data_size);
> +
> + if (debug)
> + print_hex_dump(KERN_INFO, "src: ", DUMP_PREFIX_OFFSET,
> + 16, 1, plain,
> + (data_size > 64 ? 64 : data_size), 1);
> +
> + /* Use chacha20 generic */
> + ret = test_skcipher("chacha20-generic", revert, cipher_generic,
> plain);
> + if (ret)
> + goto out;
> +
> + if (memcmp(plain, revert, data_size)) {
> + pr_info("generic en/decryption check FAILED\n");
> + ret = -2;
> + goto out;
> + }
> + else
> + pr_info("generic en/decryption check OK\n");
> +
> + memset(revert, 0, data_size);
> +
> + /* Use chacha20 s390 */
> + ret = test_skcipher("chacha20-s390", revert, cipher_s390, plain);
> + if (ret)
> + goto out;
> +
> + if (memcmp(plain, revert, data_size)) {
> + pr_info("s390 en/decryption check FAILED\n");
> + ret = -2;
> + goto out;
> + }
> + else
> + pr_info("s390 en/decryption check OK\n");
> +
> + if (memcmp(cipher_generic, cipher_s390, data_size)) {
> + pr_info("s390 vs generic check FAILED\n");
> + ret = -2;
> + goto out;
> + }
> + else
> + pr_info("s390 vs generic check OK\n");
> +
> + memset(cipher_s390, 0, data_size);
> + memset(revert, 0, data_size);
> +
> + /* Use chacha20 lib */
> + test_lib_chacha(revert, cipher_s390, plain);
> +
> + if (memcmp(plain, revert, data_size)) {
> + pr_info("lib en/decryption check FAILED\n");
> + ret = -2;
> + goto out;
> + }
> + else
> + pr_info("lib en/decryption check OK\n");
> +
> + if (memcmp(cipher_generic, cipher_s390, data_size)) {
> + pr_info("lib vs generic check FAILED\n");
> + ret = -2;
> + goto out;
> + }
> + else
> + pr_info("lib vs generic check OK\n");
> +
> + pr_info("--- chacha20 s390 test end ---\n");
> +
> +out:
> + if (plain)
> + vfree(plain);
> + if (cipher_generic)
> + vfree(cipher_generic);
> + if (cipher_s390)
> + vfree(cipher_s390);
> + if (revert)
> + vfree(revert);
> +
> + return -1;
> +}
> +
> +static void __exit chacha_s390_test_exit(void)
> +{
> + pr_info("s390 ChaCha20 test module exit\n");
> +}
> +
> +module_param_named(size, data_size, uint, 0660);
> +module_param(debug, int, 0660);
> +MODULE_PARM_DESC(size, "Size of a plaintext");
> +MODULE_PARM_DESC(debug, "Debug level (0=off,1=on)");
> +
> +module_init(chacha_s390_test_init);
> +module_exit(chacha_s390_test_exit);
> +
> +MODULE_DESCRIPTION("s390 ChaCha20 self-test");
> +MODULE_AUTHOR("Vladis Dronov <[email protected]>");
> +MODULE_LICENSE("GPL v2");
Hello Vladis
Thanks for your work. Please add my
Reviewed-by: Harald Freudenberger <[email protected]>
however, always the question who will pick and forward this patch ?
To me this looks like most parts are common so I would suggest that
Herbert Xu will pick this patch.
On Sun, May 08, 2022 at 03:09:44PM +0200, Vladis Dronov wrote:
> From: Vladis Dronov <[email protected]>
>
> Implement a crypto library interface for the s390-native ChaCha20 cipher
> algorithm. This allows us to stop to select CRYPTO_CHACHA20 and instead
> select CRYPTO_ARCH_HAVE_LIB_CHACHA. This allows BIG_KEYS=y not to build
> a whole ChaCha20 crypto infrastructure as a built-in, but build a smaller
> CRYPTO_LIB_CHACHA instead.
>
> Make CRYPTO_CHACHA_S390 config entry to look like similar ones on other
> architectures. Remove CRYPTO_ALGAPI select as anyway it is selected by
> CRYPTO_SKCIPHER.
>
> Add a new test module and a test script for ChaCha20 cipher and its
> interfaces. Here are test results on an idle z15 machine:
>
> Data | Generic crypto TFM | s390 crypto TFM | s390 lib
> size | enc dec | enc dec | enc dec
> -----+--------------------+------------------+----------------
> 512b | 1545ns 1295ns | 604ns 446ns | 430ns 407ns
> 4k | 9536ns 9463ns | 2329ns 2174ns | 2170ns 2154ns
> 64k | 149.6us 149.3us | 34.4us 34.5us | 33.9us 33.1us
> 6M | 23.61ms 23.11ms | 4223us 4160us | 3951us 4008us
> 60M | 143.9ms 143.9ms | 33.5ms 33.2ms | 32.2ms 32.1ms
>
> Signed-off-by: Vladis Dronov <[email protected]>
> ---
> arch/s390/crypto/chacha-glue.c | 34 +-
> drivers/crypto/Kconfig | 4 +-
> tools/testing/crypto/chacha20-s390/Makefile | 12 +
> .../testing/crypto/chacha20-s390/run-tests.sh | 34 ++
> .../crypto/chacha20-s390/test-cipher.c | 372 ++++++++++++++++++
> 5 files changed, 452 insertions(+), 4 deletions(-)
> create mode 100644 tools/testing/crypto/chacha20-s390/Makefile
> create mode 100644 tools/testing/crypto/chacha20-s390/run-tests.sh
> create mode 100644 tools/testing/crypto/chacha20-s390/test-cipher.c
Patch applied. Thanks.
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt