1
# -*- test-case-name: twisted.test.test_randbytes -*-
2
# Copyright (c) 2007 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
from Crypto.Util import randpool
21
class SecureRandomNotAvailable(RuntimeError):
23
Exception raised when no secure random algorithm is found.
28
class SourceNotAvailable(RuntimeError):
30
Internal exception used when a specific random source is not available.
35
class RandomFactory(object):
37
Factory providing L{secureRandom} and L{insecureRandom} methods.
39
You shouldn't have to instantiate this class, use the module level
40
functions instead: it is an implementation detail and could be removed or
43
@ivar randomPool: pool of random data.
44
@type randomPool: C{randpool.RandomPool}
46
@cvar randomSources: list of file sources used when os.urandom is not
48
@type randomSources: C{tuple}
52
randomSources = ('/dev/urandom',)
53
getrandbits = getrandbits
56
def _osUrandom(self, nbytes):
58
Wrapper around C{os.urandom} that cleanly manage its absence.
61
return os.urandom(nbytes)
62
except (AttributeError, NotImplementedError), e:
63
raise SourceNotAvailable(e)
66
def _fileUrandom(self, nbytes):
68
Wrapper around random file sources.
70
This method isn't meant to be call out of the class and could be
73
for src in self.randomSources:
76
except (IOError, OSError):
79
bytes = f.read(nbytes)
82
raise SourceNotAvailable("File sources not available: %s" %
83
(self.randomSources,))
86
def _cryptoRandom(self, nbytes):
88
Wrapper around Crypo random pool.
90
if self.randpool is not None:
91
if self.randomPool is None:
92
self.randomPool = self.randpool.RandomPool()
93
self.randomPool.stir()
94
return self.randomPool.get_bytes(nbytes)
95
raise SourceNotAvailable("PyCrypto isn't installed")
98
def secureRandom(self, nbytes, fallback=False):
100
Return a number of secure random bytes.
102
@param nbytes: number of bytes to generate.
104
@param fallback: Whether the function should fallback on non-secure
105
random or not. Default to C{False}.
106
@type fallback: C{bool}
108
@return: a string of random bytes.
111
for src in ("_osUrandom", "_fileUrandom", "_cryptoRandom"):
113
return getattr(self, src)(nbytes)
114
except SourceNotAvailable:
118
"Neither PyCrypto nor urandom available - "
119
"proceeding with non-cryptographically secure random source",
120
category=RuntimeWarning,
123
return self.insecureRandom(nbytes)
125
raise SecureRandomNotAvailable("No secure random source available")
128
def _randBits(self, nbytes):
130
Wrapper around C{os.getrandbits}.
132
if self.getrandbits is not None:
133
n = self.getrandbits(nbytes * 8)
134
hexBytes = ("%%0%dx" % (nbytes * 2)) % n
135
return hexBytes.decode('hex')
136
raise SourceNotAvailable("random.getrandbits is not available")
139
def _randRange(self, nbytes):
141
Wrapper around C{random.randrange}.
144
for i in xrange(nbytes):
145
bytes += chr(random.randrange(0, 255))
149
def insecureRandom(self, nbytes):
151
Return a number of non secure random bytes.
153
@param nbytes: number of bytes to generate.
156
@return: a string of random bytes.
159
for src in ("_randBits", "_randRange"):
161
return getattr(self, src)(nbytes)
162
except SourceNotAvailable:
167
factory = RandomFactory()
169
secureRandom = factory.secureRandom
171
insecureRandom = factory.insecureRandom
176
__all__ = ["secureRandom", "insecureRandom", "SecureRandomNotAvailable"]