test_handlers_pbkdf2.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. """passlib.tests.test_handlers - tests for passlib hash algorithms"""
  2. #=============================================================================
  3. # imports
  4. #=============================================================================
  5. # core
  6. import logging
  7. log = logging.getLogger(__name__)
  8. import warnings
  9. # site
  10. # pkg
  11. from passlib import hash
  12. from passlib.utils.compat import u
  13. from passlib.tests.utils import TestCase, HandlerCase
  14. from passlib.tests.test_handlers import UPASS_WAV
  15. # module
  16. #=============================================================================
  17. # ldap_pbkdf2_{digest}
  18. #=============================================================================
  19. # NOTE: since these are all wrappers for the pbkdf2_{digest} hasehs,
  20. # they don't extensive separate testing.
  21. class ldap_pbkdf2_test(TestCase):
  22. def test_wrappers(self):
  23. """test ldap pbkdf2 wrappers"""
  24. self.assertTrue(
  25. hash.ldap_pbkdf2_sha1.verify(
  26. "password",
  27. '{PBKDF2}1212$OB.dtnSEXZK8U5cgxU/GYQ$y5LKPOplRmok7CZp/aqVDVg8zGI',
  28. )
  29. )
  30. self.assertTrue(
  31. hash.ldap_pbkdf2_sha256.verify(
  32. "password",
  33. '{PBKDF2-SHA256}1212$4vjV83LKPjQzk31VI4E0Vw$hsYF68OiOUPdDZ1Fg'
  34. '.fJPeq1h/gXXY7acBp9/6c.tmQ'
  35. )
  36. )
  37. self.assertTrue(
  38. hash.ldap_pbkdf2_sha512.verify(
  39. "password",
  40. '{PBKDF2-SHA512}1212$RHY0Fr3IDMSVO/RSZyb5ow$eNLfBK.eVozomMr.1gYa1'
  41. '7k9B7KIK25NOEshvhrSX.esqY3s.FvWZViXz4KoLlQI.BzY/YTNJOiKc5gBYFYGww'
  42. )
  43. )
  44. #=============================================================================
  45. # pbkdf2 hashes
  46. #=============================================================================
  47. class atlassian_pbkdf2_sha1_test(HandlerCase):
  48. handler = hash.atlassian_pbkdf2_sha1
  49. known_correct_hashes = [
  50. #
  51. # generated using Jira
  52. #
  53. ("admin", '{PKCS5S2}c4xaeTQM0lUieMS3V5voiexyX9XhqC2dBd5ecVy60IPksHChwoTAVYFrhsgoq8/p'),
  54. (UPASS_WAV,
  55. "{PKCS5S2}cE9Yq6Am5tQGdHSHhky2XLeOnURwzaLBG2sur7FHKpvy2u0qDn6GcVGRjlmJoIUy"),
  56. ]
  57. known_malformed_hashes = [
  58. # bad char ---\/
  59. '{PKCS5S2}c4xaeTQM0lUieMS3V5voiexyX9XhqC2dBd5ecVy!0IPksHChwoTAVYFrhsgoq8/p'
  60. # bad size, missing padding
  61. '{PKCS5S2}c4xaeTQM0lUieMS3V5voiexyX9XhqC2dBd5ecVy60IPksHChwoTAVYFrhsgoq8/'
  62. # bad size, with correct padding
  63. '{PKCS5S2}c4xaeTQM0lUieMS3V5voiexyX9XhqC2dBd5ecVy60IPksHChwoTAVYFrhsgoq8/='
  64. ]
  65. class pbkdf2_sha1_test(HandlerCase):
  66. handler = hash.pbkdf2_sha1
  67. known_correct_hashes = [
  68. ("password", '$pbkdf2$1212$OB.dtnSEXZK8U5cgxU/GYQ$y5LKPOplRmok7CZp/aqVDVg8zGI'),
  69. (UPASS_WAV,
  70. '$pbkdf2$1212$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc'),
  71. ]
  72. known_malformed_hashes = [
  73. # zero padded rounds field
  74. '$pbkdf2$01212$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc',
  75. # empty rounds field
  76. '$pbkdf2$$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc',
  77. # too many field
  78. '$pbkdf2$1212$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc$',
  79. ]
  80. class pbkdf2_sha256_test(HandlerCase):
  81. handler = hash.pbkdf2_sha256
  82. known_correct_hashes = [
  83. ("password",
  84. '$pbkdf2-sha256$1212$4vjV83LKPjQzk31VI4E0Vw$hsYF68OiOUPdDZ1Fg.fJPeq1h/gXXY7acBp9/6c.tmQ'
  85. ),
  86. (UPASS_WAV,
  87. '$pbkdf2-sha256$1212$3SABFJGDtyhrQMVt1uABPw$WyaUoqCLgvz97s523nF4iuOqZNbp5Nt8do/cuaa7AiI'
  88. ),
  89. ]
  90. class pbkdf2_sha512_test(HandlerCase):
  91. handler = hash.pbkdf2_sha512
  92. known_correct_hashes = [
  93. ("password",
  94. '$pbkdf2-sha512$1212$RHY0Fr3IDMSVO/RSZyb5ow$eNLfBK.eVozomMr.1gYa1'
  95. '7k9B7KIK25NOEshvhrSX.esqY3s.FvWZViXz4KoLlQI.BzY/YTNJOiKc5gBYFYGww'
  96. ),
  97. (UPASS_WAV,
  98. '$pbkdf2-sha512$1212$KkbvoKGsAIcF8IslDR6skQ$8be/PRmd88Ps8fmPowCJt'
  99. 'tH9G3vgxpG.Krjt3KT.NP6cKJ0V4Prarqf.HBwz0dCkJ6xgWnSj2ynXSV7MlvMa8Q'
  100. ),
  101. ]
  102. class cta_pbkdf2_sha1_test(HandlerCase):
  103. handler = hash.cta_pbkdf2_sha1
  104. known_correct_hashes = [
  105. #
  106. # test vectors from original implementation
  107. #
  108. (u("hashy the \N{SNOWMAN}"), '$p5k2$1000$ZxK4ZBJCfQg=$jJZVscWtO--p1-xIZl6jhO2LKR0='),
  109. #
  110. # custom
  111. #
  112. ("password", "$p5k2$1$$h1TDLGSw9ST8UMAPeIE13i0t12c="),
  113. (UPASS_WAV,
  114. "$p5k2$4321$OTg3NjU0MzIx$jINJrSvZ3LXeIbUdrJkRpN62_WQ="),
  115. ]
  116. class dlitz_pbkdf2_sha1_test(HandlerCase):
  117. handler = hash.dlitz_pbkdf2_sha1
  118. known_correct_hashes = [
  119. #
  120. # test vectors from original implementation
  121. #
  122. ('cloadm', '$p5k2$$exec$r1EWMCMk7Rlv3L/RNcFXviDefYa0hlql'),
  123. ('gnu', '$p5k2$c$u9HvcT4d$Sd1gwSVCLZYAuqZ25piRnbBEoAesaa/g'),
  124. ('dcl', '$p5k2$d$tUsch7fU$nqDkaxMDOFBeJsTSfABsyn.PYUXilHwL'),
  125. ('spam', '$p5k2$3e8$H0NX9mT/$wk/sE8vv6OMKuMaqazCJYDSUhWY9YB2J'),
  126. (UPASS_WAV,
  127. '$p5k2$$KosHgqNo$9mjN8gqjt02hDoP0c2J0ABtLIwtot8cQ'),
  128. ]
  129. class grub_pbkdf2_sha512_test(HandlerCase):
  130. handler = hash.grub_pbkdf2_sha512
  131. known_correct_hashes = [
  132. #
  133. # test vectors generated from cmd line tool
  134. #
  135. # salt=32 bytes
  136. (UPASS_WAV,
  137. 'grub.pbkdf2.sha512.10000.BCAC1CEC5E4341C8C511C529'
  138. '7FA877BE91C2817B32A35A3ECF5CA6B8B257F751.6968526A'
  139. '2A5B1AEEE0A29A9E057336B48D388FFB3F600233237223C21'
  140. '04DE1752CEC35B0DD1ED49563398A282C0F471099C2803FBA'
  141. '47C7919CABC43192C68F60'),
  142. # salt=64 bytes
  143. ('toomanysecrets',
  144. 'grub.pbkdf2.sha512.10000.9B436BB6978682363D5C449B'
  145. 'BEAB322676946C632208BC1294D51F47174A9A3B04A7E4785'
  146. '986CD4EA7470FAB8FE9F6BD522D1FC6C51109A8596FB7AD48'
  147. '7C4493.0FE5EF169AFFCB67D86E2581B1E251D88C777B98BA'
  148. '2D3256ECC9F765D84956FC5CA5C4B6FD711AA285F0A04DCF4'
  149. '634083F9A20F4B6F339A52FBD6BED618E527B'),
  150. ]
  151. #=============================================================================
  152. # scram hash
  153. #=============================================================================
  154. class scram_test(HandlerCase):
  155. handler = hash.scram
  156. # TODO: need a bunch more reference vectors from some real
  157. # SCRAM transactions.
  158. known_correct_hashes = [
  159. #
  160. # taken from example in SCRAM specification (rfc 5802)
  161. #
  162. ('pencil', '$scram$4096$QSXCR.Q6sek8bf92$'
  163. 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30'),
  164. #
  165. # custom
  166. #
  167. # same as 5802 example hash, but with sha-256 & sha-512 added.
  168. ('pencil', '$scram$4096$QSXCR.Q6sek8bf92$'
  169. 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,'
  170. 'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVY,'
  171. 'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/'
  172. 'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ'),
  173. # test unicode passwords & saslprep (all the passwords below
  174. # should normalize to the same value: 'IX \xE0')
  175. (u('IX \xE0'), '$scram$6400$0BojBCBE6P2/N4bQ$'
  176. 'sha-1=YniLes.b8WFMvBhtSACZyyvxeCc'),
  177. (u('\u2168\u3000a\u0300'), '$scram$6400$0BojBCBE6P2/N4bQ$'
  178. 'sha-1=YniLes.b8WFMvBhtSACZyyvxeCc'),
  179. (u('\u00ADIX \xE0'), '$scram$6400$0BojBCBE6P2/N4bQ$'
  180. 'sha-1=YniLes.b8WFMvBhtSACZyyvxeCc'),
  181. ]
  182. known_malformed_hashes = [
  183. # zero-padding in rounds
  184. '$scram$04096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30',
  185. # non-digit in rounds
  186. '$scram$409A$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30',
  187. # bad char in salt ---\/
  188. '$scram$4096$QSXCR.Q6sek8bf9-$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30',
  189. # bad char in digest ---\/
  190. '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX3-',
  191. # missing sections
  192. '$scram$4096$QSXCR.Q6sek8bf92',
  193. '$scram$4096$QSXCR.Q6sek8bf92$',
  194. # too many sections
  195. '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30$',
  196. # missing separator
  197. '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30'
  198. 'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVY',
  199. # too many chars in alg name
  200. '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,'
  201. 'shaxxx-190=HZbuOlKbWl.eR8AfIposuKbhX30',
  202. # missing sha-1 alg
  203. '$scram$4096$QSXCR.Q6sek8bf92$sha-256=HZbuOlKbWl.eR8AfIposuKbhX30',
  204. # non-iana name
  205. '$scram$4096$QSXCR.Q6sek8bf92$sha1=HZbuOlKbWl.eR8AfIposuKbhX30',
  206. ]
  207. def setUp(self):
  208. super(scram_test, self).setUp()
  209. # some platforms lack stringprep (e.g. Jython, IronPython)
  210. self.require_stringprep()
  211. # silence norm_hash_name() warning
  212. warnings.filterwarnings("ignore", r"norm_hash_name\(\): unknown hash")
  213. def test_90_algs(self):
  214. """test parsing of 'algs' setting"""
  215. defaults = dict(salt=b'A'*10, rounds=1000)
  216. def parse(algs, **kwds):
  217. for k in defaults:
  218. kwds.setdefault(k, defaults[k])
  219. return self.handler(algs=algs, **kwds).algs
  220. # None -> default list
  221. self.assertEqual(parse(None, use_defaults=True), hash.scram.default_algs)
  222. self.assertRaises(TypeError, parse, None)
  223. # strings should be parsed
  224. self.assertEqual(parse("sha1"), ["sha-1"])
  225. self.assertEqual(parse("sha1, sha256, md5"), ["md5","sha-1","sha-256"])
  226. # lists should be normalized
  227. self.assertEqual(parse(["sha-1","sha256"]), ["sha-1","sha-256"])
  228. # sha-1 required
  229. self.assertRaises(ValueError, parse, ["sha-256"])
  230. self.assertRaises(ValueError, parse, algs=[], use_defaults=True)
  231. # alg names must be < 10 chars
  232. self.assertRaises(ValueError, parse, ["sha-1","shaxxx-190"])
  233. # alg & checksum mutually exclusive.
  234. self.assertRaises(RuntimeError, parse, ['sha-1'],
  235. checksum={"sha-1": b"\x00"*20})
  236. def test_90_checksums(self):
  237. """test internal parsing of 'checksum' keyword"""
  238. # check non-bytes checksum values are rejected
  239. self.assertRaises(TypeError, self.handler, use_defaults=True,
  240. checksum={'sha-1': u('X')*20})
  241. # check sha-1 is required
  242. self.assertRaises(ValueError, self.handler, use_defaults=True,
  243. checksum={'sha-256': b'X'*32})
  244. # XXX: anything else that's not tested by the other code already?
  245. def test_91_extract_digest_info(self):
  246. """test scram.extract_digest_info()"""
  247. edi = self.handler.extract_digest_info
  248. # return appropriate value or throw KeyError
  249. h = "$scram$10$AAAAAA$sha-1=AQ,bbb=Ag,ccc=Aw"
  250. s = b'\x00'*4
  251. self.assertEqual(edi(h,"SHA1"), (s,10, b'\x01'))
  252. self.assertEqual(edi(h,"bbb"), (s,10, b'\x02'))
  253. self.assertEqual(edi(h,"ccc"), (s,10, b'\x03'))
  254. self.assertRaises(KeyError, edi, h, "ddd")
  255. # config strings should cause value error.
  256. c = "$scram$10$....$sha-1,bbb,ccc"
  257. self.assertRaises(ValueError, edi, c, "sha-1")
  258. self.assertRaises(ValueError, edi, c, "bbb")
  259. self.assertRaises(ValueError, edi, c, "ddd")
  260. def test_92_extract_digest_algs(self):
  261. """test scram.extract_digest_algs()"""
  262. eda = self.handler.extract_digest_algs
  263. self.assertEqual(eda('$scram$4096$QSXCR.Q6sek8bf92$'
  264. 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30'), ["sha-1"])
  265. self.assertEqual(eda('$scram$4096$QSXCR.Q6sek8bf92$'
  266. 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30', format="hashlib"),
  267. ["sha1"])
  268. self.assertEqual(eda('$scram$4096$QSXCR.Q6sek8bf92$'
  269. 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,'
  270. 'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVY,'
  271. 'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/'
  272. 'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ'),
  273. ["sha-1","sha-256","sha-512"])
  274. def test_93_derive_digest(self):
  275. """test scram.derive_digest()"""
  276. # NOTE: this just does a light test, since derive_digest
  277. # is used by hash / verify, and is tested pretty well via those.
  278. hash = self.handler.derive_digest
  279. # check various encodings of password work.
  280. s1 = b'\x01\x02\x03'
  281. d1 = b'\xb2\xfb\xab\x82[tNuPnI\x8aZZ\x19\x87\xcen\xe9\xd3'
  282. self.assertEqual(hash(u("\u2168"), s1, 1000, 'sha-1'), d1)
  283. self.assertEqual(hash(b"\xe2\x85\xa8", s1, 1000, 'SHA-1'), d1)
  284. self.assertEqual(hash(u("IX"), s1, 1000, 'sha1'), d1)
  285. self.assertEqual(hash(b"IX", s1, 1000, 'SHA1'), d1)
  286. # check algs
  287. self.assertEqual(hash("IX", s1, 1000, 'md5'),
  288. b'3\x19\x18\xc0\x1c/\xa8\xbf\xe4\xa3\xc2\x8eM\xe8od')
  289. self.assertRaises(ValueError, hash, "IX", s1, 1000, 'sha-666')
  290. # check rounds
  291. self.assertRaises(ValueError, hash, "IX", s1, 0, 'sha-1')
  292. # unicode salts accepted as of passlib 1.7 (previous caused TypeError)
  293. self.assertEqual(hash(u("IX"), s1.decode("latin-1"), 1000, 'sha1'), d1)
  294. def test_94_saslprep(self):
  295. """test hash/verify use saslprep"""
  296. # NOTE: this just does a light test that saslprep() is being
  297. # called in various places, relying in saslpreps()'s tests
  298. # to verify full normalization behavior.
  299. # hash unnormalized
  300. h = self.do_encrypt(u("I\u00ADX"))
  301. self.assertTrue(self.do_verify(u("IX"), h))
  302. self.assertTrue(self.do_verify(u("\u2168"), h))
  303. # hash normalized
  304. h = self.do_encrypt(u("\xF3"))
  305. self.assertTrue(self.do_verify(u("o\u0301"), h))
  306. self.assertTrue(self.do_verify(u("\u200Do\u0301"), h))
  307. # throws error if forbidden char provided
  308. self.assertRaises(ValueError, self.do_encrypt, u("\uFDD0"))
  309. self.assertRaises(ValueError, self.do_verify, u("\uFDD0"), h)
  310. def test_94_using_w_default_algs(self, param="default_algs"):
  311. """using() -- 'default_algs' parameter"""
  312. # create subclass
  313. handler = self.handler
  314. orig = list(handler.default_algs) # in case it's modified in place
  315. subcls = handler.using(**{param: "sha1,md5"})
  316. # shouldn't have changed handler
  317. self.assertEqual(handler.default_algs, orig)
  318. # should have own set
  319. self.assertEqual(subcls.default_algs, ["md5", "sha-1"])
  320. # test hash output
  321. h1 = subcls.hash("dummy")
  322. self.assertEqual(handler.extract_digest_algs(h1), ["md5", "sha-1"])
  323. def test_94_using_w_algs(self):
  324. """using() -- 'algs' parameter"""
  325. self.test_94_using_w_default_algs(param="algs")
  326. def test_94_needs_update_algs(self):
  327. """needs_update() -- algs setting"""
  328. handler1 = self.handler.using(algs="sha1,md5")
  329. # shouldn't need update, has same algs
  330. h1 = handler1.hash("dummy")
  331. self.assertFalse(handler1.needs_update(h1))
  332. # *currently* shouldn't need update, has superset of algs required by handler2
  333. # (may change this policy)
  334. handler2 = handler1.using(algs="sha1")
  335. self.assertFalse(handler2.needs_update(h1))
  336. # should need update, doesn't have all algs required by handler3
  337. handler3 = handler1.using(algs="sha1,sha256")
  338. self.assertTrue(handler3.needs_update(h1))
  339. def test_95_context_algs(self):
  340. """test handling of 'algs' in context object"""
  341. handler = self.handler
  342. from passlib.context import CryptContext
  343. c1 = CryptContext(["scram"], scram__algs="sha1,md5")
  344. h = c1.hash("dummy")
  345. self.assertEqual(handler.extract_digest_algs(h), ["md5", "sha-1"])
  346. self.assertFalse(c1.needs_update(h))
  347. c2 = c1.copy(scram__algs="sha1")
  348. self.assertFalse(c2.needs_update(h))
  349. c2 = c1.copy(scram__algs="sha1,sha256")
  350. self.assertTrue(c2.needs_update(h))
  351. def test_96_full_verify(self):
  352. """test verify(full=True) flag"""
  353. def vpart(s, h):
  354. return self.handler.verify(s, h)
  355. def vfull(s, h):
  356. return self.handler.verify(s, h, full=True)
  357. # reference
  358. h = ('$scram$4096$QSXCR.Q6sek8bf92$'
  359. 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,'
  360. 'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVY,'
  361. 'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/'
  362. 'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ')
  363. self.assertTrue(vfull('pencil', h))
  364. self.assertFalse(vfull('tape', h))
  365. # catch truncated digests.
  366. h = ('$scram$4096$QSXCR.Q6sek8bf92$'
  367. 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,'
  368. 'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhV,' # -1 char
  369. 'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/'
  370. 'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ')
  371. self.assertRaises(ValueError, vfull, 'pencil', h)
  372. # catch padded digests.
  373. h = ('$scram$4096$QSXCR.Q6sek8bf92$'
  374. 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,'
  375. 'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVYa,' # +1 char
  376. 'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/'
  377. 'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ')
  378. self.assertRaises(ValueError, vfull, 'pencil', h)
  379. # catch hash containing digests belonging to diff passwords.
  380. # proper behavior for quick-verify (the default) is undefined,
  381. # but full-verify should throw error.
  382. h = ('$scram$4096$QSXCR.Q6sek8bf92$'
  383. 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,' # 'pencil'
  384. 'sha-256=R7RJDWIbeKRTFwhE9oxh04kab0CllrQ3kCcpZUcligc,' # 'tape'
  385. 'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/' # 'pencil'
  386. 'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ')
  387. self.assertTrue(vpart('tape', h))
  388. self.assertFalse(vpart('pencil', h))
  389. self.assertRaises(ValueError, vfull, 'pencil', h)
  390. self.assertRaises(ValueError, vfull, 'tape', h)
  391. #=============================================================================
  392. # eof
  393. #=============================================================================