| 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 |