1 # -*- test-case-name: twisted.test.test_randbytes -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
6 Cryptographically secure random implementation, with fallback on normal random.
10 import warnings, os, random
12 getrandbits = getattr(random, 'getrandbits', None)
15 class SecureRandomNotAvailable(RuntimeError):
17 Exception raised when no secure random algorithm is found.
22 class SourceNotAvailable(RuntimeError):
24 Internal exception used when a specific random source is not available.
29 class RandomFactory(object):
31 Factory providing L{secureRandom} and L{insecureRandom} methods.
33 You shouldn't have to instantiate this class, use the module level
34 functions instead: it is an implementation detail and could be removed or
38 # This variable is no longer used, and will eventually be removed.
41 getrandbits = getrandbits
44 def _osUrandom(self, nbytes):
46 Wrapper around C{os.urandom} that cleanly manage its absence.
49 return os.urandom(nbytes)
50 except (AttributeError, NotImplementedError), e:
51 raise SourceNotAvailable(e)
54 def secureRandom(self, nbytes, fallback=False):
56 Return a number of secure random bytes.
58 @param nbytes: number of bytes to generate.
60 @param fallback: Whether the function should fallback on non-secure
61 random or not. Default to C{False}.
62 @type fallback: C{bool}
64 @return: a string of random bytes.
68 return self._osUrandom(nbytes)
69 except SourceNotAvailable:
74 "urandom unavailable - "
75 "proceeding with non-cryptographically secure random source",
76 category=RuntimeWarning,
78 return self.insecureRandom(nbytes)
80 raise SecureRandomNotAvailable("No secure random source available")
83 def _randBits(self, nbytes):
85 Wrapper around C{os.getrandbits}.
87 if self.getrandbits is not None:
88 n = self.getrandbits(nbytes * 8)
89 hexBytes = ("%%0%dx" % (nbytes * 2)) % n
90 return hexBytes.decode('hex')
91 raise SourceNotAvailable("random.getrandbits is not available")
94 def _randRange(self, nbytes):
96 Wrapper around C{random.randrange}.
99 for i in xrange(nbytes):
100 bytes += chr(random.randrange(0, 255))
104 def insecureRandom(self, nbytes):
106 Return a number of non secure random bytes.
108 @param nbytes: number of bytes to generate.
111 @return: a string of random bytes.
114 for src in ("_randBits", "_randRange"):
116 return getattr(self, src)(nbytes)
117 except SourceNotAvailable:
122 factory = RandomFactory()
124 secureRandom = factory.secureRandom
126 insecureRandom = factory.insecureRandom
131 __all__ = ["secureRandom", "insecureRandom", "SecureRandomNotAvailable"]