test_BLAKE2.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. # ===================================================================
  2. #
  3. # Copyright (c) 2014, Legrandin <helderijs@gmail.com>
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions
  8. # are met:
  9. #
  10. # 1. Redistributions of source code must retain the above copyright
  11. # notice, this list of conditions and the following disclaimer.
  12. # 2. Redistributions in binary form must reproduce the above copyright
  13. # notice, this list of conditions and the following disclaimer in
  14. # the documentation and/or other materials provided with the
  15. # distribution.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25. # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  27. # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. # POSSIBILITY OF SUCH DAMAGE.
  29. # ===================================================================
  30. import os
  31. import re
  32. import unittest
  33. from binascii import unhexlify, hexlify
  34. from Crypto.Util.py3compat import b, tobytes, bchr
  35. from Crypto.Util.strxor import strxor_c
  36. from Crypto.Util._file_system import pycryptodome_filename
  37. from Crypto.SelfTest.st_common import list_test_cases
  38. from Crypto.Hash import BLAKE2b, BLAKE2s
  39. class Blake2Test(unittest.TestCase):
  40. def test_new_positive(self):
  41. h = self.BLAKE2.new(digest_bits=self.max_bits)
  42. for new_func in self.BLAKE2.new, h.new:
  43. for dbits in xrange(8, self.max_bits + 1, 8):
  44. hobj = new_func(digest_bits=dbits)
  45. self.assertEqual(hobj.digest_size, dbits // 8)
  46. for dbytes in xrange(1, self.max_bytes + 1):
  47. hobj = new_func(digest_bytes=dbytes)
  48. self.assertEqual(hobj.digest_size, dbytes)
  49. digest1 = new_func(data=b("\x90"), digest_bytes=self.max_bytes).digest()
  50. digest2 = new_func(digest_bytes=self.max_bytes).update(b("\x90")).digest()
  51. self.assertEqual(digest1, digest2)
  52. new_func(data=b("A"), key=b("5"), digest_bytes=self.max_bytes)
  53. hobj = h.new()
  54. self.assertEqual(hobj.digest_size, self.max_bytes)
  55. def test_new_negative(self):
  56. self.assertRaises(TypeError, self.BLAKE2.new)
  57. h = self.BLAKE2.new(digest_bits=self.max_bits)
  58. for new_func in self.BLAKE2.new, h.new:
  59. self.assertRaises(TypeError, new_func,
  60. digest_bytes=self.max_bytes,
  61. digest_bits=self.max_bits)
  62. self.assertRaises(ValueError, new_func, digest_bytes=0)
  63. self.assertRaises(ValueError, new_func,
  64. digest_bytes=self.max_bytes + 1)
  65. self.assertRaises(ValueError, new_func, digest_bits=7)
  66. self.assertRaises(ValueError, new_func, digest_bits=15)
  67. self.assertRaises(ValueError, new_func,
  68. digest_bits=self.max_bits + 1)
  69. self.assertRaises(TypeError, new_func,
  70. digest_bytes=self.max_bytes,
  71. key=u"string")
  72. self.assertRaises(TypeError, new_func,
  73. digest_bytes=self.max_bytes,
  74. data=u"string")
  75. def test_update(self):
  76. pieces = [bchr(10) * 200, bchr(20) * 300]
  77. h = self.BLAKE2.new(digest_bytes=self.max_bytes)
  78. h.update(pieces[0]).update(pieces[1])
  79. digest = h.digest()
  80. h = self.BLAKE2.new(digest_bytes=self.max_bytes)
  81. h.update(pieces[0] + pieces[1])
  82. self.assertEqual(h.digest(), digest)
  83. def test_update_negative(self):
  84. h = self.BLAKE2.new(digest_bytes=self.max_bytes)
  85. self.assertRaises(TypeError, h.update, u"string")
  86. def test_digest(self):
  87. h = self.BLAKE2.new(digest_bytes=self.max_bytes)
  88. digest = h.digest()
  89. # hexdigest does not change the state
  90. self.assertEqual(h.digest(), digest)
  91. # digest returns a byte string
  92. self.failUnless(isinstance(digest, type(b("digest"))))
  93. def test_update_after_digest(self):
  94. msg=b("rrrrttt")
  95. #import pdb; pdb.set_trace()
  96. # Normally, update() cannot be done after digest()
  97. h = self.BLAKE2.new(digest_bits=256, data=msg[:4])
  98. dig1 = h.digest()
  99. self.assertRaises(TypeError, h.update, msg[4:])
  100. dig2 = self.BLAKE2.new(digest_bits=256, data=msg).digest()
  101. # With the proper flag, it is allowed
  102. h = self.BLAKE2.new(digest_bits=256, data=msg[:4], update_after_digest=True)
  103. self.assertEquals(h.digest(), dig1)
  104. # ... and the subsequent digest applies to the entire message
  105. # up to that point
  106. h.update(msg[4:])
  107. self.assertEquals(h.digest(), dig2)
  108. def test_hex_digest(self):
  109. mac = self.BLAKE2.new(digest_bits=self.max_bits)
  110. digest = mac.digest()
  111. hexdigest = mac.hexdigest()
  112. # hexdigest is equivalent to digest
  113. self.assertEqual(hexlify(digest), tobytes(hexdigest))
  114. # hexdigest does not change the state
  115. self.assertEqual(mac.hexdigest(), hexdigest)
  116. # hexdigest returns a string
  117. self.failUnless(isinstance(hexdigest, type("digest")))
  118. def test_verify(self):
  119. h = self.BLAKE2.new(digest_bytes=self.max_bytes, key=b("4"))
  120. mac = h.digest()
  121. h.verify(mac)
  122. wrong_mac = strxor_c(mac, 255)
  123. self.assertRaises(ValueError, h.verify, wrong_mac)
  124. def test_hexverify(self):
  125. h = self.BLAKE2.new(digest_bytes=self.max_bytes, key=b("4"))
  126. mac = h.hexdigest()
  127. h.hexverify(mac)
  128. self.assertRaises(ValueError, h.hexverify, "4556")
  129. def test_oid(self):
  130. prefix = "1.3.6.1.4.1.1722.12.2." + self.oid_variant + "."
  131. for digest_bits in self.digest_bits_oid:
  132. h = self.BLAKE2.new(digest_bits=digest_bits)
  133. self.assertEqual(h.oid, prefix + str(digest_bits // 8))
  134. h = self.BLAKE2.new(digest_bits=digest_bits, key=b("secret"))
  135. self.assertRaises(AttributeError, lambda: h.oid)
  136. for digest_bits in (8, self.max_bits):
  137. if digest_bits in self.digest_bits_oid:
  138. continue
  139. self.assertRaises(AttributeError, lambda: h.oid)
  140. class Blake2bTest(Blake2Test):
  141. #: Module
  142. BLAKE2 = BLAKE2b
  143. #: Max output size (in bits)
  144. max_bits = 512
  145. #: Max output size (in bytes)
  146. max_bytes = 64
  147. #: Bit size of the digests for which an ASN OID exists
  148. digest_bits_oid = (160, 256, 384, 512)
  149. # http://tools.ietf.org/html/draft-saarinen-blake2-02
  150. oid_variant = "1"
  151. class Blake2sTest(Blake2Test):
  152. #: Module
  153. BLAKE2 = BLAKE2s
  154. #: Max output size (in bits)
  155. max_bits = 256
  156. #: Max output size (in bytes)
  157. max_bytes = 32
  158. #: Bit size of the digests for which an ASN OID exists
  159. digest_bits_oid = (128, 160, 224, 256)
  160. # http://tools.ietf.org/html/draft-saarinen-blake2-02
  161. oid_variant = "2"
  162. class Blake2OfficialTestVector(unittest.TestCase):
  163. def setUp(self):
  164. test_vector_file = pycryptodome_filename(
  165. ("Crypto", "SelfTest", "Hash", "test_vectors", self.name),
  166. self.name.lower() + "-test.txt")
  167. expected = "in"
  168. self.test_vectors = []
  169. for line_number, line in enumerate(open(test_vector_file, "rt")):
  170. if line.strip() == "" or line.startswith("#"):
  171. continue
  172. res = re.match("%s:\t([0-9A-Fa-f]*)" % expected, line)
  173. if not res:
  174. raise ValueError("Incorrect test vector format (line %d)"
  175. % line_number)
  176. if res.group(1):
  177. bin_value = unhexlify(tobytes(res.group(1)))
  178. else:
  179. bin_value = b("")
  180. if expected == "in":
  181. input_data = bin_value
  182. expected = "key"
  183. elif expected == "key":
  184. key = bin_value
  185. expected = "hash"
  186. else:
  187. result = bin_value
  188. expected = "in"
  189. self.test_vectors.append((input_data, key, result))
  190. def runTest(self):
  191. for (input_data, key, result) in self.test_vectors:
  192. mac = self.BLAKE2.new(key=key, digest_bytes=self.max_bytes)
  193. mac.update(input_data)
  194. self.assertEqual(mac.digest(), result)
  195. class Blake2bOfficialTestVector(Blake2OfficialTestVector):
  196. #: Module
  197. BLAKE2 = BLAKE2b
  198. #: Hash name
  199. name = "BLAKE2b"
  200. #: Max digest size
  201. max_bytes = 64
  202. class Blake2sOfficialTestVector(Blake2OfficialTestVector):
  203. #: Module
  204. BLAKE2 = BLAKE2s
  205. #: Hash name
  206. name = "BLAKE2s"
  207. #: Max digest size
  208. max_bytes = 32
  209. class Blake2TestVector1(unittest.TestCase):
  210. def setUp(self):
  211. test_vector_file = pycryptodome_filename(
  212. ("Crypto", "SelfTest", "Hash", "test_vectors", self.name),
  213. "tv1.txt")
  214. self.test_vectors = []
  215. for line_number, line in enumerate(open(test_vector_file, "rt")):
  216. if line.strip() == "" or line.startswith("#"):
  217. continue
  218. res = re.match("digest: ([0-9A-Fa-f]*)", line)
  219. if not res:
  220. raise ValueError("Incorrect test vector format (line %d)"
  221. % line_number)
  222. self.test_vectors.append(unhexlify(tobytes(res.group(1))))
  223. def runTest(self):
  224. for tv in self.test_vectors:
  225. digest_bytes = len(tv)
  226. next_data = b("")
  227. for _ in xrange(100):
  228. h = self.BLAKE2.new(digest_bytes=digest_bytes)
  229. h.update(next_data)
  230. next_data = h.digest() + next_data
  231. self.assertEqual(h.digest(), tv)
  232. class Blake2bTestVector1(Blake2TestVector1):
  233. #: Module
  234. BLAKE2 = BLAKE2b
  235. #: Hash name
  236. name = "BLAKE2b"
  237. class Blake2sTestVector1(Blake2TestVector1):
  238. #: Module
  239. BLAKE2 = BLAKE2s
  240. #: Hash name
  241. name = "BLAKE2s"
  242. class Blake2TestVector2(unittest.TestCase):
  243. def setUp(self):
  244. test_vector_file = pycryptodome_filename(
  245. ("Crypto", "SelfTest", "Hash", "test_vectors", self.name),
  246. "tv2.txt")
  247. self.test_vectors = []
  248. for line_number, line in enumerate(open(test_vector_file, "rt")):
  249. if line.strip() == "" or line.startswith("#"):
  250. continue
  251. res = re.match("digest\(([0-9]+)\): ([0-9A-Fa-f]*)", line)
  252. if not res:
  253. raise ValueError("Incorrect test vector format (line %d)"
  254. % line_number)
  255. key_size = int(res.group(1))
  256. result = unhexlify(tobytes(res.group(2)))
  257. self.test_vectors.append((key_size, result))
  258. def runTest(self):
  259. for key_size, result in self.test_vectors:
  260. next_data = b("")
  261. for _ in xrange(100):
  262. h = self.BLAKE2.new(digest_bytes=self.max_bytes,
  263. key=b("A" * key_size))
  264. h.update(next_data)
  265. next_data = h.digest() + next_data
  266. self.assertEqual(h.digest(), result)
  267. class Blake2bTestVector2(Blake2TestVector1):
  268. #: Module
  269. BLAKE2 = BLAKE2b
  270. #: Hash name
  271. name = "BLAKE2b"
  272. #: Max digest size in bytes
  273. max_bytes = 64
  274. class Blake2sTestVector2(Blake2TestVector1):
  275. #: Module
  276. BLAKE2 = BLAKE2s
  277. #: Hash name
  278. name = "BLAKE2s"
  279. #: Max digest size in bytes
  280. max_bytes = 32
  281. def get_tests(config={}):
  282. tests = []
  283. tests += list_test_cases(Blake2bTest)
  284. tests.append(Blake2bOfficialTestVector())
  285. tests.append(Blake2bTestVector1())
  286. tests.append(Blake2bTestVector2())
  287. tests += list_test_cases(Blake2sTest)
  288. tests.append(Blake2sOfficialTestVector())
  289. tests.append(Blake2sTestVector1())
  290. tests.append(Blake2sTestVector2())
  291. return tests
  292. if __name__ == '__main__':
  293. import unittest
  294. suite = lambda: unittest.TestSuite(get_tests())
  295. unittest.main(defaultTest='suite')