test_handlers_argon2.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. """passlib.tests.test_handlers_argon2 - tests for passlib hash algorithms"""
  2. #=============================================================================
  3. # imports
  4. #=============================================================================
  5. # core
  6. import logging
  7. log = logging.getLogger(__name__)
  8. import re
  9. import warnings
  10. # site
  11. # pkg
  12. from passlib import hash
  13. from passlib.utils.compat import unicode
  14. from passlib.tests.utils import HandlerCase, TEST_MODE
  15. from passlib.tests.test_handlers import UPASS_TABLE, PASS_TABLE_UTF8
  16. # module
  17. #=============================================================================
  18. # a bunch of tests lifted nearlky verbatim from official argon2 UTs...
  19. # https://github.com/P-H-C/phc-winner-argon2/blob/master/src/test.c
  20. #=============================================================================
  21. def hashtest(version, t, logM, p, secret, salt, hex_digest, hash):
  22. return dict(version=version, rounds=t, logM=logM, memory_cost=1<<logM, parallelism=p,
  23. secret=secret, salt=salt, hex_digest=hex_digest, hash=hash)
  24. # version 1.3 "I" tests
  25. version = 0x10
  26. reference_data = [
  27. hashtest(version, 2, 16, 1, "password", "somesalt",
  28. "f6c4db4a54e2a370627aff3db6176b94a2a209a62c8e36152711802f7b30c694",
  29. "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ"
  30. "$9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ"),
  31. hashtest(version, 2, 20, 1, "password", "somesalt",
  32. "9690ec55d28d3ed32562f2e73ea62b02b018757643a2ae6e79528459de8106e9",
  33. "$argon2i$m=1048576,t=2,p=1$c29tZXNhbHQ"
  34. "$lpDsVdKNPtMlYvLnPqYrArAYdXZDoq5ueVKEWd6BBuk"),
  35. hashtest(version, 2, 18, 1, "password", "somesalt",
  36. "3e689aaa3d28a77cf2bc72a51ac53166761751182f1ee292e3f677a7da4c2467",
  37. "$argon2i$m=262144,t=2,p=1$c29tZXNhbHQ"
  38. "$Pmiaqj0op3zyvHKlGsUxZnYXURgvHuKS4/Z3p9pMJGc"),
  39. hashtest(version, 2, 8, 1, "password", "somesalt",
  40. "fd4dd83d762c49bdeaf57c47bdcd0c2f1babf863fdeb490df63ede9975fccf06",
  41. "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ"
  42. "$/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY"),
  43. hashtest(version, 2, 8, 2, "password", "somesalt",
  44. "b6c11560a6a9d61eac706b79a2f97d68b4463aa3ad87e00c07e2b01e90c564fb",
  45. "$argon2i$m=256,t=2,p=2$c29tZXNhbHQ"
  46. "$tsEVYKap1h6scGt5ovl9aLRGOqOth+AMB+KwHpDFZPs"),
  47. hashtest(version, 1, 16, 1, "password", "somesalt",
  48. "81630552b8f3b1f48cdb1992c4c678643d490b2b5eb4ff6c4b3438b5621724b2",
  49. "$argon2i$m=65536,t=1,p=1$c29tZXNhbHQ"
  50. "$gWMFUrjzsfSM2xmSxMZ4ZD1JCytetP9sSzQ4tWIXJLI"),
  51. hashtest(version, 4, 16, 1, "password", "somesalt",
  52. "f212f01615e6eb5d74734dc3ef40ade2d51d052468d8c69440a3a1f2c1c2847b",
  53. "$argon2i$m=65536,t=4,p=1$c29tZXNhbHQ"
  54. "$8hLwFhXm6110c03D70Ct4tUdBSRo2MaUQKOh8sHChHs"),
  55. hashtest(version, 2, 16, 1, "differentpassword", "somesalt",
  56. "e9c902074b6754531a3a0be519e5baf404b30ce69b3f01ac3bf21229960109a3",
  57. "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ"
  58. "$6ckCB0tnVFMaOgvlGeW69ASzDOabPwGsO/ISKZYBCaM"),
  59. hashtest(version, 2, 16, 1, "password", "diffsalt",
  60. "79a103b90fe8aef8570cb31fc8b22259778916f8336b7bdac3892569d4f1c497",
  61. "$argon2i$m=65536,t=2,p=1$ZGlmZnNhbHQ"
  62. "$eaEDuQ/orvhXDLMfyLIiWXeJFvgza3vaw4kladTxxJc"),
  63. ]
  64. # version 1.9 "I" tests
  65. version = 0x13
  66. reference_data.extend([
  67. hashtest(version, 2, 16, 1, "password", "somesalt",
  68. "c1628832147d9720c5bd1cfd61367078729f6dfb6f8fea9ff98158e0d7816ed0",
  69. "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ"
  70. "$wWKIMhR9lyDFvRz9YTZweHKfbftvj+qf+YFY4NeBbtA"),
  71. hashtest(version, 2, 20, 1, "password", "somesalt",
  72. "d1587aca0922c3b5d6a83edab31bee3c4ebaef342ed6127a55d19b2351ad1f41",
  73. "$argon2i$v=19$m=1048576,t=2,p=1$c29tZXNhbHQ"
  74. "$0Vh6ygkiw7XWqD7asxvuPE667zQu1hJ6VdGbI1GtH0E"),
  75. hashtest(version, 2, 18, 1, "password", "somesalt",
  76. "296dbae80b807cdceaad44ae741b506f14db0959267b183b118f9b24229bc7cb",
  77. "$argon2i$v=19$m=262144,t=2,p=1$c29tZXNhbHQ"
  78. "$KW266AuAfNzqrUSudBtQbxTbCVkmexg7EY+bJCKbx8s"),
  79. hashtest(version, 2, 8, 1, "password", "somesalt",
  80. "89e9029f4637b295beb027056a7336c414fadd43f6b208645281cb214a56452f",
  81. "$argon2i$v=19$m=256,t=2,p=1$c29tZXNhbHQ"
  82. "$iekCn0Y3spW+sCcFanM2xBT63UP2sghkUoHLIUpWRS8"),
  83. hashtest(version, 2, 8, 2, "password", "somesalt",
  84. "4ff5ce2769a1d7f4c8a491df09d41a9fbe90e5eb02155a13e4c01e20cd4eab61",
  85. "$argon2i$v=19$m=256,t=2,p=2$c29tZXNhbHQ"
  86. "$T/XOJ2mh1/TIpJHfCdQan76Q5esCFVoT5MAeIM1Oq2E"),
  87. hashtest(version, 1, 16, 1, "password", "somesalt",
  88. "d168075c4d985e13ebeae560cf8b94c3b5d8a16c51916b6f4ac2da3ac11bbecf",
  89. "$argon2i$v=19$m=65536,t=1,p=1$c29tZXNhbHQ"
  90. "$0WgHXE2YXhPr6uVgz4uUw7XYoWxRkWtvSsLaOsEbvs8"),
  91. hashtest(version, 4, 16, 1, "password", "somesalt",
  92. "aaa953d58af3706ce3df1aefd4a64a84e31d7f54175231f1285259f88174ce5b",
  93. "$argon2i$v=19$m=65536,t=4,p=1$c29tZXNhbHQ"
  94. "$qqlT1YrzcGzj3xrv1KZKhOMdf1QXUjHxKFJZ+IF0zls"),
  95. hashtest(version, 2, 16, 1, "differentpassword", "somesalt",
  96. "14ae8da01afea8700c2358dcef7c5358d9021282bd88663a4562f59fb74d22ee",
  97. "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ"
  98. "$FK6NoBr+qHAMI1jc73xTWNkCEoK9iGY6RWL1n7dNIu4"),
  99. hashtest(version, 2, 16, 1, "password", "diffsalt",
  100. "b0357cccfbef91f3860b0dba447b2348cbefecadaf990abfe9cc40726c521271",
  101. "$argon2i$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ"
  102. "$sDV8zPvvkfOGCw26RHsjSMvv7K2vmQq/6cxAcmxSEnE"),
  103. ])
  104. # version 1.9 "ID" tests
  105. version = 0x13
  106. reference_data.extend([
  107. hashtest(version, 2, 16, 1, "password", "somesalt",
  108. "09316115d5cf24ed5a15a31a3ba326e5cf32edc24702987c02b6566f61913cf7",
  109. "$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ"
  110. "$CTFhFdXPJO1aFaMaO6Mm5c8y7cJHAph8ArZWb2GRPPc"),
  111. hashtest(version, 2, 18, 1, "password", "somesalt",
  112. "78fe1ec91fb3aa5657d72e710854e4c3d9b9198c742f9616c2f085bed95b2e8c",
  113. "$argon2id$v=19$m=262144,t=2,p=1$c29tZXNhbHQ"
  114. "$eP4eyR+zqlZX1y5xCFTkw9m5GYx0L5YWwvCFvtlbLow"),
  115. hashtest(version, 2, 8, 1, "password", "somesalt",
  116. "9dfeb910e80bad0311fee20f9c0e2b12c17987b4cac90c2ef54d5b3021c68bfe",
  117. "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ"
  118. "$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4"),
  119. hashtest(version, 2, 8, 2, "password", "somesalt",
  120. "6d093c501fd5999645e0ea3bf620d7b8be7fd2db59c20d9fff9539da2bf57037",
  121. "$argon2id$v=19$m=256,t=2,p=2$c29tZXNhbHQ"
  122. "$bQk8UB/VmZZF4Oo79iDXuL5/0ttZwg2f/5U52iv1cDc"),
  123. hashtest(version, 1, 16, 1, "password", "somesalt",
  124. "f6a5adc1ba723dddef9b5ac1d464e180fcd9dffc9d1cbf76cca2fed795d9ca98",
  125. "$argon2id$v=19$m=65536,t=1,p=1$c29tZXNhbHQ"
  126. "$9qWtwbpyPd3vm1rB1GThgPzZ3/ydHL92zKL+15XZypg"),
  127. hashtest(version, 4, 16, 1, "password", "somesalt",
  128. "9025d48e68ef7395cca9079da4c4ec3affb3c8911fe4f86d1a2520856f63172c",
  129. "$argon2id$v=19$m=65536,t=4,p=1$c29tZXNhbHQ"
  130. "$kCXUjmjvc5XMqQedpMTsOv+zyJEf5PhtGiUghW9jFyw"),
  131. hashtest(version, 2, 16, 1, "differentpassword", "somesalt",
  132. "0b84d652cf6b0c4beaef0dfe278ba6a80df6696281d7e0d2891b817d8c458fde",
  133. "$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ"
  134. "$C4TWUs9rDEvq7w3+J4umqA32aWKB1+DSiRuBfYxFj94"),
  135. hashtest(version, 2, 16, 1, "password", "diffsalt",
  136. "bdf32b05ccc42eb15d58fd19b1f856b113da1e9a5874fdcc544308565aa8141c",
  137. "$argon2id$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ"
  138. "$vfMrBczELrFdWP0ZsfhWsRPaHppYdP3MVEMIVlqoFBw"),
  139. ])
  140. #=============================================================================
  141. # argon2
  142. #=============================================================================
  143. class _base_argon2_test(HandlerCase):
  144. handler = hash.argon2
  145. known_correct_hashes = [
  146. #
  147. # custom
  148. #
  149. # sample test
  150. ("password", '$argon2i$v=19$m=256,t=1,p=1$c29tZXNhbHQ$AJFIsNZTMKTAewB4+ETN1A'),
  151. # sample w/ all parameters different
  152. ("password", '$argon2i$v=19$m=380,t=2,p=2$c29tZXNhbHQ$SrssP8n7m/12VWPM8dvNrw'),
  153. # ensures utf-8 used for unicode
  154. (UPASS_TABLE, '$argon2i$v=19$m=512,t=2,p=2$1sV0O4PWLtc12Ypv1f7oGw$'
  155. 'z+yqzlKtrq3SaNfXDfIDnQ'),
  156. (PASS_TABLE_UTF8, '$argon2i$v=19$m=512,t=2,p=2$1sV0O4PWLtc12Ypv1f7oGw$'
  157. 'z+yqzlKtrq3SaNfXDfIDnQ'),
  158. # ensure trailing null bytes handled correctly
  159. ('password\x00', '$argon2i$v=19$m=512,t=2,p=2$c29tZXNhbHQ$Fb5+nPuLzZvtqKRwqUEtUQ'),
  160. # sample with type D (generated via argon_cffi2.PasswordHasher)
  161. ("password", '$argon2d$v=19$m=102400,t=2,p=8$g2RodLh8j8WbSdCp+lUy/A$zzAJqL/HSjm809PYQu6qkA'),
  162. ]
  163. known_malformed_hashes = [
  164. # unknown hash type
  165. "$argon2qq$v=19$t=2,p=4$c29tZXNhbHQAAAAAAAAAAA$QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY",
  166. # missing 'm' param
  167. "$argon2i$v=19$t=2,p=4$c29tZXNhbHQAAAAAAAAAAA$QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY",
  168. # 't' param > max uint32
  169. "$argon2i$v=19$m=65536,t=8589934592,p=4$c29tZXNhbHQAAAAAAAAAAA$QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY",
  170. # unexpected param
  171. "$argon2i$v=19$m=65536,t=2,p=4,q=5$c29tZXNhbHQAAAAAAAAAAA$QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY",
  172. # wrong param order
  173. "$argon2i$v=19$t=2,m=65536,p=4,q=5$c29tZXNhbHQAAAAAAAAAAA$QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY",
  174. # constraint violation: m < 8 * p
  175. "$argon2i$v=19$m=127,t=2,p=16$c29tZXNhbHQ$IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4",
  176. ]
  177. known_parsehash_results = [
  178. ('$argon2i$v=19$m=256,t=2,p=3$c29tZXNhbHQ$AJFIsNZTMKTAewB4+ETN1A',
  179. dict(type="i", memory_cost=256, rounds=2, parallelism=3, salt=b'somesalt',
  180. checksum=b'\x00\x91H\xb0\xd6S0\xa4\xc0{\x00x\xf8D\xcd\xd4')),
  181. ]
  182. def setUpWarnings(self):
  183. super(_base_argon2_test, self).setUpWarnings()
  184. warnings.filterwarnings("ignore", ".*Using argon2pure backend.*")
  185. def do_stub_encrypt(self, handler=None, **settings):
  186. if self.backend == "argon2_cffi":
  187. # overriding default since no way to get stub config from argon2._calc_hash()
  188. # (otherwise test_21b_max_rounds blocks trying to do max rounds)
  189. handler = (handler or self.handler).using(**settings)
  190. self = handler(use_defaults=True)
  191. self.checksum = self._stub_checksum
  192. assert self.checksum
  193. return self.to_string()
  194. else:
  195. return super(_base_argon2_test, self).do_stub_encrypt(handler, **settings)
  196. def test_03_legacy_hash_workflow(self):
  197. # override base method
  198. raise self.skipTest("legacy 1.6 workflow not supported")
  199. def test_keyid_parameter(self):
  200. # NOTE: keyid parameter currently not supported by official argon2 hash parser,
  201. # even though it's mentioned in the format spec.
  202. # we're trying to be consistent w/ this, so hashes w/ keyid should
  203. # always through a NotImplementedError.
  204. self.assertRaises(NotImplementedError, self.handler.verify, 'password',
  205. "$argon2i$v=19$m=65536,t=2,p=4,keyid=ABCD$c29tZXNhbHQ$"
  206. "IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4")
  207. def test_data_parameter(self):
  208. # NOTE: argon2 c library doesn't support passing in a data parameter to argon2_hash();
  209. # but argon2_verify() appears to parse that info... but then discards it (!?).
  210. # not sure what proper behavior is, filed issue -- https://github.com/P-H-C/phc-winner-argon2/issues/143
  211. # For now, replicating behavior we have for the two backends, to detect when things change.
  212. handler = self.handler
  213. # ref hash of 'password' when 'data' is correctly passed into argon2()
  214. sample1 = '$argon2i$v=19$m=512,t=2,p=2,data=c29tZWRhdGE$c29tZXNhbHQ$KgHyCesFyyjkVkihZ5VNFw'
  215. # ref hash of 'password' when 'data' is silently discarded (same digest as w/o data)
  216. sample2 = '$argon2i$v=19$m=512,t=2,p=2,data=c29tZWRhdGE$c29tZXNhbHQ$uEeXt1dxN1iFKGhklseW4w'
  217. # hash of 'password' w/o the data field
  218. sample3 = '$argon2i$v=19$m=512,t=2,p=2$c29tZXNhbHQ$uEeXt1dxN1iFKGhklseW4w'
  219. #
  220. # test sample 1
  221. #
  222. if self.backend == "argon2_cffi":
  223. # argon2_cffi v16.1 would incorrectly return False here.
  224. # but v16.2 patches so it throws error on data parameter.
  225. # our code should detect that, and adapt it into a NotImplementedError
  226. self.assertRaises(NotImplementedError, handler.verify, "password", sample1)
  227. # incorrectly returns sample3, dropping data parameter
  228. self.assertEqual(handler.genhash("password", sample1), sample3)
  229. else:
  230. assert self.backend == "argon2pure"
  231. # should parse and verify
  232. self.assertTrue(handler.verify("password", sample1))
  233. # should preserve sample1
  234. self.assertEqual(handler.genhash("password", sample1), sample1)
  235. #
  236. # test sample 2
  237. #
  238. if self.backend == "argon2_cffi":
  239. # argon2_cffi v16.1 would incorrectly return True here.
  240. # but v16.2 patches so it throws error on data parameter.
  241. # our code should detect that, and adapt it into a NotImplementedError
  242. self.assertRaises(NotImplementedError, handler.verify,"password", sample2)
  243. # incorrectly returns sample3, dropping data parameter
  244. self.assertEqual(handler.genhash("password", sample1), sample3)
  245. else:
  246. assert self.backend == "argon2pure"
  247. # should parse, but fail to verify
  248. self.assertFalse(self.handler.verify("password", sample2))
  249. # should return sample1 (corrected digest)
  250. self.assertEqual(handler.genhash("password", sample2), sample1)
  251. def test_keyid_and_data_parameters(self):
  252. # test combination of the two, just in case
  253. self.assertRaises(NotImplementedError, self.handler.verify, 'stub',
  254. "$argon2i$v=19$m=65536,t=2,p=4,keyid=ABCD,data=EFGH$c29tZXNhbHQ$"
  255. "IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4")
  256. def test_type_kwd(self):
  257. cls = self.handler
  258. # XXX: this mirrors test_30_HasManyIdents();
  259. # maybe switch argon2 class to use that mixin instead of "type" kwd?
  260. # check settings
  261. self.assertTrue("type" in cls.setting_kwds)
  262. # check supported type_values
  263. for value in cls.type_values:
  264. self.assertIsInstance(value, unicode)
  265. self.assertTrue("i" in cls.type_values)
  266. self.assertTrue("d" in cls.type_values)
  267. # check default
  268. self.assertTrue(cls.type in cls.type_values)
  269. # check constructor validates ident correctly.
  270. handler = cls
  271. hash = self.get_sample_hash()[1]
  272. kwds = handler.parsehash(hash)
  273. del kwds['type']
  274. # ... accepts good type
  275. handler(type=cls.type, **kwds)
  276. # XXX: this is policy "ident" uses, maybe switch to it?
  277. # # ... requires type w/o defaults
  278. # self.assertRaises(TypeError, handler, **kwds)
  279. handler(**kwds)
  280. # ... supplies default type
  281. handler(use_defaults=True, **kwds)
  282. # ... rejects bad type
  283. self.assertRaises(ValueError, handler, type='xXx', **kwds)
  284. def test_type_using(self):
  285. handler = self.handler
  286. # XXX: this mirrors test_has_many_idents_using();
  287. # maybe switch argon2 class to use that mixin instead of "type" kwd?
  288. orig_type = handler.type
  289. for alt_type in handler.type_values:
  290. if alt_type != orig_type:
  291. break
  292. else:
  293. raise AssertionError("expected to find alternate type: default=%r values=%r" %
  294. (orig_type, handler.type_values))
  295. def effective_type(cls):
  296. return cls(use_defaults=True).type
  297. # keep default if nothing else specified
  298. subcls = handler.using()
  299. self.assertEqual(subcls.type, orig_type)
  300. # accepts alt type
  301. subcls = handler.using(type=alt_type)
  302. self.assertEqual(subcls.type, alt_type)
  303. self.assertEqual(handler.type, orig_type)
  304. # check subcls actually *generates* default type,
  305. # and that we didn't affect orig handler
  306. self.assertEqual(effective_type(subcls), alt_type)
  307. self.assertEqual(effective_type(handler), orig_type)
  308. # rejects bad type
  309. self.assertRaises(ValueError, handler.using, type='xXx')
  310. # honor 'type' alias
  311. subcls = handler.using(type=alt_type)
  312. self.assertEqual(subcls.type, alt_type)
  313. self.assertEqual(handler.type, orig_type)
  314. # check type aliases are being honored
  315. self.assertEqual(effective_type(handler.using(type="I")), "i")
  316. def test_needs_update_w_type(self):
  317. handler = self.handler
  318. hash = handler.hash("stub")
  319. self.assertFalse(handler.needs_update(hash))
  320. hash2 = re.sub(r"\$argon2\w+\$", "$argon2d$", hash)
  321. self.assertTrue(handler.needs_update(hash2))
  322. def test_needs_update_w_version(self):
  323. handler = self.handler.using(memory_cost=65536, time_cost=2, parallelism=4,
  324. digest_size=32)
  325. hash = ("$argon2i$m=65536,t=2,p=4$c29tZXNhbHQAAAAAAAAAAA$"
  326. "QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY")
  327. if handler.max_version == 0x10:
  328. self.assertFalse(handler.needs_update(hash))
  329. else:
  330. self.assertTrue(handler.needs_update(hash))
  331. def test_argon_byte_encoding(self):
  332. """verify we're using right base64 encoding for argon2"""
  333. handler = self.handler
  334. if handler.version != 0x13:
  335. # TODO: make this fatal, and add refs for other version.
  336. raise self.skipTest("handler uses wrong version for sample hashes")
  337. # 8 byte salt
  338. salt = b'somesalt'
  339. temp = handler.using(memory_cost=256, time_cost=2, parallelism=2, salt=salt,
  340. checksum_size=32, type="i")
  341. hash = temp.hash("password")
  342. self.assertEqual(hash, "$argon2i$v=19$m=256,t=2,p=2"
  343. "$c29tZXNhbHQ"
  344. "$T/XOJ2mh1/TIpJHfCdQan76Q5esCFVoT5MAeIM1Oq2E")
  345. # 16 byte salt
  346. salt = b'somesalt\x00\x00\x00\x00\x00\x00\x00\x00'
  347. temp = handler.using(memory_cost=256, time_cost=2, parallelism=2, salt=salt,
  348. checksum_size=32, type="i")
  349. hash = temp.hash("password")
  350. self.assertEqual(hash, "$argon2i$v=19$m=256,t=2,p=2"
  351. "$c29tZXNhbHQAAAAAAAAAAA"
  352. "$rqnbEp1/jFDUEKZZmw+z14amDsFqMDC53dIe57ZHD38")
  353. class FuzzHashGenerator(HandlerCase.FuzzHashGenerator):
  354. settings_map = HandlerCase.FuzzHashGenerator.settings_map.copy()
  355. settings_map.update(memory_cost="random_memory_cost", type="random_type")
  356. def random_type(self):
  357. return self.rng.choice(self.handler.type_values)
  358. def random_memory_cost(self):
  359. if self.test.backend == "argon2pure":
  360. return self.randintgauss(128, 384, 256, 128)
  361. else:
  362. return self.randintgauss(128, 32767, 16384, 4096)
  363. # TODO: fuzz parallelism, digest_size
  364. #-----------------------------------------
  365. # test suites for specific backends
  366. #-----------------------------------------
  367. class argon2_argon2_cffi_test(_base_argon2_test.create_backend_case("argon2_cffi")):
  368. # add some more test vectors that take too long under argon2pure
  369. known_correct_hashes = _base_argon2_test.known_correct_hashes + [
  370. #
  371. # sample hashes from argon2 cffi package's unittests,
  372. # which in turn were generated by official argon2 cmdline tool.
  373. #
  374. # v1.2, type I, w/o a version tag
  375. ('password', "$argon2i$m=65536,t=2,p=4$c29tZXNhbHQAAAAAAAAAAA$"
  376. "QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY"),
  377. # v1.3, type I
  378. ('password', "$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$"
  379. "IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4"),
  380. # v1.3, type D
  381. ('password', "$argon2d$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$"
  382. "cZn5d+rFh+ZfuRhm2iGUGgcrW5YLeM6q7L3vBsdmFA0"),
  383. # v1.3, type ID
  384. ('password', "$argon2id$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$"
  385. "GpZ3sK/oH9p7VIiV56G/64Zo/8GaUw434IimaPqxwCo"),
  386. #
  387. # custom
  388. #
  389. # ensure trailing null bytes handled correctly
  390. ('password\x00', "$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$"
  391. "Vpzuc0v0SrP88LcVvmg+z5RoOYpMDKH/lt6O+CZabIQ"),
  392. ]
  393. # add reference hashes from argon2 clib tests
  394. known_correct_hashes.extend(
  395. (info['secret'], info['hash']) for info in reference_data
  396. if info['logM'] <= (18 if TEST_MODE("full") else 16)
  397. )
  398. class argon2_argon2pure_test(_base_argon2_test.create_backend_case("argon2pure")):
  399. # XXX: setting max_threads at 1 to prevent argon2pure from using multiprocessing,
  400. # which causes big problems when testing under pypy.
  401. # would like a "pure_use_threads" option instead, to make it use multiprocessing.dummy instead.
  402. handler = hash.argon2.using(memory_cost=32, parallelism=2)
  403. # don't use multiprocessing for unittests, makes it a lot harder to ctrl-c
  404. # XXX: make this controlled by env var?
  405. handler.pure_use_threads = True
  406. # add reference hashes from argon2 clib tests
  407. known_correct_hashes = _base_argon2_test.known_correct_hashes[:]
  408. known_correct_hashes.extend(
  409. (info['secret'], info['hash']) for info in reference_data
  410. if info['logM'] < 16
  411. )
  412. class FuzzHashGenerator(_base_argon2_test.FuzzHashGenerator):
  413. def random_rounds(self):
  414. # decrease default rounds for fuzz testing to speed up volume.
  415. return self.randintgauss(1, 3, 2, 1)
  416. #=============================================================================
  417. # eof
  418. #=============================================================================