python3 update
This commit is contained in:
@@ -1,145 +0,0 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# FortunaAccumulator.py : Fortuna's internal accumulator
|
||||
#
|
||||
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||
#
|
||||
# ===================================================================
|
||||
# The contents of this file are dedicated to the public domain. To
|
||||
# the extent that dedication to the public domain is not available,
|
||||
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||
# non-exclusive license to exercise all rights associated with the
|
||||
# contents of this file for any purpose whatsoever.
|
||||
# No rights are reserved.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# ===================================================================
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import sys
|
||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
||||
from Crypto.Util.py21compat import *
|
||||
from Crypto.Util.py3compat import *
|
||||
|
||||
from binascii import b2a_hex
|
||||
import time
|
||||
import warnings
|
||||
|
||||
from Crypto.pct_warnings import ClockRewindWarning
|
||||
import SHAd256
|
||||
|
||||
import FortunaGenerator
|
||||
|
||||
class FortunaPool(object):
|
||||
"""Fortuna pool type
|
||||
|
||||
This object acts like a hash object, with the following differences:
|
||||
|
||||
- It keeps a count (the .length attribute) of the number of bytes that
|
||||
have been added to the pool
|
||||
- It supports a .reset() method for in-place reinitialization
|
||||
- The method to add bytes to the pool is .append(), not .update().
|
||||
"""
|
||||
|
||||
digest_size = SHAd256.digest_size
|
||||
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
|
||||
def append(self, data):
|
||||
self._h.update(data)
|
||||
self.length += len(data)
|
||||
|
||||
def digest(self):
|
||||
return self._h.digest()
|
||||
|
||||
def hexdigest(self):
|
||||
if sys.version_info[0] == 2:
|
||||
return b2a_hex(self.digest())
|
||||
else:
|
||||
return b2a_hex(self.digest()).decode()
|
||||
|
||||
def reset(self):
|
||||
self._h = SHAd256.new()
|
||||
self.length = 0
|
||||
|
||||
def which_pools(r):
|
||||
"""Return a list of pools indexes (in range(32)) that are to be included during reseed number r.
|
||||
|
||||
According to _Practical Cryptography_, chapter 10.5.2 "Pools":
|
||||
|
||||
"Pool P_i is included if 2**i is a divisor of r. Thus P_0 is used
|
||||
every reseed, P_1 every other reseed, P_2 every fourth reseed, etc."
|
||||
"""
|
||||
# This is a separate function so that it can be unit-tested.
|
||||
assert r >= 1
|
||||
retval = []
|
||||
mask = 0
|
||||
for i in range(32):
|
||||
# "Pool P_i is included if 2**i is a divisor of [reseed_count]"
|
||||
if (r & mask) == 0:
|
||||
retval.append(i)
|
||||
else:
|
||||
break # optimization. once this fails, it always fails
|
||||
mask = (mask << 1) | 1L
|
||||
return retval
|
||||
|
||||
class FortunaAccumulator(object):
|
||||
|
||||
min_pool_size = 64 # TODO: explain why
|
||||
reseed_interval = 0.100 # 100 ms TODO: explain why
|
||||
|
||||
def __init__(self):
|
||||
self.reseed_count = 0
|
||||
self.generator = FortunaGenerator.AESGenerator()
|
||||
self.last_reseed = None
|
||||
|
||||
# Initialize 32 FortunaPool instances.
|
||||
# NB: This is _not_ equivalent to [FortunaPool()]*32, which would give
|
||||
# us 32 references to the _same_ FortunaPool instance (and cause the
|
||||
# assertion below to fail).
|
||||
self.pools = [FortunaPool() for i in range(32)] # 32 pools
|
||||
assert(self.pools[0] is not self.pools[1])
|
||||
|
||||
def random_data(self, bytes):
|
||||
current_time = time.time()
|
||||
if (self.last_reseed is not None and self.last_reseed > current_time): # Avoid float comparison to None to make Py3k happy
|
||||
warnings.warn("Clock rewind detected. Resetting last_reseed.", ClockRewindWarning)
|
||||
self.last_reseed = None
|
||||
if (self.pools[0].length >= self.min_pool_size and
|
||||
(self.last_reseed is None or
|
||||
current_time > self.last_reseed + self.reseed_interval)):
|
||||
self._reseed(current_time)
|
||||
# The following should fail if we haven't seeded the pool yet.
|
||||
return self.generator.pseudo_random_data(bytes)
|
||||
|
||||
def _reseed(self, current_time=None):
|
||||
if current_time is None:
|
||||
current_time = time.time()
|
||||
seed = []
|
||||
self.reseed_count += 1
|
||||
self.last_reseed = current_time
|
||||
for i in which_pools(self.reseed_count):
|
||||
seed.append(self.pools[i].digest())
|
||||
self.pools[i].reset()
|
||||
|
||||
seed = b("").join(seed)
|
||||
self.generator.reseed(seed)
|
||||
|
||||
def add_random_event(self, source_number, pool_number, data):
|
||||
assert 1 <= len(data) <= 32
|
||||
assert 0 <= source_number <= 255
|
||||
assert 0 <= pool_number <= 31
|
||||
self.pools[pool_number].append(bchr(source_number))
|
||||
self.pools[pool_number].append(bchr(len(data)))
|
||||
self.pools[pool_number].append(data)
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
@@ -1,132 +0,0 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# FortunaGenerator.py : Fortuna's internal PRNG
|
||||
#
|
||||
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||
#
|
||||
# ===================================================================
|
||||
# The contents of this file are dedicated to the public domain. To
|
||||
# the extent that dedication to the public domain is not available,
|
||||
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||
# non-exclusive license to exercise all rights associated with the
|
||||
# contents of this file for any purpose whatsoever.
|
||||
# No rights are reserved.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# ===================================================================
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import sys
|
||||
if sys.version_info[0] is 2 and sys.version_info[1] is 1:
|
||||
from Crypto.Util.py21compat import *
|
||||
from Crypto.Util.py3compat import *
|
||||
|
||||
import struct
|
||||
|
||||
from Crypto.Util.number import ceil_shift, exact_log2, exact_div
|
||||
from Crypto.Util import Counter
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
import SHAd256
|
||||
|
||||
class AESGenerator(object):
|
||||
"""The Fortuna "generator"
|
||||
|
||||
This is used internally by the Fortuna PRNG to generate arbitrary amounts
|
||||
of pseudorandom data from a smaller amount of seed data.
|
||||
|
||||
The output is generated by running AES-256 in counter mode and re-keying
|
||||
after every mebibyte (2**16 blocks) of output.
|
||||
"""
|
||||
|
||||
block_size = AES.block_size # output block size in octets (128 bits)
|
||||
key_size = 32 # key size in octets (256 bits)
|
||||
|
||||
# Because of the birthday paradox, we expect to find approximately one
|
||||
# collision for every 2**64 blocks of output from a real random source.
|
||||
# However, this code generates pseudorandom data by running AES in
|
||||
# counter mode, so there will be no collisions until the counter
|
||||
# (theoretically) wraps around at 2**128 blocks. Thus, in order to prevent
|
||||
# Fortuna's pseudorandom output from deviating perceptibly from a true
|
||||
# random source, Ferguson and Schneier specify a limit of 2**16 blocks
|
||||
# without rekeying.
|
||||
max_blocks_per_request = 2**16 # Allow no more than this number of blocks per _pseudo_random_data request
|
||||
|
||||
_four_kiblocks_of_zeros = b("\0") * block_size * 4096
|
||||
|
||||
def __init__(self):
|
||||
self.counter = Counter.new(nbits=self.block_size*8, initial_value=0, little_endian=True)
|
||||
self.key = None
|
||||
|
||||
# Set some helper constants
|
||||
self.block_size_shift = exact_log2(self.block_size)
|
||||
assert (1 << self.block_size_shift) == self.block_size
|
||||
|
||||
self.blocks_per_key = exact_div(self.key_size, self.block_size)
|
||||
assert self.key_size == self.blocks_per_key * self.block_size
|
||||
|
||||
self.max_bytes_per_request = self.max_blocks_per_request * self.block_size
|
||||
|
||||
def reseed(self, seed):
|
||||
if self.key is None:
|
||||
self.key = b("\0") * self.key_size
|
||||
|
||||
self._set_key(SHAd256.new(self.key + seed).digest())
|
||||
self.counter() # increment counter
|
||||
assert len(self.key) == self.key_size
|
||||
|
||||
def pseudo_random_data(self, bytes):
|
||||
assert bytes >= 0
|
||||
|
||||
num_full_blocks = bytes >> 20
|
||||
remainder = bytes & ((1<<20)-1)
|
||||
|
||||
retval = []
|
||||
for i in xrange(num_full_blocks):
|
||||
retval.append(self._pseudo_random_data(1<<20))
|
||||
retval.append(self._pseudo_random_data(remainder))
|
||||
|
||||
return b("").join(retval)
|
||||
|
||||
def _set_key(self, key):
|
||||
self.key = key
|
||||
self._cipher = AES.new(key, AES.MODE_CTR, counter=self.counter)
|
||||
|
||||
def _pseudo_random_data(self, bytes):
|
||||
if not (0 <= bytes <= self.max_bytes_per_request):
|
||||
raise AssertionError("You cannot ask for more than 1 MiB of data per request")
|
||||
|
||||
num_blocks = ceil_shift(bytes, self.block_size_shift) # num_blocks = ceil(bytes / self.block_size)
|
||||
|
||||
# Compute the output
|
||||
retval = self._generate_blocks(num_blocks)[:bytes]
|
||||
|
||||
# Switch to a new key to avoid later compromises of this output (i.e.
|
||||
# state compromise extension attacks)
|
||||
self._set_key(self._generate_blocks(self.blocks_per_key))
|
||||
|
||||
assert len(retval) == bytes
|
||||
assert len(self.key) == self.key_size
|
||||
|
||||
return retval
|
||||
|
||||
def _generate_blocks(self, num_blocks):
|
||||
if self.key is None:
|
||||
raise AssertionError("generator must be seeded before use")
|
||||
assert 0 <= num_blocks <= self.max_blocks_per_request
|
||||
retval = []
|
||||
for i in xrange(num_blocks >> 12): # xrange(num_blocks / 4096)
|
||||
retval.append(self._cipher.encrypt(self._four_kiblocks_of_zeros))
|
||||
remaining_bytes = (num_blocks & 4095) << self.block_size_shift # (num_blocks % 4095) * self.block_size
|
||||
retval.append(self._cipher.encrypt(self._four_kiblocks_of_zeros[:remaining_bytes]))
|
||||
return b("").join(retval)
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
@@ -1,98 +0,0 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Random/Fortuna/SHAd256.py : SHA_d-256 hash function implementation
|
||||
#
|
||||
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||
#
|
||||
# ===================================================================
|
||||
# The contents of this file are dedicated to the public domain. To
|
||||
# the extent that dedication to the public domain is not available,
|
||||
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||
# non-exclusive license to exercise all rights associated with the
|
||||
# contents of this file for any purpose whatsoever.
|
||||
# No rights are reserved.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# ===================================================================
|
||||
|
||||
"""\
|
||||
SHA_d-256 hash function implementation.
|
||||
|
||||
This module should comply with PEP 247.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id$"
|
||||
__all__ = ['new', 'digest_size']
|
||||
|
||||
import sys
|
||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
||||
from Crypto.Util.py21compat import *
|
||||
from Crypto.Util.py3compat import *
|
||||
|
||||
from binascii import b2a_hex
|
||||
|
||||
from Crypto.Hash import SHA256
|
||||
|
||||
assert SHA256.digest_size == 32
|
||||
|
||||
class _SHAd256(object):
|
||||
"""SHA-256, doubled.
|
||||
|
||||
Returns SHA-256(SHA-256(data)).
|
||||
"""
|
||||
|
||||
digest_size = SHA256.digest_size
|
||||
|
||||
_internal = object()
|
||||
|
||||
def __init__(self, internal_api_check, sha256_hash_obj):
|
||||
if internal_api_check is not self._internal:
|
||||
raise AssertionError("Do not instantiate this class directly. Use %s.new()" % (__name__,))
|
||||
self._h = sha256_hash_obj
|
||||
|
||||
# PEP 247 "copy" method
|
||||
def copy(self):
|
||||
"""Return a copy of this hashing object"""
|
||||
return _SHAd256(SHAd256._internal, self._h.copy())
|
||||
|
||||
# PEP 247 "digest" method
|
||||
def digest(self):
|
||||
"""Return the hash value of this object as a binary string"""
|
||||
retval = SHA256.new(self._h.digest()).digest()
|
||||
assert len(retval) == 32
|
||||
return retval
|
||||
|
||||
# PEP 247 "hexdigest" method
|
||||
def hexdigest(self):
|
||||
"""Return the hash value of this object as a (lowercase) hexadecimal string"""
|
||||
retval = b2a_hex(self.digest())
|
||||
assert len(retval) == 64
|
||||
if sys.version_info[0] == 2:
|
||||
return retval
|
||||
else:
|
||||
return retval.decode()
|
||||
|
||||
# PEP 247 "update" method
|
||||
def update(self, data):
|
||||
self._h.update(data)
|
||||
|
||||
# PEP 247 module-level "digest_size" variable
|
||||
digest_size = _SHAd256.digest_size
|
||||
|
||||
# PEP 247 module-level "new" function
|
||||
def new(data=None):
|
||||
"""Return a new SHAd256 hashing object"""
|
||||
if not data:
|
||||
data=b("")
|
||||
sha = _SHAd256(_SHAd256._internal, SHA256.new(data))
|
||||
sha.new = globals()['new']
|
||||
return sha
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
@@ -1,40 +0,0 @@
|
||||
#
|
||||
# Random/OSRNG/__init__.py : Platform-independent OS RNG API
|
||||
#
|
||||
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||
#
|
||||
# ===================================================================
|
||||
# The contents of this file are dedicated to the public domain. To
|
||||
# the extent that dedication to the public domain is not available,
|
||||
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||
# non-exclusive license to exercise all rights associated with the
|
||||
# contents of this file for any purpose whatsoever.
|
||||
# No rights are reserved.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# ===================================================================
|
||||
|
||||
"""Provides a platform-independent interface to the random number generators
|
||||
supplied by various operating systems."""
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import os
|
||||
|
||||
if os.name == 'posix':
|
||||
from Crypto.Random.OSRNG.posix import new
|
||||
elif os.name == 'nt':
|
||||
from Crypto.Random.OSRNG.nt import new
|
||||
elif hasattr(os, 'urandom'):
|
||||
from Crypto.Random.OSRNG.fallback import new
|
||||
else:
|
||||
raise ImportError("Not implemented")
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
@@ -1,46 +0,0 @@
|
||||
#
|
||||
# Random/OSRNG/fallback.py : Fallback entropy source for systems with os.urandom
|
||||
#
|
||||
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||
#
|
||||
# ===================================================================
|
||||
# The contents of this file are dedicated to the public domain. To
|
||||
# the extent that dedication to the public domain is not available,
|
||||
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||
# non-exclusive license to exercise all rights associated with the
|
||||
# contents of this file for any purpose whatsoever.
|
||||
# No rights are reserved.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# ===================================================================
|
||||
|
||||
|
||||
__revision__ = "$Id$"
|
||||
__all__ = ['PythonOSURandomRNG']
|
||||
|
||||
import os
|
||||
|
||||
from rng_base import BaseRNG
|
||||
|
||||
class PythonOSURandomRNG(BaseRNG):
|
||||
|
||||
name = "<os.urandom>"
|
||||
|
||||
def __init__(self):
|
||||
self._read = os.urandom
|
||||
BaseRNG.__init__(self)
|
||||
|
||||
def _close(self):
|
||||
self._read = None
|
||||
|
||||
def new(*args, **kwargs):
|
||||
return PythonOSURandomRNG(*args, **kwargs)
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
@@ -1,74 +0,0 @@
|
||||
#
|
||||
# Random/OSRNG/nt.py : OS entropy source for MS Windows
|
||||
#
|
||||
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||
#
|
||||
# ===================================================================
|
||||
# The contents of this file are dedicated to the public domain. To
|
||||
# the extent that dedication to the public domain is not available,
|
||||
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||
# non-exclusive license to exercise all rights associated with the
|
||||
# contents of this file for any purpose whatsoever.
|
||||
# No rights are reserved.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# ===================================================================
|
||||
|
||||
|
||||
__revision__ = "$Id$"
|
||||
__all__ = ['WindowsRNG']
|
||||
|
||||
import winrandom
|
||||
from rng_base import BaseRNG
|
||||
|
||||
class WindowsRNG(BaseRNG):
|
||||
|
||||
name = "<CryptGenRandom>"
|
||||
|
||||
def __init__(self):
|
||||
self.__winrand = winrandom.new()
|
||||
BaseRNG.__init__(self)
|
||||
|
||||
def flush(self):
|
||||
"""Work around weakness in Windows RNG.
|
||||
|
||||
The CryptGenRandom mechanism in some versions of Windows allows an
|
||||
attacker to learn 128 KiB of past and future output. As a workaround,
|
||||
this function reads 128 KiB of 'random' data from Windows and discards
|
||||
it.
|
||||
|
||||
For more information about the weaknesses in CryptGenRandom, see
|
||||
_Cryptanalysis of the Random Number Generator of the Windows Operating
|
||||
System_, by Leo Dorrendorf and Zvi Gutterman and Benny Pinkas
|
||||
http://eprint.iacr.org/2007/419
|
||||
"""
|
||||
if self.closed:
|
||||
raise ValueError("I/O operation on closed file")
|
||||
data = self.__winrand.get_bytes(128*1024)
|
||||
assert (len(data) == 128*1024)
|
||||
BaseRNG.flush(self)
|
||||
|
||||
def _close(self):
|
||||
self.__winrand = None
|
||||
|
||||
def _read(self, N):
|
||||
# Unfortunately, research shows that CryptGenRandom doesn't provide
|
||||
# forward secrecy and fails the next-bit test unless we apply a
|
||||
# workaround, which we do here. See http://eprint.iacr.org/2007/419
|
||||
# for information on the vulnerability.
|
||||
self.flush()
|
||||
data = self.__winrand.get_bytes(N)
|
||||
self.flush()
|
||||
return data
|
||||
|
||||
def new(*args, **kwargs):
|
||||
return WindowsRNG(*args, **kwargs)
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
@@ -1,86 +0,0 @@
|
||||
#
|
||||
# Random/OSRNG/posix.py : OS entropy source for POSIX systems
|
||||
#
|
||||
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||
#
|
||||
# ===================================================================
|
||||
# The contents of this file are dedicated to the public domain. To
|
||||
# the extent that dedication to the public domain is not available,
|
||||
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||
# non-exclusive license to exercise all rights associated with the
|
||||
# contents of this file for any purpose whatsoever.
|
||||
# No rights are reserved.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# ===================================================================
|
||||
|
||||
|
||||
__revision__ = "$Id$"
|
||||
__all__ = ['DevURandomRNG']
|
||||
|
||||
import errno
|
||||
import os
|
||||
import stat
|
||||
|
||||
from rng_base import BaseRNG
|
||||
from Crypto.Util.py3compat import b
|
||||
|
||||
class DevURandomRNG(BaseRNG):
|
||||
|
||||
def __init__(self, devname=None):
|
||||
if devname is None:
|
||||
self.name = "/dev/urandom"
|
||||
else:
|
||||
self.name = devname
|
||||
|
||||
# Test that /dev/urandom is a character special device
|
||||
f = open(self.name, "rb", 0)
|
||||
fmode = os.fstat(f.fileno())[stat.ST_MODE]
|
||||
if not stat.S_ISCHR(fmode):
|
||||
f.close()
|
||||
raise TypeError("%r is not a character special device" % (self.name,))
|
||||
|
||||
self.__file = f
|
||||
|
||||
BaseRNG.__init__(self)
|
||||
|
||||
def _close(self):
|
||||
self.__file.close()
|
||||
|
||||
def _read(self, N):
|
||||
# Starting with Python 3 open with buffering=0 returns a FileIO object.
|
||||
# FileIO.read behaves like read(2) and not like fread(3) and thus we
|
||||
# have to handle the case that read returns less data as requested here
|
||||
# more carefully.
|
||||
data = b("")
|
||||
while len(data) < N:
|
||||
try:
|
||||
d = self.__file.read(N - len(data))
|
||||
except IOError, e:
|
||||
# read(2) has been interrupted by a signal; redo the read
|
||||
if e.errno == errno.EINTR:
|
||||
continue
|
||||
raise
|
||||
|
||||
if d is None:
|
||||
# __file is in non-blocking mode and no data is available
|
||||
return data
|
||||
if len(d) == 0:
|
||||
# __file is in blocking mode and arrived at EOF
|
||||
return data
|
||||
|
||||
data += d
|
||||
return data
|
||||
|
||||
def new(*args, **kwargs):
|
||||
return DevURandomRNG(*args, **kwargs)
|
||||
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
@@ -1,88 +0,0 @@
|
||||
#
|
||||
# Random/OSRNG/rng_base.py : Base class for OSRNG
|
||||
#
|
||||
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||
#
|
||||
# ===================================================================
|
||||
# The contents of this file are dedicated to the public domain. To
|
||||
# the extent that dedication to the public domain is not available,
|
||||
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||
# non-exclusive license to exercise all rights associated with the
|
||||
# contents of this file for any purpose whatsoever.
|
||||
# No rights are reserved.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# ===================================================================
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import sys
|
||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
||||
from Crypto.Util.py21compat import *
|
||||
|
||||
class BaseRNG(object):
|
||||
|
||||
def __init__(self):
|
||||
self.closed = False
|
||||
self._selftest()
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def _selftest(self):
|
||||
# Test that urandom can return data
|
||||
data = self.read(16)
|
||||
if len(data) != 16:
|
||||
raise AssertionError("read truncated")
|
||||
|
||||
# Test that we get different data every time (if we don't, the RNG is
|
||||
# probably malfunctioning)
|
||||
data2 = self.read(16)
|
||||
if data == data2:
|
||||
raise AssertionError("OS RNG returned duplicate data")
|
||||
|
||||
# PEP 343: Support for the "with" statement
|
||||
def __enter__(self):
|
||||
pass
|
||||
def __exit__(self):
|
||||
"""PEP 343 support"""
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
if not self.closed:
|
||||
self._close()
|
||||
self.closed = True
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
def read(self, N=-1):
|
||||
"""Return N bytes from the RNG."""
|
||||
if self.closed:
|
||||
raise ValueError("I/O operation on closed file")
|
||||
if not isinstance(N, (long, int)):
|
||||
raise TypeError("an integer is required")
|
||||
if N < 0:
|
||||
raise ValueError("cannot read to end of infinite stream")
|
||||
elif N == 0:
|
||||
return ""
|
||||
data = self._read(N)
|
||||
if len(data) != N:
|
||||
raise AssertionError("%s produced truncated output (requested %d, got %d)" % (self.name, N, len(data)))
|
||||
return data
|
||||
|
||||
def _close(self):
|
||||
raise NotImplementedError("child class must implement this")
|
||||
|
||||
def _read(self, N):
|
||||
raise NotImplementedError("child class must implement this")
|
||||
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
@@ -1,215 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Random/_UserFriendlyRNG.py : A user-friendly random number generator
|
||||
#
|
||||
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||
#
|
||||
# ===================================================================
|
||||
# The contents of this file are dedicated to the public domain. To
|
||||
# the extent that dedication to the public domain is not available,
|
||||
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||
# non-exclusive license to exercise all rights associated with the
|
||||
# contents of this file for any purpose whatsoever.
|
||||
# No rights are reserved.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# ===================================================================
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import sys
|
||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
||||
from Crypto.Util.py21compat import *
|
||||
|
||||
import os
|
||||
import threading
|
||||
import struct
|
||||
import time
|
||||
from math import floor
|
||||
|
||||
from Crypto.Random import OSRNG
|
||||
from Crypto.Random.Fortuna import FortunaAccumulator
|
||||
|
||||
class _EntropySource(object):
|
||||
def __init__(self, accumulator, src_num):
|
||||
self._fortuna = accumulator
|
||||
self._src_num = src_num
|
||||
self._pool_num = 0
|
||||
|
||||
def feed(self, data):
|
||||
self._fortuna.add_random_event(self._src_num, self._pool_num, data)
|
||||
self._pool_num = (self._pool_num + 1) & 31
|
||||
|
||||
class _EntropyCollector(object):
|
||||
|
||||
def __init__(self, accumulator):
|
||||
self._osrng = OSRNG.new()
|
||||
self._osrng_es = _EntropySource(accumulator, 255)
|
||||
self._time_es = _EntropySource(accumulator, 254)
|
||||
self._clock_es = _EntropySource(accumulator, 253)
|
||||
|
||||
def reinit(self):
|
||||
# Add 256 bits to each of the 32 pools, twice. (For a total of 16384
|
||||
# bits collected from the operating system.)
|
||||
for i in range(2):
|
||||
block = self._osrng.read(32*32)
|
||||
for p in range(32):
|
||||
self._osrng_es.feed(block[p*32:(p+1)*32])
|
||||
block = None
|
||||
self._osrng.flush()
|
||||
|
||||
def collect(self):
|
||||
# Collect 64 bits of entropy from the operating system and feed it to Fortuna.
|
||||
self._osrng_es.feed(self._osrng.read(8))
|
||||
|
||||
# Add the fractional part of time.time()
|
||||
t = time.time()
|
||||
self._time_es.feed(struct.pack("@I", int(2**30 * (t - floor(t)))))
|
||||
|
||||
# Add the fractional part of time.clock()
|
||||
t = time.clock()
|
||||
self._clock_es.feed(struct.pack("@I", int(2**30 * (t - floor(t)))))
|
||||
|
||||
|
||||
class _UserFriendlyRNG(object):
|
||||
|
||||
def __init__(self):
|
||||
self.closed = False
|
||||
self._fa = FortunaAccumulator.FortunaAccumulator()
|
||||
self._ec = _EntropyCollector(self._fa)
|
||||
self.reinit()
|
||||
|
||||
def reinit(self):
|
||||
"""Initialize the random number generator and seed it with entropy from
|
||||
the operating system.
|
||||
"""
|
||||
self._pid = os.getpid()
|
||||
self._ec.reinit()
|
||||
|
||||
def close(self):
|
||||
self.closed = True
|
||||
self._osrng = None
|
||||
self._fa = None
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
def read(self, N):
|
||||
"""Return N bytes from the RNG."""
|
||||
if self.closed:
|
||||
raise ValueError("I/O operation on closed file")
|
||||
if not isinstance(N, (long, int)):
|
||||
raise TypeError("an integer is required")
|
||||
if N < 0:
|
||||
raise ValueError("cannot read to end of infinite stream")
|
||||
|
||||
# Collect some entropy and feed it to Fortuna
|
||||
self._ec.collect()
|
||||
|
||||
# Ask Fortuna to generate some bytes
|
||||
retval = self._fa.random_data(N)
|
||||
|
||||
# Check that we haven't forked in the meantime. (If we have, we don't
|
||||
# want to use the data, because it might have been duplicated in the
|
||||
# parent process.
|
||||
self._check_pid()
|
||||
|
||||
# Return the random data.
|
||||
return retval
|
||||
|
||||
def _check_pid(self):
|
||||
# Lame fork detection to remind developers to invoke Random.atfork()
|
||||
# after every call to os.fork(). Note that this check is not reliable,
|
||||
# since process IDs can be reused on most operating systems.
|
||||
#
|
||||
# You need to do Random.atfork() in the child process after every call
|
||||
# to os.fork() to avoid reusing PRNG state. If you want to avoid
|
||||
# leaking PRNG state to child processes (for example, if you are using
|
||||
# os.setuid()) then you should also invoke Random.atfork() in the
|
||||
# *parent* process.
|
||||
if os.getpid() != self._pid:
|
||||
raise AssertionError("PID check failed. RNG must be re-initialized after fork(). Hint: Try Random.atfork()")
|
||||
|
||||
|
||||
class _LockingUserFriendlyRNG(_UserFriendlyRNG):
|
||||
def __init__(self):
|
||||
self._lock = threading.Lock()
|
||||
_UserFriendlyRNG.__init__(self)
|
||||
|
||||
def close(self):
|
||||
self._lock.acquire()
|
||||
try:
|
||||
return _UserFriendlyRNG.close(self)
|
||||
finally:
|
||||
self._lock.release()
|
||||
|
||||
def reinit(self):
|
||||
self._lock.acquire()
|
||||
try:
|
||||
return _UserFriendlyRNG.reinit(self)
|
||||
finally:
|
||||
self._lock.release()
|
||||
|
||||
def read(self, bytes):
|
||||
self._lock.acquire()
|
||||
try:
|
||||
return _UserFriendlyRNG.read(self, bytes)
|
||||
finally:
|
||||
self._lock.release()
|
||||
|
||||
class RNGFile(object):
|
||||
def __init__(self, singleton):
|
||||
self.closed = False
|
||||
self._singleton = singleton
|
||||
|
||||
# PEP 343: Support for the "with" statement
|
||||
def __enter__(self):
|
||||
"""PEP 343 support"""
|
||||
def __exit__(self):
|
||||
"""PEP 343 support"""
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
# Don't actually close the singleton, just close this RNGFile instance.
|
||||
self.closed = True
|
||||
self._singleton = None
|
||||
|
||||
def read(self, bytes):
|
||||
if self.closed:
|
||||
raise ValueError("I/O operation on closed file")
|
||||
return self._singleton.read(bytes)
|
||||
|
||||
def flush(self):
|
||||
if self.closed:
|
||||
raise ValueError("I/O operation on closed file")
|
||||
|
||||
_singleton_lock = threading.Lock()
|
||||
_singleton = None
|
||||
def _get_singleton():
|
||||
global _singleton
|
||||
_singleton_lock.acquire()
|
||||
try:
|
||||
if _singleton is None:
|
||||
_singleton = _LockingUserFriendlyRNG()
|
||||
return _singleton
|
||||
finally:
|
||||
_singleton_lock.release()
|
||||
|
||||
def new():
|
||||
return RNGFile(_get_singleton())
|
||||
|
||||
def reinit():
|
||||
_get_singleton().reinit()
|
||||
|
||||
def get_random_bytes(n):
|
||||
"""Return the specified number of cryptographically-strong random bytes."""
|
||||
return _get_singleton().read(n)
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
@@ -1,43 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Random/__init__.py : PyCrypto random number generation
|
||||
#
|
||||
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||
#
|
||||
# ===================================================================
|
||||
# The contents of this file are dedicated to the public domain. To
|
||||
# the extent that dedication to the public domain is not available,
|
||||
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||
# non-exclusive license to exercise all rights associated with the
|
||||
# contents of this file for any purpose whatsoever.
|
||||
# No rights are reserved.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# ===================================================================
|
||||
|
||||
__revision__ = "$Id$"
|
||||
__all__ = ['new']
|
||||
|
||||
from Crypto.Random import OSRNG
|
||||
from Crypto.Random import _UserFriendlyRNG
|
||||
|
||||
def new(*args, **kwargs):
|
||||
"""Return a file-like object that outputs cryptographically random bytes."""
|
||||
return _UserFriendlyRNG.new(*args, **kwargs)
|
||||
|
||||
def atfork():
|
||||
"""Call this whenever you call os.fork()"""
|
||||
_UserFriendlyRNG.reinit()
|
||||
|
||||
def get_random_bytes(n):
|
||||
"""Return the specified number of cryptographically-strong random bytes."""
|
||||
return _UserFriendlyRNG.get_random_bytes(n)
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
@@ -1,142 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Random/random.py : Strong alternative for the standard 'random' module
|
||||
#
|
||||
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||
#
|
||||
# ===================================================================
|
||||
# The contents of this file are dedicated to the public domain. To
|
||||
# the extent that dedication to the public domain is not available,
|
||||
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||
# non-exclusive license to exercise all rights associated with the
|
||||
# contents of this file for any purpose whatsoever.
|
||||
# No rights are reserved.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# ===================================================================
|
||||
|
||||
"""A cryptographically strong version of Python's standard "random" module."""
|
||||
|
||||
__revision__ = "$Id$"
|
||||
__all__ = ['StrongRandom', 'getrandbits', 'randrange', 'randint', 'choice', 'shuffle', 'sample']
|
||||
|
||||
from Crypto import Random
|
||||
import sys
|
||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
||||
from Crypto.Util.py21compat import *
|
||||
|
||||
class StrongRandom(object):
|
||||
def __init__(self, rng=None, randfunc=None):
|
||||
if randfunc is None and rng is None:
|
||||
self._randfunc = None
|
||||
elif randfunc is not None and rng is None:
|
||||
self._randfunc = randfunc
|
||||
elif randfunc is None and rng is not None:
|
||||
self._randfunc = rng.read
|
||||
else:
|
||||
raise ValueError("Cannot specify both 'rng' and 'randfunc'")
|
||||
|
||||
def getrandbits(self, k):
|
||||
"""Return a python long integer with k random bits."""
|
||||
if self._randfunc is None:
|
||||
self._randfunc = Random.new().read
|
||||
mask = (1L << k) - 1
|
||||
return mask & bytes_to_long(self._randfunc(ceil_div(k, 8)))
|
||||
|
||||
def randrange(self, *args):
|
||||
"""randrange([start,] stop[, step]):
|
||||
Return a randomly-selected element from range(start, stop, step)."""
|
||||
if len(args) == 3:
|
||||
(start, stop, step) = args
|
||||
elif len(args) == 2:
|
||||
(start, stop) = args
|
||||
step = 1
|
||||
elif len(args) == 1:
|
||||
(stop,) = args
|
||||
start = 0
|
||||
step = 1
|
||||
else:
|
||||
raise TypeError("randrange expected at most 3 arguments, got %d" % (len(args),))
|
||||
if (not isinstance(start, (int, long))
|
||||
or not isinstance(stop, (int, long))
|
||||
or not isinstance(step, (int, long))):
|
||||
raise TypeError("randrange requires integer arguments")
|
||||
if step == 0:
|
||||
raise ValueError("randrange step argument must not be zero")
|
||||
|
||||
num_choices = ceil_div(stop - start, step)
|
||||
if num_choices < 0:
|
||||
num_choices = 0
|
||||
if num_choices < 1:
|
||||
raise ValueError("empty range for randrange(%r, %r, %r)" % (start, stop, step))
|
||||
|
||||
# Pick a random number in the range of possible numbers
|
||||
r = num_choices
|
||||
while r >= num_choices:
|
||||
r = self.getrandbits(size(num_choices))
|
||||
|
||||
return start + (step * r)
|
||||
|
||||
def randint(self, a, b):
|
||||
"""Return a random integer N such that a <= N <= b."""
|
||||
if not isinstance(a, (int, long)) or not isinstance(b, (int, long)):
|
||||
raise TypeError("randint requires integer arguments")
|
||||
N = self.randrange(a, b+1)
|
||||
assert a <= N <= b
|
||||
return N
|
||||
|
||||
def choice(self, seq):
|
||||
"""Return a random element from a (non-empty) sequence.
|
||||
|
||||
If the seqence is empty, raises IndexError.
|
||||
"""
|
||||
if len(seq) == 0:
|
||||
raise IndexError("empty sequence")
|
||||
return seq[self.randrange(len(seq))]
|
||||
|
||||
def shuffle(self, x):
|
||||
"""Shuffle the sequence in place."""
|
||||
# Make a (copy) of the list of objects we want to shuffle
|
||||
items = list(x)
|
||||
|
||||
# Choose a random item (without replacement) until all the items have been
|
||||
# chosen.
|
||||
for i in xrange(len(x)):
|
||||
x[i] = items.pop(self.randrange(len(items)))
|
||||
|
||||
def sample(self, population, k):
|
||||
"""Return a k-length list of unique elements chosen from the population sequence."""
|
||||
|
||||
num_choices = len(population)
|
||||
if k > num_choices:
|
||||
raise ValueError("sample larger than population")
|
||||
|
||||
retval = []
|
||||
selected = {} # we emulate a set using a dict here
|
||||
for i in xrange(k):
|
||||
r = None
|
||||
while r is None or selected.has_key(r):
|
||||
r = self.randrange(num_choices)
|
||||
retval.append(population[r])
|
||||
selected[r] = 1
|
||||
return retval
|
||||
|
||||
_r = StrongRandom()
|
||||
getrandbits = _r.getrandbits
|
||||
randrange = _r.randrange
|
||||
randint = _r.randint
|
||||
choice = _r.choice
|
||||
shuffle = _r.shuffle
|
||||
sample = _r.sample
|
||||
|
||||
# These are at the bottom to avoid problems with recursive imports
|
||||
from Crypto.Util.number import ceil_div, bytes_to_long, long_to_bytes, size
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
Reference in New Issue
Block a user