History

crypto: drbg - reseed 'nopr' drbgs periodically from get_random_bytes()

In contrast to the fully prediction resistant 'pr' DRBGs, the 'nopr' variants get seeded once at boot and reseeded only rarely thereafter, namely only after 2^20 requests have been served each. AFAICT, this reseeding based on the number of requests served is primarily motivated by information theoretic considerations, c.f. NIST SP800-90Ar1, sec. 8.6.8 ("Reseeding"). However, given the relatively large seed lifetime of 2^20 requests, the 'nopr' DRBGs can hardly be considered to provide any prediction resistance whatsoever, i.e. to protect against threats like side channel leaks of the internal DRBG state (think e.g. leaked VM snapshots). This is expected and completely in line with the 'nopr' naming, but as e.g. the "drbg_nopr_hmac_sha512" implementation is potentially being used for providing the "stdrng" and thus, the crypto_default_rng serving the in-kernel crypto, it would certainly be desirable to achieve at least the same level of prediction resistance as get_random_bytes() does. Note that the chacha20 rngs underlying get_random_bytes() get reseeded every CRNG_RESEED_INTERVAL == 5min: the secondary, per-NUMA node rngs from the primary one and the primary rng in turn from the entropy pool, provided sufficient entropy is available. The 'nopr' DRBGs do draw randomness from get_random_bytes() for their initial seed already, so making them to reseed themselves periodically from get_random_bytes() in order to let them benefit from the latter's prediction resistance is not such a big change conceptually. In principle, it would have been also possible to make the 'nopr' DRBGs to periodically invoke a full reseeding operation, i.e. to also consider the jitterentropy source (if enabled) in addition to get_random_bytes() for the seed value. However, get_random_bytes() is relatively lightweight as compared to the jitterentropy generation process and thus, even though the 'nopr' reseeding is supposed to get invoked infrequently, it's IMO still worthwhile to avoid occasional latency spikes for drbg_generate() and stick to get_random_bytes() only. As an additional remark, note that drawing randomness from the non-SP800-90B-conforming get_random_bytes() only won't adversely affect SP800-90A conformance either: the very same is being done during boot via drbg_seed_from_random() already once rng_is_initialized() flips to true and it follows that if the DRBG implementation does conform to SP800-90A now, it will continue to do so. Make the 'nopr' DRBGs to reseed themselves periodically from get_random_bytes() every CRNG_RESEED_INTERVAL == 5min. More specifically, introduce a new member ->last_seed_time to struct drbg_state for recording in units of jiffies when the last seeding operation had taken place. Make __drbg_seed() maintain it and let drbg_generate() invoke a reseed from get_random_bytes() via drbg_seed_from_random() if more than 5min have passed by since the last seeding operation. Be careful to not to reseed if in testing mode though, or otherwise the drbg related tests in crypto/testmgr.c would fail to reproduce the expected output. In order to keep the formatting clean in drbg_generate() wrap the logic for deciding whether or not a reseed is due in a new helper, drbg_nopr_reseed_interval_elapsed().

Nicolai Stange committed 5 years ago

Commit 8ea5ee01 parent 559edd42 files · +26 −1Browse files

Unified · Split

2 files
  1. crypto/drbg.c +25 −1
  2. include/crypto/drbg.h +1 −0
crypto/drbg.c+25−1
@@ -100,6 +100,7 @@ · 99 unmodified lines
100#include <crypto/drbg.h>100#include <crypto/drbg.h>
101#include <crypto/internal/cipher.h>101#include <crypto/internal/cipher.h>
102#include <linux/kernel.h>102#include <linux/kernel.h>
103#include <linux/jiffies.h>
103 104
104/***************************************************************105/***************************************************************
105 * Backend cipher definitions available to DRBG106 * Backend cipher definitions available to DRBG
@@ -1044,6 +1045,7 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, · 938 unmodified lines
1044 return ret;1045 return ret;
1045 1046
1046 drbg->seeded = new_seed_state;1047 drbg->seeded = new_seed_state;
1048 drbg->last_seed_time = jiffies;
1047 /* 10.1.1.2 / 10.1.1.3 step 5 */1049 /* 10.1.1.2 / 10.1.1.3 step 5 */
1048 drbg->reseed_ctr = 1;1050 drbg->reseed_ctr = 1;
1049 1051
@@ -1112,6 +1114,26 @@ out: · 62 unmodified lines
1112 return ret;1114 return ret;
1113}1115}
1114 1116
1117static bool drbg_nopr_reseed_interval_elapsed(struct drbg_state *drbg)
1118{
1119 unsigned long next_reseed;
1120
1121 /* Don't ever reseed from get_random_bytes() in test mode. */
1122 if (list_empty(&drbg->test_data.list))
1123 return false;
1124
1125 /*
1126 * Obtain fresh entropy for the nopr DRBGs after 300s have
1127 * elapsed in order to still achieve sort of partial
1128 * prediction resistance over the time domain at least. Note
1129 * that the period of 300s has been chosen to match the
1130 * CRNG_RESEED_INTERVAL of the get_random_bytes()' chacha
1131 * rngs.
1132 */
1133 next_reseed = drbg->last_seed_time + 300 * HZ;
1134 return time_after(jiffies, next_reseed);
1135}
1136
1115/*1137/*
1116 * Seeding or reseeding of the DRBG1138 * Seeding or reseeding of the DRBG
1117 *1139 *
@@ -1413,7 +1435,8 @@ static int drbg_generate(struct drbg_state *drbg, · 295 unmodified lines
1413 /* 9.3.1 step 7.4 */1435 /* 9.3.1 step 7.4 */
1414 addtl = NULL;1436 addtl = NULL;
1415 } else if (rng_is_initialized() &&1437 } else if (rng_is_initialized() &&
1416 drbg->seeded == DRBG_SEED_STATE_PARTIAL) {1438 (drbg->seeded == DRBG_SEED_STATE_PARTIAL ||
1439 drbg_nopr_reseed_interval_elapsed(drbg))) {
1417 len = drbg_seed_from_random(drbg);1440 len = drbg_seed_from_random(drbg);
1418 if (len)1441 if (len)
1419 goto err;1442 goto err;
@@ -1569,6 +1592,7 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, · 149 unmodified lines
1569 drbg->core = &drbg_cores[coreref];1592 drbg->core = &drbg_cores[coreref];
1570 drbg->pr = pr;1593 drbg->pr = pr;
1571 drbg->seeded = DRBG_SEED_STATE_UNSEEDED;1594 drbg->seeded = DRBG_SEED_STATE_UNSEEDED;
1595 drbg->last_seed_time = 0;
1572 drbg->reseed_threshold = drbg_max_requests(drbg);1596 drbg->reseed_threshold = drbg_max_requests(drbg);
1573 1597
1574 ret = drbg_alloc_state(drbg);1598 ret = drbg_alloc_state(drbg);
include/crypto/drbg.h+1−0
@@ -134,6 +134,7 @@ struct drbg_state { · 133 unmodified lines
134 struct scatterlist sg_in, sg_out; /* CTR mode SGLs */134 struct scatterlist sg_in, sg_out; /* CTR mode SGLs */
135 135
136 enum drbg_seed_state seeded; /* DRBG fully seeded? */136 enum drbg_seed_state seeded; /* DRBG fully seeded? */
137 unsigned long last_seed_time;
137 bool pr; /* Prediction resistance enabled? */138 bool pr; /* Prediction resistance enabled? */
138 bool fips_primed; /* Continuous test primed? */139 bool fips_primed; /* Continuous test primed? */
139 unsigned char *prev; /* FIPS 140-2 continuous test value */140 unsigned char *prev; /* FIPS 140-2 continuous test value */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t