diff options
Diffstat (limited to 'lib/Crypto/Random/Fortuna/FortunaAccumulator.py')
-rw-r--r-- | lib/Crypto/Random/Fortuna/FortunaAccumulator.py | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/lib/Crypto/Random/Fortuna/FortunaAccumulator.py b/lib/Crypto/Random/Fortuna/FortunaAccumulator.py index 42e998c..5ffe825 100644 --- a/lib/Crypto/Random/Fortuna/FortunaAccumulator.py +++ b/lib/Crypto/Random/Fortuna/FortunaAccumulator.py @@ -97,8 +97,25 @@ def which_pools(r): class FortunaAccumulator(object): - min_pool_size = 64 # TODO: explain why - reseed_interval = 0.100 # 100 ms TODO: explain why + # An estimate of how many bytes we must append to pool 0 before it will + # contain 128 bits of entropy (with respect to an attack). We reseed the + # generator only after pool 0 contains `min_pool_size` bytes. Note that + # unlike with some other PRNGs, Fortuna's security does not rely on the + # accuracy of this estimate---we can accord to be optimistic here. + min_pool_size = 64 # size in bytes + + # If an attacker can predict some (but not all) of our entropy sources, the + # `min_pool_size` check may not be sufficient to prevent a successful state + # compromise extension attack. To resist this attack, Fortuna spreads the + # input across 32 pools, which are then consumed (to reseed the output + # generator) with exponentially decreasing frequency. + # + # In order to prevent an attacker from gaining knowledge of all 32 pools + # before we have a chance to fill them with enough information that the + # attacker cannot predict, we impose a rate limit of 10 reseeds/second (one + # per 100 ms). This ensures that a hypothetical 33rd pool would only be + # needed after a minimum of 13 years of sustained attack. + reseed_interval = 0.100 # time in seconds def __init__(self): self.reseed_count = 0 @@ -112,6 +129,15 @@ class FortunaAccumulator(object): self.pools = [FortunaPool() for i in range(32)] # 32 pools assert(self.pools[0] is not self.pools[1]) + def _forget_last_reseed(self): + # This is not part of the standard Fortuna definition, and using this + # function frequently can weaken Fortuna's ability to resist a state + # compromise extension attack, but we need this in order to properly + # implement Crypto.Random.atfork(). Otherwise, forked child processes + # might continue to use their parent's PRNG state for up to 100ms in + # some cases. (e.g. CVE-2013-1445) + self.last_reseed = None + def random_data(self, bytes): current_time = maybe_monotonic_time() if (self.last_reseed is not None and self.last_reseed > current_time): # Avoid float comparison to None to make Py3k happy |