]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
crypto: xilinx-trng - Add CTR_DRBG DF processing of seed
authorHarsh Jain <h.jain@amd.com>
Mon, 15 Sep 2025 13:30:27 +0000 (19:00 +0530)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 17 Oct 2025 08:03:57 +0000 (16:03 +0800)
Versal TRNG IP does not support Derivation Function (DF) of seed.
Add DF processing for CTR_DRBG mode.

Signed-off-by: Harsh Jain <h.jain@amd.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/xilinx/xilinx-trng.c

index 4e4700d68127dcf50518bdb2c1a6b40bb259b173..b89a2f70bf8213dc4633409abde0650f540770b4 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/clk.h>
 #include <linux/crypto.h>
 #include <linux/delay.h>
-#include <linux/errno.h>
 #include <linux/firmware/xlnx-zynqmp.h>
 #include <linux/hw_random.h>
 #include <linux/io.h>
 #include <linux/mutex.h>
 #include <linux/mod_devicetable.h>
 #include <linux/platform_device.h>
-#include <linux/string.h>
+#include <crypto/aes.h>
+#include <crypto/df_sp80090a.h>
+#include <crypto/internal/drbg.h>
 #include <crypto/internal/cipher.h>
 #include <crypto/internal/rng.h>
-#include <crypto/aes.h>
 
 /* TRNG Registers Offsets */
 #define TRNG_STATUS_OFFSET                     0x4U
@@ -59,6 +59,8 @@
 struct xilinx_rng {
        void __iomem *rng_base;
        struct device *dev;
+       unsigned char *scratchpadbuf;
+       struct crypto_aes_ctx *aesctx;
        struct mutex lock;      /* Protect access to TRNG device */
        struct hwrng trng;
 };
@@ -182,9 +184,13 @@ static void xtrng_enable_entropy(struct xilinx_rng *rng)
 static int xtrng_reseed_internal(struct xilinx_rng *rng)
 {
        u8 entropy[TRNG_ENTROPY_SEED_LEN_BYTES];
+       struct drbg_string data;
+       LIST_HEAD(seedlist);
        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);
 
@@ -192,9 +198,14 @@ static int xtrng_reseed_internal(struct xilinx_rng *rng)
        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->aesctx, rng->scratchpadbuf,
+                                TRNG_SEED_LEN_BYTES, &seedlist, AES_BLOCK_SIZE,
+                                TRNG_SEED_LEN_BYTES);
+       if (ret)
+               return ret;
 
        xtrng_write_multiple_registers(rng->rng_base + TRNG_EXT_SEED_OFFSET,
-                                      (u32 *)entropy, TRNG_NUM_INIT_REGS);
+                                      (u32 *)rng->scratchpadbuf, TRNG_NUM_INIT_REGS);
        /* select reseed operation */
        iowrite32(TRNG_CTRL_PRNGXS_MASK, rng->rng_base + TRNG_CTRL_OFFSET);
 
@@ -324,6 +335,7 @@ 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);
@@ -337,11 +349,22 @@ static int xtrng_probe(struct platform_device *pdev)
                return PTR_ERR(rng->rng_base);
        }
 
+       rng->aesctx = devm_kzalloc(&pdev->dev, sizeof(*rng->aesctx), GFP_KERNEL);
+       if (!rng->aesctx)
+               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;
+       }
+
        xtrng_trng_reset(rng->rng_base);
        ret = xtrng_reseed_internal(rng);
        if (ret) {
                dev_err(&pdev->dev, "TRNG Seed fail\n");
-               return ret;
+               goto end;
        }
 
        xilinx_rng_dev = rng;
@@ -349,8 +372,9 @@ static int xtrng_probe(struct platform_device *pdev)
        ret = crypto_register_rng(&xtrng_trng_alg);
        if (ret) {
                dev_err(&pdev->dev, "Crypto Random device registration failed: %d\n", ret);
-               return ret;
+               goto end;
        }
+
        ret = xtrng_hwrng_register(&rng->trng);
        if (ret) {
                dev_err(&pdev->dev, "HWRNG device registration failed: %d\n", ret);
@@ -363,6 +387,7 @@ static int xtrng_probe(struct platform_device *pdev)
 crypto_rng_free:
        crypto_unregister_rng(&xtrng_trng_alg);
 
+end:
        return ret;
 }