summaryrefslogtreecommitdiff
path: root/lib/Crypto/Random/Fortuna/FortunaAccumulator.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Crypto/Random/Fortuna/FortunaAccumulator.py')
-rw-r--r--lib/Crypto/Random/Fortuna/FortunaAccumulator.py30
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