From: Herbert Xu Date: Mon, 20 Apr 2015 03:29:15 +0000 (+0800) Subject: crypto: drbg - Do not seed RNG in drbg_kcapi_init X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=2a57e4241ec9a11ce89f43099a0f6b83a28058fa;p=openwrt%2Fstaging%2Fblogic.git crypto: drbg - Do not seed RNG in drbg_kcapi_init Initialising the RNG in drbg_kcapi_init is a waste of precious entropy because all users will immediately seed the RNG after the allocation. In fact, all users should seed the RNG before using it. So there is no point in doing the seeding in drbg_kcapi_init. This patch removes the initial seeding and the user must seed the RNG explicitly (as they all currently do). This patch also changes drbg_kcapi_reset to allow reseeding. That is, if you call it after a successful initial seeding, then it will not reset the internal state of the DRBG before mixing the new input and entropy. If you still wish to reset the internal state, you can always free the DRBG and allocate a new one. Finally this patch removes locking from drbg_uninstantiate because it's now only called from the destruction path which must not be executed in parallel with normal operations. Signed-off-by: Herbert Xu Acked-by: Stephan Mueller --- diff --git a/crypto/drbg.c b/crypto/drbg.c index 57fd479b8f77..5bce15918de5 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1136,6 +1136,8 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) kzfree(drbg->scratchpad); drbg->scratchpad = NULL; drbg->reseed_ctr = 0; + drbg->d_ops = NULL; + drbg->core = NULL; #ifdef CONFIG_CRYPTO_FIPS kzfree(drbg->prev); drbg->prev = NULL; @@ -1152,6 +1154,27 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) int ret = -ENOMEM; unsigned int sb_size = 0; + switch (drbg->core->flags & DRBG_TYPE_MASK) { +#ifdef CONFIG_CRYPTO_DRBG_HMAC + case DRBG_HMAC: + drbg->d_ops = &drbg_hmac_ops; + break; +#endif /* CONFIG_CRYPTO_DRBG_HMAC */ +#ifdef CONFIG_CRYPTO_DRBG_HASH + case DRBG_HASH: + drbg->d_ops = &drbg_hash_ops; + break; +#endif /* CONFIG_CRYPTO_DRBG_HASH */ +#ifdef CONFIG_CRYPTO_DRBG_CTR + case DRBG_CTR: + drbg->d_ops = &drbg_ctr_ops; + break; +#endif /* CONFIG_CRYPTO_DRBG_CTR */ + default: + ret = -EOPNOTSUPP; + goto err; + } + drbg->V = kmalloc(drbg_statelen(drbg), GFP_KERNEL); if (!drbg->V) goto err; @@ -1215,6 +1238,10 @@ static int drbg_generate(struct drbg_state *drbg, int len = 0; LIST_HEAD(addtllist); + if (!drbg->core) { + pr_devel("DRBG: not yet seeded\n"); + return -EINVAL; + } if (0 == buflen || !buf) { pr_devel("DRBG: no output buffer provided\n"); return -EINVAL; @@ -1372,33 +1399,12 @@ static int drbg_generate_long(struct drbg_state *drbg, static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, int coreref, bool pr) { - int ret = -EOPNOTSUPP; + int ret; + bool reseed = true; pr_devel("DRBG: Initializing DRBG core %d with prediction resistance " "%s\n", coreref, pr ? "enabled" : "disabled"); mutex_lock(&drbg->drbg_mutex); - drbg->core = &drbg_cores[coreref]; - drbg->pr = pr; - drbg->seeded = false; - switch (drbg->core->flags & DRBG_TYPE_MASK) { -#ifdef CONFIG_CRYPTO_DRBG_HMAC - case DRBG_HMAC: - drbg->d_ops = &drbg_hmac_ops; - break; -#endif /* CONFIG_CRYPTO_DRBG_HMAC */ -#ifdef CONFIG_CRYPTO_DRBG_HASH - case DRBG_HASH: - drbg->d_ops = &drbg_hash_ops; - break; -#endif /* CONFIG_CRYPTO_DRBG_HASH */ -#ifdef CONFIG_CRYPTO_DRBG_CTR - case DRBG_CTR: - drbg->d_ops = &drbg_ctr_ops; - break; -#endif /* CONFIG_CRYPTO_DRBG_CTR */ - default: - goto unlock; - } /* 9.1 step 1 is implicit with the selected DRBG type */ @@ -1410,21 +1416,31 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, /* 9.1 step 4 is implicit in drbg_sec_strength */ - ret = drbg_alloc_state(drbg); - if (ret) - goto unlock; + if (!drbg->core) { + drbg->core = &drbg_cores[coreref]; + drbg->pr = pr; + drbg->seeded = false; - ret = -EFAULT; - if (drbg->d_ops->crypto_init(drbg)) - goto err; - ret = drbg_seed(drbg, pers, false); - if (ret) { + ret = drbg_alloc_state(drbg); + if (ret) + goto unlock; + + ret = -EFAULT; + if (drbg->d_ops->crypto_init(drbg)) + goto err; + + reseed = false; + } + + ret = drbg_seed(drbg, pers, reseed); + + if (ret && !reseed) { drbg->d_ops->crypto_fini(drbg); goto err; } mutex_unlock(&drbg->drbg_mutex); - return 0; + return ret; err: drbg_dealloc_state(drbg); @@ -1444,11 +1460,10 @@ unlock: */ static int drbg_uninstantiate(struct drbg_state *drbg) { - mutex_lock(&drbg->drbg_mutex); - drbg->d_ops->crypto_fini(drbg); + if (drbg->d_ops) + drbg->d_ops->crypto_fini(drbg); drbg_dealloc_state(drbg); /* no scrubbing of test_data -- this shall survive an uninstantiate */ - mutex_unlock(&drbg->drbg_mutex); return 0; } @@ -1615,16 +1630,10 @@ static inline void drbg_convert_tfm_core(const char *cra_driver_name, static int drbg_kcapi_init(struct crypto_tfm *tfm) { struct drbg_state *drbg = crypto_tfm_ctx(tfm); - bool pr = false; - int coreref = 0; mutex_init(&drbg->drbg_mutex); - drbg_convert_tfm_core(crypto_tfm_alg_driver_name(tfm), &coreref, &pr); - /* - * when personalization string is needed, the caller must call reset - * and provide the personalization string as seed information - */ - return drbg_instantiate(drbg, NULL, coreref, pr); + + return 0; } static void drbg_kcapi_cleanup(struct crypto_tfm *tfm) @@ -1665,10 +1674,9 @@ static int drbg_kcapi_random(struct crypto_rng *tfm, u8 *rdata, } /* - * Reset the DRBG invoked by the kernel crypto API - * The reset implies a full re-initialization of the DRBG. Similar to the - * generate function of drbg_kcapi_random, this function extends the - * kernel crypto API interface with struct drbg_gen + * Seed the DRBG invoked by the kernel crypto API + * Similar to the generate function of drbg_kcapi_random, this + * function extends the kernel crypto API interface with struct drbg_gen */ static int drbg_kcapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen) { @@ -1678,7 +1686,6 @@ static int drbg_kcapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen) struct drbg_string seed_string; int coreref = 0; - drbg_uninstantiate(drbg); drbg_convert_tfm_core(crypto_tfm_alg_driver_name(tfm_base), &coreref, &pr); if (0 < slen) {