common.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. # -*- coding: utf-8 -*-
  2. #
  3. # SelfTest/Hash/common.py: Common code for Cryptodome.SelfTest.Hash
  4. #
  5. # Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
  6. #
  7. # ===================================================================
  8. # The contents of this file are dedicated to the public domain. To
  9. # the extent that dedication to the public domain is not available,
  10. # everyone is granted a worldwide, perpetual, royalty-free,
  11. # non-exclusive license to exercise all rights associated with the
  12. # contents of this file for any purpose whatsoever.
  13. # No rights are reserved.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  19. # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  20. # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21. # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. # SOFTWARE.
  23. # ===================================================================
  24. """Self-testing for PyCryptodome hash modules"""
  25. import re
  26. import sys
  27. import unittest
  28. import binascii
  29. import Cryptodome.Hash
  30. from binascii import hexlify, unhexlify
  31. from Cryptodome.Util.py3compat import b, tobytes
  32. from Cryptodome.Util.strxor import strxor_c
  33. def t2b(hex_string):
  34. shorter = re.sub(br'\s+', b'', tobytes(hex_string))
  35. return unhexlify(shorter)
  36. class HashDigestSizeSelfTest(unittest.TestCase):
  37. def __init__(self, hashmod, description, expected, extra_params):
  38. unittest.TestCase.__init__(self)
  39. self.hashmod = hashmod
  40. self.expected = expected
  41. self.description = description
  42. self.extra_params = extra_params
  43. def shortDescription(self):
  44. return self.description
  45. def runTest(self):
  46. if "truncate" not in self.extra_params:
  47. self.failUnless(hasattr(self.hashmod, "digest_size"))
  48. self.assertEquals(self.hashmod.digest_size, self.expected)
  49. h = self.hashmod.new(**self.extra_params)
  50. self.failUnless(hasattr(h, "digest_size"))
  51. self.assertEquals(h.digest_size, self.expected)
  52. class HashSelfTest(unittest.TestCase):
  53. def __init__(self, hashmod, description, expected, input, extra_params):
  54. unittest.TestCase.__init__(self)
  55. self.hashmod = hashmod
  56. self.expected = expected.lower()
  57. self.input = input
  58. self.description = description
  59. self.extra_params = extra_params
  60. def shortDescription(self):
  61. return self.description
  62. def runTest(self):
  63. h = self.hashmod.new(**self.extra_params)
  64. h.update(self.input)
  65. out1 = binascii.b2a_hex(h.digest())
  66. out2 = h.hexdigest()
  67. h = self.hashmod.new(self.input, **self.extra_params)
  68. out3 = h.hexdigest()
  69. out4 = binascii.b2a_hex(h.digest())
  70. # PY3K: hexdigest() should return str(), and digest() bytes
  71. self.assertEqual(self.expected, out1) # h = .new(); h.update(data); h.digest()
  72. if sys.version_info[0] == 2:
  73. self.assertEqual(self.expected, out2) # h = .new(); h.update(data); h.hexdigest()
  74. self.assertEqual(self.expected, out3) # h = .new(data); h.hexdigest()
  75. else:
  76. self.assertEqual(self.expected.decode(), out2) # h = .new(); h.update(data); h.hexdigest()
  77. self.assertEqual(self.expected.decode(), out3) # h = .new(data); h.hexdigest()
  78. self.assertEqual(self.expected, out4) # h = .new(data); h.digest()
  79. # Verify that the .new() method produces a fresh hash object, except
  80. # for MD5 and SHA1, which are hashlib objects. (But test any .new()
  81. # method that does exist.)
  82. if self.hashmod.__name__ not in ('Cryptodome.Hash.MD5', 'Cryptodome.Hash.SHA1') or hasattr(h, 'new'):
  83. h2 = h.new()
  84. h2.update(self.input)
  85. out5 = binascii.b2a_hex(h2.digest())
  86. self.assertEqual(self.expected, out5)
  87. class HashTestOID(unittest.TestCase):
  88. def __init__(self, hashmod, oid, extra_params):
  89. unittest.TestCase.__init__(self)
  90. self.hashmod = hashmod
  91. self.oid = oid
  92. self.extra_params = extra_params
  93. def runTest(self):
  94. h = self.hashmod.new(**self.extra_params)
  95. self.assertEqual(h.oid, self.oid)
  96. class ByteArrayTest(unittest.TestCase):
  97. def __init__(self, module, extra_params):
  98. unittest.TestCase.__init__(self)
  99. self.module = module
  100. self.extra_params = extra_params
  101. def runTest(self):
  102. data = b("\x00\x01\x02")
  103. # Data can be a bytearray (during initialization)
  104. ba = bytearray(data)
  105. h1 = self.module.new(data, **self.extra_params)
  106. h2 = self.module.new(ba, **self.extra_params)
  107. ba[:1] = b'\xFF'
  108. self.assertEqual(h1.digest(), h2.digest())
  109. # Data can be a bytearray (during operation)
  110. ba = bytearray(data)
  111. h1 = self.module.new(**self.extra_params)
  112. h2 = self.module.new(**self.extra_params)
  113. h1.update(data)
  114. h2.update(ba)
  115. ba[:1] = b'\xFF'
  116. self.assertEqual(h1.digest(), h2.digest())
  117. class MemoryViewTest(unittest.TestCase):
  118. def __init__(self, module, extra_params):
  119. unittest.TestCase.__init__(self)
  120. self.module = module
  121. self.extra_params = extra_params
  122. def runTest(self):
  123. data = b"\x00\x01\x02"
  124. def get_mv_ro(data):
  125. return memoryview(data)
  126. def get_mv_rw(data):
  127. return memoryview(bytearray(data))
  128. for get_mv in get_mv_ro, get_mv_rw:
  129. # Data can be a memoryview (during initialization)
  130. mv = get_mv(data)
  131. h1 = self.module.new(data, **self.extra_params)
  132. h2 = self.module.new(mv, **self.extra_params)
  133. if not mv.readonly:
  134. mv[:1] = b'\xFF'
  135. self.assertEqual(h1.digest(), h2.digest())
  136. # Data can be a memoryview (during operation)
  137. mv = get_mv(data)
  138. h1 = self.module.new(**self.extra_params)
  139. h2 = self.module.new(**self.extra_params)
  140. h1.update(data)
  141. h2.update(mv)
  142. if not mv.readonly:
  143. mv[:1] = b'\xFF'
  144. self.assertEqual(h1.digest(), h2.digest())
  145. class MACSelfTest(unittest.TestCase):
  146. def __init__(self, module, description, result, data, key, params):
  147. unittest.TestCase.__init__(self)
  148. self.module = module
  149. self.result = t2b(result)
  150. self.data = t2b(data)
  151. self.key = t2b(key)
  152. self.params = params
  153. self.description = description
  154. def shortDescription(self):
  155. return self.description
  156. def runTest(self):
  157. result_hex = hexlify(self.result)
  158. # Verify result
  159. h = self.module.new(self.key, **self.params)
  160. h.update(self.data)
  161. self.assertEqual(self.result, h.digest())
  162. self.assertEqual(hexlify(self.result).decode('ascii'), h.hexdigest())
  163. # Verify that correct MAC does not raise any exception
  164. h.verify(self.result)
  165. h.hexverify(result_hex)
  166. # Verify that incorrect MAC does raise ValueError exception
  167. wrong_mac = strxor_c(self.result, 255)
  168. self.assertRaises(ValueError, h.verify, wrong_mac)
  169. self.assertRaises(ValueError, h.hexverify, "4556")
  170. # Verify again, with data passed to new()
  171. h = self.module.new(self.key, self.data, **self.params)
  172. self.assertEqual(self.result, h.digest())
  173. self.assertEqual(hexlify(self.result).decode('ascii'), h.hexdigest())
  174. # Test .copy()
  175. try:
  176. h = self.module.new(self.key, self.data, **self.params)
  177. h2 = h.copy()
  178. h3 = h.copy()
  179. # Verify that changing the copy does not change the original
  180. h2.update(b"bla")
  181. self.assertEqual(h3.digest(), self.result)
  182. # Verify that both can reach the same state
  183. h.update(b"bla")
  184. self.assertEqual(h.digest(), h2.digest())
  185. except NotImplementedError:
  186. pass
  187. # PY3K: Check that hexdigest() returns str and digest() returns bytes
  188. self.assertTrue(isinstance(h.digest(), type(b"")))
  189. self.assertTrue(isinstance(h.hexdigest(), type("")))
  190. # PY3K: Check that .hexverify() accepts bytes or str
  191. h.hexverify(h.hexdigest())
  192. h.hexverify(h.hexdigest().encode('ascii'))
  193. def make_hash_tests(module, module_name, test_data, digest_size, oid=None,
  194. extra_params={}):
  195. tests = []
  196. for i in range(len(test_data)):
  197. row = test_data[i]
  198. (expected, input) = map(tobytes,row[0:2])
  199. if len(row) < 3:
  200. description = repr(input)
  201. else:
  202. description = row[2]
  203. name = "%s #%d: %s" % (module_name, i+1, description)
  204. tests.append(HashSelfTest(module, name, expected, input, extra_params))
  205. name = "%s #%d: digest_size" % (module_name, len(test_data) + 1)
  206. tests.append(HashDigestSizeSelfTest(module, name, digest_size, extra_params))
  207. if oid is not None:
  208. tests.append(HashTestOID(module, oid, extra_params))
  209. tests.append(ByteArrayTest(module, extra_params))
  210. tests.append(MemoryViewTest(module, extra_params))
  211. return tests
  212. def make_mac_tests(module, module_name, test_data):
  213. tests = []
  214. for i, row in enumerate(test_data):
  215. if len(row) == 4:
  216. (key, data, results, description, params) = list(row) + [ {} ]
  217. else:
  218. (key, data, results, description, params) = row
  219. name = "%s #%d: %s" % (module_name, i+1, description)
  220. tests.append(MACSelfTest(module, name, results, data, key, params))
  221. return tests
  222. # vim:set ts=4 sw=4 sts=4 expandtab: