1
# Copyright (c) 2007 Twisted Matrix Laboratories.
2
# See LICENSE for details.
5
Test cases for L{twisted.python.randbytes}.
10
from twisted.trial import unittest
11
from twisted.python import randbytes
14
from Crypto.Util import randpool
20
class SecureRandomTestCaseBase(object):
22
Base class for secureRandom test cases.
25
def _check(self, source):
27
The given random bytes source should return the number of bytes
28
requested each time it is called and should probably not return the
29
same bytes on two consecutive calls (although this is a perfectly
30
legitimate occurrence and rejecting it may generate a spurious failure
31
-- maybe we'll get lucky and the heat death with come first).
33
for nbytes in range(17, 25):
35
self.assertEquals(len(s), nbytes)
37
self.assertEquals(len(s2), nbytes)
38
# This is crude but hey
39
self.assertNotEquals(s2, s)
43
class SecureRandomTestCase(SecureRandomTestCaseBase, unittest.TestCase):
45
Test secureRandom under normal conditions.
48
def test_normal(self):
50
L{randbytes.secureRandom} should return a string of the requested
51
length and make some effort to make its result otherwise unpredictable.
53
self._check(randbytes.secureRandom)
57
class ConditionalSecureRandomTestCase(SecureRandomTestCaseBase,
60
Test random sources one by one, then remove it to.
65
Create a L{randbytes.RandomFactory} to use in the tests.
67
self.factory = randbytes.RandomFactory()
70
def errorFactory(self, nbytes):
72
A factory raising an error when a source is not available.
74
raise randbytes.SourceNotAvailable()
77
def test_osUrandom(self):
79
L{RandomFactory._osUrandom} should work as a random source whenever
80
L{os.urandom} is available.
83
self._check(self.factory._osUrandom)
84
except randbytes.SourceNotAvailable:
85
# Not available on Python 2.3
86
self.assertTrue(sys.version_info < (2, 4))
89
def test_fileUrandom(self):
91
L{RandomFactory._fileUrandom} should work as a random source whenever
92
C{/dev/urandom} is available.
95
self._check(self.factory._fileUrandom)
96
except randbytes.SourceNotAvailable:
97
# The test should only fail in /dev/urandom doesn't exist
98
self.assertFalse(os.path.exists('/dev/urandom'))
101
def test_cryptoRandom(self):
103
L{RandomFactory._cryptoRandom} should work as a random source whenever
104
L{PyCrypto} is installed.
107
self._check(self.factory._cryptoRandom)
108
except randbytes.SourceNotAvailable:
109
# It fails if PyCrypto is not here
110
self.assertIdentical(randpool, None)
113
def test_withoutOsUrandom(self):
115
If L{os.urandom} is not available but L{PyCrypto} is,
116
L{RandomFactory.secureRandom} should still work as a random source.
118
self.factory._osUrandom = self.errorFactory
119
self._check(self.factory.secureRandom)
122
test_withoutOsUrandom.skip = "PyCrypto not available"
125
def test_withoutOsAndFileUrandom(self):
127
Remove C{os.urandom} and /dev/urandom read.
129
self.factory._osUrandom = self.errorFactory
130
self.factory._fileUrandom = self.errorFactory
131
self._check(self.factory.secureRandom)
134
test_withoutOsAndFileUrandom.skip = "PyCrypto not available"
137
def test_withoutAnything(self):
139
Remove all secure sources and assert it raises a failure. Then try the
142
self.factory._osUrandom = self.errorFactory
143
self.factory._fileUrandom = self.errorFactory
144
self.factory._cryptoRandom = self.errorFactory
145
self.assertRaises(randbytes.SecureRandomNotAvailable,
146
self.factory.secureRandom, 18)
148
return self.factory.secureRandom(18, fallback=True)
149
s = self.assertWarns(
151
"Neither PyCrypto nor urandom available - "
152
"proceeding with non-cryptographically secure random source",
155
self.assertEquals(len(s), 18)
159
class RandomTestCaseBase(SecureRandomTestCaseBase, unittest.TestCase):
161
'Normal' random test cases.
164
def test_normal(self):
168
self._check(randbytes.insecureRandom)
171
def test_withoutGetrandbits(self):
173
Test C{insecureRandom} without C{random.getrandbits}.
175
factory = randbytes.RandomFactory()
176
factory.getrandbits = None
177
self._check(factory.insecureRandom)