@@ -294,10 +294,11 @@ 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 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 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,
@@ -306,28 +307,31 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg,
#define DRBG_OUTSCRATCHLEN 256
/* BCC function for CTR DRBG as defined in 10.4.3 */
-static int drbg_ctr_bcc(struct drbg_state *drbg,
+
+static int drbg_ctr_bcc(struct crypto_cipher *tfm,
unsigned char *out, const unsigned char *key,
- struct list_head *in)
+ 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, drbg_blocklen(drbg));
+ drbg_string_fill(&data, out, blocklen_bytes);
/* 10.4.3 step 2 / 4 */
- drbg_kcapi_symsetkey(drbg, key);
+ 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 (drbg_blocklen(drbg) == cnt) {
+ if (blocklen_bytes == cnt) {
cnt = 0;
- ret = drbg_kcapi_sym(drbg, out, &data);
+ ret = drbg_kcapi_sym(tfm, out, &data, blocklen_bytes);
if (ret)
return ret;
}
@@ -339,13 +343,13 @@ static int drbg_ctr_bcc(struct drbg_state *drbg,
}
/* 10.4.3 step 4.2 for last block */
if (cnt)
- ret = drbg_kcapi_sym(drbg, out, &data);
+ ret = drbg_kcapi_sym(tfm, out, &data, blocklen_bytes);
return ret;
}
/*
- * scratchpad usage: drbg_ctr_update is interlinked with drbg_ctr_df
+ * 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:
@@ -362,7 +366,7 @@ static int drbg_ctr_bcc(struct drbg_state *drbg,
* drbg_statelen(drbg) + drbg_blocklen(drbg)
* length: drbg_statelen(drbg)
*
- * drbg_ctr_df:
+ * crypto_drbg_ctr_df:
* pad
* start: df_data + drbg_statelen(drbg)
* length: drbg_blocklen(drbg)
@@ -381,21 +385,24 @@ static int drbg_ctr_bcc(struct drbg_state *drbg,
* 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 */
-static int drbg_ctr_df(struct drbg_state *drbg,
+int crypto_drbg_ctr_df(struct crypto_cipher *tfm,
unsigned char *df_data, size_t bytes_to_return,
- struct list_head *seedlist)
+ 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 + drbg_statelen(drbg);
- unsigned char *iv = pad + drbg_blocklen(drbg);
- unsigned char *temp = iv + drbg_blocklen(drbg);
+ 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 */
@@ -410,10 +417,11 @@ static int drbg_ctr_df(struct drbg_state *drbg,
size_t generated_len = 0;
size_t inputlen = 0;
struct drbg_string *seed = NULL;
+ u8 keylen;
- memset(pad, 0, drbg_blocklen(drbg));
- memset(iv, 0, drbg_blocklen(drbg));
-
+ 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 */
@@ -429,10 +437,10 @@ static int drbg_ctr_df(struct drbg_state *drbg,
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));
+ padlen = (inputlen + sizeof(L_N) + 1) % (blocklen_bytes);
/* wrap the padlen appropriately */
if (padlen)
- padlen = drbg_blocklen(drbg) - 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
@@ -442,7 +450,7 @@ static int drbg_ctr_df(struct drbg_state *drbg,
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));
+ 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);
@@ -451,7 +459,7 @@ static int drbg_ctr_df(struct drbg_state *drbg,
list_add_tail(&S4.list, &bcc_list);
/* 10.4.2 step 9 */
- while (templen < (drbg_keylen(drbg) + (drbg_blocklen(drbg)))) {
+ 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
@@ -459,22 +467,23 @@ static int drbg_ctr_df(struct drbg_state *drbg,
*/
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);
+ 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 += drbg_blocklen(drbg);
+ templen += blocklen_bytes;
}
/* 10.4.2 step 11 */
- X = temp + (drbg_keylen(drbg));
- drbg_string_fill(&cipherin, X, drbg_blocklen(drbg));
+ 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(drbg, temp);
+ drbg_kcapi_symsetkey(tfm, temp, keylen);
while (generated_len < bytes_to_return) {
short blocklen = 0;
/*
@@ -482,12 +491,12 @@ static int drbg_ctr_df(struct drbg_state *drbg,
* 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);
+ ret = drbg_kcapi_sym(tfm, X, &cipherin, blocklen_bytes);
if (ret)
goto out;
- blocklen = (drbg_blocklen(drbg) <
+ blocklen = (blocklen_bytes <
(bytes_to_return - generated_len)) ?
- drbg_blocklen(drbg) :
+ blocklen_bytes :
(bytes_to_return - generated_len);
/* 10.4.2 step 13.2 and 14 */
memcpy(df_data + generated_len, X, blocklen);
@@ -497,11 +506,12 @@ static int drbg_ctr_df(struct drbg_state *drbg,
ret = 0;
out:
- memset(iv, 0, drbg_blocklen(drbg));
- memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg));
- memset(pad, 0, drbg_blocklen(drbg));
+ 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);
/*
* update function of CTR DRBG as defined in 10.2.1.2
@@ -548,7 +558,9 @@ static int drbg_ctr_update(struct drbg_state *drbg, struct list_head *seed,
/* 10.2.1.3.2 step 2 and 10.2.1.4.2 step 2 */
if (seed) {
- ret = drbg_ctr_df(drbg, df_data, drbg_statelen(drbg), seed);
+ ret = crypto_drbg_ctr_df(drbg->priv_data, df_data, drbg_statelen(drbg), seed,
+ drbg_blocklen(drbg),
+ drbg_statelen(drbg));
if (ret)
goto out;
}
@@ -1310,10 +1322,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,21 +1810,17 @@ 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)
+static void drbg_kcapi_symsetkey(struct crypto_cipher *tfm,
+ const unsigned char *key, u8 keylen)
{
- struct crypto_cipher *tfm = drbg->priv_data;
-
- crypto_cipher_setkey(tfm, key, (drbg_keylen(drbg)));
+ crypto_cipher_setkey(tfm, key, keylen);
}
-static int drbg_kcapi_sym(struct drbg_state *drbg, unsigned char *outval,
- const struct drbg_string *in)
+static int drbg_kcapi_sym(struct crypto_cipher *tfm, unsigned char *outval,
+ const struct drbg_string *in, u8 blocklen_bytes)
{
- struct crypto_cipher *tfm = drbg->priv_data;
-
/* there is only component in *in */
- BUG_ON(in->len < drbg_blocklen(drbg));
+ BUG_ON(in->len < blocklen_bytes);
crypto_cipher_encrypt_one(tfm, outval, in->buf);
return 0;
}
@@ -714,6 +714,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_DRBG_CTR
select CRYPTO_RNG
select HW_RANDOM
help
@@ -57,6 +57,8 @@
struct xilinx_rng {
void __iomem *rng_base;
struct device *dev;
+ unsigned char *scratchpadbuf;
+ struct crypto_cipher *tfm;
struct mutex lock; /* Protect access to TRNG device */
struct hwrng trng;
};
@@ -195,9 +197,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->tfm, 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);
@@ -327,6 +334,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);
@@ -340,6 +348,19 @@ static int xtrng_probe(struct platform_device *pdev)
return PTR_ERR(rng->rng_base);
}
+ rng->tfm = crypto_alloc_cipher("aes", 0, 0);
+ if (IS_ERR(rng->tfm)) {
+ pr_info("DRBG: could not allocate cipher TFM handle:\n");
+ return PTR_ERR(rng->tfm);
+ }
+
+ 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 cipher_cleanup;
+ }
+
xtrng_trng_reset(rng->rng_base);
ret = xtrng_reseed_internal(rng);
if (ret) {
@@ -352,8 +373,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 cipher_cleanup;
}
+
ret = xtrng_hwrng_register(&rng->trng);
if (ret) {
dev_err(&pdev->dev, "HWRNG device registration failed: %d\n", ret);
@@ -366,6 +388,9 @@ static int xtrng_probe(struct platform_device *pdev)
crypto_rng_free:
crypto_unregister_rng(&xtrng_trng_alg);
+cipher_cleanup:
+ crypto_free_cipher(rng->tfm);
+
return ret;
}
@@ -377,6 +402,7 @@ static void xtrng_remove(struct platform_device *pdev)
rng = platform_get_drvdata(pdev);
xtrng_hwrng_unregister(&rng->trng);
crypto_unregister_rng(&xtrng_trng_alg);
+ crypto_free_cipher(rng->tfm);
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,
@@ -53,6 +53,7 @@
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/workqueue.h>
+#include <crypto/internal/cipher.h>
/*
* Concatenation Helper and string operation helper
@@ -264,6 +265,14 @@ static inline int crypto_drbg_reset_test(struct crypto_rng *drng,
return crypto_rng_reset(drng, pers->buf, pers->len);
}
+static inline int crypto_drbg_ctr_df_datalen(u8 statelen, u8 blocklen)
+{
+ return statelen + /* df_data */
+ blocklen + /* pad */
+ blocklen + /* iv */
+ statelen + blocklen; /* temp */
+}
+
/* DRBG type flags */
#define DRBG_CTR ((drbg_flag_t)1<<0)
#define DRBG_HMAC ((drbg_flag_t)1<<1)
@@ -283,4 +292,10 @@ enum drbg_prefixes {
DRBG_PREFIX3
};
+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 /* _DRBG_H */
Export drbg_ctr_df() derivative function to re-use it in xilinx trng driver. Changes has been tested by enabling CONFIG_CRYPTO_USER_API_RNG_CAVP Signed-off-by: Harsh Jain <h.jain@amd.com> --- crypto/drbg.c | 108 +++++++++++++++------------- drivers/crypto/Kconfig | 1 + drivers/crypto/xilinx/xilinx-trng.c | 30 +++++++- include/crypto/drbg.h | 15 ++++ 4 files changed, 101 insertions(+), 53 deletions(-)