You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1791 lines
61 KiB
1791 lines
61 KiB
6 years ago
|
--- lib/Crypto/Random/__init__.py
|
||
|
+++ lib/Crypto/Random/__init__.py
|
||
|
@@ -2,8 +2,6 @@
|
||
|
#
|
||
|
# 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,
|
||
|
@@ -22,22 +20,38 @@
|
||
|
# SOFTWARE.
|
||
|
# ===================================================================
|
||
|
|
||
|
-__revision__ = "$Id$"
|
||
|
-__all__ = ['new']
|
||
|
+__all__ = ['new', 'get_random_bytes']
|
||
|
+
|
||
|
+from os import urandom
|
||
|
+
|
||
|
+class _UrandomRNG(object):
|
||
|
+
|
||
|
+ def read(self, n):
|
||
|
+ """Return a random byte string of the desired size."""
|
||
|
+ return urandom(n)
|
||
|
+
|
||
|
+ def flush(self):
|
||
|
+ """Method provided for backward compatibility only."""
|
||
|
+ pass
|
||
|
+
|
||
|
+ def reinit(self):
|
||
|
+ """Method provided for backward compatibility only."""
|
||
|
+ pass
|
||
|
+
|
||
|
+ def close(self):
|
||
|
+ """Method provided for backward compatibility only."""
|
||
|
+ pass
|
||
|
|
||
|
-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)
|
||
|
+ return _UrandomRNG()
|
||
|
+
|
||
|
|
||
|
def atfork():
|
||
|
- """Call this whenever you call os.fork()"""
|
||
|
- _UserFriendlyRNG.reinit()
|
||
|
+ pass
|
||
|
+
|
||
|
|
||
|
-def get_random_bytes(n):
|
||
|
- """Return the specified number of cryptographically-strong random bytes."""
|
||
|
- return _UserFriendlyRNG.get_random_bytes(n)
|
||
|
+#: Function that returns a random byte string of the desired size.
|
||
|
+get_random_bytes = urandom
|
||
|
|
||
|
-# vim:set ts=4 sw=4 sts=4 expandtab:
|
||
|
--- lib/Crypto/Random/OSRNG/fallback.py
|
||
|
+++ /dev/null
|
||
|
@@ -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:
|
||
|
--- lib/Crypto/Random/OSRNG/__init__.py
|
||
|
+++ /dev/null
|
||
|
@@ -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:
|
||
|
--- lib/Crypto/Random/OSRNG/nt.py
|
||
|
+++ /dev/null
|
||
|
@@ -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:
|
||
|
--- lib/Crypto/Random/OSRNG/posix.py
|
||
|
+++ /dev/null
|
||
|
@@ -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:
|
||
|
--- lib/Crypto/Random/OSRNG/rng_base.py
|
||
|
+++ /dev/null
|
||
|
@@ -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:
|
||
|
--- lib/Crypto/Random/_UserFriendlyRNG.py
|
||
|
+++ /dev/null
|
||
|
@@ -1,230 +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.
|
||
|
- """
|
||
|
-
|
||
|
- # Save the pid (helps ensure that Crypto.Random.atfork() gets called)
|
||
|
- self._pid = os.getpid()
|
||
|
-
|
||
|
- # Collect entropy from the operating system and feed it to
|
||
|
- # FortunaAccumulator
|
||
|
- self._ec.reinit()
|
||
|
-
|
||
|
- # Override FortunaAccumulator's 100ms minimum re-seed interval. This
|
||
|
- # is necessary to avoid a race condition between this function and
|
||
|
- # self.read(), which that can otherwise cause forked child processes to
|
||
|
- # produce identical output. (e.g. CVE-2013-1445)
|
||
|
- #
|
||
|
- # Note that if this function can be called frequently by an attacker,
|
||
|
- # (and if the bits from OSRNG are insufficiently random) it will weaken
|
||
|
- # Fortuna's ability to resist a state compromise extension attack.
|
||
|
- self._fa._forget_last_reseed()
|
||
|
-
|
||
|
- 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:
|
||
|
--- lib/Crypto/SelfTest/Random/__init__.py
|
||
|
+++ lib/Crypto/SelfTest/Random/__init__.py
|
||
|
@@ -29,10 +29,8 @@ __revision__ = "$Id$"
|
||
|
def get_tests(config={}):
|
||
|
tests = []
|
||
|
from Crypto.SelfTest.Random import Fortuna; tests += Fortuna.get_tests(config=config)
|
||
|
- from Crypto.SelfTest.Random import OSRNG; tests += OSRNG.get_tests(config=config)
|
||
|
from Crypto.SelfTest.Random import test_random; tests += test_random.get_tests(config=config)
|
||
|
from Crypto.SelfTest.Random import test_rpoolcompat; tests += test_rpoolcompat.get_tests(config=config)
|
||
|
- from Crypto.SelfTest.Random import test__UserFriendlyRNG; tests += test__UserFriendlyRNG.get_tests(config=config)
|
||
|
return tests
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
--- lib/Crypto/SelfTest/Random/OSRNG/__init__.py
|
||
|
+++ /dev/null
|
||
|
@@ -1,49 +0,0 @@
|
||
|
-# -*- coding: utf-8 -*-
|
||
|
-#
|
||
|
-# SelfTest/Random/OSRNG/__init__.py: Self-test for OSRNG modules
|
||
|
-#
|
||
|
-# 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.
|
||
|
-# ===================================================================
|
||
|
-
|
||
|
-"""Self-test for Crypto.Random.OSRNG package"""
|
||
|
-
|
||
|
-__revision__ = "$Id$"
|
||
|
-
|
||
|
-import os
|
||
|
-
|
||
|
-def get_tests(config={}):
|
||
|
- tests = []
|
||
|
- if os.name == 'nt':
|
||
|
- from Crypto.SelfTest.Random.OSRNG import test_nt; tests += test_nt.get_tests(config=config)
|
||
|
- from Crypto.SelfTest.Random.OSRNG import test_winrandom; tests += test_winrandom.get_tests(config=config)
|
||
|
- elif os.name == 'posix':
|
||
|
- from Crypto.SelfTest.Random.OSRNG import test_posix; tests += test_posix.get_tests(config=config)
|
||
|
- if hasattr(os, 'urandom'):
|
||
|
- from Crypto.SelfTest.Random.OSRNG import test_fallback; tests += test_fallback.get_tests(config=config)
|
||
|
- from Crypto.SelfTest.Random.OSRNG import test_generic; tests += test_generic.get_tests(config=config)
|
||
|
- return tests
|
||
|
-
|
||
|
-if __name__ == '__main__':
|
||
|
- import unittest
|
||
|
- suite = lambda: unittest.TestSuite(get_tests())
|
||
|
- unittest.main(defaultTest='suite')
|
||
|
-
|
||
|
-
|
||
|
-# vim:set ts=4 sw=4 sts=4 expandtab:
|
||
|
--- lib/Crypto/SelfTest/Random/OSRNG/test_fallback.py
|
||
|
+++ /dev/null
|
||
|
@@ -1,48 +0,0 @@
|
||
|
-# -*- coding: utf-8 -*-
|
||
|
-#
|
||
|
-# SelfTest/Util/test_fallback.py: Self-test for the OSRNG.fallback.new() function
|
||
|
-#
|
||
|
-# 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.
|
||
|
-# ===================================================================
|
||
|
-
|
||
|
-"""Self-test suite for Crypto.Random.OSRNG.fallback"""
|
||
|
-
|
||
|
-__revision__ = "$Id$"
|
||
|
-
|
||
|
-import unittest
|
||
|
-
|
||
|
-class SimpleTest(unittest.TestCase):
|
||
|
- def runTest(self):
|
||
|
- """Crypto.Random.OSRNG.fallback.new()"""
|
||
|
- # Import the OSRNG.nt module and try to use it
|
||
|
- import Crypto.Random.OSRNG.fallback
|
||
|
- randobj = Crypto.Random.OSRNG.fallback.new()
|
||
|
- x = randobj.read(16)
|
||
|
- y = randobj.read(16)
|
||
|
- self.assertNotEqual(x, y)
|
||
|
-
|
||
|
-def get_tests(config={}):
|
||
|
- return [SimpleTest()]
|
||
|
-
|
||
|
-if __name__ == '__main__':
|
||
|
- suite = lambda: unittest.TestSuite(get_tests())
|
||
|
- unittest.main(defaultTest='suite')
|
||
|
-
|
||
|
-# vim:set ts=4 sw=4 sts=4 expandtab:
|
||
|
--- lib/Crypto/SelfTest/Random/OSRNG/test_generic.py
|
||
|
+++ /dev/null
|
||
|
@@ -1,48 +0,0 @@
|
||
|
-# -*- coding: utf-8 -*-
|
||
|
-#
|
||
|
-# SelfTest/Util/test_generic.py: Self-test for the OSRNG.new() function
|
||
|
-#
|
||
|
-# 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.
|
||
|
-# ===================================================================
|
||
|
-
|
||
|
-"""Self-test suite for Crypto.Random.OSRNG"""
|
||
|
-
|
||
|
-__revision__ = "$Id$"
|
||
|
-
|
||
|
-import unittest
|
||
|
-
|
||
|
-class SimpleTest(unittest.TestCase):
|
||
|
- def runTest(self):
|
||
|
- """Crypto.Random.OSRNG.new()"""
|
||
|
- # Import the OSRNG module and try to use it
|
||
|
- import Crypto.Random.OSRNG
|
||
|
- randobj = Crypto.Random.OSRNG.new()
|
||
|
- x = randobj.read(16)
|
||
|
- y = randobj.read(16)
|
||
|
- self.assertNotEqual(x, y)
|
||
|
-
|
||
|
-def get_tests(config={}):
|
||
|
- return [SimpleTest()]
|
||
|
-
|
||
|
-if __name__ == '__main__':
|
||
|
- suite = lambda: unittest.TestSuite(get_tests())
|
||
|
- unittest.main(defaultTest='suite')
|
||
|
-
|
||
|
-# vim:set ts=4 sw=4 sts=4 expandtab:
|
||
|
--- lib/Crypto/SelfTest/Random/OSRNG/test_nt.py
|
||
|
+++ /dev/null
|
||
|
@@ -1,48 +0,0 @@
|
||
|
-# -*- coding: utf-8 -*-
|
||
|
-#
|
||
|
-# SelfTest/Util/test_generic.py: Self-test for the OSRNG.nt.new() function
|
||
|
-#
|
||
|
-# 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.
|
||
|
-# ===================================================================
|
||
|
-
|
||
|
-"""Self-test suite for Crypto.Random.OSRNG.nt"""
|
||
|
-
|
||
|
-__revision__ = "$Id$"
|
||
|
-
|
||
|
-import unittest
|
||
|
-
|
||
|
-class SimpleTest(unittest.TestCase):
|
||
|
- def runTest(self):
|
||
|
- """Crypto.Random.OSRNG.nt.new()"""
|
||
|
- # Import the OSRNG.nt module and try to use it
|
||
|
- import Crypto.Random.OSRNG.nt
|
||
|
- randobj = Crypto.Random.OSRNG.nt.new()
|
||
|
- x = randobj.read(16)
|
||
|
- y = randobj.read(16)
|
||
|
- self.assertNotEqual(x, y)
|
||
|
-
|
||
|
-def get_tests(config={}):
|
||
|
- return [SimpleTest()]
|
||
|
-
|
||
|
-if __name__ == '__main__':
|
||
|
- suite = lambda: unittest.TestSuite(get_tests())
|
||
|
- unittest.main(defaultTest='suite')
|
||
|
-
|
||
|
-# vim:set ts=4 sw=4 sts=4 expandtab:
|
||
|
--- lib/Crypto/SelfTest/Random/OSRNG/test_posix.py
|
||
|
+++ /dev/null
|
||
|
@@ -1,48 +0,0 @@
|
||
|
-# -*- coding: utf-8 -*-
|
||
|
-#
|
||
|
-# SelfTest/Util/test_posix.py: Self-test for the OSRNG.posix.new() function
|
||
|
-#
|
||
|
-# 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.
|
||
|
-# ===================================================================
|
||
|
-
|
||
|
-"""Self-test suite for Crypto.Random.OSRNG.posix"""
|
||
|
-
|
||
|
-__revision__ = "$Id$"
|
||
|
-
|
||
|
-import unittest
|
||
|
-
|
||
|
-class SimpleTest(unittest.TestCase):
|
||
|
- def runTest(self):
|
||
|
- """Crypto.Random.OSRNG.posix.new()"""
|
||
|
- # Import the OSRNG.nt module and try to use it
|
||
|
- import Crypto.Random.OSRNG.posix
|
||
|
- randobj = Crypto.Random.OSRNG.posix.new()
|
||
|
- x = randobj.read(16)
|
||
|
- y = randobj.read(16)
|
||
|
- self.assertNotEqual(x, y)
|
||
|
-
|
||
|
-def get_tests(config={}):
|
||
|
- return [SimpleTest()]
|
||
|
-
|
||
|
-if __name__ == '__main__':
|
||
|
- suite = lambda: unittest.TestSuite(get_tests())
|
||
|
- unittest.main(defaultTest='suite')
|
||
|
-
|
||
|
-# vim:set ts=4 sw=4 sts=4 expandtab:
|
||
|
--- lib/Crypto/SelfTest/Random/OSRNG/test_winrandom.py
|
||
|
+++ /dev/null
|
||
|
@@ -1,48 +0,0 @@
|
||
|
-# -*- coding: utf-8 -*-
|
||
|
-#
|
||
|
-# SelfTest/Util/test_winrandom.py: Self-test for the winrandom 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.
|
||
|
-# ===================================================================
|
||
|
-
|
||
|
-"""Self-test suite for Crypto.Random.OSRNG.winrandom"""
|
||
|
-
|
||
|
-__revision__ = "$Id$"
|
||
|
-
|
||
|
-import unittest
|
||
|
-
|
||
|
-class SimpleTest(unittest.TestCase):
|
||
|
- def runTest(self):
|
||
|
- """Crypto.Random.OSRNG.winrandom"""
|
||
|
- # Import the winrandom module and try to use it
|
||
|
- from Crypto.Random.OSRNG import winrandom
|
||
|
- randobj = winrandom.new()
|
||
|
- x = randobj.get_bytes(16)
|
||
|
- y = randobj.get_bytes(16)
|
||
|
- self.assertNotEqual(x, y)
|
||
|
-
|
||
|
-def get_tests(config={}):
|
||
|
- return [SimpleTest()]
|
||
|
-
|
||
|
-if __name__ == '__main__':
|
||
|
- suite = lambda: unittest.TestSuite(get_tests())
|
||
|
- unittest.main(defaultTest='suite')
|
||
|
-
|
||
|
-# vim:set ts=4 sw=4 sts=4 expandtab:
|
||
|
--- lib/Crypto/SelfTest/Random/test__UserFriendlyRNG.py
|
||
|
+++ /dev/null
|
||
|
@@ -1,171 +0,0 @@
|
||
|
-# -*- coding: utf-8 -*-
|
||
|
-# Self-tests for the user-friendly Crypto.Random interface
|
||
|
-#
|
||
|
-# Written in 2013 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.
|
||
|
-# ===================================================================
|
||
|
-
|
||
|
-"""Self-test suite for generic Crypto.Random stuff """
|
||
|
-
|
||
|
-from __future__ import nested_scopes
|
||
|
-
|
||
|
-__revision__ = "$Id$"
|
||
|
-
|
||
|
-import binascii
|
||
|
-import pprint
|
||
|
-import unittest
|
||
|
-import os
|
||
|
-import time
|
||
|
-import sys
|
||
|
-if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
||
|
- from Crypto.Util.py21compat import *
|
||
|
-from Crypto.Util.py3compat import *
|
||
|
-
|
||
|
-try:
|
||
|
- import multiprocessing
|
||
|
-except ImportError:
|
||
|
- multiprocessing = None
|
||
|
-
|
||
|
-import Crypto.Random._UserFriendlyRNG
|
||
|
-import Crypto.Random.random
|
||
|
-
|
||
|
-class RNGForkTest(unittest.TestCase):
|
||
|
-
|
||
|
- def _get_reseed_count(self):
|
||
|
- """
|
||
|
- Get `FortunaAccumulator.reseed_count`, the global count of the
|
||
|
- number of times that the PRNG has been reseeded.
|
||
|
- """
|
||
|
- rng_singleton = Crypto.Random._UserFriendlyRNG._get_singleton()
|
||
|
- rng_singleton._lock.acquire()
|
||
|
- try:
|
||
|
- return rng_singleton._fa.reseed_count
|
||
|
- finally:
|
||
|
- rng_singleton._lock.release()
|
||
|
-
|
||
|
- def runTest(self):
|
||
|
- # Regression test for CVE-2013-1445. We had a bug where, under the
|
||
|
- # right conditions, two processes might see the same random sequence.
|
||
|
-
|
||
|
- if sys.platform.startswith('win'): # windows can't fork
|
||
|
- assert not hasattr(os, 'fork') # ... right?
|
||
|
- return
|
||
|
-
|
||
|
- # Wait 150 ms so that we don't trigger the rate-limit prematurely.
|
||
|
- time.sleep(0.15)
|
||
|
-
|
||
|
- reseed_count_before = self._get_reseed_count()
|
||
|
-
|
||
|
- # One or both of these calls together should trigger a reseed right here.
|
||
|
- Crypto.Random._UserFriendlyRNG._get_singleton().reinit()
|
||
|
- Crypto.Random.get_random_bytes(1)
|
||
|
-
|
||
|
- reseed_count_after = self._get_reseed_count()
|
||
|
- self.assertNotEqual(reseed_count_before, reseed_count_after) # sanity check: test should reseed parent before forking
|
||
|
-
|
||
|
- rfiles = []
|
||
|
- for i in range(10):
|
||
|
- rfd, wfd = os.pipe()
|
||
|
- if os.fork() == 0:
|
||
|
- # child
|
||
|
- os.close(rfd)
|
||
|
- f = os.fdopen(wfd, "wb")
|
||
|
-
|
||
|
- Crypto.Random.atfork()
|
||
|
-
|
||
|
- data = Crypto.Random.get_random_bytes(16)
|
||
|
-
|
||
|
- f.write(data)
|
||
|
- f.close()
|
||
|
- os._exit(0)
|
||
|
- # parent
|
||
|
- os.close(wfd)
|
||
|
- rfiles.append(os.fdopen(rfd, "rb"))
|
||
|
-
|
||
|
- results = []
|
||
|
- results_dict = {}
|
||
|
- for f in rfiles:
|
||
|
- data = binascii.hexlify(f.read())
|
||
|
- results.append(data)
|
||
|
- results_dict[data] = 1
|
||
|
- f.close()
|
||
|
-
|
||
|
- if len(results) != len(results_dict.keys()):
|
||
|
- raise AssertionError("RNG output duplicated across fork():\n%s" %
|
||
|
- (pprint.pformat(results)))
|
||
|
-
|
||
|
-
|
||
|
-# For RNGMultiprocessingForkTest
|
||
|
-def _task_main(q):
|
||
|
- a = Crypto.Random.get_random_bytes(16)
|
||
|
- time.sleep(0.1) # wait 100 ms
|
||
|
- b = Crypto.Random.get_random_bytes(16)
|
||
|
- q.put(binascii.b2a_hex(a))
|
||
|
- q.put(binascii.b2a_hex(b))
|
||
|
- q.put(None) # Wait for acknowledgment
|
||
|
-
|
||
|
-
|
||
|
-class RNGMultiprocessingForkTest(unittest.TestCase):
|
||
|
-
|
||
|
- def runTest(self):
|
||
|
- # Another regression test for CVE-2013-1445. This is basically the
|
||
|
- # same as RNGForkTest, but less compatible with old versions of Python,
|
||
|
- # and a little easier to read.
|
||
|
-
|
||
|
- n_procs = 5
|
||
|
- manager = multiprocessing.Manager()
|
||
|
- queues = [manager.Queue(1) for i in range(n_procs)]
|
||
|
-
|
||
|
- # Reseed the pool
|
||
|
- time.sleep(0.15)
|
||
|
- Crypto.Random._UserFriendlyRNG._get_singleton().reinit()
|
||
|
- Crypto.Random.get_random_bytes(1)
|
||
|
-
|
||
|
- # Start the child processes
|
||
|
- pool = multiprocessing.Pool(processes=n_procs, initializer=Crypto.Random.atfork)
|
||
|
- map_result = pool.map_async(_task_main, queues)
|
||
|
-
|
||
|
- # Get the results, ensuring that no pool processes are reused.
|
||
|
- aa = [queues[i].get(30) for i in range(n_procs)]
|
||
|
- bb = [queues[i].get(30) for i in range(n_procs)]
|
||
|
- res = list(zip(aa, bb))
|
||
|
-
|
||
|
- # Shut down the pool
|
||
|
- map_result.get(30)
|
||
|
- pool.close()
|
||
|
- pool.join()
|
||
|
-
|
||
|
- # Check that the results are unique
|
||
|
- if len(set(aa)) != len(aa) or len(set(res)) != len(res):
|
||
|
- raise AssertionError("RNG output duplicated across fork():\n%s" %
|
||
|
- (pprint.pformat(res),))
|
||
|
-
|
||
|
-
|
||
|
-def get_tests(config={}):
|
||
|
- tests = []
|
||
|
- tests += [RNGForkTest()]
|
||
|
- if multiprocessing is not None:
|
||
|
- tests += [RNGMultiprocessingForkTest()]
|
||
|
- return tests
|
||
|
-
|
||
|
-if __name__ == '__main__':
|
||
|
- suite = lambda: unittest.TestSuite(get_tests())
|
||
|
- unittest.main(defaultTest='suite')
|
||
|
-
|
||
|
-# vim:set ts=4 sw=4 sts=4 expandtab:
|
||
|
--- lib/Crypto/SelfTest/Util/__init__.py
|
||
|
+++ lib/Crypto/SelfTest/Util/__init__.py
|
||
|
@@ -30,8 +30,6 @@ import os
|
||
|
|
||
|
def get_tests(config={}):
|
||
|
tests = []
|
||
|
- if os.name == 'nt':
|
||
|
- from Crypto.SelfTest.Util import test_winrandom; tests += test_winrandom.get_tests(config=config)
|
||
|
from Crypto.SelfTest.Util import test_number; tests += test_number.get_tests(config=config)
|
||
|
from Crypto.SelfTest.Util import test_Counter; tests += test_Counter.get_tests(config=config)
|
||
|
return tests
|
||
|
--- lib/Crypto/SelfTest/Util/test_winrandom.py
|
||
|
+++ /dev/null
|
||
|
@@ -1,48 +0,0 @@
|
||
|
-# -*- coding: utf-8 -*-
|
||
|
-#
|
||
|
-# SelfTest/Util/test_winrandom.py: Self-test for the winrandom 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.
|
||
|
-# ===================================================================
|
||
|
-
|
||
|
-"""Self-test suite for Crypto.Util.winrandom"""
|
||
|
-
|
||
|
-__revision__ = "$Id$"
|
||
|
-
|
||
|
-import unittest
|
||
|
-
|
||
|
-class WinRandomImportTest(unittest.TestCase):
|
||
|
- def runTest(self):
|
||
|
- """winrandom: simple test"""
|
||
|
- # Import the winrandom module and try to use it
|
||
|
- from Crypto.Util import winrandom
|
||
|
- randobj = winrandom.new()
|
||
|
- x = randobj.get_bytes(16)
|
||
|
- y = randobj.get_bytes(16)
|
||
|
- self.assertNotEqual(x, y)
|
||
|
-
|
||
|
-def get_tests(config={}):
|
||
|
- return [WinRandomImportTest()]
|
||
|
-
|
||
|
-if __name__ == '__main__':
|
||
|
- suite = lambda: unittest.TestSuite(get_tests())
|
||
|
- unittest.main(defaultTest='suite')
|
||
|
-
|
||
|
-# vim:set ts=4 sw=4 sts=4 expandtab:
|
||
|
--- lib/Crypto/Util/winrandom.py
|
||
|
+++ /dev/null
|
||
|
@@ -1,28 +0,0 @@
|
||
|
-#
|
||
|
-# Util/winrandom.py : Stub for Crypto.Random.OSRNG.winrandom
|
||
|
-#
|
||
|
-# 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$"
|
||
|
-
|
||
|
-from Crypto.Random.OSRNG.winrandom import *
|
||
|
-
|
||
|
-# vim:set ts=4 sw=4 sts=4 expandtab:
|
||
|
--- setup.py
|
||
|
+++ setup.py
|
||
|
@@ -48,18 +48,6 @@ if sys.version[0:1] == '1':
|
||
|
raise RuntimeError ("The Python Cryptography Toolkit requires "
|
||
|
"Python 2.x or 3.x to build.")
|
||
|
|
||
|
-if sys.platform == 'win32':
|
||
|
- HTONS_LIBS = ['ws2_32']
|
||
|
- plat_ext = [
|
||
|
- Extension("Crypto.Random.OSRNG.winrandom",
|
||
|
- libraries = HTONS_LIBS + ['advapi32'],
|
||
|
- include_dirs=['src/'],
|
||
|
- sources=["src/winrand.c"])
|
||
|
- ]
|
||
|
-else:
|
||
|
- HTONS_LIBS = []
|
||
|
- plat_ext = []
|
||
|
-
|
||
|
# For test development: Set this to 1 to build with gcov support.
|
||
|
# Use "gcov -p -o build/temp.*/src build/temp.*/src/*.gcda" to build the
|
||
|
# .gcov files
|
||
|
@@ -73,18 +61,6 @@ except ImportError:
|
||
|
# Python 2
|
||
|
from distutils.command.build_py import build_py
|
||
|
|
||
|
-# List of pure Python modules that will be excluded from the binary packages.
|
||
|
-# The list consists of (package, module_name) tuples
|
||
|
-if sys.version_info[0] == 2:
|
||
|
- EXCLUDE_PY = []
|
||
|
-else:
|
||
|
- EXCLUDE_PY = [
|
||
|
- # We don't want Py3k to choke on the 2.x compat code
|
||
|
- ('Crypto.Util', 'py21compat'),
|
||
|
- ]
|
||
|
- if sys.platform != "win32": # Avoid nt.py, as 2to3 can't fix it w/o winrandom
|
||
|
- EXCLUDE_PY += [('Crypto.Random.OSRNG','nt')]
|
||
|
-
|
||
|
# Work around the print / print() issue with Python 2.x and 3.x. We only need
|
||
|
# to print at one point of the code, which makes this easy
|
||
|
|
||
|
@@ -264,8 +240,6 @@ class PCTBuildPy(build_py):
|
||
|
retval = []
|
||
|
for item in modules:
|
||
|
pkg, module = item[:2]
|
||
|
- if (pkg, module) in EXCLUDE_PY:
|
||
|
- continue
|
||
|
retval.append(item)
|
||
|
return retval
|
||
|
|
||
|
@@ -330,7 +304,6 @@ kw = {'name':"pycrypto",
|
||
|
'packages' : ["Crypto", "Crypto.Hash", "Crypto.Cipher", "Crypto.Util",
|
||
|
"Crypto.Random",
|
||
|
"Crypto.Random.Fortuna",
|
||
|
- "Crypto.Random.OSRNG",
|
||
|
"Crypto.SelfTest",
|
||
|
"Crypto.SelfTest.Cipher",
|
||
|
"Crypto.SelfTest.Hash",
|
||
|
@@ -338,14 +311,13 @@ kw = {'name':"pycrypto",
|
||
|
"Crypto.SelfTest.PublicKey",
|
||
|
"Crypto.SelfTest.Random",
|
||
|
"Crypto.SelfTest.Random.Fortuna",
|
||
|
- "Crypto.SelfTest.Random.OSRNG",
|
||
|
"Crypto.SelfTest.Util",
|
||
|
"Crypto.SelfTest.Signature",
|
||
|
"Crypto.Protocol",
|
||
|
"Crypto.PublicKey",
|
||
|
"Crypto.Signature"],
|
||
|
'package_dir' : { "Crypto": "lib/Crypto" },
|
||
|
- 'ext_modules': plat_ext + [
|
||
|
+ 'ext_modules': [
|
||
|
# _fastmath (uses GNU mp library)
|
||
|
Extension("Crypto.PublicKey._fastmath",
|
||
|
include_dirs=['src/','/usr/include/'],
|
||
|
@@ -443,11 +415,3 @@ def touch(path):
|
||
|
os.utime(path, (now, now))
|
||
|
except os.error:
|
||
|
PrintErr("Failed to update timestamp of "+path)
|
||
|
-
|
||
|
-# PY3K: Workaround for winrandom.pyd not existing during the first pass.
|
||
|
-# It needs to be there for 2to3 to fix the import in nt.py
|
||
|
-if (sys.platform == 'win32' and sys.version_info[0] == 3 and
|
||
|
- 'build' in sys.argv[1:]):
|
||
|
- PrintErr("\nSecond pass to allow 2to3 to fix nt.py. No cause for alarm.\n")
|
||
|
- touch("./lib/Crypto/Random/OSRNG/nt.py")
|
||
|
- core.setup(**kw)
|
||
|
--- src/winrand.c
|
||
|
+++ /dev/null
|
||
|
@@ -1,472 +0,0 @@
|
||
|
-/* -*- C -*- */
|
||
|
-/*
|
||
|
- * Uses Windows CryptoAPI CryptGenRandom to get random bytes.
|
||
|
- * The "new" method returns an object, whose "get_bytes" method
|
||
|
- * can be called repeatedly to get random bytes, seeded by the
|
||
|
- * OS. See the description in the comment at the end.
|
||
|
- *
|
||
|
- * If you have the Intel Security Driver header files (icsp4ms.h)
|
||
|
- * for their hardware random number generator in the 810 and 820 chipsets,
|
||
|
- * then define HAVE_INTEL_RNG.
|
||
|
- *
|
||
|
- * =======================================================================
|
||
|
- * 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.
|
||
|
- * =======================================================================
|
||
|
- *
|
||
|
- */
|
||
|
-
|
||
|
-/* Author: Mark Moraes */
|
||
|
-
|
||
|
-#include "Python.h"
|
||
|
-#include "pycrypto_compat.h"
|
||
|
-
|
||
|
-#ifdef MS_WIN32
|
||
|
-
|
||
|
-#define _WIN32_WINNT 0x400
|
||
|
-#define WINSOCK
|
||
|
-
|
||
|
-#include <windows.h>
|
||
|
-#include <wincrypt.h>
|
||
|
-
|
||
|
-#ifdef HAVE_INTEL_RNG
|
||
|
-# include "icsp4ms.h"
|
||
|
-#else
|
||
|
-# define PROV_INTEL_SEC 22
|
||
|
-# define INTEL_DEF_PROV "Intel Hardware Cryptographic Service Provider"
|
||
|
-#endif
|
||
|
-
|
||
|
-/* To-Do: store provider name and type for print/repr? */
|
||
|
-
|
||
|
-typedef struct
|
||
|
-{
|
||
|
- PyObject_HEAD
|
||
|
- HCRYPTPROV hcp;
|
||
|
-} WRobject;
|
||
|
-
|
||
|
-/* Please see PEP3123 for a discussion of PyObject_HEAD and changes made in 3.x to make it conform to Standard C.
|
||
|
- * These changes also dictate using Py_TYPE to check type, and PyVarObject_HEAD_INIT(NULL, 0) to initialize
|
||
|
- */
|
||
|
-#ifdef IS_PY3K
|
||
|
-static PyTypeObject WRtype;
|
||
|
-#define is_WRobject(v) (Py_TYPE(v) == &WRtype)
|
||
|
-#else
|
||
|
-staticforward PyTypeObject WRtype;
|
||
|
-#define is_WRobject(v) ((v)->ob_type == &WRtype)
|
||
|
-#define PyLong_FromLong PyInt_FromLong /* for Python 2.x */
|
||
|
-#endif
|
||
|
-
|
||
|
-static void
|
||
|
-WRdealloc(PyObject *ptr)
|
||
|
-{
|
||
|
- WRobject *o = (WRobject *)ptr;
|
||
|
-
|
||
|
- if (! is_WRobject(ptr)) {
|
||
|
- PyErr_Format(PyExc_TypeError,
|
||
|
- "WinRandom trying to dealloc non-WinRandom object");
|
||
|
- return;
|
||
|
- }
|
||
|
- if (! CryptReleaseContext(o->hcp, 0)) {
|
||
|
- PyErr_Format(PyExc_SystemError,
|
||
|
- "CryptReleaseContext failed, error 0x%x",
|
||
|
- (unsigned int) GetLastError());
|
||
|
- return;
|
||
|
- }
|
||
|
- /* Overwrite the contents of the object */
|
||
|
- o->hcp = 0;
|
||
|
- PyObject_Del(ptr);
|
||
|
-}
|
||
|
-
|
||
|
-static char winrandom__doc__[] =
|
||
|
-"new([provider], [provtype]): Returns an object handle to Windows\n\
|
||
|
-CryptoAPI that can be used to access a cryptographically strong\n\
|
||
|
-pseudo-random generator that uses OS-gathered entropy.\n\
|
||
|
-Provider is a string that specifies the Cryptographic Service Provider\n\
|
||
|
-to use, default is the default OS CSP.\n\
|
||
|
-provtype is an integer specifying the provider type to use, default\n\
|
||
|
-is 1 (PROV_RSA_FULL)";
|
||
|
-
|
||
|
-static char WR_get_bytes__doc__[] =
|
||
|
-"get_bytes(nbytes, [userdata]]): Returns nbytes of random data\n\
|
||
|
-from Windows CryptGenRandom.\n\
|
||
|
-userdata is a string with any additional entropic data that the\n\
|
||
|
-user wishes to provide.";
|
||
|
-
|
||
|
-static WRobject *
|
||
|
-winrandom_new(PyObject *self, PyObject *args, PyObject *kwdict)
|
||
|
-{
|
||
|
- HCRYPTPROV hcp = 0;
|
||
|
- WRobject *res;
|
||
|
- char *provname = NULL;
|
||
|
- int provtype = PROV_RSA_FULL;
|
||
|
- static char *kwlist[] = { "provider", "provtype", NULL};
|
||
|
-
|
||
|
- if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|si", kwlist,
|
||
|
- &provname, &provtype)) {
|
||
|
- return NULL;
|
||
|
- }
|
||
|
- if (! CryptAcquireContext(&hcp, NULL, (LPCTSTR) provname,
|
||
|
- (DWORD) provtype,
|
||
|
- CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
|
||
|
- PyErr_Format(PyExc_SystemError,
|
||
|
- "CryptAcquireContext for provider \"%s\" type %i failed, error 0x%x",
|
||
|
- provname? provname : "(null)", provtype,
|
||
|
- (unsigned int) GetLastError());
|
||
|
- return NULL;
|
||
|
- }
|
||
|
- res = PyObject_New(WRobject, &WRtype);
|
||
|
- res->hcp = hcp;
|
||
|
- return res;
|
||
|
-}
|
||
|
-
|
||
|
-static PyObject *
|
||
|
-WR_get_bytes(WRobject *self, PyObject *args)
|
||
|
-{
|
||
|
- int n, nbytes, len = 0;
|
||
|
- PyObject *res;
|
||
|
- char *buf, *str = NULL;
|
||
|
-
|
||
|
- if (! is_WRobject(self)) {
|
||
|
- PyErr_Format(PyExc_TypeError,
|
||
|
- "WinRandom trying to get_bytes with non-WinRandom object");
|
||
|
- return NULL;
|
||
|
- }
|
||
|
- if (!PyArg_ParseTuple(args, "i|s#", &n, &str, &len)) {
|
||
|
- return NULL;
|
||
|
- }
|
||
|
- if (n <= 0) {
|
||
|
- PyErr_SetString(PyExc_ValueError, "nbytes must be positive number");
|
||
|
- return NULL;
|
||
|
- }
|
||
|
- /* Just in case char != BYTE, or userdata > desired result */
|
||
|
- nbytes = (((n > len) ? n : len) * sizeof(char)) / sizeof(BYTE) + 1;
|
||
|
- if ((buf = (char *) PyMem_Malloc(nbytes)) == NULL)
|
||
|
- return PyErr_NoMemory();
|
||
|
- if (len > 0)
|
||
|
- memcpy(buf, str, len);
|
||
|
- /*
|
||
|
- * if userdata > desired result, we end up getting
|
||
|
- * more bytes than we really needed to return. No
|
||
|
- * easy way to avoid that: we prefer that
|
||
|
- * CryptGenRandom does the distillation of userdata
|
||
|
- * down to entropy, rather than trying to do it
|
||
|
- * ourselves. Since the extra bytes presumably come
|
||
|
- * from an RC4 stream, they should be relatively
|
||
|
- * cheap.
|
||
|
- */
|
||
|
-
|
||
|
- if (! CryptGenRandom(self->hcp, (DWORD) nbytes, (BYTE *) buf)) {
|
||
|
- PyErr_Format(PyExc_SystemError,
|
||
|
- "CryptGenRandom failed, error 0x%x",
|
||
|
- (unsigned int) GetLastError());
|
||
|
- PyMem_Free(buf);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- res = PyBytes_FromStringAndSize(buf, n);
|
||
|
- PyMem_Free(buf);
|
||
|
- return res;
|
||
|
-}
|
||
|
-
|
||
|
-/* WinRandom object methods */
|
||
|
-
|
||
|
-static PyMethodDef WRmethods[] =
|
||
|
-{
|
||
|
- {"get_bytes", (PyCFunction) WR_get_bytes, METH_VARARGS,
|
||
|
- WR_get_bytes__doc__},
|
||
|
- {NULL, NULL} /* sentinel */
|
||
|
-};
|
||
|
-
|
||
|
-/* winrandom module methods */
|
||
|
-
|
||
|
-static PyMethodDef WR_mod_methods[] = {
|
||
|
- {"new", (PyCFunction) winrandom_new, METH_VARARGS|METH_KEYWORDS,
|
||
|
- winrandom__doc__},
|
||
|
- {NULL, NULL} /* Sentinel */
|
||
|
-};
|
||
|
-
|
||
|
-static PyObject *
|
||
|
-#ifdef IS_PY3K
|
||
|
-WRgetattro(PyObject *s, PyObject *attr)
|
||
|
-#else
|
||
|
-WRgetattr(PyObject *s, char *name)
|
||
|
-#endif
|
||
|
-{
|
||
|
- WRobject *self = (WRobject*)s;
|
||
|
- if (! is_WRobject(self)) {
|
||
|
- PyErr_Format(PyExc_TypeError,
|
||
|
- "WinRandom trying to getattr with non-WinRandom object");
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-#ifdef IS_PY3K
|
||
|
- if (!PyUnicode_Check(attr))
|
||
|
- goto generic;
|
||
|
- if (PyUnicode_CompareWithASCIIString(attr, "hcp") == 0)
|
||
|
-#else
|
||
|
- if (strcmp(name, "hcp") == 0)
|
||
|
-#endif
|
||
|
- return PyLong_FromLong((long) self->hcp);
|
||
|
-#ifdef IS_PY3K
|
||
|
- generic:
|
||
|
- return PyObject_GenericGetAttr(s, attr);
|
||
|
-#else
|
||
|
- return Py_FindMethod(WRmethods, (PyObject *) self, name);
|
||
|
-#endif
|
||
|
-}
|
||
|
-
|
||
|
-static PyTypeObject WRtype =
|
||
|
- {
|
||
|
- #ifdef IS_PY3K
|
||
|
- PyVarObject_HEAD_INIT(NULL, 0) /* deferred type init for compilation on Windows, type will be filled in at runtime */
|
||
|
-#else
|
||
|
- PyObject_HEAD_INIT(NULL)
|
||
|
- 0, /*ob_size*/
|
||
|
-#endif
|
||
|
- "winrandom.WinRandom", /*tp_name*/
|
||
|
- sizeof(WRobject), /*tp_size*/
|
||
|
- 0, /*tp_itemsize*/
|
||
|
- /* methods */
|
||
|
- (destructor) WRdealloc, /*tp_dealloc*/
|
||
|
- 0, /*tp_print*/
|
||
|
-#ifndef IS_PY3K
|
||
|
- WRgetattr, /*tp_getattr*/
|
||
|
-#else
|
||
|
- 0, /*tp_getattr*/
|
||
|
- 0, /*tp_setattr*/
|
||
|
- 0, /*tp_compare*/
|
||
|
- 0, /*tp_repr*/
|
||
|
- 0, /*tp_as_number */
|
||
|
- 0, /*tp_as_sequence */
|
||
|
- 0, /*tp_as_mapping */
|
||
|
- 0, /*tp_hash*/
|
||
|
- 0, /*tp_call*/
|
||
|
- 0, /*tp_str*/
|
||
|
- WRgetattro, /*tp_getattro*/
|
||
|
- 0, /*tp_setattro*/
|
||
|
- 0, /*tp_as_buffer*/
|
||
|
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||
|
- 0, /*tp_doc*/
|
||
|
- 0, /*tp_traverse*/
|
||
|
- 0, /*tp_clear*/
|
||
|
- 0, /*tp_richcompare*/
|
||
|
- 0, /*tp_weaklistoffset*/
|
||
|
- 0, /*tp_iter*/
|
||
|
- 0, /*tp_iternext*/
|
||
|
- WRmethods, /*tp_methods*/
|
||
|
-#endif
|
||
|
-};
|
||
|
-
|
||
|
-#ifdef IS_PY3K
|
||
|
-static struct PyModuleDef moduledef = {
|
||
|
- PyModuleDef_HEAD_INIT,
|
||
|
- "winrandom",
|
||
|
- NULL,
|
||
|
- -1,
|
||
|
- WR_mod_methods,
|
||
|
- NULL,
|
||
|
- NULL,
|
||
|
- NULL,
|
||
|
- NULL
|
||
|
- };
|
||
|
-#endif
|
||
|
-
|
||
|
-#ifdef IS_PY3K
|
||
|
-PyMODINIT_FUNC
|
||
|
-PyInit_winrandom()
|
||
|
-#else
|
||
|
-void
|
||
|
-initwinrandom()
|
||
|
-#endif
|
||
|
-{
|
||
|
- PyObject *m;
|
||
|
-#ifdef IS_PY3K
|
||
|
- /* PyType_Ready automatically fills in ob_type with &PyType_Type if it's not already set */
|
||
|
- if (PyType_Ready(&WRtype) < 0)
|
||
|
- return NULL;
|
||
|
- /* Initialize the module */
|
||
|
- m = PyModule_Create(&moduledef);
|
||
|
- if (m == NULL)
|
||
|
- return NULL;
|
||
|
-#else
|
||
|
- WRtype.ob_type = &PyType_Type;
|
||
|
- m = Py_InitModule("winrandom", WR_mod_methods);
|
||
|
-#endif
|
||
|
-
|
||
|
- /* define Windows CSP Provider Types */
|
||
|
-#ifdef PROV_RSA_FULL
|
||
|
- PyModule_AddIntConstant(m, "PROV_RSA_FULL", PROV_RSA_FULL);
|
||
|
-#endif
|
||
|
-#ifdef PROV_RSA_SIG
|
||
|
- PyModule_AddIntConstant(m, "PROV_RSA_SIG", PROV_RSA_SIG);
|
||
|
-#endif
|
||
|
-#ifdef PROV_DSS
|
||
|
- PyModule_AddIntConstant(m, "PROV_DSS", PROV_DSS);
|
||
|
-#endif
|
||
|
-#ifdef PROV_FORTEZZA
|
||
|
- PyModule_AddIntConstant(m, "PROV_FORTEZZA", PROV_FORTEZZA);
|
||
|
-#endif
|
||
|
-#ifdef PROV_MS_EXCHANGE
|
||
|
- PyModule_AddIntConstant(m, "PROV_MS_EXCHANGE", PROV_MS_EXCHANGE);
|
||
|
-#endif
|
||
|
-#ifdef PROV_SSL
|
||
|
- PyModule_AddIntConstant(m, "PROV_SSL", PROV_SSL);
|
||
|
-#endif
|
||
|
-#ifdef PROV_RSA_SCHANNEL
|
||
|
- PyModule_AddIntConstant(m, "PROV_RSA_SCHANNEL", PROV_RSA_SCHANNEL);
|
||
|
-#endif
|
||
|
-#ifdef PROV_DSS_DH
|
||
|
- PyModule_AddIntConstant(m, "PROV_DSS_DH", PROV_DSS_DH);
|
||
|
-#endif
|
||
|
-#ifdef PROV_EC_ECDSA_SIG
|
||
|
- PyModule_AddIntConstant(m, "PROV_EC_ECDSA_SIG", PROV_EC_ECDSA_SIG);
|
||
|
-#endif
|
||
|
-#ifdef PROV_EC_ECNRA_SIG
|
||
|
- PyModule_AddIntConstant(m, "PROV_EC_ECNRA_SIG", PROV_EC_ECNRA_SIG);
|
||
|
-#endif
|
||
|
-#ifdef PROV_EC_ECDSA_FULL
|
||
|
- PyModule_AddIntConstant(m, "PROV_EC_ECDSA_FULL", PROV_EC_ECDSA_FULL);
|
||
|
-#endif
|
||
|
-#ifdef PROV_EC_ECNRA_FULL
|
||
|
- PyModule_AddIntConstant(m, "PROV_EC_ECNRA_FULL", PROV_EC_ECNRA_FULL);
|
||
|
-#endif
|
||
|
-#ifdef PROV_SPYRUS_LYNKS
|
||
|
- PyModule_AddIntConstant(m, "PROV_SPYRUS_LYNKS", PROV_SPYRUS_LYNKS);
|
||
|
-#endif
|
||
|
-#ifdef PROV_INTEL_SEC
|
||
|
- PyModule_AddIntConstant(m, "PROV_INTEL_SEC", PROV_INTEL_SEC);
|
||
|
-#endif
|
||
|
-
|
||
|
- /* Define Windows CSP Provider Names */
|
||
|
-#ifdef MS_DEF_PROV
|
||
|
- PyModule_AddStringConstant(m, "MS_DEF_PROV", MS_DEF_PROV);
|
||
|
-#endif
|
||
|
-#ifdef MS_ENHANCED_PROV
|
||
|
- PyModule_AddStringConstant(m, "MS_ENHANCED_PROV", MS_ENHANCED_PROV);
|
||
|
-#endif
|
||
|
-#ifdef MS_DEF_RSA_SIG_PROV
|
||
|
- PyModule_AddStringConstant(m, "MS_DEF_RSA_SIG_PROV",
|
||
|
- MS_DEF_RSA_SIG_PROV);
|
||
|
-#endif
|
||
|
-#ifdef MS_DEF_RSA_SCHANNEL_PROV
|
||
|
- PyModule_AddStringConstant(m, "MS_DEF_RSA_SCHANNEL_PROV",
|
||
|
- MS_DEF_RSA_SCHANNEL_PROV);
|
||
|
-#endif
|
||
|
-#ifdef MS_ENHANCED_RSA_SCHANNEL_PROV
|
||
|
- PyModule_AddStringConstant(m, "MS_ENHANCED_RSA_SCHANNEL_PROV",
|
||
|
- MS_ENHANCED_RSA_SCHANNEL_PROV);
|
||
|
-#endif
|
||
|
-#ifdef MS_DEF_DSS_PROV
|
||
|
- PyModule_AddStringConstant(m, "MS_DEF_DSS_PROV", MS_DEF_DSS_PROV);
|
||
|
-#endif
|
||
|
-#ifdef MS_DEF_DSS_DH_PROV
|
||
|
- PyModule_AddStringConstant(m, "MS_DEF_DSS_DH_PROV",
|
||
|
- MS_DEF_DSS_DH_PROV);
|
||
|
-#endif
|
||
|
-#ifdef INTEL_DEF_PROV
|
||
|
- PyModule_AddStringConstant(m, "INTEL_DEF_PROV", INTEL_DEF_PROV);
|
||
|
-#endif
|
||
|
-
|
||
|
- if (PyErr_Occurred())
|
||
|
- Py_FatalError("can't initialize module winrandom");
|
||
|
-
|
||
|
-#ifdef IS_PY3K
|
||
|
- return m;
|
||
|
-#endif
|
||
|
-}
|
||
|
-/*
|
||
|
-
|
||
|
-CryptGenRandom usage is described in
|
||
|
-http://msdn.microsoft.com/library/en-us/security/security/cryptgenrandom.asp
|
||
|
-and many associated pages on Windows Cryptographic Service
|
||
|
-Providers, which say:
|
||
|
-
|
||
|
- With Microsoft CSPs, CryptGenRandom uses the same
|
||
|
- random number generator used by other security
|
||
|
- components. This allows numerous processes to
|
||
|
- contribute to a system-wide seed. CryptoAPI stores
|
||
|
- an intermediate random seed with every user. To form
|
||
|
- the seed for the random number generator, a calling
|
||
|
- application supplies bits it might havefor instance,
|
||
|
- mouse or keyboard timing inputthat are then added to
|
||
|
- both the stored seed and various system data and
|
||
|
- user data such as the process ID and thread ID, the
|
||
|
- system clock, the system time, the system counter,
|
||
|
- memory status, free disk clusters, the hashed user
|
||
|
- environment block. This result is SHA-1 hashed, and
|
||
|
- the output is used to seed an RC4 stream, which is
|
||
|
- then used as the random stream and used to update
|
||
|
- the stored seed.
|
||
|
-
|
||
|
-The only other detailed description I've found of the
|
||
|
-sources of randomness for CryptGenRandom is this excerpt
|
||
|
-from a posting
|
||
|
-http://www.der-keiler.de/Newsgroups/comp.security.ssh/2002-06/0169.html
|
||
|
-
|
||
|
-From: Jon McClelland (dowot69@hotmail.com)
|
||
|
-Date: 06/12/02
|
||
|
-...
|
||
|
-
|
||
|
-Windows, call a function such as CryptGenRandom, which has two of
|
||
|
-the properties of a good random number generator, unpredictability and
|
||
|
-even value distribution. This function, declared in Wincrypt.h, is
|
||
|
-available on just about every Windows platform, including Windows 95
|
||
|
-with Internet Explorer 3.02 or later, Windows 98, Windows Me, Windows
|
||
|
-CE v3, Windows NT 4, Windows 2000, and Windows XP.
|
||
|
-
|
||
|
-CryptGenRandom gets its randomness, also known as entropy, from many
|
||
|
-sources in Windows 2000, including the following:
|
||
|
-The current process ID (GetCurrentProcessID).
|
||
|
-The current thread ID (GetCurrentThreadID).
|
||
|
-The ticks since boot (GetTickCount).
|
||
|
-The current time (GetLocalTime).
|
||
|
-Various high-precision performance counters (QueryPerformanceCounter).
|
||
|
-A Message Digest 4 (MD4) hash of the user's environment block, which
|
||
|
-includes username, computer name, and search path.
|
||
|
-
|
||
|
-High-precision internal CPU counters, such as RDTSC, RDMSR, RDPMC (x86
|
||
|
-only-more information about these counters is at
|
||
|
-developer.intel.com/software/idap/resources/technical_collateral/pentiumii/RDTSCPM1.HTM
|
||
|
-<http://developer.intel.com>).
|
||
|
-
|
||
|
-Low-level system information, such as idle time, kernel time,
|
||
|
-interrupt times, commit limit, page read count, cache read count,
|
||
|
-nonpaged pool allocations, alignment fixup count, operating system
|
||
|
-lookaside information.
|
||
|
-
|
||
|
-Such information is added to a buffer, which is hashed using MD4 and
|
||
|
-used as the key to modify a buffer, using RC4, provided by the user.
|
||
|
-(Refer to the CryptGenRandom documentation in the Platform SDK for
|
||
|
-more information about the user-provided buffer.) Hence, if the user
|
||
|
-provides additional data in the buffer, this is used as an element in
|
||
|
-the witches brew to generate the random data. The result is a
|
||
|
-cryptographically random number generator.
|
||
|
-Also, note that if you plan to sell your software to the United States
|
||
|
-federal government, you'll need to use FIPS 140-1-approved algorithms.
|
||
|
-The default versions of CryptGenRandom in Microsoft Windows CE v3,
|
||
|
-Windows 95, Windows 98, Windows Me, Windows 2000, and Windows XP are
|
||
|
-FIPS-approved. Obviously FIPS-140 compliance is necessary but not
|
||
|
-sufficient to provide a properly secure source of random data.
|
||
|
-
|
||
|
-*/
|
||
|
-/*
|
||
|
-[Update: 2007-11-13]
|
||
|
-CryptGenRandom does not necessarily provide forward secrecy or reverse
|
||
|
-secrecy. See the paper by Leo Dorrendorf and Zvi Gutterman and Benny
|
||
|
-Pinkas, _Cryptanalysis of the Random Number Generator of the Windows
|
||
|
-Operating System_, Cryptology ePrint Archive, Report 2007/419,
|
||
|
-http://eprint.iacr.org/2007/419
|
||
|
-*/
|
||
|
-
|
||
|
-#endif /* MS_WIN32 */
|