openmedialibrary_platform/Darwin/lib/python2.7/site-packages/twisted/python/randbytes.py

151 lines
3.9 KiB
Python
Raw Normal View History

2013-10-11 17:28:32 +00:00
# -*- test-case-name: twisted.test.test_randbytes -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Cryptographically secure random implementation, with fallback on normal random.
"""
from __future__ import division, absolute_import
import warnings, os, random, string
from twisted.python.compat import _PY3
getrandbits = getattr(random, 'getrandbits', None)
if _PY3:
_fromhex = bytes.fromhex
else:
def _fromhex(hexBytes):
return hexBytes.decode('hex')
class SecureRandomNotAvailable(RuntimeError):
"""
Exception raised when no secure random algorithm is found.
"""
class SourceNotAvailable(RuntimeError):
"""
Internal exception used when a specific random source is not available.
"""
class RandomFactory(object):
"""
Factory providing L{secureRandom} and L{insecureRandom} methods.
You shouldn't have to instantiate this class, use the module level
functions instead: it is an implementation detail and could be removed or
changed arbitrarily.
"""
# This variable is no longer used, and will eventually be removed.
randomSources = ()
getrandbits = getrandbits
def _osUrandom(self, nbytes):
"""
Wrapper around C{os.urandom} that cleanly manage its absence.
"""
try:
return os.urandom(nbytes)
except (AttributeError, NotImplementedError) as e:
raise SourceNotAvailable(e)
def secureRandom(self, nbytes, fallback=False):
"""
Return a number of secure random bytes.
@param nbytes: number of bytes to generate.
@type nbytes: C{int}
@param fallback: Whether the function should fallback on non-secure
random or not. Default to C{False}.
@type fallback: C{bool}
@return: a string of random bytes.
@rtype: C{str}
"""
try:
return self._osUrandom(nbytes)
except SourceNotAvailable:
pass
if fallback:
warnings.warn(
"urandom unavailable - "
"proceeding with non-cryptographically secure random source",
category=RuntimeWarning,
stacklevel=2)
return self.insecureRandom(nbytes)
else:
raise SecureRandomNotAvailable("No secure random source available")
def _randBits(self, nbytes):
"""
Wrapper around C{os.getrandbits}.
"""
if self.getrandbits is not None:
n = self.getrandbits(nbytes * 8)
hexBytes = ("%%0%dx" % (nbytes * 2)) % n
return _fromhex(hexBytes)
raise SourceNotAvailable("random.getrandbits is not available")
if _PY3:
_maketrans = bytes.maketrans
def _randModule(self, nbytes):
"""
Wrapper around the C{random} module.
"""
return b"".join([
bytes([random.choice(self._BYTES)]) for i in range(nbytes)])
else:
_maketrans = string.maketrans
def _randModule(self, nbytes):
"""
Wrapper around the C{random} module.
"""
return b"".join([
random.choice(self._BYTES) for i in range(nbytes)])
_BYTES = _maketrans(b'', b'')
def insecureRandom(self, nbytes):
"""
Return a number of non secure random bytes.
@param nbytes: number of bytes to generate.
@type nbytes: C{int}
@return: a string of random bytes.
@rtype: C{str}
"""
for src in ("_randBits", "_randModule"):
try:
return getattr(self, src)(nbytes)
except SourceNotAvailable:
pass
factory = RandomFactory()
secureRandom = factory.secureRandom
insecureRandom = factory.insecureRandom
del factory
__all__ = ["secureRandom", "insecureRandom", "SecureRandomNotAvailable"]