From a5fd7148fb0e9d5526f24feb1bb708bf203480b9 Mon Sep 17 00:00:00 2001 From: Paul Howarth Date: Fri, 7 Jun 2019 17:48:53 +0100 Subject: [PATCH] Replace the user-space RNG with a thin wrapper to os.urandom Replace the user-space RNG with a thin wrapper to os.urandom - Based on https://github.com/Legrandin/pycryptodome/commit/afd6328f - Fixes compatibility with Python 3.8 (#1718332) - Drop support for Python 2.1 --- pycrypto-2.6.1-drop-py2.1-support.patch | 296 ++++ pycrypto-2.6.1-use-os-random.patch | 1790 +++++++++++++++++++++++ python-crypto.spec | 19 +- 3 files changed, 2104 insertions(+), 1 deletion(-) create mode 100644 pycrypto-2.6.1-drop-py2.1-support.patch create mode 100644 pycrypto-2.6.1-use-os-random.patch diff --git a/pycrypto-2.6.1-drop-py2.1-support.patch b/pycrypto-2.6.1-drop-py2.1-support.patch new file mode 100644 index 0000000..682a2aa --- /dev/null +++ b/pycrypto-2.6.1-drop-py2.1-support.patch @@ -0,0 +1,296 @@ +--- lib/Crypto/Cipher/blockalgo.py ++++ lib/Crypto/Cipher/blockalgo.py +@@ -22,8 +22,6 @@ + """Module with definitions common to all block ciphers.""" + + import sys +-if sys.version_info[0] == 2 and sys.version_info[1] == 1: +- from Crypto.Util.py21compat import * + from Crypto.Util.py3compat import * + + #: *Electronic Code Book (ECB)*. +--- lib/Crypto/PublicKey/DSA.py ++++ lib/Crypto/PublicKey/DSA.py +@@ -82,8 +82,6 @@ __revision__ = "$Id$" + __all__ = ['generate', 'construct', 'error', 'DSAImplementation', '_DSAobj'] + + import sys +-if sys.version_info[0] == 2 and sys.version_info[1] == 1: +- from Crypto.Util.py21compat import * + + from Crypto.PublicKey import _DSA, _slowmath, pubkey + from Crypto import Random +--- lib/Crypto/PublicKey/RSA.py ++++ lib/Crypto/PublicKey/RSA.py +@@ -68,8 +68,6 @@ __revision__ = "$Id$" + __all__ = ['generate', 'construct', 'error', 'importKey', 'RSAImplementation', '_RSAobj'] + + 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 Crypto.Util.python_compat import * + from Crypto.Util.number import getRandomRange, bytes_to_long, long_to_bytes +--- lib/Crypto/PublicKey/_slowmath.py ++++ lib/Crypto/PublicKey/_slowmath.py +@@ -30,8 +30,6 @@ __all__ = ['rsa_construct'] + + import sys + +-if sys.version_info[0] == 2 and sys.version_info[1] == 1: +- from Crypto.Util.py21compat import * + from Crypto.Util.number import size, inverse, GCD + + class error(Exception): +--- lib/Crypto/Random/Fortuna/FortunaAccumulator.py ++++ lib/Crypto/Random/Fortuna/FortunaAccumulator.py +@@ -25,8 +25,6 @@ + __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 +--- lib/Crypto/Random/Fortuna/FortunaGenerator.py ++++ lib/Crypto/Random/Fortuna/FortunaGenerator.py +@@ -25,8 +25,6 @@ + __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 +--- lib/Crypto/Random/Fortuna/SHAd256.py ++++ lib/Crypto/Random/Fortuna/SHAd256.py +@@ -32,8 +32,6 @@ __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 +--- lib/Crypto/Random/random.py ++++ lib/Crypto/Random/random.py +@@ -29,8 +29,6 @@ __all__ = ['StrongRandom', 'getrandbits' + + 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): +--- lib/Crypto/SelfTest/PublicKey/test_DSA.py ++++ lib/Crypto/SelfTest/PublicKey/test_DSA.py +@@ -28,8 +28,6 @@ __revision__ = "$Id$" + + import sys + import os +-if sys.version_info[0] == 2 and sys.version_info[1] == 1: +- from Crypto.Util.py21compat import * + from Crypto.Util.py3compat import * + + import unittest +--- lib/Crypto/SelfTest/PublicKey/test_RSA.py ++++ lib/Crypto/SelfTest/PublicKey/test_RSA.py +@@ -28,8 +28,6 @@ __revision__ = "$Id$" + + import sys + import os +-if sys.version_info[0] == 2 and sys.version_info[1] == 1: +- from Crypto.Util.py21compat import * + from Crypto.Util.py3compat import * + + import unittest +--- lib/Crypto/SelfTest/Random/Fortuna/test_FortunaAccumulator.py ++++ lib/Crypto/SelfTest/Random/Fortuna/test_FortunaAccumulator.py +@@ -27,8 +27,6 @@ + __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 * + + import unittest +--- lib/Crypto/SelfTest/Random/Fortuna/test_FortunaGenerator.py ++++ lib/Crypto/SelfTest/Random/Fortuna/test_FortunaGenerator.py +@@ -27,8 +27,6 @@ + __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 * + + import unittest +--- lib/Crypto/SelfTest/Random/test_random.py ++++ lib/Crypto/SelfTest/Random/test_random.py +@@ -28,8 +28,6 @@ __revision__ = "$Id$" + + import unittest + import sys +-if sys.version_info[0] == 2 and sys.version_info[1] == 1: +- from Crypto.Util.py21compat import * + from Crypto.Util.py3compat import * + + class SimpleTest(unittest.TestCase): +--- lib/Crypto/SelfTest/st_common.py ++++ lib/Crypto/SelfTest/st_common.py +@@ -29,8 +29,6 @@ __revision__ = "$Id$" + import unittest + import binascii + import sys +-if sys.version_info[0] == 2 and sys.version_info[1] == 1: +- from Crypto.Util.py21compat import * + from Crypto.Util.py3compat import * + + class _list_testloader(unittest.TestLoader): +--- lib/Crypto/SelfTest/Util/test_Counter.py ++++ lib/Crypto/SelfTest/Util/test_Counter.py +@@ -27,8 +27,6 @@ + __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 * + + import unittest +--- lib/Crypto/SelfTest/Util/test_number.py ++++ lib/Crypto/SelfTest/Util/test_number.py +@@ -27,8 +27,6 @@ + __revision__ = "$Id$" + + import sys +-if sys.version_info[0] == 2 and sys.version_info[1] == 1: +- from Crypto.Util.py21compat import * + + import unittest + +--- lib/Crypto/Signature/PKCS1_PSS.py ++++ lib/Crypto/Signature/PKCS1_PSS.py +@@ -67,8 +67,6 @@ __revision__ = "$Id$" + __all__ = [ 'new', 'PSS_SigScheme' ] + + from Crypto.Util.py3compat import * +-if sys.version_info[0] == 2 and sys.version_info[1] == 1: +- from Crypto.Util.py21compat import * + import Crypto.Util.number + from Crypto.Util.number import ceil_shift, ceil_div, long_to_bytes + from Crypto.Util.strxor import strxor +--- lib/Crypto/Util/Counter.py ++++ lib/Crypto/Util/Counter.py +@@ -52,8 +52,6 @@ An example of usage is the following: + :undocumented: __package__ + """ + 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 Crypto.Util import _counter +--- lib/Crypto/Util/_number_new.py ++++ lib/Crypto/Util/_number_new.py +@@ -28,8 +28,6 @@ __revision__ = "$Id$" + __all__ = ['ceil_shift', 'ceil_div', 'floor_div', 'exact_log2', 'exact_div'] + + import sys +-if sys.version_info[0] == 2 and sys.version_info[1] == 1: +- from Crypto.Util.py21compat import * + + def ceil_shift(n, b): + """Return ceil(n / 2**b) without performing any floating-point or division operations. +--- lib/Crypto/Util/py21compat.py ++++ /dev/null +@@ -1,84 +0,0 @@ +-# -*- coding: utf-8 -*- +-# +-# Util/py21compat.py : Compatibility code for Python 2.1 +-# +-# Written in 2008 by Dwayne C. Litzenberger +-# +-# =================================================================== +-# 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. +-# =================================================================== +- +-"""Compatibility code for Python 2.1 +- +-Currently, this just defines: +- - True and False +- - object +- - isinstance +-""" +- +-__revision__ = "$Id$" +-__all__ = [] +- +-import sys +-import __builtin__ +- +-# 'True' and 'False' aren't defined in Python 2.1. Define them. +-try: +- True, False +-except NameError: +- (True, False) = (1, 0) +- __all__ += ['True', 'False'] +- +-# New-style classes were introduced in Python 2.2. Defining "object" in Python +-# 2.1 lets us use new-style classes in versions of Python that support them, +-# while still maintaining backward compatibility with old-style classes +-try: +- object +-except NameError: +- class object: pass +- __all__ += ['object'] +- +-# Starting with Python 2.2, isinstance allows a tuple for the second argument. +-# Also, builtins like "tuple", "list", "str", "unicode", "int", and "long" +-# became first-class types, rather than functions. We want to support +-# constructs like: +-# isinstance(x, (int, long)) +-# So we hack it for Python 2.1. +-try: +- isinstance(5, (int, long)) +-except TypeError: +- __all__ += ['isinstance'] +- _builtin_type_map = { +- tuple: type(()), +- list: type([]), +- str: type(""), +- unicode: type(u""), +- int: type(0), +- long: type(0L), +- } +- def isinstance(obj, t): +- if not __builtin__.isinstance(t, type(())): +- # t is not a tuple +- return __builtin__.isinstance(obj, _builtin_type_map.get(t, t)) +- else: +- # t is a tuple +- for typ in t: +- if __builtin__.isinstance(obj, _builtin_type_map.get(typ, typ)): +- return True +- return False +- +-# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/pycrypto-2.6.1-use-os-random.patch b/pycrypto-2.6.1-use-os-random.patch new file mode 100644 index 0000000..c7a4e24 --- /dev/null +++ b/pycrypto-2.6.1-use-os-random.patch @@ -0,0 +1,1790 @@ +--- 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 +-# + # =================================================================== + # 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 +-# +-# =================================================================== +-# 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 = "" +- +- 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 +-# +-# =================================================================== +-# 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 +-# +-# =================================================================== +-# 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 = "" +- +- 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 +-# +-# =================================================================== +-# 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 +-# +-# =================================================================== +-# 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 +-# +-# =================================================================== +-# 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 +-# +-# =================================================================== +-# 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 +-# +-# =================================================================== +-# 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 +-# +-# =================================================================== +-# 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 +-# +-# =================================================================== +-# 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 +-# +-# =================================================================== +-# 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 +-# +-# =================================================================== +-# 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 +-# +-# =================================================================== +-# 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 +-# +-# =================================================================== +-# 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 +-# +-# =================================================================== +-# 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 +-#include +- +-#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 +-). +- +-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 */ diff --git a/python-crypto.spec b/python-crypto.spec index 552be54..4a6ef8f 100644 --- a/python-crypto.spec +++ b/python-crypto.spec @@ -10,7 +10,7 @@ Summary: Cryptography library for Python Name: python-crypto Version: 2.6.1 -Release: 25%{?dist} +Release: 26%{?dist} # Mostly Public Domain apart from parts of HMAC.py and setup.py, which are Python License: Public Domain and Python URL: http://www.pycrypto.org/ @@ -21,6 +21,8 @@ Patch2: pycrypto-2.6.1-CVE-2013-7459.patch Patch3: pycrypto-2.6.1-unbundle-libtomcrypt.patch Patch4: python-crypto-2.6.1-link.patch Patch5: pycrypto-2.6.1-CVE-2018-6594.patch +Patch6: pycrypto-2.6.1-use-os-random.patch +Patch7: pycrypto-2.6.1-drop-py2.1-support.patch BuildRequires: coreutils BuildRequires: findutils BuildRequires: gcc @@ -88,6 +90,15 @@ rm -rf src/libtom # https://github.com/dlitz/pycrypto/pull/256 %patch5 +# Replace the user-space RNG with a thin wrapper to os.urandom +# Based on https://github.com/Legrandin/pycryptodome/commit/afd6328f +# Fixes compatibility with Python 3.8 (#1718332) +%patch6 + +# We already require Python 2.4 or later, so drop support for Python 2.1 +# in the code +%patch7 + # setup.py doesn't run 2to3 on pct-speedtest.py cp pct-speedtest.py pct-speedtest3.py 2to3 -wn pct-speedtest3.py @@ -126,6 +137,12 @@ PYTHONPATH=%{buildroot}%{python3_sitearch} %{__python3} pct-speedtest3.py %{python3_sitearch}/pycrypto-%{version}-py3.*.egg-info %changelog +* Fri Jun 7 2019 Paul Howarth - 2.6.1-26 +- Replace the user-space RNG with a thin wrapper to os.urandom + - Based on https://github.com/Legrandin/pycryptodome/commit/afd6328f + - Fixes compatibility with Python 3.8 (#1718332) +- Drop support for Python 2.1 + * Sat Feb 02 2019 Fedora Release Engineering - 2.6.1-25 - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild