]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
crypto: drbg - Export CTR DRBG DF functions
authorHarsh Jain <h.jain@amd.com>
Mon, 15 Sep 2025 13:30:25 +0000 (19:00 +0530)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 17 Oct 2025 08:03:57 +0000 (16:03 +0800)
Export drbg_ctr_df() derivative function to new module df_sp80090.

Signed-off-by: Harsh Jain <h.jain@amd.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/Kconfig
crypto/Makefile
crypto/df_sp80090a.c [new file with mode: 0644]
crypto/drbg.c
drivers/crypto/Kconfig
include/crypto/df_sp80090a.h [new file with mode: 0644]
include/crypto/drbg.h
include/crypto/internal/drbg.h [new file with mode: 0644]

index a04595f9d0ca4b4c54a787cc58b8f6ef80f68dea..b9afd8505b89c312a8b3dd519bc7e8346a498b4e 100644 (file)
@@ -1205,8 +1205,7 @@ config CRYPTO_DRBG_HASH
 
 config CRYPTO_DRBG_CTR
        bool "CTR_DRBG"
-       select CRYPTO_AES
-       select CRYPTO_CTR
+       select CRYPTO_DF80090A
        help
          CTR_DRBG variant as defined in NIST SP800-90A.
 
@@ -1342,6 +1341,11 @@ config CRYPTO_KDF800108_CTR
        select CRYPTO_HMAC
        select CRYPTO_SHA256
 
+config CRYPTO_DF80090A
+       tristate
+       select CRYPTO_AES
+       select CRYPTO_CTR
+
 endmenu
 menu "Userspace interface"
 
index e430e6e99b6a24029f2ff298338e1be1e9d4f085..c47f2bf5db61a64aad2124148f806b110180a8b3 100644 (file)
@@ -209,4 +209,6 @@ obj-$(CONFIG_CRYPTO_SIMD) += crypto_simd.o
 #
 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
new file mode 100644 (file)
index 0000000..8309e62
--- /dev/null
@@ -0,0 +1,247 @@
+// 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 <crypto/df_sp80090a.h>
+#include <crypto/internal/drbg.h>
+
+static void drbg_kcapi_symsetkey(struct crypto_cipher *tfm,
+                                const unsigned char *key,
+                                u8 keylen);
+static int drbg_kcapi_sym(struct crypto_cipher *tfm, unsigned char *outval,
+                         const struct drbg_string *in, u8 blocklen_bytes);
+
+static void drbg_kcapi_symsetkey(struct crypto_cipher *tfm,
+                                const unsigned char *key, u8 keylen)
+{
+       crypto_cipher_setkey(tfm, key, keylen);
+}
+
+static int drbg_kcapi_sym(struct crypto_cipher *tfm, unsigned char *outval,
+                         const struct drbg_string *in, u8 blocklen_bytes)
+{
+       /* there is only component in *in */
+       BUG_ON(in->len < blocklen_bytes);
+       crypto_cipher_encrypt_one(tfm, outval, in->buf);
+       return 0;
+}
+
+/* BCC function for CTR DRBG as defined in 10.4.3 */
+
+static int drbg_ctr_bcc(struct crypto_cipher *tfm,
+                       unsigned char *out, const unsigned char *key,
+                       struct list_head *in,
+                       u8 blocklen_bytes,
+                       u8 keylen)
+{
+       int ret = 0;
+       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 */
+       drbg_kcapi_symsetkey(tfm, 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;
+                               ret = drbg_kcapi_sym(tfm, out, &data, blocklen_bytes);
+                               if (ret)
+                                       return ret;
+                       }
+                       out[cnt] ^= *pos;
+                       pos++;
+                       cnt++;
+                       len--;
+               }
+       }
+       /* 10.4.3 step 4.2 for last block */
+       if (cnt)
+               ret = drbg_kcapi_sym(tfm, out, &data, blocklen_bytes);
+
+       return ret;
+}
+
+/*
+ * 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 crypto_cipher *tfm,
+                      unsigned char *df_data, size_t bytes_to_return,
+                      struct list_head *seedlist,
+                      u8 blocklen_bytes,
+                      u8 statelen)
+{
+       int ret = -EFAULT;
+       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;
+       drbg_cpu_to_be32(inputlen, &L_N[0]);
+
+       /* 10.4.2 step 3 */
+       drbg_cpu_to_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
+                */
+               drbg_cpu_to_be32(i, iv);
+               /* 10.4.2 step 9.2 -- BCC and concatenation with temp */
+               ret = drbg_ctr_bcc(tfm, temp + templen, K, &bcc_list,
+                                  blocklen_bytes, keylen);
+               if (ret)
+                       goto out;
+               /* 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 */
+       drbg_kcapi_symsetkey(tfm, 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
+                */
+               ret = drbg_kcapi_sym(tfm, X, &cipherin, blocklen_bytes);
+               if (ret)
+                       goto out;
+               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;
+       }
+
+       ret = 0;
+
+out:
+       memset(iv, 0, blocklen_bytes);
+       memset(temp, 0, statelen + blocklen_bytes);
+       memset(pad, 0, blocklen_bytes);
+       return ret;
+}
+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");
index dbe4c8bb5ceb73ba4a9d49066b926dee2e429e26..bad005eef03d62e2ecc75d251b4c20d962a295aa 100644 (file)
@@ -98,6 +98,7 @@
  */
 
 #include <crypto/drbg.h>
+#include <crypto/df_sp80090a.h>
 #include <crypto/internal/cipher.h>
 #include <linux/kernel.h>
 #include <linux/jiffies.h>
@@ -261,26 +262,6 @@ static int drbg_fips_continuous_test(struct drbg_state *drbg,
        return 0;
 }
 
-/*
- * Convert an integer into a byte representation of this integer.
- * The byte representation is big-endian
- *
- * @val value to be converted
- * @buf buffer holding the converted integer -- caller must ensure that
- *      buffer size is at least 32 bit
- */
-#if (defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_CTR))
-static inline void drbg_cpu_to_be32(__u32 val, unsigned char *buf)
-{
-       struct s {
-               __be32 conv;
-       };
-       struct s *conversion = (struct s *) buf;
-
-       conversion->conv = cpu_to_be32(val);
-}
-#endif /* defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_CTR) */
-
 /******************************************************************
  * CTR DRBG callback functions
  ******************************************************************/
@@ -294,10 +275,6 @@ MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes192");
 MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes128");
 MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes128");
 
-static void drbg_kcapi_symsetkey(struct drbg_state *drbg,
-                                const unsigned char *key);
-static int drbg_kcapi_sym(struct drbg_state *drbg, unsigned char *outval,
-                         const struct drbg_string *in);
 static int drbg_init_sym_kernel(struct drbg_state *drbg);
 static int drbg_fini_sym_kernel(struct drbg_state *drbg);
 static int drbg_kcapi_sym_ctr(struct drbg_state *drbg,
@@ -305,202 +282,12 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg,
                              u8 *outbuf, u32 outlen);
 #define DRBG_OUTSCRATCHLEN 256
 
-/* BCC function for CTR DRBG as defined in 10.4.3 */
-static int drbg_ctr_bcc(struct drbg_state *drbg,
-                       unsigned char *out, const unsigned char *key,
-                       struct list_head *in)
-{
-       int ret = 0;
-       struct drbg_string *curr = NULL;
-       struct drbg_string data;
-       short cnt = 0;
-
-       drbg_string_fill(&data, out, drbg_blocklen(drbg));
-
-       /* 10.4.3 step 2 / 4 */
-       drbg_kcapi_symsetkey(drbg, key);
-       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 (drbg_blocklen(drbg) == cnt) {
-                               cnt = 0;
-                               ret = drbg_kcapi_sym(drbg, out, &data);
-                               if (ret)
-                                       return ret;
-                       }
-                       out[cnt] ^= *pos;
-                       pos++;
-                       cnt++;
-                       len--;
-               }
-       }
-       /* 10.4.3 step 4.2 for last block */
-       if (cnt)
-               ret = drbg_kcapi_sym(drbg, out, &data);
-
-       return ret;
-}
-
-/*
- * scratchpad usage: drbg_ctr_update is interlinked with 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)
- *
- * 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.
- */
-
-/* Derivation Function for CTR DRBG as defined in 10.4.2 */
 static int drbg_ctr_df(struct drbg_state *drbg,
                       unsigned char *df_data, size_t bytes_to_return,
                       struct list_head *seedlist)
 {
-       int ret = -EFAULT;
-       unsigned char L_N[8];
-       /* S3 is input */
-       struct drbg_string S1, S2, S4, cipherin;
-       LIST_HEAD(bcc_list);
-       unsigned char *pad = df_data + drbg_statelen(drbg);
-       unsigned char *iv = pad + drbg_blocklen(drbg);
-       unsigned char *temp = iv + drbg_blocklen(drbg);
-       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;
-
-       memset(pad, 0, drbg_blocklen(drbg));
-       memset(iv, 0, drbg_blocklen(drbg));
-
-       /* 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;
-       drbg_cpu_to_be32(inputlen, &L_N[0]);
-
-       /* 10.4.2 step 3 */
-       drbg_cpu_to_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) % (drbg_blocklen(drbg));
-       /* wrap the padlen appropriately */
-       if (padlen)
-               padlen = drbg_blocklen(drbg) - 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, drbg_blocklen(drbg));
-       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 < (drbg_keylen(drbg) + (drbg_blocklen(drbg)))) {
-               /*
-                * 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
-                */
-               drbg_cpu_to_be32(i, iv);
-               /* 10.4.2 step 9.2 -- BCC and concatenation with temp */
-               ret = drbg_ctr_bcc(drbg, temp + templen, K, &bcc_list);
-               if (ret)
-                       goto out;
-               /* 10.4.2 step 9.3 */
-               i++;
-               templen += drbg_blocklen(drbg);
-       }
-
-       /* 10.4.2 step 11 */
-       X = temp + (drbg_keylen(drbg));
-       drbg_string_fill(&cipherin, X, drbg_blocklen(drbg));
-
-       /* 10.4.2 step 12: overwriting of outval is implemented in next step */
-
-       /* 10.4.2 step 13 */
-       drbg_kcapi_symsetkey(drbg, temp);
-       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
-                */
-               ret = drbg_kcapi_sym(drbg, X, &cipherin);
-               if (ret)
-                       goto out;
-               blocklen = (drbg_blocklen(drbg) <
-                               (bytes_to_return - generated_len)) ?
-                           drbg_blocklen(drbg) :
-                               (bytes_to_return - generated_len);
-               /* 10.4.2 step 13.2 and 14 */
-               memcpy(df_data + generated_len, X, blocklen);
-               generated_len += blocklen;
-       }
-
-       ret = 0;
-
-out:
-       memset(iv, 0, drbg_blocklen(drbg));
-       memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg));
-       memset(pad, 0, drbg_blocklen(drbg));
-       return ret;
+       return crypto_drbg_ctr_df(drbg->priv_data, df_data, drbg_statelen(drbg),
+                                 seedlist, drbg_blocklen(drbg), drbg_statelen(drbg));
 }
 
 /*
@@ -1310,10 +1097,8 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
                sb_size = 0;
        else if (drbg->core->flags & DRBG_CTR)
                sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg) + /* temp */
-                         drbg_statelen(drbg) + /* df_data */
-                         drbg_blocklen(drbg) + /* pad */
-                         drbg_blocklen(drbg) + /* iv */
-                         drbg_statelen(drbg) + drbg_blocklen(drbg); /* temp */
+                         crypto_drbg_ctr_df_datalen(drbg_statelen(drbg),
+                                                    drbg_blocklen(drbg));
        else
                sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg);
 
@@ -1800,25 +1585,6 @@ static int drbg_init_sym_kernel(struct drbg_state *drbg)
        return alignmask;
 }
 
-static void drbg_kcapi_symsetkey(struct drbg_state *drbg,
-                                const unsigned char *key)
-{
-       struct crypto_cipher *tfm = drbg->priv_data;
-
-       crypto_cipher_setkey(tfm, key, (drbg_keylen(drbg)));
-}
-
-static int drbg_kcapi_sym(struct drbg_state *drbg, unsigned char *outval,
-                         const struct drbg_string *in)
-{
-       struct crypto_cipher *tfm = drbg->priv_data;
-
-       /* there is only component in *in */
-       BUG_ON(in->len < drbg_blocklen(drbg));
-       crypto_cipher_encrypt_one(tfm, outval, in->buf);
-       return 0;
-}
-
 static int drbg_kcapi_sym_ctr(struct drbg_state *drbg,
                              u8 *inbuf, u32 inlen,
                              u8 *outbuf, u32 outlen)
index a6688d54984c4d26c6273a06d7e13587ce128530..8d3b5d2890f8b72e096efb30821883287f70aee9 100644 (file)
@@ -728,6 +728,7 @@ 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
diff --git a/include/crypto/df_sp80090a.h b/include/crypto/df_sp80090a.h
new file mode 100644 (file)
index 0000000..1828655
--- /dev/null
@@ -0,0 +1,27 @@
+/* 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>
+
+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 crypto_cipher *tfm,
+                      unsigned char *df_data,
+                      size_t bytes_to_return,
+                      struct list_head *seedlist,
+                      u8 blocklen_bytes,
+                      u8 statelen);
+
+#endif /* _CRYPTO_DF80090A_H */
index af5ad51d3eef81212a55fb7e41a668b62435e142..2d42518cbdce8061d4f4f9bffff62c96e99381ba 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/module.h>
 #include <linux/crypto.h>
 #include <linux/slab.h>
+#include <crypto/internal/drbg.h>
 #include <crypto/internal/rng.h>
 #include <crypto/rng.h>
 #include <linux/fips.h>
 #include <linux/list.h>
 #include <linux/workqueue.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);
-}
-
 struct drbg_state;
 typedef uint32_t drbg_flag_t;
 
diff --git a/include/crypto/internal/drbg.h b/include/crypto/internal/drbg.h
new file mode 100644 (file)
index 0000000..371e52d
--- /dev/null
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * NIST SP800-90A DRBG derivation function
+ *
+ * Copyright (C) 2014, Stephan Mueller <smueller@chronox.de>
+ */
+
+#ifndef _INTERNAL_DRBG_H
+#define _INTERNAL_DRBG_H
+
+/*
+ * Convert an integer into a byte representation of this integer.
+ * The byte representation is big-endian
+ *
+ * @val value to be converted
+ * @buf buffer holding the converted integer -- caller must ensure that
+ *      buffer size is at least 32 bit
+ */
+static inline void drbg_cpu_to_be32(__u32 val, unsigned char *buf)
+{
+       struct s {
+               __be32 conv;
+       };
+       struct s *conversion = (struct s *)buf;
+
+       conversion->conv = cpu_to_be32(val);
+}
+
+/*
+ * 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);
+}
+
+#endif //_INTERNAL_DRBG_H