* [PATCH 0/4] Xilinx TRNG fix and simplification
@ 2026-05-31 19:17 Eric Biggers
2026-05-31 19:17 ` [PATCH 1/4] crypto: xilinx-trng - Remove crypto_rng interface Eric Biggers
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Eric Biggers @ 2026-05-31 19:17 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: linux-kernel, Mounika Botcha, Harsh Jain, Olivia Mackall,
Michal Simek, linux-arm-kernel, Eric Biggers
This series fixes and greatly simplifies the Xilinx TRNG driver by:
- Removing the gratuitous crypto_rng interface, leaving just hwrng which
is the one that actually matters.
- Replacing the really complicated AES based entropy extraction
algorithm with a much simpler one.
Note that this mirrors similar changes in other drivers.
Eric Biggers (4):
crypto: xilinx-trng - Remove crypto_rng interface
crypto: xilinx-trng - Fix return value of xtrng_hwrng_trng_read()
crypto: xilinx-trng - Replace crypto_drbg_ctr_df() with HMAC-SHA512
hwrng: xilinx - Move xilinx-rng into drivers/char/hw_random/
MAINTAINERS | 2 +-
arch/arm64/configs/defconfig | 2 +-
crypto/Kconfig | 5 -
crypto/Makefile | 2 -
crypto/df_sp80090a.c | 222 ------------------
drivers/char/hw_random/Kconfig | 11 +
drivers/char/hw_random/Makefile | 1 +
.../xilinx => char/hw_random}/xilinx-trng.c | 134 ++---------
drivers/crypto/Kconfig | 13 -
drivers/crypto/xilinx/Makefile | 1 -
include/crypto/df_sp80090a.h | 53 -----
11 files changed, 37 insertions(+), 409 deletions(-)
delete mode 100644 crypto/df_sp80090a.c
rename drivers/{crypto/xilinx => char/hw_random}/xilinx-trng.c (75%)
delete mode 100644 include/crypto/df_sp80090a.h
base-commit: 5624ea54f3ba5c83d2e5503411a31a8be0278c1e
prerequisite-patch-id: 07e982b663ac3f8312ca524f6b91b5b38661df5e
prerequisite-patch-id: 72064361a8f36e015ab0b7e1fa4d364b40d90506
prerequisite-patch-id: 8978b8e0db7f47935e5f6f0aff14a97f55d3073c
prerequisite-patch-id: 6aa0e3e93a008279d71e535a3d0cf48643f55e19
--
2.54.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/4] crypto: xilinx-trng - Remove crypto_rng interface
2026-05-31 19:17 [PATCH 0/4] Xilinx TRNG fix and simplification Eric Biggers
@ 2026-05-31 19:17 ` Eric Biggers
2026-05-31 19:17 ` [PATCH 2/4] crypto: xilinx-trng - Fix return value of xtrng_hwrng_trng_read() Eric Biggers
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Eric Biggers @ 2026-05-31 19:17 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: linux-kernel, Mounika Botcha, Harsh Jain, Olivia Mackall,
Michal Simek, linux-arm-kernel, Eric Biggers, stable
Implementing the crypto_rng interface has no purpose, as it isn't used
in practice. It's being removed from other drivers too. Just remove
it. This leaves hwrng, which is actually used.
Tagging with 'Cc stable' due to the bugs that this removes:
- xtrng_trng_generate() sometimes returned success even when it didn't
fill in all the bytes.
- It was possible for xtrng_trng_generate() and
xtrng_hwrng_trng_read() to run concurrently and interfere with each
other, as the locking code in xtrng_hwrng_trng_read() was broken.
Fixes: 8979744aca80 ("crypto: xilinx - Add TRNG driver for Versal")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
drivers/crypto/Kconfig | 1 -
drivers/crypto/xilinx/xilinx-trng.c | 85 ++---------------------------
2 files changed, 4 insertions(+), 82 deletions(-)
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 07f0fa3341fc..26194c33cb32 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -708,11 +708,10 @@ config CRYPTO_DEV_TEGRA
config CRYPTO_DEV_XILINX_TRNG
tristate "Support for Xilinx True Random Generator"
depends on ZYNQMP_FIRMWARE || COMPILE_TEST
select CRYPTO_DF80090A
- select CRYPTO_RNG
select HW_RANDOM
help
Xilinx Versal SoC driver provides kernel-side support for True Random Number
Generator and Pseudo random Number in CTR_DRBG mode as defined in NIST SP800-90A.
diff --git a/drivers/crypto/xilinx/xilinx-trng.c b/drivers/crypto/xilinx/xilinx-trng.c
index 43a4832f07e7..a35643baa489 100644
--- a/drivers/crypto/xilinx/xilinx-trng.c
+++ b/drivers/crypto/xilinx/xilinx-trng.c
@@ -4,25 +4,22 @@
* Copyright (c) 2024 - 2025 Advanced Micro Devices, Inc.
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
-#include <linux/crypto.h>
#include <linux/delay.h>
#include <linux/firmware/xlnx-zynqmp.h>
#include <linux/hw_random.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mutex.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <crypto/aes.h>
#include <crypto/df_sp80090a.h>
#include <crypto/internal/cipher.h>
-#include <crypto/internal/rng.h>
/* TRNG Registers Offsets */
#define TRNG_STATUS_OFFSET 0x4U
#define TRNG_CTRL_OFFSET 0x8U
#define TRNG_EXT_SEED_OFFSET 0x40U
@@ -58,20 +55,13 @@
struct xilinx_rng {
void __iomem *rng_base;
struct device *dev;
unsigned char *scratchpadbuf;
struct aes_enckey *aeskey;
- struct mutex lock; /* Protect access to TRNG device */
struct hwrng trng;
};
-struct xilinx_rng_ctx {
- struct xilinx_rng *rng;
-};
-
-static struct xilinx_rng *xilinx_rng_dev;
-
static void xtrng_readwrite32(void __iomem *addr, u32 mask, u8 value)
{
u32 val;
val = ioread32(addr);
@@ -243,74 +233,25 @@ static int xtrng_random_bytes_generate(struct xilinx_rng *rng, u8 *rand_buf_ptr,
}
return nbytes;
}
-static int xtrng_trng_generate(struct crypto_rng *tfm, const u8 *src, u32 slen,
- u8 *dst, u32 dlen)
-{
- struct xilinx_rng_ctx *ctx = crypto_rng_ctx(tfm);
- int ret;
-
- mutex_lock(&ctx->rng->lock);
- ret = xtrng_random_bytes_generate(ctx->rng, dst, dlen, true);
- mutex_unlock(&ctx->rng->lock);
-
- return ret < 0 ? ret : 0;
-}
-
-static int xtrng_trng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen)
-{
- return 0;
-}
-
-static int xtrng_trng_init(struct crypto_tfm *rtfm)
-{
- struct xilinx_rng_ctx *ctx = crypto_tfm_ctx(rtfm);
-
- ctx->rng = xilinx_rng_dev;
-
- return 0;
-}
-
-static struct rng_alg xtrng_trng_alg = {
- .generate = xtrng_trng_generate,
- .seed = xtrng_trng_seed,
- .seedsize = 0,
- .base = {
- .cra_name = "stdrng",
- .cra_driver_name = "xilinx-trng",
- .cra_priority = 300,
- .cra_ctxsize = sizeof(struct xilinx_rng_ctx),
- .cra_module = THIS_MODULE,
- .cra_init = xtrng_trng_init,
- },
-};
-
static int xtrng_hwrng_trng_read(struct hwrng *hwrng, void *data, size_t max, bool wait)
{
u8 buf[TRNG_SEC_STRENGTH_BYTES];
struct xilinx_rng *rng;
int ret = -EINVAL, i = 0;
rng = container_of(hwrng, struct xilinx_rng, trng);
- /* Return in case wait not set and lock not available. */
- if (!mutex_trylock(&rng->lock) && !wait)
- return 0;
- else if (!mutex_is_locked(&rng->lock) && wait)
- mutex_lock(&rng->lock);
-
while (i < max) {
ret = xtrng_random_bytes_generate(rng, buf, TRNG_SEC_STRENGTH_BYTES, wait);
if (ret < 0)
break;
memcpy(data + i, buf, min_t(int, ret, (max - i)));
i += min_t(int, ret, (max - i));
}
- mutex_unlock(&rng->lock);
-
return ret;
}
static int xtrng_hwrng_register(struct hwrng *trng)
{
@@ -352,60 +293,42 @@ static int xtrng_probe(struct platform_device *pdev)
if (!rng->aeskey)
return -ENOMEM;
sb_size = crypto_drbg_ctr_df_datalen(TRNG_SEED_LEN_BYTES, AES_BLOCK_SIZE);
rng->scratchpadbuf = devm_kzalloc(&pdev->dev, sb_size, GFP_KERNEL);
- if (!rng->scratchpadbuf) {
- ret = -ENOMEM;
- goto end;
- }
+ if (!rng->scratchpadbuf)
+ return -ENOMEM;
xtrng_trng_reset(rng->rng_base);
ret = xtrng_reseed_internal(rng);
if (ret) {
dev_err(&pdev->dev, "TRNG Seed fail\n");
- goto end;
- }
-
- xilinx_rng_dev = rng;
- mutex_init(&rng->lock);
- ret = crypto_register_rng(&xtrng_trng_alg);
- if (ret) {
- dev_err(&pdev->dev, "Crypto Random device registration failed: %d\n", ret);
- goto end;
+ return ret;
}
ret = xtrng_hwrng_register(&rng->trng);
if (ret) {
dev_err(&pdev->dev, "HWRNG device registration failed: %d\n", ret);
- goto crypto_rng_free;
+ return ret;
}
platform_set_drvdata(pdev, rng);
return 0;
-
-crypto_rng_free:
- crypto_unregister_rng(&xtrng_trng_alg);
-
-end:
- return ret;
}
static void xtrng_remove(struct platform_device *pdev)
{
struct xilinx_rng *rng;
u32 zero[TRNG_NUM_INIT_REGS] = { };
rng = platform_get_drvdata(pdev);
xtrng_hwrng_unregister(&rng->trng);
- crypto_unregister_rng(&xtrng_trng_alg);
xtrng_write_multiple_registers(rng->rng_base + TRNG_EXT_SEED_OFFSET, zero,
TRNG_NUM_INIT_REGS);
xtrng_write_multiple_registers(rng->rng_base + TRNG_PER_STRNG_OFFSET, zero,
TRNG_NUM_INIT_REGS);
xtrng_hold_reset(rng->rng_base);
- xilinx_rng_dev = NULL;
}
static const struct of_device_id xtrng_of_match[] = {
{ .compatible = "xlnx,versal-trng", },
{},
--
2.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/4] crypto: xilinx-trng - Fix return value of xtrng_hwrng_trng_read()
2026-05-31 19:17 [PATCH 0/4] Xilinx TRNG fix and simplification Eric Biggers
2026-05-31 19:17 ` [PATCH 1/4] crypto: xilinx-trng - Remove crypto_rng interface Eric Biggers
@ 2026-05-31 19:17 ` Eric Biggers
2026-05-31 19:17 ` [PATCH 3/4] crypto: xilinx-trng - Replace crypto_drbg_ctr_df() with HMAC-SHA512 Eric Biggers
2026-05-31 19:17 ` [PATCH 4/4] hwrng: xilinx - Move xilinx-rng into drivers/char/hw_random/ Eric Biggers
3 siblings, 0 replies; 5+ messages in thread
From: Eric Biggers @ 2026-05-31 19:17 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: linux-kernel, Mounika Botcha, Harsh Jain, Olivia Mackall,
Michal Simek, linux-arm-kernel, Eric Biggers, stable
Implementations of hwrng::read are expected to return the number of
bytes generated. Update xtrng_hwrng_trng_read() to match that.
Fixes: 8979744aca80 ("crypto: xilinx - Add TRNG driver for Versal")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
drivers/crypto/xilinx/xilinx-trng.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/crypto/xilinx/xilinx-trng.c b/drivers/crypto/xilinx/xilinx-trng.c
index a35643baa489..a30b0b3b3685 100644
--- a/drivers/crypto/xilinx/xilinx-trng.c
+++ b/drivers/crypto/xilinx/xilinx-trng.c
@@ -237,22 +237,25 @@ static int xtrng_random_bytes_generate(struct xilinx_rng *rng, u8 *rand_buf_ptr,
static int xtrng_hwrng_trng_read(struct hwrng *hwrng, void *data, size_t max, bool wait)
{
u8 buf[TRNG_SEC_STRENGTH_BYTES];
struct xilinx_rng *rng;
- int ret = -EINVAL, i = 0;
+ int ret = 0, i = 0;
rng = container_of(hwrng, struct xilinx_rng, trng);
while (i < max) {
ret = xtrng_random_bytes_generate(rng, buf, TRNG_SEC_STRENGTH_BYTES, wait);
- if (ret < 0)
+ if (ret < 0) {
+ if (i == 0)
+ return ret;
break;
+ }
memcpy(data + i, buf, min_t(int, ret, (max - i)));
i += min_t(int, ret, (max - i));
}
- return ret;
+ return i;
}
static int xtrng_hwrng_register(struct hwrng *trng)
{
int ret;
--
2.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/4] crypto: xilinx-trng - Replace crypto_drbg_ctr_df() with HMAC-SHA512
2026-05-31 19:17 [PATCH 0/4] Xilinx TRNG fix and simplification Eric Biggers
2026-05-31 19:17 ` [PATCH 1/4] crypto: xilinx-trng - Remove crypto_rng interface Eric Biggers
2026-05-31 19:17 ` [PATCH 2/4] crypto: xilinx-trng - Fix return value of xtrng_hwrng_trng_read() Eric Biggers
@ 2026-05-31 19:17 ` Eric Biggers
2026-05-31 19:17 ` [PATCH 4/4] hwrng: xilinx - Move xilinx-rng into drivers/char/hw_random/ Eric Biggers
3 siblings, 0 replies; 5+ messages in thread
From: Eric Biggers @ 2026-05-31 19:17 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: linux-kernel, Mounika Botcha, Harsh Jain, Olivia Mackall,
Michal Simek, linux-arm-kernel, Eric Biggers
This code is just trying to condition 48 bytes of random data. This can
be done easily using HKDF-SHA512-Extract, saving 300 lines of code.
This commit also fixes forward security (in this particular case) by
clearing the entropy from memory after it's used.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
crypto/Kconfig | 5 -
crypto/Makefile | 2 -
crypto/df_sp80090a.c | 222 ----------------------------
drivers/crypto/Kconfig | 2 +-
drivers/crypto/xilinx/xilinx-trng.c | 44 ++----
include/crypto/df_sp80090a.h | 53 -------
6 files changed, 16 insertions(+), 312 deletions(-)
delete mode 100644 crypto/df_sp80090a.c
delete mode 100644 include/crypto/df_sp80090a.h
diff --git a/crypto/Kconfig b/crypto/Kconfig
index b5c5a1e04435..c3d7a20d5cb1 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1244,15 +1244,10 @@ endif # if CRYPTO_JITTERENTROPY
config CRYPTO_KDF800108_CTR
tristate
select CRYPTO_HMAC
select CRYPTO_SHA256
-config CRYPTO_DF80090A
- tristate
- select CRYPTO_AES
- select CRYPTO_CTR
-
endmenu
menu "Userspace interface (deprecated)"
config CRYPTO_USER_API
tristate
diff --git a/crypto/Makefile b/crypto/Makefile
index c73f4d51d036..f98f57c7a49f 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -206,8 +206,6 @@ obj-$(CONFIG_CRYPTO_SIMD) += crypto_simd.o
#
# Key derivation function
#
obj-$(CONFIG_CRYPTO_KDF800108_CTR) += kdf_sp800108.o
-obj-$(CONFIG_CRYPTO_DF80090A) += df_sp80090a.o
-
obj-$(CONFIG_CRYPTO_KRB5) += krb5/
diff --git a/crypto/df_sp80090a.c b/crypto/df_sp80090a.c
deleted file mode 100644
index 90e1973ee40c..000000000000
--- a/crypto/df_sp80090a.c
+++ /dev/null
@@ -1,222 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-/*
- * NIST SP800-90A DRBG derivation function
- *
- * Copyright (C) 2014, Stephan Mueller <smueller@chronox.de>
- */
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/unaligned.h>
-#include <crypto/aes.h>
-#include <crypto/df_sp80090a.h>
-
-static void drbg_kcapi_sym(struct aes_enckey *aeskey, unsigned char *outval,
- const struct drbg_string *in, u8 blocklen_bytes)
-{
- /* there is only component in *in */
- BUG_ON(in->len < blocklen_bytes);
- aes_encrypt(aeskey, outval, in->buf);
-}
-
-/* BCC function for CTR DRBG as defined in 10.4.3 */
-
-static void drbg_ctr_bcc(struct aes_enckey *aeskey,
- unsigned char *out, const unsigned char *key,
- struct list_head *in,
- u8 blocklen_bytes,
- u8 keylen)
-{
- struct drbg_string *curr = NULL;
- struct drbg_string data;
- short cnt = 0;
-
- drbg_string_fill(&data, out, blocklen_bytes);
-
- /* 10.4.3 step 2 / 4 */
- aes_prepareenckey(aeskey, key, keylen);
- list_for_each_entry(curr, in, list) {
- const unsigned char *pos = curr->buf;
- size_t len = curr->len;
- /* 10.4.3 step 4.1 */
- while (len) {
- /* 10.4.3 step 4.2 */
- if (blocklen_bytes == cnt) {
- cnt = 0;
- drbg_kcapi_sym(aeskey, out, &data, blocklen_bytes);
- }
- out[cnt] ^= *pos;
- pos++;
- cnt++;
- len--;
- }
- }
- /* 10.4.3 step 4.2 for last block */
- if (cnt)
- drbg_kcapi_sym(aeskey, out, &data, blocklen_bytes);
-}
-
-/*
- * scratchpad usage: drbg_ctr_update is interlinked with crypto_drbg_ctr_df
- * (and drbg_ctr_bcc, but this function does not need any temporary buffers),
- * the scratchpad is used as follows:
- * drbg_ctr_update:
- * temp
- * start: drbg->scratchpad
- * length: drbg_statelen(drbg) + drbg_blocklen(drbg)
- * note: the cipher writing into this variable works
- * blocklen-wise. Now, when the statelen is not a multiple
- * of blocklen, the generateion loop below "spills over"
- * by at most blocklen. Thus, we need to give sufficient
- * memory.
- * df_data
- * start: drbg->scratchpad +
- * drbg_statelen(drbg) + drbg_blocklen(drbg)
- * length: drbg_statelen(drbg)
- *
- * crypto_drbg_ctr_df:
- * pad
- * start: df_data + drbg_statelen(drbg)
- * length: drbg_blocklen(drbg)
- * iv
- * start: pad + drbg_blocklen(drbg)
- * length: drbg_blocklen(drbg)
- * temp
- * start: iv + drbg_blocklen(drbg)
- * length: drbg_satelen(drbg) + drbg_blocklen(drbg)
- * note: temp is the buffer that the BCC function operates
- * on. BCC operates blockwise. drbg_statelen(drbg)
- * is sufficient when the DRBG state length is a multiple
- * of the block size. For AES192 (and maybe other ciphers)
- * this is not correct and the length for temp is
- * insufficient (yes, that also means for such ciphers,
- * the final output of all BCC rounds are truncated).
- * Therefore, add drbg_blocklen(drbg) to cover all
- * possibilities.
- * refer to crypto_drbg_ctr_df_datalen() to get required length
- */
-
-/* Derivation Function for CTR DRBG as defined in 10.4.2 */
-int crypto_drbg_ctr_df(struct aes_enckey *aeskey,
- unsigned char *df_data, size_t bytes_to_return,
- struct list_head *seedlist,
- u8 blocklen_bytes,
- u8 statelen)
-{
- unsigned char L_N[8];
- /* S3 is input */
- struct drbg_string S1, S2, S4, cipherin;
- LIST_HEAD(bcc_list);
- unsigned char *pad = df_data + statelen;
- unsigned char *iv = pad + blocklen_bytes;
- unsigned char *temp = iv + blocklen_bytes;
- size_t padlen = 0;
- unsigned int templen = 0;
- /* 10.4.2 step 7 */
- unsigned int i = 0;
- /* 10.4.2 step 8 */
- const unsigned char *K = (unsigned char *)
- "\x00\x01\x02\x03\x04\x05\x06\x07"
- "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
- "\x10\x11\x12\x13\x14\x15\x16\x17"
- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f";
- unsigned char *X;
- size_t generated_len = 0;
- size_t inputlen = 0;
- struct drbg_string *seed = NULL;
- u8 keylen;
-
- memset(pad, 0, blocklen_bytes);
- memset(iv, 0, blocklen_bytes);
- keylen = statelen - blocklen_bytes;
- /* 10.4.2 step 1 is implicit as we work byte-wise */
-
- /* 10.4.2 step 2 */
- if ((512 / 8) < bytes_to_return)
- return -EINVAL;
-
- /* 10.4.2 step 2 -- calculate the entire length of all input data */
- list_for_each_entry(seed, seedlist, list)
- inputlen += seed->len;
- put_unaligned_be32(inputlen, &L_N[0]);
-
- /* 10.4.2 step 3 */
- put_unaligned_be32(bytes_to_return, &L_N[4]);
-
- /* 10.4.2 step 5: length is L_N, input_string, one byte, padding */
- padlen = (inputlen + sizeof(L_N) + 1) % (blocklen_bytes);
- /* wrap the padlen appropriately */
- if (padlen)
- padlen = blocklen_bytes - padlen;
- /*
- * pad / padlen contains the 0x80 byte and the following zero bytes.
- * As the calculated padlen value only covers the number of zero
- * bytes, this value has to be incremented by one for the 0x80 byte.
- */
- padlen++;
- pad[0] = 0x80;
-
- /* 10.4.2 step 4 -- first fill the linked list and then order it */
- drbg_string_fill(&S1, iv, blocklen_bytes);
- list_add_tail(&S1.list, &bcc_list);
- drbg_string_fill(&S2, L_N, sizeof(L_N));
- list_add_tail(&S2.list, &bcc_list);
- list_splice_tail(seedlist, &bcc_list);
- drbg_string_fill(&S4, pad, padlen);
- list_add_tail(&S4.list, &bcc_list);
-
- /* 10.4.2 step 9 */
- while (templen < (keylen + (blocklen_bytes))) {
- /*
- * 10.4.2 step 9.1 - the padding is implicit as the buffer
- * holds zeros after allocation -- even the increment of i
- * is irrelevant as the increment remains within length of i
- */
- put_unaligned_be32(i, iv);
- /* 10.4.2 step 9.2 -- BCC and concatenation with temp */
- drbg_ctr_bcc(aeskey, temp + templen, K, &bcc_list,
- blocklen_bytes, keylen);
- /* 10.4.2 step 9.3 */
- i++;
- templen += blocklen_bytes;
- }
-
- /* 10.4.2 step 11 */
- X = temp + (keylen);
- drbg_string_fill(&cipherin, X, blocklen_bytes);
-
- /* 10.4.2 step 12: overwriting of outval is implemented in next step */
-
- /* 10.4.2 step 13 */
- aes_prepareenckey(aeskey, temp, keylen);
- while (generated_len < bytes_to_return) {
- short blocklen = 0;
- /*
- * 10.4.2 step 13.1: the truncation of the key length is
- * implicit as the key is only drbg_blocklen in size based on
- * the implementation of the cipher function callback
- */
- drbg_kcapi_sym(aeskey, X, &cipherin, blocklen_bytes);
- blocklen = (blocklen_bytes <
- (bytes_to_return - generated_len)) ?
- blocklen_bytes :
- (bytes_to_return - generated_len);
- /* 10.4.2 step 13.2 and 14 */
- memcpy(df_data + generated_len, X, blocklen);
- generated_len += blocklen;
- }
-
- memset(iv, 0, blocklen_bytes);
- memset(temp, 0, statelen + blocklen_bytes);
- memset(pad, 0, blocklen_bytes);
- return 0;
-}
-EXPORT_SYMBOL_GPL(crypto_drbg_ctr_df);
-
-MODULE_IMPORT_NS("CRYPTO_INTERNAL");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
-MODULE_DESCRIPTION("Derivation Function conformant to SP800-90A");
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 26194c33cb32..ad6427f08d4f 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -707,11 +707,11 @@ config CRYPTO_DEV_TEGRA
AES encryption/decryption and HASH algorithms.
config CRYPTO_DEV_XILINX_TRNG
tristate "Support for Xilinx True Random Generator"
depends on ZYNQMP_FIRMWARE || COMPILE_TEST
- select CRYPTO_DF80090A
+ select CRYPTO_LIB_SHA512
select HW_RANDOM
help
Xilinx Versal SoC driver provides kernel-side support for True Random Number
Generator and Pseudo random Number in CTR_DRBG mode as defined in NIST SP800-90A.
diff --git a/drivers/crypto/xilinx/xilinx-trng.c b/drivers/crypto/xilinx/xilinx-trng.c
index a30b0b3b3685..f615d5adddde 100644
--- a/drivers/crypto/xilinx/xilinx-trng.c
+++ b/drivers/crypto/xilinx/xilinx-trng.c
@@ -2,10 +2,11 @@
/*
* AMD Versal True Random Number Generator driver
* Copyright (c) 2024 - 2025 Advanced Micro Devices, Inc.
*/
+#include <crypto/sha2.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware/xlnx-zynqmp.h>
#include <linux/hw_random.h>
@@ -13,13 +14,10 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
-#include <crypto/aes.h>
-#include <crypto/df_sp80090a.h>
-#include <crypto/internal/cipher.h>
/* TRNG Registers Offsets */
#define TRNG_STATUS_OFFSET 0x4U
#define TRNG_CTRL_OFFSET 0x8U
#define TRNG_EXT_SEED_OFFSET 0x40U
@@ -41,11 +39,10 @@
#define TRNG_STATUS_QCNT_MASK GENMASK(11, 9)
#define TRNG_STATUS_QCNT_16_BYTES 0x800
/* Sizes in bytes */
#define TRNG_SEED_LEN_BYTES 48U
-#define TRNG_ENTROPY_SEED_LEN_BYTES 64U
#define TRNG_SEC_STRENGTH_SHIFT 5U
#define TRNG_SEC_STRENGTH_BYTES BIT(TRNG_SEC_STRENGTH_SHIFT)
#define TRNG_BYTES_PER_REG 4U
#define TRNG_RESET_DELAY 10
#define TRNG_NUM_INIT_REGS 12U
@@ -53,12 +50,10 @@
#define TRNG_DATA_READ_DELAY 8000
struct xilinx_rng {
void __iomem *rng_base;
struct device *dev;
- unsigned char *scratchpadbuf;
- struct aes_enckey *aeskey;
struct hwrng trng;
};
static void xtrng_readwrite32(void __iomem *addr, u32 mask, u8 value)
{
@@ -170,33 +165,34 @@ static void xtrng_enable_entropy(struct xilinx_rng *rng)
iowrite32(TRNG_CTRL_EUMODE_MASK | TRNG_CTRL_TRSSEN_MASK, rng->rng_base + TRNG_CTRL_OFFSET);
}
static int xtrng_reseed_internal(struct xilinx_rng *rng)
{
- u8 entropy[TRNG_ENTROPY_SEED_LEN_BYTES];
- struct drbg_string data;
- LIST_HEAD(seedlist);
+ static const u8 default_salt[SHA512_DIGEST_SIZE];
+ u8 entropy[SHA512_DIGEST_SIZE] __aligned(4);
u32 val;
int ret;
- drbg_string_fill(&data, entropy, TRNG_SEED_LEN_BYTES);
- list_add_tail(&data.list, &seedlist);
- memset(entropy, 0, sizeof(entropy));
xtrng_enable_entropy(rng);
- /* collect random data to use it as entropy (input for DF) */
+ /* Collect some output from the TRNG. */
+ static_assert(sizeof(entropy) >= TRNG_SEED_LEN_BYTES);
ret = xtrng_collect_random_data(rng, entropy, TRNG_SEED_LEN_BYTES, true);
if (ret != TRNG_SEED_LEN_BYTES)
return -EINVAL;
- ret = crypto_drbg_ctr_df(rng->aeskey, rng->scratchpadbuf,
- TRNG_SEED_LEN_BYTES, &seedlist, AES_BLOCK_SIZE,
- TRNG_SEED_LEN_BYTES);
- if (ret)
- return ret;
+ /* Extract entropy from the TRNG output using HKDF-SHA512-Extract. */
+ hmac_sha512_usingrawkey(default_salt, sizeof(default_salt), entropy,
+ TRNG_SEED_LEN_BYTES, entropy);
+
+ /* Write the extracted entropy to the hardware. */
xtrng_write_multiple_registers(rng->rng_base + TRNG_EXT_SEED_OFFSET,
- (u32 *)rng->scratchpadbuf, TRNG_NUM_INIT_REGS);
+ (u32 *)entropy, TRNG_NUM_INIT_REGS);
+
+ /* Clear the entropy from the stack. */
+ memzero_explicit(entropy, sizeof(entropy));
+
/* select reseed operation */
iowrite32(TRNG_CTRL_PRNGXS_MASK, rng->rng_base + TRNG_CTRL_OFFSET);
/* Start the reseed operation with above configuration and wait for STATUS.Done bit to be
* set. Monitor STATUS.CERTF bit, if set indicates SP800-90B entropy health test has failed.
@@ -276,11 +272,10 @@ static void xtrng_hwrng_unregister(struct hwrng *trng)
}
static int xtrng_probe(struct platform_device *pdev)
{
struct xilinx_rng *rng;
- size_t sb_size;
int ret;
rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
if (!rng)
return -ENOMEM;
@@ -290,19 +285,10 @@ static int xtrng_probe(struct platform_device *pdev)
if (IS_ERR(rng->rng_base)) {
dev_err(&pdev->dev, "Failed to map resource %pe\n", rng->rng_base);
return PTR_ERR(rng->rng_base);
}
- rng->aeskey = devm_kzalloc(&pdev->dev, sizeof(*rng->aeskey), GFP_KERNEL);
- if (!rng->aeskey)
- return -ENOMEM;
-
- sb_size = crypto_drbg_ctr_df_datalen(TRNG_SEED_LEN_BYTES, AES_BLOCK_SIZE);
- rng->scratchpadbuf = devm_kzalloc(&pdev->dev, sb_size, GFP_KERNEL);
- if (!rng->scratchpadbuf)
- return -ENOMEM;
-
xtrng_trng_reset(rng->rng_base);
ret = xtrng_reseed_internal(rng);
if (ret) {
dev_err(&pdev->dev, "TRNG Seed fail\n");
return ret;
diff --git a/include/crypto/df_sp80090a.h b/include/crypto/df_sp80090a.h
deleted file mode 100644
index e594fb718eb8..000000000000
--- a/include/crypto/df_sp80090a.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-/*
- * Copyright Stephan Mueller <smueller@chronox.de>, 2014
- */
-
-#ifndef _CRYPTO_DF80090A_H
-#define _CRYPTO_DF80090A_H
-
-#include <crypto/internal/cipher.h>
-#include <crypto/aes.h>
-#include <linux/list.h>
-
-/*
- * Concatenation Helper and string operation helper
- *
- * SP800-90A requires the concatenation of different data. To avoid copying
- * buffers around or allocate additional memory, the following data structure
- * is used to point to the original memory with its size. In addition, it
- * is used to build a linked list. The linked list defines the concatenation
- * of individual buffers. The order of memory block referenced in that
- * linked list determines the order of concatenation.
- */
-struct drbg_string {
- const unsigned char *buf;
- size_t len;
- struct list_head list;
-};
-
-static inline void drbg_string_fill(struct drbg_string *string,
- const unsigned char *buf, size_t len)
-{
- string->buf = buf;
- string->len = len;
- INIT_LIST_HEAD(&string->list);
-}
-
-static inline int crypto_drbg_ctr_df_datalen(u8 statelen, u8 blocklen)
-{
- return statelen + /* df_data */
- blocklen + /* pad */
- blocklen + /* iv */
- statelen + blocklen; /* temp */
-}
-
-int crypto_drbg_ctr_df(struct aes_enckey *aes,
- unsigned char *df_data,
- size_t bytes_to_return,
- struct list_head *seedlist,
- u8 blocklen_bytes,
- u8 statelen);
-
-#endif /* _CRYPTO_DF80090A_H */
--
2.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 4/4] hwrng: xilinx - Move xilinx-rng into drivers/char/hw_random/
2026-05-31 19:17 [PATCH 0/4] Xilinx TRNG fix and simplification Eric Biggers
` (2 preceding siblings ...)
2026-05-31 19:17 ` [PATCH 3/4] crypto: xilinx-trng - Replace crypto_drbg_ctr_df() with HMAC-SHA512 Eric Biggers
@ 2026-05-31 19:17 ` Eric Biggers
3 siblings, 0 replies; 5+ messages in thread
From: Eric Biggers @ 2026-05-31 19:17 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: linux-kernel, Mounika Botcha, Harsh Jain, Olivia Mackall,
Michal Simek, linux-arm-kernel, Eric Biggers
Since this file just implements a hwrng driver, move it into
drivers/char/hw_random/. Rename the kconfig option accordingly as well.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
MAINTAINERS | 2 +-
arch/arm64/configs/defconfig | 2 +-
drivers/char/hw_random/Kconfig | 11 +++++++++++
drivers/char/hw_random/Makefile | 1 +
.../{crypto/xilinx => char/hw_random}/xilinx-trng.c | 0
drivers/crypto/Kconfig | 12 ------------
drivers/crypto/xilinx/Makefile | 1 -
7 files changed, 14 insertions(+), 15 deletions(-)
rename drivers/{crypto/xilinx => char/hw_random}/xilinx-trng.c (100%)
diff --git a/MAINTAINERS b/MAINTAINERS
index 882214b0e7db..a593e78c30fc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -29218,11 +29218,11 @@ F: include/uapi/misc/xilinx_sdfec.h
XILINX TRNG DRIVER
M: Mounika Botcha <mounika.botcha@amd.com>
M: Harsh Jain <h.jain@amd.com>
S: Maintained
-F: drivers/crypto/xilinx/xilinx-trng.c
+F: drivers/char/hw_random/xilinx-trng.c
XILINX UARTLITE SERIAL DRIVER
M: Peter Korsgaard <jacmet@sunsite.dk>
L: linux-serial@vger.kernel.org
S: Maintained
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index bb930cce7233..d8fb11e4c36d 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -549,10 +549,11 @@ CONFIG_IPMI_HANDLER=m
CONFIG_IPMI_DEVICE_INTERFACE=m
CONFIG_IPMI_SI=m
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_VIRTIO=y
CONFIG_HW_RANDOM_QCOM=m
+CONFIG_HW_RANDOM_XILINX=m
CONFIG_TCG_TPM=y
CONFIG_TCG_TIS=m
CONFIG_TCG_TIS_SPI=m
CONFIG_TCG_TIS_SPI_CR50=y
CONFIG_TCG_TIS_I2C_CR50=m
@@ -1953,11 +1954,10 @@ CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
CONFIG_CRYPTO_DEV_SUN8I_CE=m
CONFIG_CRYPTO_DEV_FSL_CAAM=m
CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM=m
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_TEGRA=m
-CONFIG_CRYPTO_DEV_XILINX_TRNG=m
CONFIG_CRYPTO_DEV_ZYNQMP_AES=m
CONFIG_CRYPTO_DEV_ZYNQMP_SHA3=m
CONFIG_CRYPTO_DEV_CCREE=m
CONFIG_CRYPTO_DEV_HISI_SEC2=m
CONFIG_CRYPTO_DEV_HISI_ZIP=m
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 7102e03dcf0a..e0a53ba558a0 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -624,10 +624,21 @@ config HW_RANDOM_QCOM
Generator hardware found on some Qualcomm SoCs.
To compile this driver as a module, choose M here. The
module will be called qcom-rng. If unsure, say N.
+config HW_RANDOM_XILINX
+ tristate "Support for Xilinx True Random Generator"
+ depends on ZYNQMP_FIRMWARE || COMPILE_TEST
+ select CRYPTO_LIB_SHA512
+ help
+ Xilinx Versal SoC driver provides kernel-side support for True Random Number
+ Generator and Pseudo random Number in CTR_DRBG mode as defined in NIST SP800-90A.
+
+ To compile this driver as a module, choose M here: the module
+ will be called xilinx-trng.
+
endif # HW_RANDOM
config UML_RANDOM
depends on UML
select HW_RANDOM
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 605ba8df5a8f..470004ad841a 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -51,5 +51,6 @@ obj-$(CONFIG_HW_RANDOM_ARM_SMCCC_TRNG) += arm_smccc_trng.o
obj-$(CONFIG_HW_RANDOM_CN10K) += cn10k-rng.o
obj-$(CONFIG_HW_RANDOM_POLARFIRE_SOC) += mpfs-rng.o
obj-$(CONFIG_HW_RANDOM_ROCKCHIP) += rockchip-rng.o
obj-$(CONFIG_HW_RANDOM_JH7110) += jh7110-trng.o
obj-$(CONFIG_HW_RANDOM_QCOM) += qcom-rng.o
+obj-$(CONFIG_HW_RANDOM_XILINX) += xilinx-trng.o
diff --git a/drivers/crypto/xilinx/xilinx-trng.c b/drivers/char/hw_random/xilinx-trng.c
similarity index 100%
rename from drivers/crypto/xilinx/xilinx-trng.c
rename to drivers/char/hw_random/xilinx-trng.c
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index ad6427f08d4f..451d61b33143 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -704,22 +704,10 @@ config CRYPTO_DEV_TEGRA
help
Select this to enable Tegra Security Engine which accelerates various
AES encryption/decryption and HASH algorithms.
-config CRYPTO_DEV_XILINX_TRNG
- tristate "Support for Xilinx True Random Generator"
- depends on ZYNQMP_FIRMWARE || COMPILE_TEST
- select CRYPTO_LIB_SHA512
- select HW_RANDOM
- help
- Xilinx Versal SoC driver provides kernel-side support for True Random Number
- Generator and Pseudo random Number in CTR_DRBG mode as defined in NIST SP800-90A.
-
- To compile this driver as a module, choose M here: the module
- will be called xilinx-trng.
-
config CRYPTO_DEV_ZYNQMP_AES
tristate "Support for Xilinx ZynqMP AES hw accelerator"
depends on ZYNQMP_FIRMWARE || COMPILE_TEST
select CRYPTO_AES
select CRYPTO_ENGINE
diff --git a/drivers/crypto/xilinx/Makefile b/drivers/crypto/xilinx/Makefile
index 9b51636ef75e..730feff5b5f2 100644
--- a/drivers/crypto/xilinx/Makefile
+++ b/drivers/crypto/xilinx/Makefile
@@ -1,4 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_CRYPTO_DEV_XILINX_TRNG) += xilinx-trng.o
obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_AES) += zynqmp-aes-gcm.o
obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_SHA3) += zynqmp-sha.o
--
2.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-05-31 19:23 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-31 19:17 [PATCH 0/4] Xilinx TRNG fix and simplification Eric Biggers
2026-05-31 19:17 ` [PATCH 1/4] crypto: xilinx-trng - Remove crypto_rng interface Eric Biggers
2026-05-31 19:17 ` [PATCH 2/4] crypto: xilinx-trng - Fix return value of xtrng_hwrng_trng_read() Eric Biggers
2026-05-31 19:17 ` [PATCH 3/4] crypto: xilinx-trng - Replace crypto_drbg_ctr_df() with HMAC-SHA512 Eric Biggers
2026-05-31 19:17 ` [PATCH 4/4] hwrng: xilinx - Move xilinx-rng into drivers/char/hw_random/ Eric Biggers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox