From 021ba8b87e270abdb892ae853fc863cb7e258265 Mon Sep 17 00:00:00 2001
From: Stephan Mueller <smueller@chronox.de>
Date: Sun, 9 Oct 2022 10:22:39 +0200
Subject: [PATCH 23/25] LRNG - add kernel crypto API interface

The LRNG can be registered with the kernel crypto API's random number
generator framework. This offers a random number generator with the name
"lrng" and a priority that is intended to be higher than the existing
RNG implementations.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 drivers/char/lrng/Kconfig                |  26 ++---
 drivers/char/lrng/Makefile               |   1 +
 drivers/char/lrng/lrng_interface_kcapi.c | 129 +++++++++++++++++++++++
 3 files changed, 143 insertions(+), 13 deletions(-)
 create mode 100644 drivers/char/lrng/lrng_interface_kcapi.c

--- a/drivers/char/lrng/Kconfig
+++ b/drivers/char/lrng/Kconfig
@@ -89,18 +89,18 @@ config LRNG_AIS2031_NTG1_SEEDING_STRATEG
 
 endmenu # "Specific DRNG seeding strategies"
 
-# menu "LRNG Interfaces"
-#
-# config LRNG_KCAPI_IF
-# 	tristate "Interface with Kernel Crypto API"
-# 	depends on CRYPTO_RNG
-# 	help
-# 	  The LRNG can be registered with the kernel crypto API's
-# 	  random number generator framework. This offers a random
-# 	  number generator with the name "lrng" and a priority that
-# 	  is intended to be higher than the existing RNG
-# 	  implementations.
-#
+menu "LRNG Interfaces"
+
+config LRNG_KCAPI_IF
+	tristate "Interface with Kernel Crypto API"
+	depends on CRYPTO_RNG
+	help
+	  The LRNG can be registered with the kernel crypto API's
+	  random number generator framework. This offers a random
+	  number generator with the name "lrng" and a priority that
+	  is intended to be higher than the existing RNG
+	  implementations.
+
 # config LRNG_HWRAND_IF
 # 	tristate "Interface with Hardware Random Number Generator Framework"
 # 	depends on HW_RANDOM
@@ -120,7 +120,7 @@ endmenu # "Specific DRNG seeding strateg
 # 	  identically to /dev/random including IOCTL, read and write
 # 	  operations.
 #
-# endmenu # "LRNG Interfaces"
+endmenu # "LRNG Interfaces"
 
 menu "Entropy Source Configuration"
 
--- a/drivers/char/lrng/Makefile
+++ b/drivers/char/lrng/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_LRNG_COMMON_DEV_IF)	+= lrng
 obj-$(CONFIG_LRNG_RANDOM_IF)		+= lrng_interface_random_user.o \
 					   lrng_interface_random_kernel.o \
 					   lrng_interface_aux.o
+obj-$(CONFIG_LRNG_KCAPI_IF)		+= lrng_interface_kcapi.o
--- /dev/null
+++ b/drivers/char/lrng/lrng_interface_kcapi.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * LRNG interface with the RNG framework of the kernel crypto API
+ *
+ * Copyright (C) 2022, Stephan Mueller <smueller@chronox.de>
+ */
+
+#include <linux/lrng.h>
+#include <linux/module.h>
+#include <crypto/internal/rng.h>
+
+#include "lrng_drng_mgr.h"
+#include "lrng_es_aux.h"
+
+static int lrng_kcapi_if_init(struct crypto_tfm *tfm)
+{
+	return 0;
+}
+
+static void lrng_kcapi_if_cleanup(struct crypto_tfm *tfm) { }
+
+static int lrng_kcapi_if_reseed(const u8 *src, unsigned int slen)
+{
+	int ret;
+
+	if (!slen)
+		return 0;
+
+	/* Insert caller-provided data without crediting entropy */
+	ret = lrng_pool_insert_aux((u8 *)src, slen, 0);
+	if (ret)
+		return ret;
+
+	/* Make sure the new data is immediately available to DRNG */
+	lrng_drng_force_reseed();
+
+	return 0;
+}
+
+static int lrng_kcapi_if_random(struct crypto_rng *tfm,
+				const u8 *src, unsigned int slen,
+				u8 *rdata, unsigned int dlen)
+{
+	int ret = lrng_kcapi_if_reseed(src, slen);
+
+	if (!ret)
+		lrng_get_random_bytes_full(rdata, dlen);
+
+	return ret;
+}
+
+static int lrng_kcapi_if_reset(struct crypto_rng *tfm,
+			       const u8 *seed, unsigned int slen)
+{
+	return lrng_kcapi_if_reseed(seed, slen);
+}
+
+static struct rng_alg lrng_alg = {
+	.generate		= lrng_kcapi_if_random,
+	.seed			= lrng_kcapi_if_reset,
+	.seedsize		= 0,
+	.base			= {
+		.cra_name               = "stdrng",
+		.cra_driver_name        = "lrng",
+		.cra_priority           = 500,
+		.cra_ctxsize            = 0,
+		.cra_module             = THIS_MODULE,
+		.cra_init               = lrng_kcapi_if_init,
+		.cra_exit               = lrng_kcapi_if_cleanup,
+
+	}
+};
+
+#ifdef CONFIG_LRNG_DRNG_ATOMIC
+static int lrng_kcapi_if_random_atomic(struct crypto_rng *tfm,
+				       const u8 *src, unsigned int slen,
+				       u8 *rdata, unsigned int dlen)
+{
+	int ret = lrng_kcapi_if_reseed(src, slen);
+
+	if (!ret)
+		lrng_get_random_bytes(rdata, dlen);
+
+	return ret;
+}
+
+static struct rng_alg lrng_alg_atomic = {
+	.generate		= lrng_kcapi_if_random_atomic,
+	.seed			= lrng_kcapi_if_reset,
+	.seedsize		= 0,
+	.base			= {
+		.cra_name               = "lrng_atomic",
+		.cra_driver_name        = "lrng_atomic",
+		.cra_priority           = 100,
+		.cra_ctxsize            = 0,
+		.cra_module             = THIS_MODULE,
+		.cra_init               = lrng_kcapi_if_init,
+		.cra_exit               = lrng_kcapi_if_cleanup,
+
+	}
+};
+#endif /* CONFIG_LRNG_DRNG_ATOMIC */
+
+static int __init lrng_kcapi_if_mod_init(void)
+{
+	return
+#ifdef CONFIG_LRNG_DRNG_ATOMIC
+	       crypto_register_rng(&lrng_alg_atomic) ?:
+#endif
+	       crypto_register_rng(&lrng_alg);
+}
+
+static void __exit lrng_kcapi_if_mod_exit(void)
+{
+	crypto_unregister_rng(&lrng_alg);
+#ifdef CONFIG_LRNG_DRNG_ATOMIC
+	crypto_unregister_rng(&lrng_alg_atomic);
+#endif
+}
+
+module_init(lrng_kcapi_if_mod_init);
+module_exit(lrng_kcapi_if_mod_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
+MODULE_DESCRIPTION("Entropy Source and DRNG Manager kernel crypto API RNG framework interface");
+MODULE_ALIAS_CRYPTO("lrng");
+MODULE_ALIAS_CRYPTO("lrng_atomic");
+MODULE_ALIAS_CRYPTO("stdrng");
