OLD | NEW |
| (Empty) |
1 # Copyright (c) 2007 Twisted Matrix Laboratories. | |
2 # See LICENSE for details. | |
3 | |
4 """ | |
5 Test cases for L{twisted.python.randbytes}. | |
6 """ | |
7 | |
8 import os, sys | |
9 | |
10 from twisted.trial import unittest | |
11 from twisted.python import randbytes | |
12 | |
13 try: | |
14 from Crypto.Util import randpool | |
15 except ImportError: | |
16 randpool = None | |
17 | |
18 | |
19 | |
20 class SecureRandomTestCaseBase(object): | |
21 """ | |
22 Base class for secureRandom test cases. | |
23 """ | |
24 | |
25 def _check(self, source): | |
26 """ | |
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). | |
32 """ | |
33 for nbytes in range(17, 25): | |
34 s = source(nbytes) | |
35 self.assertEquals(len(s), nbytes) | |
36 s2 = source(nbytes) | |
37 self.assertEquals(len(s2), nbytes) | |
38 # This is crude but hey | |
39 self.assertNotEquals(s2, s) | |
40 | |
41 | |
42 | |
43 class SecureRandomTestCase(SecureRandomTestCaseBase, unittest.TestCase): | |
44 """ | |
45 Test secureRandom under normal conditions. | |
46 """ | |
47 | |
48 def test_normal(self): | |
49 """ | |
50 L{randbytes.secureRandom} should return a string of the requested | |
51 length and make some effort to make its result otherwise unpredictable. | |
52 """ | |
53 self._check(randbytes.secureRandom) | |
54 | |
55 | |
56 | |
57 class ConditionalSecureRandomTestCase(SecureRandomTestCaseBase, | |
58 unittest.TestCase): | |
59 """ | |
60 Test random sources one by one, then remove it to. | |
61 """ | |
62 | |
63 def setUp(self): | |
64 """ | |
65 Create a L{randbytes.RandomFactory} to use in the tests. | |
66 """ | |
67 self.factory = randbytes.RandomFactory() | |
68 | |
69 | |
70 def errorFactory(self, nbytes): | |
71 """ | |
72 A factory raising an error when a source is not available. | |
73 """ | |
74 raise randbytes.SourceNotAvailable() | |
75 | |
76 | |
77 def test_osUrandom(self): | |
78 """ | |
79 L{RandomFactory._osUrandom} should work as a random source whenever | |
80 L{os.urandom} is available. | |
81 """ | |
82 try: | |
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)) | |
87 | |
88 | |
89 def test_fileUrandom(self): | |
90 """ | |
91 L{RandomFactory._fileUrandom} should work as a random source whenever | |
92 C{/dev/urandom} is available. | |
93 """ | |
94 try: | |
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')) | |
99 | |
100 | |
101 def test_cryptoRandom(self): | |
102 """ | |
103 L{RandomFactory._cryptoRandom} should work as a random source whenever | |
104 L{PyCrypto} is installed. | |
105 """ | |
106 try: | |
107 self._check(self.factory._cryptoRandom) | |
108 except randbytes.SourceNotAvailable: | |
109 # It fails if PyCrypto is not here | |
110 self.assertIdentical(randpool, None) | |
111 | |
112 | |
113 def test_withoutOsUrandom(self): | |
114 """ | |
115 If L{os.urandom} is not available but L{PyCrypto} is, | |
116 L{RandomFactory.secureRandom} should still work as a random source. | |
117 """ | |
118 self.factory._osUrandom = self.errorFactory | |
119 self._check(self.factory.secureRandom) | |
120 | |
121 if randpool is None: | |
122 test_withoutOsUrandom.skip = "PyCrypto not available" | |
123 | |
124 | |
125 def test_withoutOsAndFileUrandom(self): | |
126 """ | |
127 Remove C{os.urandom} and /dev/urandom read. | |
128 """ | |
129 self.factory._osUrandom = self.errorFactory | |
130 self.factory._fileUrandom = self.errorFactory | |
131 self._check(self.factory.secureRandom) | |
132 | |
133 if randpool is None: | |
134 test_withoutOsAndFileUrandom.skip = "PyCrypto not available" | |
135 | |
136 | |
137 def test_withoutAnything(self): | |
138 """ | |
139 Remove all secure sources and assert it raises a failure. Then try the | |
140 fallback parameter. | |
141 """ | |
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) | |
147 def wrapper(): | |
148 return self.factory.secureRandom(18, fallback=True) | |
149 s = self.assertWarns( | |
150 RuntimeWarning, | |
151 "Neither PyCrypto nor urandom available - " | |
152 "proceeding with non-cryptographically secure random source", | |
153 __file__, | |
154 wrapper) | |
155 self.assertEquals(len(s), 18) | |
156 | |
157 | |
158 | |
159 class RandomTestCaseBase(SecureRandomTestCaseBase, unittest.TestCase): | |
160 """ | |
161 'Normal' random test cases. | |
162 """ | |
163 | |
164 def test_normal(self): | |
165 """ | |
166 Test basic case. | |
167 """ | |
168 self._check(randbytes.insecureRandom) | |
169 | |
170 | |
171 def test_withoutGetrandbits(self): | |
172 """ | |
173 Test C{insecureRandom} without C{random.getrandbits}. | |
174 """ | |
175 factory = randbytes.RandomFactory() | |
176 factory.getrandbits = None | |
177 self._check(factory.insecureRandom) | |
178 | |
OLD | NEW |