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