1"""passlib.tests.test_handlers - tests for passlib hash algorithms"""
2#=============================================================================
3# imports
4#=============================================================================
5from __future__ import with_statement
6# core
7import logging; log = logging.getLogger(__name__)
8import os
9import sys
10import warnings
11# site
12# pkg
13from passlib import exc, hash
14from passlib.utils import repeat_string
15from passlib.utils.compat import irange, PY3, u, get_method_function
16from passlib.tests.utils import TestCase, HandlerCase, skipUnless, \
17        TEST_MODE, UserHandlerMixin, EncodingHandlerMixin
18# module
19
20#=============================================================================
21# constants & support
22#=============================================================================
23
24# some common unicode passwords which used as test cases
25UPASS_WAV = u('\u0399\u03c9\u03b1\u03bd\u03bd\u03b7\u03c2')
26UPASS_USD = u("\u20AC\u00A5$")
27UPASS_TABLE = u("t\u00e1\u0411\u2113\u0259")
28
29PASS_TABLE_UTF8 = b't\xc3\xa1\xd0\x91\xe2\x84\x93\xc9\x99' # utf-8
30
31# handlers which support multiple backends, but don't have multi-backend tests.
32_omitted_backend_tests = ["django_bcrypt", "django_bcrypt_sha256", "django_argon2"]
33
34#: modules where get_handler_case() should search for test cases.
35_handler_test_modules = [
36    "test_handlers",
37    "test_handlers_argon2",
38    "test_handlers_bcrypt",
39    "test_handlers_cisco",
40    "test_handlers_django",
41    "test_handlers_pbkdf2",
42    "test_handlers_scrypt",
43]
44
45def get_handler_case(scheme):
46    """
47    return HandlerCase instance for scheme, used by other tests.
48
49    :param scheme: name of hasher to locate test for (e.g. "bcrypt")
50
51    :raises KeyError:
52        if scheme isn't known hasher.
53
54    :raises MissingBackendError:
55        if hasher doesn't have any available backends.
56
57    :returns:
58        HandlerCase subclass (which derives from TestCase)
59    """
60    from passlib.registry import get_crypt_handler
61    handler = get_crypt_handler(scheme)
62    if hasattr(handler, "backends") and scheme not in _omitted_backend_tests:
63        # XXX: if no backends available, could proceed to pick first backend for test lookup;
64        #      should investigate if that would be useful to callers.
65        try:
66            backend = handler.get_backend()
67        except exc.MissingBackendError:
68            assert scheme in conditionally_available_hashes
69            raise
70        name = "%s_%s_test" % (scheme, backend)
71    else:
72        name = "%s_test" % scheme
73    for module in _handler_test_modules:
74        modname = "passlib.tests." + module
75        __import__(modname)
76        mod = sys.modules[modname]
77        try:
78            return getattr(mod, name)
79        except AttributeError:
80            pass
81    # every hasher should have test suite, so if we get here, means test is either missing,
82    # misnamed, or _handler_test_modules list is out of date.
83    raise RuntimeError("can't find test case named %r for %r" % (name, scheme))
84
85#: hashes which there may not be a backend available for,
86#: and get_handler_case() may (correctly) throw a MissingBackendError
87conditionally_available_hashes = ["argon2", "bcrypt", "bcrypt_sha256"]
88
89#=============================================================================
90# apr md5 crypt
91#=============================================================================
92class apr_md5_crypt_test(HandlerCase):
93    handler = hash.apr_md5_crypt
94
95    known_correct_hashes = [
96        #
97        # http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
98        #
99        ('myPassword', '$apr1$r31.....$HqJZimcKQFAMYayBlzkrA/'),
100
101        #
102        # custom
103        #
104
105        # ensures utf-8 used for unicode
106        (UPASS_TABLE, '$apr1$bzYrOHUx$a1FcpXuQDJV3vPY20CS6N1'),
107        ]
108
109    known_malformed_hashes = [
110        # bad char in otherwise correct hash ----\/
111            '$apr1$r31.....$HqJZimcKQFAMYayBlzkrA!'
112        ]
113
114#=============================================================================
115# bigcrypt
116#=============================================================================
117class bigcrypt_test(HandlerCase):
118    handler = hash.bigcrypt
119
120    # TODO: find an authoritative source of test vectors
121    known_correct_hashes = [
122
123        #
124        # various docs & messages on the web.
125        #
126        ("passphrase",               "qiyh4XPJGsOZ2MEAyLkfWqeQ"),
127        ("This is very long passwd", "f8.SVpL2fvwjkAnxn8/rgTkwvrif6bjYB5c"),
128
129        #
130        # custom
131        #
132
133        # ensures utf-8 used for unicode
134        (UPASS_TABLE, 'SEChBAyMbMNhgGLyP7kD1HZU'),
135    ]
136
137    known_unidentified_hashes = [
138        # one char short (10 % 11)
139        "qiyh4XPJGsOZ2MEAyLkfWqe"
140
141        # one char too many (1 % 11)
142        "f8.SVpL2fvwjkAnxn8/rgTkwvrif6bjYB5cd"
143    ]
144
145    # omit des_crypt from known_other since it's a valid bigcrypt hash too.
146    known_other_hashes = [row for row in HandlerCase.known_other_hashes
147                          if row[0] != "des_crypt"]
148
149    def test_90_internal(self):
150        # check that _norm_checksum() also validates checksum size.
151        # (current code uses regex in parser)
152        self.assertRaises(ValueError, hash.bigcrypt, use_defaults=True,
153                          checksum=u('yh4XPJGsOZ'))
154
155#=============================================================================
156# bsdi crypt
157#=============================================================================
158class _bsdi_crypt_test(HandlerCase):
159    """test BSDiCrypt algorithm"""
160    handler = hash.bsdi_crypt
161
162    known_correct_hashes = [
163        #
164        # from JTR 1.7.9
165        #
166        ('U*U*U*U*', '_J9..CCCCXBrJUJV154M'),
167        ('U*U***U', '_J9..CCCCXUhOBTXzaiE'),
168        ('U*U***U*', '_J9..CCCC4gQ.mB/PffM'),
169        ('*U*U*U*U', '_J9..XXXXvlzQGqpPPdk'),
170        ('*U*U*U*U*', '_J9..XXXXsqM/YSSP..Y'),
171        ('*U*U*U*U*U*U*U*U', '_J9..XXXXVL7qJCnku0I'),
172        ('*U*U*U*U*U*U*U*U*', '_J9..XXXXAj8cFbP5scI'),
173        ('ab1234567', '_J9..SDizh.vll5VED9g'),
174        ('cr1234567', '_J9..SDizRjWQ/zePPHc'),
175        ('zxyDPWgydbQjgq', '_J9..SDizxmRI1GjnQuE'),
176        ('726 even', '_K9..SaltNrQgIYUAeoY'),
177        ('', '_J9..SDSD5YGyRCr4W4c'),
178
179        #
180        # custom
181        #
182        (" ", "_K1..crsmZxOLzfJH8iw"),
183        ("my", '_KR/.crsmykRplHbAvwA'), # <-- to detect old 12-bit rounds bug
184        ("my socra", "_K1..crsmf/9NzZr1fLM"),
185        ("my socrates", '_K1..crsmOv1rbde9A9o'),
186        ("my socrates note", "_K1..crsm/2qeAhdISMA"),
187
188        # ensures utf-8 used for unicode
189        (UPASS_TABLE, '_7C/.ABw0WIKy0ILVqo2'),
190    ]
191    known_unidentified_hashes = [
192        # bad char in otherwise correctly formatted hash
193        #    \/
194        "_K1.!crsmZxOLzfJH8iw"
195    ]
196
197    platform_crypt_support = [
198        # openbsd 5.8 dropped everything except bcrypt
199        ("openbsd[6789]", False),
200        ("openbsd5", None),
201        ("openbsd", True),
202
203        ("freebsd|netbsd|darwin", True),
204        ("solaris", False),
205        ("linux", None),  # may be present if libxcrypt is in use
206    ]
207
208    def test_77_fuzz_input(self, **kwds):
209        # we want to generate even rounds to verify it's correct, but want to ignore warnings
210        warnings.filterwarnings("ignore", "bsdi_crypt rounds should be odd.*")
211        super(_bsdi_crypt_test, self).test_77_fuzz_input(**kwds)
212
213    def test_needs_update_w_even_rounds(self):
214        """needs_update() should flag even rounds"""
215        handler = self.handler
216        even_hash = '_Y/../cG0zkJa6LY6k4c'
217        odd_hash = '_Z/..TgFg0/ptQtpAgws'
218        secret = 'test'
219
220        # don't issue warning
221        self.assertTrue(handler.verify(secret, even_hash))
222        self.assertTrue(handler.verify(secret, odd_hash))
223
224        # *do* signal as needing updates
225        self.assertTrue(handler.needs_update(even_hash))
226        self.assertFalse(handler.needs_update(odd_hash))
227
228        # new hashes shouldn't have even rounds
229        new_hash = handler.hash("stub")
230        self.assertFalse(handler.needs_update(new_hash))
231
232# create test cases for specific backends
233bsdi_crypt_os_crypt_test = _bsdi_crypt_test.create_backend_case("os_crypt")
234bsdi_crypt_builtin_test = _bsdi_crypt_test.create_backend_case("builtin")
235
236#=============================================================================
237# crypt16
238#=============================================================================
239class crypt16_test(HandlerCase):
240    handler = hash.crypt16
241
242    # TODO: find an authortative source of test vectors
243    known_correct_hashes = [
244        #
245        # from messages around the web, including
246        # http://seclists.org/bugtraq/1999/Mar/76
247        #
248        ("passphrase",  "qi8H8R7OM4xMUNMPuRAZxlY."),
249        ("printf",      "aaCjFz4Sh8Eg2QSqAReePlq6"),
250        ("printf",      "AA/xje2RyeiSU0iBY3PDwjYo"),
251        ("LOLOAQICI82QB4IP", "/.FcK3mad6JwYt8LVmDqz9Lc"),
252        ("LOLOAQICI",   "/.FcK3mad6JwYSaRHJoTPzY2"),
253        ("LOLOAQIC",    "/.FcK3mad6JwYelhbtlysKy6"),
254        ("L",           "/.CIu/PzYCkl6elhbtlysKy6"),
255
256        #
257        # custom
258        #
259
260        # ensures utf-8 used for unicode
261        (UPASS_TABLE, 'YeDc9tKkkmDvwP7buzpwhoqQ'),
262        ]
263
264#=============================================================================
265# des crypt
266#=============================================================================
267class _des_crypt_test(HandlerCase):
268    """test des-crypt algorithm"""
269    handler = hash.des_crypt
270
271    known_correct_hashes = [
272        #
273        # from JTR 1.7.9
274        #
275        ('U*U*U*U*', 'CCNf8Sbh3HDfQ'),
276        ('U*U***U', 'CCX.K.MFy4Ois'),
277        ('U*U***U*', 'CC4rMpbg9AMZ.'),
278        ('*U*U*U*U', 'XXxzOu6maQKqQ'),
279        ('', 'SDbsugeBiC58A'),
280
281        #
282        # custom
283        #
284        ('', 'OgAwTx2l6NADI'),
285        (' ', '/Hk.VPuwQTXbc'),
286        ('test', 'N1tQbOFcM5fpg'),
287        ('Compl3X AlphaNu3meric', 'um.Wguz3eVCx2'),
288        ('4lpHa N|_|M3r1K W/ Cur5Es: #$%(*)(*%#', 'sNYqfOyauIyic'),
289        ('AlOtBsOl', 'cEpWz5IUCShqM'),
290
291        # ensures utf-8 used for unicode
292        (u('hell\u00D6'), 'saykDgk3BPZ9E'),
293        ]
294    known_unidentified_hashes = [
295        # bad char in otherwise correctly formatted hash
296        #\/
297        '!gAwTx2l6NADI',
298
299        # wrong size
300        'OgAwTx2l6NAD',
301        'OgAwTx2l6NADIj',
302        ]
303
304    platform_crypt_support = [
305        # openbsd 5.8 dropped everything except bcrypt
306        ("openbsd[6789]", False),
307        ("openbsd5", None),
308        ("openbsd", True),
309
310        ("freebsd|netbsd|linux|solaris|darwin", True),
311    ]
312
313# create test cases for specific backends
314des_crypt_os_crypt_test = _des_crypt_test.create_backend_case("os_crypt")
315des_crypt_builtin_test = _des_crypt_test.create_backend_case("builtin")
316
317#=============================================================================
318# fshp
319#=============================================================================
320class fshp_test(HandlerCase):
321    """test fshp algorithm"""
322    handler = hash.fshp
323
324    known_correct_hashes = [
325        #
326        # test vectors from FSHP reference implementation
327        # https://github.com/bdd/fshp-is-not-secure-anymore/blob/master/python/test.py
328        #
329        ('test', '{FSHP0|0|1}qUqP5cyxm6YcTAhz05Hph5gvu9M='),
330
331        ('test',
332            '{FSHP1|8|4096}MTIzNDU2NzjTdHcmoXwNc0f'
333            'f9+ArUHoN0CvlbPZpxFi1C6RDM/MHSA=='
334            ),
335
336        ('OrpheanBeholderScryDoubt',
337            '{FSHP1|8|4096}GVSUFDAjdh0vBosn1GUhz'
338            'GLHP7BmkbCZVH/3TQqGIjADXpc+6NCg3g=='
339            ),
340        ('ExecuteOrder66',
341            '{FSHP3|16|8192}0aY7rZQ+/PR+Rd5/I9ss'
342            'RM7cjguyT8ibypNaSp/U1uziNO3BVlg5qPU'
343            'ng+zHUDQC3ao/JbzOnIBUtAeWHEy7a2vZeZ'
344            '7jAwyJJa2EqOsq4Io='
345            ),
346
347        #
348        # custom
349        #
350
351        # ensures utf-8 used for unicode
352        (UPASS_TABLE, '{FSHP1|16|16384}9v6/l3Lu/d9by5nznpOS'
353         'cqQo8eKu/b/CKli3RCkgYg4nRTgZu5y659YV8cCZ68UL'),
354        ]
355
356    known_unidentified_hashes = [
357        # incorrect header
358        '{FSHX0|0|1}qUqP5cyxm6YcTAhz05Hph5gvu9M=',
359        'FSHP0|0|1}qUqP5cyxm6YcTAhz05Hph5gvu9M=',
360        ]
361
362    known_malformed_hashes = [
363        # bad base64 padding
364        '{FSHP0|0|1}qUqP5cyxm6YcTAhz05Hph5gvu9M',
365
366        # wrong salt size
367        '{FSHP0|1|1}qUqP5cyxm6YcTAhz05Hph5gvu9M=',
368
369        # bad rounds
370        '{FSHP0|0|A}qUqP5cyxm6YcTAhz05Hph5gvu9M=',
371    ]
372
373    def test_90_variant(self):
374        """test variant keyword"""
375        handler = self.handler
376        kwds = dict(salt=b'a', rounds=1)
377
378        # accepts ints
379        handler(variant=1, **kwds)
380
381        # accepts bytes or unicode
382        handler(variant=u('1'), **kwds)
383        handler(variant=b'1', **kwds)
384
385        # aliases
386        handler(variant=u('sha256'), **kwds)
387        handler(variant=b'sha256', **kwds)
388
389        # rejects None
390        self.assertRaises(TypeError, handler, variant=None, **kwds)
391
392        # rejects other types
393        self.assertRaises(TypeError, handler, variant=complex(1,1), **kwds)
394
395        # invalid variant
396        self.assertRaises(ValueError, handler, variant='9', **kwds)
397        self.assertRaises(ValueError, handler, variant=9, **kwds)
398
399#=============================================================================
400# hex digests
401#=============================================================================
402class hex_md4_test(HandlerCase):
403    handler = hash.hex_md4
404    known_correct_hashes = [
405        ("password", '8a9d093f14f8701df17732b2bb182c74'),
406        (UPASS_TABLE, '876078368c47817ce5f9115f3a42cf74'),
407    ]
408
409class hex_md5_test(HandlerCase):
410    handler = hash.hex_md5
411    known_correct_hashes = [
412        ("password", '5f4dcc3b5aa765d61d8327deb882cf99'),
413        (UPASS_TABLE, '05473f8a19f66815e737b33264a0d0b0'),
414    ]
415
416    # XXX: should test this for ALL the create_hex_md5() hashers.
417    def test_mock_fips_mode(self):
418        """
419        if md5 isn't available, a dummy instance should be created.
420        (helps on FIPS systems).
421        """
422        from passlib.exc import UnknownHashError
423        from passlib.crypto.digest import lookup_hash, _set_mock_fips_mode
424
425        # check if md5 is available so we can test mock helper
426        supported = lookup_hash("md5", required=False).supported
427        self.assertEqual(self.handler.supported, supported)
428        if supported:
429            _set_mock_fips_mode()
430            self.addCleanup(_set_mock_fips_mode, False)
431
432        # HACK: have to recreate hasher, since underlying HashInfo has changed.
433        #       could reload module and re-import, but this should be good enough.
434        from passlib.handlers.digests import create_hex_hash
435        hasher = create_hex_hash("md5", required=False)
436        self.assertFalse(hasher.supported)
437
438        # can identify hashes even if disabled
439        ref1 = '5f4dcc3b5aa765d61d8327deb882cf99'
440        ref2 = 'xxx'
441        self.assertTrue(hasher.identify(ref1))
442        self.assertFalse(hasher.identify(ref2))
443
444        # throw error if try to use it
445        pat = "'md5' hash disabled for fips"
446        self.assertRaisesRegex(UnknownHashError, pat, hasher.hash, "password")
447        self.assertRaisesRegex(UnknownHashError, pat, hasher.verify, "password", ref1)
448
449
450class hex_sha1_test(HandlerCase):
451    handler = hash.hex_sha1
452    known_correct_hashes = [
453        ("password", '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8'),
454        (UPASS_TABLE, 'e059b2628e3a3e2de095679de9822c1d1466e0f0'),
455    ]
456
457class hex_sha256_test(HandlerCase):
458    handler = hash.hex_sha256
459    known_correct_hashes = [
460        ("password", '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8'),
461        (UPASS_TABLE, '6ed729e19bf24d3d20f564375820819932029df05547116cfc2cc868a27b4493'),
462    ]
463
464class hex_sha512_test(HandlerCase):
465    handler = hash.hex_sha512
466    known_correct_hashes = [
467        ("password", 'b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c'
468         '706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cac'
469         'bc86'),
470        (UPASS_TABLE, 'd91bb0a23d66dca07a1781fd63ae6a05f6919ee5fc368049f350c9f'
471         '293b078a18165d66097cf0d89fdfbeed1ad6e7dba2344e57348cd6d51308c843a06f'
472         '29caf'),
473    ]
474
475#=============================================================================
476# htdigest hash
477#=============================================================================
478class htdigest_test(UserHandlerMixin, HandlerCase):
479    handler = hash.htdigest
480
481    known_correct_hashes = [
482        # secret, user, realm
483
484        # from RFC 2617
485        (("Circle Of Life", "Mufasa", "testrealm@host.com"),
486            '939e7578ed9e3c518a452acee763bce9'),
487
488        # custom
489        ((UPASS_TABLE, UPASS_USD, UPASS_WAV),
490            '4dabed2727d583178777fab468dd1f17'),
491    ]
492
493    known_unidentified_hashes = [
494        # bad char \/ - currently rejecting upper hex chars, may change
495        '939e7578edAe3c518a452acee763bce9',
496
497        # bad char \/
498        '939e7578edxe3c518a452acee763bce9',
499    ]
500
501    def test_80_user(self):
502        raise self.skipTest("test case doesn't support 'realm' keyword")
503
504    def populate_context(self, secret, kwds):
505        """insert username into kwds"""
506        if isinstance(secret, tuple):
507            secret, user, realm = secret
508        else:
509            user, realm = "user", "realm"
510        kwds.setdefault("user", user)
511        kwds.setdefault("realm", realm)
512        return secret
513
514#=============================================================================
515# ldap hashes
516#=============================================================================
517class ldap_md5_test(HandlerCase):
518    handler = hash.ldap_md5
519    known_correct_hashes = [
520        ("helloworld", '{MD5}/F4DjTilcDIIVEHn/nAQsA=='),
521        (UPASS_TABLE, '{MD5}BUc/ihn2aBXnN7MyZKDQsA=='),
522    ]
523
524class ldap_sha1_test(HandlerCase):
525    handler = hash.ldap_sha1
526    known_correct_hashes = [
527        ("helloworld", '{SHA}at+xg6SiyUovktq1redipHiJpaE='),
528        (UPASS_TABLE, '{SHA}4FmyYo46Pi3glWed6YIsHRRm4PA='),
529    ]
530
531class ldap_salted_md5_test(HandlerCase):
532    handler = hash.ldap_salted_md5
533    known_correct_hashes = [
534        ("testing1234", '{SMD5}UjFY34os/pnZQ3oQOzjqGu4yeXE='),
535        (UPASS_TABLE, '{SMD5}Z0ioJ58LlzUeRxm3K6JPGAvBGIM='),
536
537        # alternate salt sizes (8, 15, 16)
538        ('test', '{SMD5}LnuZPJhiaY95/4lmVFpg548xBsD4P4cw'),
539        ('test', '{SMD5}XRlncfRzvGi0FDzgR98tUgBg7B3jXOs9p9S615qTkg=='),
540        ('test', '{SMD5}FbAkzOMOxRbMp6Nn4hnZuel9j9Gas7a2lvI+x5hT6j0='),
541    ]
542
543    known_malformed_hashes = [
544        # salt too small (3)
545        '{SMD5}IGVhwK+anvspmfDt2t0vgGjt/Q==',
546
547        # incorrect base64 encoding
548        '{SMD5}LnuZPJhiaY95/4lmVFpg548xBsD4P4c',
549        '{SMD5}LnuZPJhiaY95/4lmVFpg548xBsD4P4cw'
550        '{SMD5}LnuZPJhiaY95/4lmVFpg548xBsD4P4cw=',
551        '{SMD5}LnuZPJhiaY95/4lmV=pg548xBsD4P4cw',
552        '{SMD5}LnuZPJhiaY95/4lmVFpg548xBsD4P===',
553    ]
554
555class ldap_salted_sha1_test(HandlerCase):
556    handler = hash.ldap_salted_sha1
557    known_correct_hashes = [
558        ("testing123", '{SSHA}0c0blFTXXNuAMHECS4uxrj3ZieMoWImr'),
559        ("secret", "{SSHA}0H+zTv8o4MR4H43n03eCsvw1luG8LdB7"),
560        (UPASS_TABLE, '{SSHA}3yCSD1nLZXznra4N8XzZgAL+s1sQYsx5'),
561
562        # alternate salt sizes (8, 15, 16)
563        ('test', '{SSHA}P90+qijSp8MJ1tN25j5o1PflUvlqjXHOGeOckw=='),
564        ('test', '{SSHA}/ZMF5KymNM+uEOjW+9STKlfCFj51bg3BmBNCiPHeW2ttbU0='),
565        ('test', '{SSHA}Pfx6Vf48AT9x3FVv8znbo8WQkEVSipHSWovxXmvNWUvp/d/7'),
566    ]
567
568    known_malformed_hashes = [
569        # salt too small (3)
570        '{SSHA}ZQK3Yvtvl6wtIRoISgMGPkcWU7Nfq5U=',
571
572        # incorrect base64 encoding
573        '{SSHA}P90+qijSp8MJ1tN25j5o1PflUvlqjXHOGeOck',
574        '{SSHA}P90+qijSp8MJ1tN25j5o1PflUvlqjXHOGeOckw=',
575        '{SSHA}P90+qijSp8MJ1tN25j5o1Pf=UvlqjXHOGeOckw==',
576        '{SSHA}P90+qijSp8MJ1tN25j5o1PflUvlqjXHOGeOck===',
577    ]
578
579
580class ldap_salted_sha256_test(HandlerCase):
581    handler = hash.ldap_salted_sha256
582    known_correct_hashes = [
583        # generated locally
584        # salt size = 8
585        ("password", '{SSHA256}x1tymSTVjozxQ2PtT46ysrzhZxbcskK0o2f8hEFx7fAQQmhtDSEkJA=='),
586        ("test", '{SSHA256}xfqc9aOR6z15YaEk3/Ufd7UL9+JozB/1EPmCDTizL0GkdA7BuNda6w=='),
587        ("toomanysecrets", '{SSHA256}RrTKrg6HFXcjJ+eDAq4UtbODxOr9RLeG+I69FoJvutcbY0zpfU+p1Q=='),
588        (u('letm\xe8\xefn'), '{SSHA256}km7UjUTBZN8a+gf1ND2/qn15N7LsO/jmGYJXvyTfJKAbI0RoLWWslQ=='),
589
590        # alternate salt sizes (4, 15, 16)
591        # generated locally
592        ('test', '{SSHA256}TFv2RpwyO0U9mA0Hk8FsXRa1I+4dNUtv27Qa8dzGVLinlDIm'),
593        ('test', '{SSHA256}J6MFQdkfjdmXz9UyUPb773kekJdm4dgSL4y8WQEQW11VipHSundOKaV0LsV4L6U='),
594        ('test', '{SSHA256}uBLazLaiBaPb6Cpnvq2XTYDkvXbYIuqRW1anMKk85d1/j1GqFQIgpHSOMUYIIcS4'),
595    ]
596
597    known_malformed_hashes = [
598        # salt too small (3)
599        '{SSHA256}Lpdyr1+lR+rtxgp3SpQnUuNw33ENivTl28nzF2ZI4Gm41/o=',
600
601        # incorrect base64 encoding
602        '{SSHA256}TFv2RpwyO0U9mA0Hk8FsXRa1I+4dNUtv27Qa8dzGVLinlDI@',
603        '{SSHA256}TFv2RpwyO0U9mA0Hk8FsXRa1I+4dNUtv27Qa8dzGVLinlDI',
604        '{SSHA256}TFv2RpwyO0U9mA0Hk8FsXRa1I+4dNUtv27Qa8dzGVLinlDIm===',
605    ]
606
607
608
609class ldap_salted_sha512_test(HandlerCase):
610    handler = hash.ldap_salted_sha512
611    known_correct_hashes = [
612        # generated by testing ldap server web interface (see issue 124 comments)
613        # salt size = 8
614        ("toomanysecrets", '{SSHA512}wExp4xjiCHS0zidJDC4UJq9EEeIebAQPJ1PWSwfhxWjfutI9XiiKuHm2AE41cEFfK+8HyI8bh+ztbczUGsvVFIgICWWPt7qu'),
615        (u('letm\xe8\xefn'), '{SSHA512}mpNUSmZc3TNx+RnPwkIAVMf7ocEKLPrIoQNsg4Eu8dHvyCeb2xzHp5A6n4tF7ntknSvfvRZaJII4ImvNJlYsgiwAm0FMqR+3'),
616
617        # generated locally
618        # salt size = 8
619        ("password", '{SSHA512}f/lFQskkl7PdMsTGJxHZq8LDt/l+UqRMm6/pj4pV7/xZkcOaKCgvQqp+KCeXc/Vd4RY6vEHWn4y0DnFcQ6wgyv9fyxk='),
620        ("test", '{SSHA512}Tgx/uhHnlM9/GgQvI31dN7cheDXg7WypZwaaIkyRsgV/BKIzBG3G/wUd9o1dpi06p3SYzMedg0lvTc3b6CtdO0Xo/f9/L+Uc'),
621
622        # alternate salt sizes (4, 15, 16)
623        # generated locally
624        ('test', '{SSHA512}Yg9DQ2wURCFGwobu7R2O6cq7nVbnGMPrFCX0aPQ9kj/y1hd6k9PEzkgWCB5aXdPwPzNrVb0PkiHiBnG1CxFiT+B8L8U='),
625        ('test', '{SSHA512}5ecDGWs5RY4xLszUO6hAcl90W3wAozGQoI4Gqj8xSZdcfU1lVEM4aY8s+4xVeLitcn7BO8i7xkzMFWLoxas7SeHc23sP4dx77937PyeE0A=='),
626        ('test', '{SSHA512}6FQv5W47HGg2MFBFZofoiIbO8KRW75Pm51NKoInpthYQQ5ujazHGhVGzrj3JXgA7j0k+UNmkHdbJjdY5xcUHPzynFEII4fwfIySEcG5NKSU='),
627    ]
628
629    known_malformed_hashes = [
630        # salt too small (3)
631        '{SSHA512}zFnn4/8x8GveUaMqgrYWyIWqFQ0Irt6gADPtRk4Uv3nUC6uR5cD8+YdQni/0ZNij9etm6p17kSFuww3M6l+d6AbAeA==',
632
633        # incorrect base64 encoding
634        '{SSHA512}Tgx/uhHnlM9/GgQvI31dN7cheDXg7WypZwaaIkyRsgV/BKIzBG3G/wUd9o1dpi06p3SYzMedg0lvTc3b6CtdO0Xo/f9/L+U',
635        '{SSHA512}Tgx/uhHnlM9/GgQvI31dN7cheDXg7WypZwaaIkyRsgV/BKIzBG3G/wUd9o1dpi06p3SYzMedg0lvTc3b6CtdO0Xo/f9/L+U@',
636        '{SSHA512}Tgx/uhHnlM9/GgQvI31dN7cheDXg7WypZwaaIkyRsgV/BKIzBG3G/wUd9o1dpi06p3SYzMedg0lvTc3b6CtdO0Xo/f9/L+U===',
637    ]
638
639
640class ldap_plaintext_test(HandlerCase):
641    # TODO: integrate EncodingHandlerMixin
642    handler = hash.ldap_plaintext
643    known_correct_hashes = [
644        ("password", 'password'),
645        (UPASS_TABLE, UPASS_TABLE if PY3 else PASS_TABLE_UTF8),
646        (PASS_TABLE_UTF8, UPASS_TABLE if PY3 else PASS_TABLE_UTF8),
647    ]
648    known_unidentified_hashes = [
649        "{FOO}bar",
650
651        # NOTE: this hash currently rejects the empty string.
652        "",
653    ]
654
655    known_other_hashes = [
656        ("ldap_md5", "{MD5}/F4DjTilcDIIVEHn/nAQsA==")
657    ]
658
659    class FuzzHashGenerator(HandlerCase.FuzzHashGenerator):
660
661        def random_password(self):
662            # NOTE: this hash currently rejects the empty string.
663            while True:
664                pwd = super(ldap_plaintext_test.FuzzHashGenerator, self).random_password()
665                if pwd:
666                    return pwd
667
668class _ldap_md5_crypt_test(HandlerCase):
669    # NOTE: since the ldap_{crypt} handlers are all wrappers, don't need
670    #       separate test; this is just to test the codebase end-to-end
671    handler = hash.ldap_md5_crypt
672
673    known_correct_hashes = [
674        #
675        # custom
676        #
677        ('', '{CRYPT}$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.'),
678        (' ', '{CRYPT}$1$m/5ee7ol$bZn0kIBFipq39e.KDXX8I0'),
679        ('test', '{CRYPT}$1$ec6XvcoW$ghEtNK2U1MC5l.Dwgi3020'),
680        ('Compl3X AlphaNu3meric', '{CRYPT}$1$nX1e7EeI$ljQn72ZUgt6Wxd9hfvHdV0'),
681        ('4lpHa N|_|M3r1K W/ Cur5Es: #$%(*)(*%#', '{CRYPT}$1$jQS7o98J$V6iTcr71CGgwW2laf17pi1'),
682        ('test', '{CRYPT}$1$SuMrG47N$ymvzYjr7QcEQjaK5m1PGx1'),
683
684        # ensures utf-8 used for unicode
685        (UPASS_TABLE, '{CRYPT}$1$d6/Ky1lU$/xpf8m7ftmWLF.TjHCqel0'),
686        ]
687
688    known_malformed_hashes = [
689        # bad char in otherwise correct hash
690        '{CRYPT}$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o!',
691        ]
692
693# create test cases for specific backends
694ldap_md5_crypt_os_crypt_test =_ldap_md5_crypt_test.create_backend_case("os_crypt")
695ldap_md5_crypt_builtin_test =_ldap_md5_crypt_test.create_backend_case("builtin")
696
697class _ldap_sha1_crypt_test(HandlerCase):
698    # NOTE: this isn't for testing the hash (see ldap_md5_crypt note)
699    # but as a self-test of the os_crypt patching code in HandlerCase.
700    handler = hash.ldap_sha1_crypt
701
702    known_correct_hashes = [
703        ('password', '{CRYPT}$sha1$10$c.mcTzCw$gF8UeYst9yXX7WNZKc5Fjkq0.au7'),
704        (UPASS_TABLE, '{CRYPT}$sha1$10$rnqXlOsF$aGJf.cdRPewJAXo1Rn1BkbaYh0fP'),
705    ]
706
707    def populate_settings(self, kwds):
708        kwds.setdefault("rounds", 10)
709        super(_ldap_sha1_crypt_test, self).populate_settings(kwds)
710
711    def test_77_fuzz_input(self, **ignored):
712        raise self.skipTest("unneeded")
713
714# create test cases for specific backends
715ldap_sha1_crypt_os_crypt_test = _ldap_sha1_crypt_test.create_backend_case("os_crypt")
716
717#=============================================================================
718# lanman
719#=============================================================================
720class lmhash_test(EncodingHandlerMixin, HandlerCase):
721    handler = hash.lmhash
722    secret_case_insensitive = True
723
724    known_correct_hashes = [
725        #
726        # http://msdn.microsoft.com/en-us/library/cc245828(v=prot.10).aspx
727        #
728        ("OLDPASSWORD", "c9b81d939d6fd80cd408e6b105741864"),
729        ("NEWPASSWORD", '09eeab5aa415d6e4d408e6b105741864'),
730        ("welcome", "c23413a8a1e7665faad3b435b51404ee"),
731
732        #
733        # custom
734        #
735        ('', 'aad3b435b51404eeaad3b435b51404ee'),
736        ('zzZZZzz', 'a5e6066de61c3e35aad3b435b51404ee'),
737        ('passphrase', '855c3697d9979e78ac404c4ba2c66533'),
738        ('Yokohama', '5ecd9236d21095ce7584248b8d2c9f9e'),
739
740        # ensures cp437 used for unicode
741        (u('ENCYCLOP\xC6DIA'), 'fed6416bffc9750d48462b9d7aaac065'),
742        (u('encyclop\xE6dia'), 'fed6416bffc9750d48462b9d7aaac065'),
743
744        # test various encoding values
745        ((u("\xC6"), None), '25d8ab4a0659c97aaad3b435b51404ee'),
746        ((u("\xC6"), "cp437"), '25d8ab4a0659c97aaad3b435b51404ee'),
747        ((u("\xC6"), "latin-1"), '184eecbbe9991b44aad3b435b51404ee'),
748        ((u("\xC6"), "utf-8"), '00dd240fcfab20b8aad3b435b51404ee'),
749    ]
750
751    known_unidentified_hashes = [
752        # bad char in otherwise correct hash
753        '855c3697d9979e78ac404c4ba2c6653X',
754    ]
755
756    def test_90_raw(self):
757        """test lmhash.raw() method"""
758        from binascii import unhexlify
759        from passlib.utils.compat import str_to_bascii
760        lmhash = self.handler
761        for secret, hash in self.known_correct_hashes:
762            kwds = {}
763            secret = self.populate_context(secret, kwds)
764            data = unhexlify(str_to_bascii(hash))
765            self.assertEqual(lmhash.raw(secret, **kwds), data)
766        self.assertRaises(TypeError, lmhash.raw, 1)
767
768#=============================================================================
769# md5 crypt
770#=============================================================================
771class _md5_crypt_test(HandlerCase):
772    handler = hash.md5_crypt
773
774    known_correct_hashes = [
775        #
776        # from JTR 1.7.9
777        #
778        ('U*U*U*U*', '$1$dXc3I7Rw$ctlgjDdWJLMT.qwHsWhXR1'),
779        ('U*U***U', '$1$dXc3I7Rw$94JPyQc/eAgQ3MFMCoMF.0'),
780        ('U*U***U*', '$1$dXc3I7Rw$is1mVIAEtAhIzSdfn5JOO0'),
781        ('*U*U*U*U', '$1$eQT9Hwbt$XtuElNJD.eW5MN5UCWyTQ0'),
782        ('', '$1$Eu.GHtia$CFkL/nE1BYTlEPiVx1VWX0'),
783
784        #
785        # custom
786        #
787
788        # NOTE: would need to patch HandlerCase to coerce hashes
789        # to native str for this first one to work under py3.
790##        ('', b('$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.')),
791        ('', '$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.'),
792        (' ', '$1$m/5ee7ol$bZn0kIBFipq39e.KDXX8I0'),
793        ('test', '$1$ec6XvcoW$ghEtNK2U1MC5l.Dwgi3020'),
794        ('Compl3X AlphaNu3meric', '$1$nX1e7EeI$ljQn72ZUgt6Wxd9hfvHdV0'),
795        ('4lpHa N|_|M3r1K W/ Cur5Es: #$%(*)(*%#', '$1$jQS7o98J$V6iTcr71CGgwW2laf17pi1'),
796        ('test', '$1$SuMrG47N$ymvzYjr7QcEQjaK5m1PGx1'),
797        (b'test', '$1$SuMrG47N$ymvzYjr7QcEQjaK5m1PGx1'),
798        (u('s'), '$1$ssssssss$YgmLTApYTv12qgTwBoj8i/'),
799
800        # ensures utf-8 used for unicode
801        (UPASS_TABLE, '$1$d6/Ky1lU$/xpf8m7ftmWLF.TjHCqel0'),
802        ]
803
804    known_malformed_hashes = [
805        # bad char in otherwise correct hash \/
806           '$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o!',
807
808        # too many fields
809        '$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.$',
810        ]
811
812    platform_crypt_support = [
813        # openbsd 5.8 dropped everything except bcrypt
814        ("openbsd[6789]", False),
815        ("openbsd5", None),
816        ("openbsd", True),
817
818        ("freebsd|netbsd|linux|solaris", True),
819        ("darwin", False),
820    ]
821
822# create test cases for specific backends
823md5_crypt_os_crypt_test = _md5_crypt_test.create_backend_case("os_crypt")
824md5_crypt_builtin_test = _md5_crypt_test.create_backend_case("builtin")
825
826#=============================================================================
827# msdcc 1 & 2
828#=============================================================================
829class msdcc_test(UserHandlerMixin, HandlerCase):
830    handler = hash.msdcc
831    user_case_insensitive = True
832
833    known_correct_hashes = [
834
835        #
836        # http://www.jedge.com/wordpress/windows-password-cache/
837        #
838        (("Asdf999", "sevans"), "b1176c2587478785ec1037e5abc916d0"),
839
840        #
841        # http://infosecisland.com/blogview/12156-Cachedump-for-Meterpreter-in-Action.html
842        #
843        (("ASDqwe123", "jdoe"), "592cdfbc3f1ef77ae95c75f851e37166"),
844
845        #
846        # http://comments.gmane.org/gmane.comp.security.openwall.john.user/1917
847        #
848        (("test1", "test1"), "64cd29e36a8431a2b111378564a10631"),
849        (("test2", "test2"), "ab60bdb4493822b175486810ac2abe63"),
850        (("test3", "test3"), "14dd041848e12fc48c0aa7a416a4a00c"),
851        (("test4", "test4"), "b945d24866af4b01a6d89b9d932a153c"),
852
853        #
854        # http://ciscoit.wordpress.com/2011/04/13/metasploit-hashdump-vs-cachedump/
855        #
856        (("1234qwer!@#$", "Administrator"), "7b69d06ef494621e3f47b9802fe7776d"),
857
858        #
859        # http://www.securiteam.com/tools/5JP0I2KFPA.html
860        #
861        (("password", "user"), "2d9f0b052932ad18b87f315641921cda"),
862
863        #
864        # from JTR 1.7.9
865        #
866        (("", "root"), "176a4c2bd45ac73687676c2f09045353"),
867        (("test1", "TEST1"), "64cd29e36a8431a2b111378564a10631"),
868        (("okolada", "nineteen_characters"), "290efa10307e36a79b3eebf2a6b29455"),
869        ((u("\u00FC"), u("\u00FC")), "48f84e6f73d6d5305f6558a33fa2c9bb"),
870        ((u("\u00FC\u00FC"), u("\u00FC\u00FC")), "593246a8335cf0261799bda2a2a9c623"),
871        ((u("\u20AC\u20AC"), "user"), "9121790702dda0fa5d353014c334c2ce"),
872
873        #
874        # custom
875        #
876
877        # ensures utf-8 used for unicode
878        ((UPASS_TABLE, 'bob'), 'fcb82eb4212865c7ac3503156ca3f349'),
879    ]
880
881    known_alternate_hashes = [
882        # check uppercase accepted.
883        ("B1176C2587478785EC1037E5ABC916D0", ("Asdf999", "sevans"),
884            "b1176c2587478785ec1037e5abc916d0"),
885    ]
886
887class msdcc2_test(UserHandlerMixin, HandlerCase):
888    handler = hash.msdcc2
889    user_case_insensitive = True
890
891    known_correct_hashes = [
892        #
893        # from JTR 1.7.9
894        #
895        (("test1", "test1"), "607bbe89611e37446e736f7856515bf8"),
896        (("qerwt", "Joe"), "e09b38f84ab0be586b730baf61781e30"),
897        (("12345", "Joe"), "6432f517a900b3fc34ffe57f0f346e16"),
898        (("", "bin"), "c0cbe0313a861062e29f92ede58f9b36"),
899        (("w00t", "nineteen_characters"), "87136ae0a18b2dafe4a41d555425b2ed"),
900        (("w00t", "eighteencharacters"), "fc5df74eca97afd7cd5abb0032496223"),
901        (("longpassword", "twentyXXX_characters"), "cfc6a1e33eb36c3d4f84e4c2606623d2"),
902        (("longpassword", "twentyoneX_characters"), "99ff74cea552799da8769d30b2684bee"),
903        (("longpassword", "twentytwoXX_characters"), "0a721bdc92f27d7fb23b87a445ec562f"),
904        (("test2", "TEST2"), "c6758e5be7fc943d00b97972a8a97620"),
905        (("test3", "test3"), "360e51304a2d383ea33467ab0b639cc4"),
906        (("test4", "test4"), "6f79ee93518306f071c47185998566ae"),
907        ((u("\u00FC"), "joe"), "bdb80f2c4656a8b8591bd27d39064a54"),
908        ((u("\u20AC\u20AC"), "joe"), "1e1e20f482ff748038e47d801d0d1bda"),
909        ((u("\u00FC\u00FC"), "admin"), "0839e4a07c00f18a8c65cf5b985b9e73"),
910
911        #
912        # custom
913        #
914
915        # custom unicode test
916        ((UPASS_TABLE, 'bob'), 'cad511dc9edefcf69201da72efb6bb55'),
917    ]
918
919#=============================================================================
920# mssql 2000 & 2005
921#=============================================================================
922class mssql2000_test(HandlerCase):
923    handler = hash.mssql2000
924    secret_case_insensitive = "verify-only"
925    # FIXME: fix UT framework - this hash is sensitive to password case, but verify() is not
926
927    known_correct_hashes = [
928        #
929        # http://hkashfi.blogspot.com/2007/08/breaking-sql-server-2005-hashes.html
930        #
931        ('Test', '0x010034767D5C0CFA5FDCA28C4A56085E65E882E71CB0ED2503412FD54D6119FFF04129A1D72E7C3194F7284A7F3A'),
932        ('TEST', '0x010034767D5C2FD54D6119FFF04129A1D72E7C3194F7284A7F3A2FD54D6119FFF04129A1D72E7C3194F7284A7F3A'),
933
934        #
935        # http://www.sqlmag.com/forums/aft/68438
936        #
937        ('x', '0x010086489146C46DD7318D2514D1AC706457CBF6CD3DF8407F071DB4BBC213939D484BF7A766E974F03C96524794'),
938
939        #
940        # http://stackoverflow.com/questions/173329/how-to-decrypt-a-password-from-sql-server
941        #
942        ('AAAA', '0x0100CF465B7B12625EF019E157120D58DD46569AC7BF4118455D12625EF019E157120D58DD46569AC7BF4118455D'),
943
944        #
945        # http://msmvps.com/blogs/gladchenko/archive/2005/04/06/41083.aspx
946        #
947        ('123', '0x01002D60BA07FE612C8DE537DF3BFCFA49CD9968324481C1A8A8FE612C8DE537DF3BFCFA49CD9968324481C1A8A8'),
948
949        #
950        # http://www.simple-talk.com/sql/t-sql-programming/temporarily-changing-an-unknown-password-of-the-sa-account-/
951        #
952        ('12345', '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3'),
953
954        #
955        # XXX: sample is incomplete, password unknown
956        # https://anthonystechblog.wordpress.com/2011/04/20/password-encryption-in-sql-server-how-to-tell-if-a-user-is-using-a-weak-password/
957        # (????, '0x0100813F782D66EF15E40B1A3FDF7AB88B322F51401A87D8D3E3A8483C4351A3D96FC38499E6CDD2B6F?????????'),
958        #
959
960        #
961        # from JTR 1.7.9
962        #
963        ('foo', '0x0100A607BA7C54A24D17B565C59F1743776A10250F581D482DA8B6D6261460D3F53B279CC6913CE747006A2E3254'),
964        ('bar', '0x01000508513EADDF6DB7DDD270CCA288BF097F2FF69CC2DB74FBB9644D6901764F999BAB9ECB80DE578D92E3F80D'),
965        ('canard', '0x01008408C523CF06DCB237835D701C165E68F9460580132E28ED8BC558D22CEDF8801F4503468A80F9C52A12C0A3'),
966        ('lapin', '0x0100BF088517935FC9183FE39FDEC77539FD5CB52BA5F5761881E5B9638641A79DBF0F1501647EC941F3355440A2'),
967
968        #
969        # custom
970        #
971
972        # ensures utf-8 used for unicode
973        (UPASS_USD,   '0x0100624C0961B28E39FEE13FD0C35F57B4523F0DA1861C11D5A5B28E39FEE13FD0C35F57B4523F0DA1861C11D5A5'),
974        (UPASS_TABLE, '0x010083104228FAD559BE52477F2131E538BE9734E5C4B0ADEFD7F6D784B03C98585DC634FE2B8CA3A6DFFEC729B4'),
975
976    ]
977
978    known_alternate_hashes = [
979        # lower case hex
980        ('0x01005b20054332752e1bc2e7c5df0f9ebfe486e9bee063e8d3b332752e1bc2e7c5df0f9ebfe486e9bee063e8d3b3',
981         '12345', '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3'),
982    ]
983
984    known_unidentified_hashes = [
985        # malformed start
986        '0X01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3',
987
988        # wrong magic value
989        '0x02005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3',
990
991        # wrong size
992        '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3',
993        '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3AF',
994
995        # mssql2005
996        '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3',
997    ]
998
999    known_malformed_hashes = [
1000        # non-hex char -----\/
1001        b'0x01005B200543327G2E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3',
1002        u('0x01005B200543327G2E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3'),
1003    ]
1004
1005class mssql2005_test(HandlerCase):
1006    handler = hash.mssql2005
1007
1008    known_correct_hashes = [
1009        #
1010        # http://hkashfi.blogspot.com/2007/08/breaking-sql-server-2005-hashes.html
1011        #
1012        ('TEST', '0x010034767D5C2FD54D6119FFF04129A1D72E7C3194F7284A7F3A'),
1013
1014        #
1015        # http://www.openwall.com/lists/john-users/2009/07/14/2
1016        #
1017        ('toto', '0x01004086CEB6BF932BC4151A1AF1F13CD17301D70816A8886908'),
1018
1019        #
1020        # http://msmvps.com/blogs/gladchenko/archive/2005/04/06/41083.aspx
1021        #
1022        ('123', '0x01004A335DCEDB366D99F564D460B1965B146D6184E4E1025195'),
1023        ('123', '0x0100E11D573F359629B344990DCD3D53DE82CF8AD6BBA7B638B6'),
1024
1025        #
1026        # XXX: password unknown
1027        # http://www.simple-talk.com/sql/t-sql-programming/temporarily-changing-an-unknown-password-of-the-sa-account-/
1028        # (???, '0x01004086CEB6301EEC0A994E49E30DA235880057410264030797'),
1029        #
1030
1031        #
1032        # http://therelentlessfrontend.com/2010/03/26/encrypting-and-decrypting-passwords-in-sql-server/
1033        #
1034        ('AAAA', '0x010036D726AE86834E97F20B198ACD219D60B446AC5E48C54F30'),
1035
1036        #
1037        # from JTR 1.7.9
1038        #
1039        ("toto", "0x01004086CEB6BF932BC4151A1AF1F13CD17301D70816A8886908"),
1040        ("titi", "0x01004086CEB60ED526885801C23B366965586A43D3DEAC6DD3FD"),
1041        ("foo", "0x0100A607BA7C54A24D17B565C59F1743776A10250F581D482DA8"),
1042        ("bar", "0x01000508513EADDF6DB7DDD270CCA288BF097F2FF69CC2DB74FB"),
1043        ("canard", "0x01008408C523CF06DCB237835D701C165E68F9460580132E28ED"),
1044        ("lapin", "0x0100BF088517935FC9183FE39FDEC77539FD5CB52BA5F5761881"),
1045
1046        #
1047        # adapted from mssql2000.known_correct_hashes (above)
1048        #
1049        ('Test',  '0x010034767D5C0CFA5FDCA28C4A56085E65E882E71CB0ED250341'),
1050        ('Test',  '0x0100993BF2315F36CC441485B35C4D84687DC02C78B0E680411F'),
1051        ('x',     '0x010086489146C46DD7318D2514D1AC706457CBF6CD3DF8407F07'),
1052        ('AAAA',  '0x0100CF465B7B12625EF019E157120D58DD46569AC7BF4118455D'),
1053        ('123',   '0x01002D60BA07FE612C8DE537DF3BFCFA49CD9968324481C1A8A8'),
1054        ('12345', '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3'),
1055
1056        #
1057        # custom
1058        #
1059
1060        # ensures utf-8 used for unicode
1061        (UPASS_USD,   '0x0100624C0961B28E39FEE13FD0C35F57B4523F0DA1861C11D5A5'),
1062        (UPASS_TABLE, '0x010083104228FAD559BE52477F2131E538BE9734E5C4B0ADEFD7'),
1063    ]
1064
1065    known_alternate_hashes = [
1066        # lower case hex
1067        ('0x01005b20054332752e1bc2e7c5df0f9ebfe486e9bee063e8d3b3',
1068         '12345', '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3'),
1069    ]
1070
1071    known_unidentified_hashes = [
1072        # malformed start
1073        '0X010036D726AE86834E97F20B198ACD219D60B446AC5E48C54F30',
1074
1075        # wrong magic value
1076        '0x020036D726AE86834E97F20B198ACD219D60B446AC5E48C54F30',
1077
1078        # wrong size
1079        '0x010036D726AE86834E97F20B198ACD219D60B446AC5E48C54F',
1080        '0x010036D726AE86834E97F20B198ACD219D60B446AC5E48C54F3012',
1081
1082        # mssql2000
1083        '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3',
1084    ]
1085
1086    known_malformed_hashes = [
1087        # non-hex char --\/
1088        '0x010036D726AE86G34E97F20B198ACD219D60B446AC5E48C54F30',
1089    ]
1090
1091#=============================================================================
1092# mysql 323 & 41
1093#=============================================================================
1094class mysql323_test(HandlerCase):
1095    handler = hash.mysql323
1096
1097    known_correct_hashes = [
1098        #
1099        # from JTR 1.7.9
1100        #
1101        ('drew', '697a7de87c5390b2'),
1102        ('password', "5d2e19393cc5ef67"),
1103
1104        #
1105        # custom
1106        #
1107        ('mypass', '6f8c114b58f2ce9e'),
1108
1109        # ensures utf-8 used for unicode
1110        (UPASS_TABLE, '4ef327ca5491c8d7'),
1111    ]
1112
1113    known_unidentified_hashes = [
1114        # bad char in otherwise correct hash
1115        '6z8c114b58f2ce9e',
1116    ]
1117
1118    def test_90_whitespace(self):
1119        """check whitespace is ignored per spec"""
1120        h = self.do_encrypt("mypass")
1121        h2 = self.do_encrypt("my pass")
1122        self.assertEqual(h, h2)
1123
1124    class FuzzHashGenerator(HandlerCase.FuzzHashGenerator):
1125
1126        def accept_password_pair(self, secret, other):
1127            # override to handle whitespace
1128            return secret.replace(" ","") != other.replace(" ","")
1129
1130class mysql41_test(HandlerCase):
1131    handler = hash.mysql41
1132    known_correct_hashes = [
1133        #
1134        # from JTR 1.7.9
1135        #
1136        ('verysecretpassword', '*2C905879F74F28F8570989947D06A8429FB943E6'),
1137        ('12345678123456781234567812345678', '*F9F1470004E888963FB466A5452C9CBD9DF6239C'),
1138        ("' OR 1 /*'", '*97CF7A3ACBE0CA58D5391AC8377B5D9AC11D46D9'),
1139
1140        #
1141        # custom
1142        #
1143        ('mypass', '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4'),
1144
1145        # ensures utf-8 used for unicode
1146        (UPASS_TABLE, '*E7AFE21A9CFA2FC9D15D942AE8FB5C240FE5837B'),
1147    ]
1148    known_unidentified_hashes = [
1149        # bad char in otherwise correct hash
1150        '*6Z8989366EAF75BB670AD8EA7A7FC1176A95CEF4',
1151    ]
1152
1153#=============================================================================
1154# NTHASH
1155#=============================================================================
1156class nthash_test(HandlerCase):
1157    handler = hash.nthash
1158
1159    known_correct_hashes = [
1160        #
1161        # http://msdn.microsoft.com/en-us/library/cc245828(v=prot.10).aspx
1162        #
1163        ("OLDPASSWORD", u("6677b2c394311355b54f25eec5bfacf5")),
1164        ("NEWPASSWORD", u("256781a62031289d3c2c98c14f1efc8c")),
1165
1166        #
1167        # from JTR 1.7.9
1168        #
1169
1170        # ascii
1171        ('', '31d6cfe0d16ae931b73c59d7e0c089c0'),
1172        ('tigger', 'b7e0ea9fbffcf6dd83086e905089effd'),
1173
1174        # utf-8
1175        (b'\xC3\xBC', '8bd6e4fb88e01009818749c5443ea712'),
1176        (b'\xC3\xBC\xC3\xBC', 'cc1260adb6985ca749f150c7e0b22063'),
1177        (b'\xE2\x82\xAC', '030926b781938db4365d46adc7cfbcb8'),
1178        (b'\xE2\x82\xAC\xE2\x82\xAC','682467b963bb4e61943e170a04f7db46'),
1179
1180        #
1181        # custom
1182        #
1183        ('passphrase', '7f8fe03093cc84b267b109625f6bbf4b'),
1184    ]
1185
1186    known_unidentified_hashes = [
1187        # bad char in otherwise correct hash
1188        '7f8fe03093cc84b267b109625f6bbfxb',
1189    ]
1190
1191class bsd_nthash_test(HandlerCase):
1192    handler = hash.bsd_nthash
1193
1194    known_correct_hashes = [
1195        ('passphrase', '$3$$7f8fe03093cc84b267b109625f6bbf4b'),
1196        (b'\xC3\xBC', '$3$$8bd6e4fb88e01009818749c5443ea712'),
1197    ]
1198
1199    known_unidentified_hashes = [
1200        # bad char in otherwise correct hash --\/
1201            '$3$$7f8fe03093cc84b267b109625f6bbfxb',
1202    ]
1203
1204#=============================================================================
1205# oracle 10 & 11
1206#=============================================================================
1207class oracle10_test(UserHandlerMixin, HandlerCase):
1208    handler = hash.oracle10
1209    secret_case_insensitive = True
1210    user_case_insensitive = True
1211
1212    # TODO: get more test vectors (especially ones which properly test unicode)
1213    known_correct_hashes = [
1214        # ((secret,user),hash)
1215
1216        #
1217        # http://www.petefinnigan.com/default/default_password_list.htm
1218        #
1219        (('tiger', 'scott'), 'F894844C34402B67'),
1220        ((u('ttTiGGeR'), u('ScO')), '7AA1A84E31ED7771'),
1221        (("d_syspw", "SYSTEM"), '1B9F1F9A5CB9EB31'),
1222        (("strat_passwd", "strat_user"), 'AEBEDBB4EFB5225B'),
1223
1224        #
1225        # http://openwall.info/wiki/john/sample-hashes
1226        #
1227        (('#95LWEIGHTS', 'USER'), '000EA4D72A142E29'),
1228        (('CIAO2010', 'ALFREDO'), 'EB026A76F0650F7B'),
1229
1230        #
1231        # from JTR 1.7.9
1232        #
1233        (('GLOUGlou', 'Bob'), 'CDC6B483874B875B'),
1234        (('GLOUGLOUTER', 'bOB'), 'EF1F9139DB2D5279'),
1235        (('LONG_MOT_DE_PASSE_OUI', 'BOB'), 'EC8147ABB3373D53'),
1236
1237        #
1238        # custom
1239        #
1240        ((UPASS_TABLE, 'System'), 'B915A853F297B281'),
1241    ]
1242
1243    known_unidentified_hashes = [
1244        # bad char in hash --\
1245             'F894844C34402B6Z',
1246    ]
1247
1248class oracle11_test(HandlerCase):
1249    handler = hash.oracle11
1250    # TODO: find more test vectors (especially ones which properly test unicode)
1251    known_correct_hashes = [
1252        #
1253        # from JTR 1.7.9
1254        #
1255        ("abc123", "S:5FDAB69F543563582BA57894FE1C1361FB8ED57B903603F2C52ED1B4D642"),
1256        ("SyStEm123!@#", "S:450F957ECBE075D2FA009BA822A9E28709FBC3DA82B44D284DDABEC14C42"),
1257        ("oracle", "S:3437FF72BD69E3FB4D10C750B92B8FB90B155E26227B9AB62D94F54E5951"),
1258        ("11g", "S:61CE616647A4F7980AFD7C7245261AF25E0AFE9C9763FCF0D54DA667D4E6"),
1259        ("11g", "S:B9E7556F53500C8C78A58F50F24439D79962DE68117654B6700CE7CC71CF"),
1260
1261        #
1262        # source?
1263        #
1264        ("SHAlala", "S:2BFCFDF5895014EE9BB2B9BA067B01E0389BB5711B7B5F82B7235E9E182C"),
1265
1266        #
1267        # custom
1268        #
1269        (UPASS_TABLE, 'S:51586343E429A6DF024B8F242F2E9F8507B1096FACD422E29142AA4974B0'),
1270    ]
1271
1272#=============================================================================
1273# PHPass Portable Crypt
1274#=============================================================================
1275class phpass_test(HandlerCase):
1276    handler = hash.phpass
1277
1278    known_correct_hashes = [
1279        #
1280        # from official 0.3 implementation
1281        # http://www.openwall.com/phpass/
1282        #
1283        ('test12345', '$P$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r.L0'), # from the source
1284
1285        #
1286        # from JTR 1.7.9
1287        #
1288        ('test1', '$H$9aaaaaSXBjgypwqm.JsMssPLiS8YQ00'),
1289        ('123456', '$H$9PE8jEklgZhgLmZl5.HYJAzfGCQtzi1'),
1290        ('123456', '$H$9pdx7dbOW3Nnt32sikrjAxYFjX8XoK1'),
1291        ('thisisalongertestPW', '$P$912345678LIjjb6PhecupozNBmDndU0'),
1292        ('JohnRipper', '$P$612345678si5M0DDyPpmRCmcltU/YW/'),
1293        ('JohnRipper', '$H$712345678WhEyvy1YWzT4647jzeOmo0'),
1294        ('JohnRipper', '$P$B12345678L6Lpt4BxNotVIMILOa9u81'),
1295
1296        #
1297        # custom
1298        #
1299        ('', '$P$7JaFQsPzJSuenezefD/3jHgt5hVfNH0'),
1300        ('compL3X!', '$P$FiS0N5L672xzQx1rt1vgdJQRYKnQM9/'),
1301
1302        # ensures utf-8 used for unicode
1303        (UPASS_TABLE, '$P$7SMy8VxnfsIy2Sxm7fJxDSdil.h7TW.'),
1304        ]
1305
1306    known_malformed_hashes = [
1307        # bad char in otherwise correct hash
1308        #                            ---\/
1309        '$P$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r!L0',
1310        ]
1311
1312#=============================================================================
1313# plaintext
1314#=============================================================================
1315class plaintext_test(HandlerCase):
1316    # TODO: integrate EncodingHandlerMixin
1317    handler = hash.plaintext
1318    accepts_all_hashes = True
1319
1320    known_correct_hashes = [
1321        ('',''),
1322        ('password', 'password'),
1323
1324        # ensure unicode uses utf-8
1325        (UPASS_TABLE, UPASS_TABLE if PY3 else PASS_TABLE_UTF8),
1326        (PASS_TABLE_UTF8, UPASS_TABLE if PY3 else PASS_TABLE_UTF8),
1327    ]
1328
1329#=============================================================================
1330# postgres_md5
1331#=============================================================================
1332class postgres_md5_test(UserHandlerMixin, HandlerCase):
1333    handler = hash.postgres_md5
1334    known_correct_hashes = [
1335        # ((secret,user),hash)
1336
1337        #
1338        # generated using postgres 8.1
1339        #
1340        (('mypass', 'postgres'), 'md55fba2ea04fd36069d2574ea71c8efe9d'),
1341        (('mypass', 'root'), 'md540c31989b20437833f697e485811254b'),
1342        (("testpassword",'testuser'), 'md5d4fc5129cc2c25465a5370113ae9835f'),
1343
1344        #
1345        # custom
1346        #
1347
1348        # verify unicode->utf8
1349        ((UPASS_TABLE, 'postgres'), 'md5cb9f11283265811ce076db86d18a22d2'),
1350    ]
1351    known_unidentified_hashes = [
1352        # bad 'z' char in otherwise correct hash
1353        'md54zc31989b20437833f697e485811254b',
1354    ]
1355
1356#=============================================================================
1357# (netbsd's) sha1 crypt
1358#=============================================================================
1359class _sha1_crypt_test(HandlerCase):
1360    handler = hash.sha1_crypt
1361
1362    known_correct_hashes = [
1363        #
1364        # custom
1365        #
1366        ("password", "$sha1$19703$iVdJqfSE$v4qYKl1zqYThwpjJAoKX6UvlHq/a"),
1367        ("password", "$sha1$21773$uV7PTeux$I9oHnvwPZHMO0Nq6/WgyGV/tDJIH"),
1368        (UPASS_TABLE, '$sha1$40000$uJ3Sp7LE$.VEmLO5xntyRFYihC7ggd3297T/D'),
1369    ]
1370
1371    known_malformed_hashes = [
1372        # bad char in otherwise correct hash
1373        '$sha1$21773$u!7PTeux$I9oHnvwPZHMO0Nq6/WgyGV/tDJIH',
1374
1375        # zero padded rounds
1376        '$sha1$01773$uV7PTeux$I9oHnvwPZHMO0Nq6/WgyGV/tDJIH',
1377
1378        # too many fields
1379        '$sha1$21773$uV7PTeux$I9oHnvwPZHMO0Nq6/WgyGV/tDJIH$',
1380
1381        # empty rounds field
1382        '$sha1$$uV7PTeux$I9oHnvwPZHMO0Nq6/WgyGV/tDJIH$',
1383    ]
1384
1385    platform_crypt_support = [
1386        ("netbsd", True),
1387        ("freebsd|openbsd|solaris|darwin", False),
1388        ("linux", None),  # may be present if libxcrypt is in use
1389    ]
1390
1391# create test cases for specific backends
1392sha1_crypt_os_crypt_test = _sha1_crypt_test.create_backend_case("os_crypt")
1393sha1_crypt_builtin_test = _sha1_crypt_test.create_backend_case("builtin")
1394
1395#=============================================================================
1396# roundup
1397#=============================================================================
1398
1399# NOTE: all roundup hashes use PrefixWrapper,
1400#       so there's nothing natively to test.
1401#       so we just have a few quick cases...
1402
1403class RoundupTest(TestCase):
1404
1405    def _test_pair(self, h, secret, hash):
1406        self.assertTrue(h.verify(secret, hash))
1407        self.assertFalse(h.verify('x'+secret, hash))
1408
1409    def test_pairs(self):
1410        self._test_pair(
1411            hash.ldap_hex_sha1,
1412            "sekrit",
1413            '{SHA}8d42e738c7adee551324955458b5e2c0b49ee655')
1414
1415        self._test_pair(
1416            hash.ldap_hex_md5,
1417            "sekrit",
1418            '{MD5}ccbc53f4464604e714f69dd11138d8b5')
1419
1420        self._test_pair(
1421            hash.ldap_des_crypt,
1422            "sekrit",
1423            '{CRYPT}nFia0rj2TT59A')
1424
1425        self._test_pair(
1426            hash.roundup_plaintext,
1427            "sekrit",
1428            '{plaintext}sekrit')
1429
1430        self._test_pair(
1431            hash.ldap_pbkdf2_sha1,
1432            "sekrit",
1433            '{PBKDF2}5000$7BvbBq.EZzz/O0HuwX3iP.nAG3s$g3oPnFFaga2BJaX5PoPRljl4XIE')
1434
1435#=============================================================================
1436# sha256-crypt
1437#=============================================================================
1438class _sha256_crypt_test(HandlerCase):
1439    handler = hash.sha256_crypt
1440
1441    known_correct_hashes = [
1442        #
1443        # from JTR 1.7.9
1444        #
1445        ('U*U*U*U*', '$5$LKO/Ute40T3FNF95$U0prpBQd4PloSGU0pnpM4z9wKn4vZ1.jsrzQfPqxph9'),
1446        ('U*U***U', '$5$LKO/Ute40T3FNF95$fdgfoJEBoMajNxCv3Ru9LyQ0xZgv0OBMQoq80LQ/Qd.'),
1447        ('U*U***U*', '$5$LKO/Ute40T3FNF95$8Ry82xGnnPI/6HtFYnvPBTYgOL23sdMXn8C29aO.x/A'),
1448        ('*U*U*U*U', '$5$9mx1HkCz7G1xho50$O7V7YgleJKLUhcfk9pgzdh3RapEaWqMtEp9UUBAKIPA'),
1449        ('', '$5$kc7lRD1fpYg0g.IP$d7CMTcEqJyTXyeq8hTdu/jB/I6DGkoo62NXbHIR7S43'),
1450
1451        #
1452        # custom tests
1453        #
1454        ('', '$5$rounds=10428$uy/jIAhCetNCTtb0$YWvUOXbkqlqhyoPMpN8BMe.ZGsGx2aBvxTvDFI613c3'),
1455        (' ', '$5$rounds=10376$I5lNtXtRmf.OoMd8$Ko3AI1VvTANdyKhBPavaRjJzNpSatKU6QVN9uwS9MH.'),
1456        ('test', '$5$rounds=11858$WH1ABM5sKhxbkgCK$aTQsjPkz0rBsH3lQlJxw9HDTDXPKBxC0LlVeV69P.t1'),
1457        ('Compl3X AlphaNu3meric', '$5$rounds=10350$o.pwkySLCzwTdmQX$nCMVsnF3TXWcBPOympBUUSQi6LGGloZoOsVJMGJ09UB'),
1458        ('4lpHa N|_|M3r1K W/ Cur5Es: #$%(*)(*%#', '$5$rounds=11944$9dhlu07dQMRWvTId$LyUI5VWkGFwASlzntk1RLurxX54LUhgAcJZIt0pYGT7'),
1459        (u('with unic\u00D6de'), '$5$rounds=1000$IbG0EuGQXw5EkMdP$LQ5AfPf13KufFsKtmazqnzSGZ4pxtUNw3woQ.ELRDF4'),
1460        ]
1461
1462    if TEST_MODE("full"):
1463        # builtin alg was changed in 1.6, and had possibility of fencepost
1464        # errors near rounds that are multiples of 42. these hashes test rounds
1465        # 1004..1012 (42*24=1008 +/- 4) to ensure no mistakes were made.
1466        # (also relying on fuzz testing against os_crypt backend).
1467        known_correct_hashes.extend([
1468        ("secret", '$5$rounds=1004$nacl$oiWPbm.kQ7.jTCZoOtdv7/tO5mWv/vxw5yTqlBagVR7'),
1469        ("secret", '$5$rounds=1005$nacl$6Mo/TmGDrXxg.bMK9isRzyWH3a..6HnSVVsJMEX7ud/'),
1470        ("secret", '$5$rounds=1006$nacl$I46VwuAiUBwmVkfPFakCtjVxYYaOJscsuIeuZLbfKID'),
1471        ("secret", '$5$rounds=1007$nacl$9fY4j1AV3N/dV/YMUn1enRHKH.7nEL4xf1wWB6wfDD4'),
1472        ("secret", '$5$rounds=1008$nacl$CiFWCfn8ODmWs0I1xAdXFo09tM8jr075CyP64bu3by9'),
1473        ("secret", '$5$rounds=1009$nacl$QtpFX.CJHgVQ9oAjVYStxAeiU38OmFILWm684c6FyED'),
1474        ("secret", '$5$rounds=1010$nacl$ktAwXuT5WbjBW/0ZU1eNMpqIWY1Sm4twfRE1zbZyo.B'),
1475        ("secret", '$5$rounds=1011$nacl$QJWLBEhO9qQHyMx4IJojSN9sS41P1Yuz9REddxdO721'),
1476        ("secret", '$5$rounds=1012$nacl$mmf/k2PkbBF4VCtERgky3bEVavmLZKFwAcvxD1p3kV2'),
1477        ])
1478
1479    known_malformed_hashes = [
1480        # bad char in otherwise correct hash
1481        '$5$rounds=10428$uy/:jIAhCetNCTtb0$YWvUOXbkqlqhyoPMpN8BMeZGsGx2aBvxTvDFI613c3',
1482
1483        # zero-padded rounds
1484       '$5$rounds=010428$uy/jIAhCetNCTtb0$YWvUOXbkqlqhyoPMpN8BMe.ZGsGx2aBvxTvDFI613c3',
1485
1486        # extra "$"
1487       '$5$rounds=10428$uy/jIAhCetNCTtb0$YWvUOXbkqlqhyoPMpN8BMe.ZGsGx2aBvxTvDFI613c3$',
1488    ]
1489
1490    known_correct_configs = [
1491        # config, secret, result
1492
1493        #
1494        # taken from official specification at http://www.akkadia.org/drepper/SHA-crypt.txt
1495        #
1496        ( "$5$saltstring", "Hello world!",
1497          "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5" ),
1498        ( "$5$rounds=10000$saltstringsaltstring", "Hello world!",
1499          "$5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2."
1500          "opqey6IcA" ),
1501        ( "$5$rounds=5000$toolongsaltstring", "This is just a test",
1502          "$5$rounds=5000$toolongsaltstrin$Un/5jzAHMgOGZ5.mWJpuVolil07guHPvOW8"
1503          "mGRcvxa5" ),
1504        ( "$5$rounds=1400$anotherlongsaltstring",
1505          "a very much longer text to encrypt.  This one even stretches over more"
1506          "than one line.",
1507          "$5$rounds=1400$anotherlongsalts$Rx.j8H.h8HjEDGomFU8bDkXm3XIUnzyxf12"
1508          "oP84Bnq1" ),
1509        ( "$5$rounds=77777$short",
1510          "we have a short salt string but not a short password",
1511          "$5$rounds=77777$short$JiO1O3ZpDAxGJeaDIuqCoEFysAe1mZNJRs3pw0KQRd/" ),
1512        ( "$5$rounds=123456$asaltof16chars..", "a short string",
1513          "$5$rounds=123456$asaltof16chars..$gP3VQ/6X7UUEW3HkBn2w1/Ptq2jxPyzV/"
1514          "cZKmF/wJvD" ),
1515        ( "$5$rounds=10$roundstoolow", "the minimum number is still observed",
1516          "$5$rounds=1000$roundstoolow$yfvwcWrQ8l/K0DAWyuPMDNHpIVlTQebY9l/gL97"
1517          "2bIC" ),
1518    ]
1519
1520    filter_config_warnings = True # rounds too low, salt too small
1521
1522    platform_crypt_support = [
1523        ("freebsd(9|1\d)|linux", True),
1524        ("freebsd8", None),  # added in freebsd 8.3
1525        ("freebsd|openbsd|netbsd|darwin", False),
1526        ("solaris", None),  # depends on policy
1527    ]
1528
1529# create test cases for specific backends
1530sha256_crypt_os_crypt_test = _sha256_crypt_test.create_backend_case("os_crypt")
1531sha256_crypt_builtin_test = _sha256_crypt_test.create_backend_case("builtin")
1532
1533#=============================================================================
1534# test sha512-crypt
1535#=============================================================================
1536class _sha512_crypt_test(HandlerCase):
1537    handler = hash.sha512_crypt
1538
1539    known_correct_hashes = [
1540        #
1541        # from JTR 1.7.9
1542        #
1543        ('U*U*U*U*', "$6$LKO/Ute40T3FNF95$6S/6T2YuOIHY0N3XpLKABJ3soYcXD9mB7uVbtEZDj/LNscVhZoZ9DEH.sBciDrMsHOWOoASbNLTypH/5X26gN0"),
1544        ('U*U***U', "$6$LKO/Ute40T3FNF95$wK80cNqkiAUzFuVGxW6eFe8J.fSVI65MD5yEm8EjYMaJuDrhwe5XXpHDJpwF/kY.afsUs1LlgQAaOapVNbggZ1"),
1545        ('U*U***U*', "$6$LKO/Ute40T3FNF95$YS81pp1uhOHTgKLhSMtQCr2cDiUiN03Ud3gyD4ameviK1Zqz.w3oXsMgO6LrqmIEcG3hiqaUqHi/WEE2zrZqa/"),
1546        ('*U*U*U*U', "$6$OmBOuxFYBZCYAadG$WCckkSZok9xhp4U1shIZEV7CCVwQUwMVea7L3A77th6SaE9jOPupEMJB.z0vIWCDiN9WLh2m9Oszrj5G.gt330"),
1547        ('', "$6$ojWH1AiTee9x1peC$QVEnTvRVlPRhcLQCk/HnHaZmlGAAjCfrAN0FtOsOnUk5K5Bn/9eLHHiRzrTzaIKjW9NTLNIBUCtNVOowWS2mN."),
1548
1549        #
1550        # custom tests
1551        #
1552        ('', '$6$rounds=11021$KsvQipYPWpr93wWP$v7xjI4X6vyVptJjB1Y02vZC5SaSijBkGmq1uJhPr3cvqvvkd42Xvo48yLVPFt8dvhCsnlUgpX.//Cxn91H4qy1'),
1553        (' ', '$6$rounds=11104$ED9SA4qGmd57Fq2m$q/.PqACDM/JpAHKmr86nkPzzuR5.YpYa8ZJJvI8Zd89ZPUYTJExsFEIuTYbM7gAGcQtTkCEhBKmp1S1QZwaXx0'),
1554        ('test', '$6$rounds=11531$G/gkPn17kHYo0gTF$Kq.uZBHlSBXyzsOJXtxJruOOH4yc0Is13uY7yK0PvAvXxbvc1w8DO1RzREMhKsc82K/Jh8OquV8FZUlreYPJk1'),
1555        ('Compl3X AlphaNu3meric', '$6$rounds=10787$wakX8nGKEzgJ4Scy$X78uqaX1wYXcSCtS4BVYw2trWkvpa8p7lkAtS9O/6045fK4UB2/Jia0Uy/KzCpODlfVxVNZzCCoV9s2hoLfDs/'),
1556        ('4lpHa N|_|M3r1K W/ Cur5Es: #$%(*)(*%#', '$6$rounds=11065$5KXQoE1bztkY5IZr$Jf6krQSUKKOlKca4hSW07MSerFFzVIZt/N3rOTsUgKqp7cUdHrwV8MoIVNCk9q9WL3ZRMsdbwNXpVk0gVxKtz1'),
1557
1558        # ensures utf-8 used for unicode
1559        (UPASS_TABLE, '$6$rounds=40000$PEZTJDiyzV28M3.m$GTlnzfzGB44DGd1XqlmC4erAJKCP.rhvLvrYxiT38htrNzVGBnplFOHjejUGVrCfusGWxLQCc3pFO0A/1jYYr0'),
1560        ]
1561
1562    known_malformed_hashes = [
1563        # zero-padded rounds
1564        '$6$rounds=011021$KsvQipYPWpr93wWP$v7xjI4X6vyVptJjB1Y02vZC5SaSijBkGmq1uJhPr3cvqvvkd42Xvo48yLVPFt8dvhCsnlUgpX.//Cxn91H4qy1',
1565        # bad char in otherwise correct hash
1566        '$6$rounds=11021$KsvQipYPWpr9:wWP$v7xjI4X6vyVptJjB1Y02vZC5SaSijBkGmq1uJhPr3cvqvvkd42Xvo48yLVPFt8dvhCsnlUgpX.//Cxn91H4qy1',
1567    ]
1568
1569    known_correct_configs = [
1570        # config, secret, result
1571
1572        #
1573        # taken from official specification at http://www.akkadia.org/drepper/SHA-crypt.txt
1574        #
1575        ("$6$saltstring", "Hello world!",
1576        "$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJu"
1577        "esI68u4OTLiBFdcbYEdFCoEOfaS35inz1" ),
1578
1579      ( "$6$rounds=10000$saltstringsaltstring", "Hello world!",
1580        "$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sb"
1581        "HbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v." ),
1582
1583      ( "$6$rounds=5000$toolongsaltstring", "This is just a test",
1584        "$6$rounds=5000$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQ"
1585        "zQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0" ),
1586
1587      ( "$6$rounds=1400$anotherlongsaltstring",
1588        "a very much longer text to encrypt.  This one even stretches over more"
1589        "than one line.",
1590        "$6$rounds=1400$anotherlongsalts$POfYwTEok97VWcjxIiSOjiykti.o/pQs.wP"
1591        "vMxQ6Fm7I6IoYN3CmLs66x9t0oSwbtEW7o7UmJEiDwGqd8p4ur1" ),
1592
1593      ( "$6$rounds=77777$short",
1594        "we have a short salt string but not a short password",
1595        "$6$rounds=77777$short$WuQyW2YR.hBNpjjRhpYD/ifIw05xdfeEyQoMxIXbkvr0g"
1596        "ge1a1x3yRULJ5CCaUeOxFmtlcGZelFl5CxtgfiAc0" ),
1597
1598      ( "$6$rounds=123456$asaltof16chars..", "a short string",
1599        "$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwc"
1600        "elCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1" ),
1601
1602      ( "$6$rounds=10$roundstoolow", "the minimum number is still observed",
1603        "$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1x"
1604        "hLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX." ),
1605    ]
1606
1607    filter_config_warnings = True # rounds too low, salt too small
1608
1609    platform_crypt_support = _sha256_crypt_test.platform_crypt_support
1610
1611# create test cases for specific backends
1612sha512_crypt_os_crypt_test = _sha512_crypt_test.create_backend_case("os_crypt")
1613sha512_crypt_builtin_test = _sha512_crypt_test.create_backend_case("builtin")
1614
1615#=============================================================================
1616# sun md5 crypt
1617#=============================================================================
1618class sun_md5_crypt_test(HandlerCase):
1619    handler = hash.sun_md5_crypt
1620
1621    # TODO: this scheme needs some real test vectors, especially due to
1622    # the "bare salt" issue which plagued the official parser.
1623    known_correct_hashes = [
1624        #
1625        # http://forums.halcyoninc.com/showthread.php?t=258
1626        #
1627        ("Gpcs3_adm", "$md5$zrdhpMlZ$$wBvMOEqbSjU.hu5T2VEP01"),
1628
1629        #
1630        # http://www.c0t0d0s0.org/archives/4453-Less-known-Solaris-features-On-passwords-Part-2-Using-stronger-password-hashing.html
1631        #
1632        ("aa12345678", "$md5$vyy8.OVF$$FY4TWzuauRl4.VQNobqMY."),
1633
1634        #
1635        # http://www.cuddletech.com/blog/pivot/entry.php?id=778
1636        #
1637        ("this", "$md5$3UqYqndY$$6P.aaWOoucxxq.l00SS9k0"),
1638
1639        #
1640        # http://compgroups.net/comp.unix.solaris/password-file-in-linux-and-solaris-8-9
1641        #
1642        ("passwd", "$md5$RPgLF6IJ$WTvAlUJ7MqH5xak2FMEwS/"),
1643
1644        #
1645        # source: http://solaris-training.com/301_HTML/docs/deepdiv.pdf page 27
1646        # FIXME: password unknown
1647        # "$md5,rounds=8000$kS9FT1JC$$mnUrRO618lLah5iazwJ9m1"
1648
1649        #
1650        # source: http://www.visualexams.com/310-303.htm
1651        # XXX: this has 9 salt chars unlike all other hashes. is that valid?
1652        # FIXME: password unknown
1653        # "$md5,rounds=2006$2amXesSj5$$kCF48vfPsHDjlKNXeEw7V."
1654        #
1655
1656        #
1657        # custom
1658        #
1659
1660        # ensures utf-8 used for unicode
1661        (UPASS_TABLE, '$md5,rounds=5000$10VYDzAA$$1arAVtMA3trgE1qJ2V0Ez1'),
1662        ]
1663
1664    known_correct_configs = [
1665        # (config, secret, hash)
1666
1667        #---------------------------
1668        # test salt string handling
1669        #
1670        # these tests attempt to verify that passlib is handling
1671        # the "bare salt" issue (see sun md5 crypt docs)
1672        # in a sane manner
1673        #---------------------------
1674
1675        # config with "$" suffix, hash strings with "$$" suffix,
1676        # should all be treated the same, with one "$" added to salt digest.
1677        ("$md5$3UqYqndY$",
1678            "this", "$md5$3UqYqndY$$6P.aaWOoucxxq.l00SS9k0"),
1679        ("$md5$3UqYqndY$$.................DUMMY",
1680            "this", "$md5$3UqYqndY$$6P.aaWOoucxxq.l00SS9k0"),
1681
1682        # config with no suffix, hash strings with "$" suffix,
1683        # should all be treated the same, and no suffix added to salt digest.
1684        # NOTE: this is just a guess re: config w/ no suffix,
1685        #       but otherwise there's no sane way to encode bare_salt=False
1686        #       within config string.
1687        ("$md5$3UqYqndY",
1688            "this", "$md5$3UqYqndY$HIZVnfJNGCPbDZ9nIRSgP1"),
1689        ("$md5$3UqYqndY$.................DUMMY",
1690            "this", "$md5$3UqYqndY$HIZVnfJNGCPbDZ9nIRSgP1"),
1691    ]
1692
1693    known_malformed_hashes = [
1694        # unexpected end of hash
1695        "$md5,rounds=5000",
1696
1697        # bad rounds
1698        "$md5,rounds=500A$xxxx",
1699        "$md5,rounds=0500$xxxx",
1700        "$md5,rounds=0$xxxx",
1701
1702        # bad char in otherwise correct hash
1703        "$md5$RPgL!6IJ$WTvAlUJ7MqH5xak2FMEwS/",
1704
1705        # digest too short
1706        "$md5$RPgLa6IJ$WTvAlUJ7MqH5xak2FMEwS",
1707
1708        # digest too long
1709        "$md5$RPgLa6IJ$WTvAlUJ7MqH5xak2FMEwS/.",
1710
1711        # 2+ "$" at end of salt in config
1712        # NOTE: not sure what correct behavior is, so forbidding format for now.
1713        "$md5$3UqYqndY$$",
1714
1715        # 3+ "$" at end of salt in hash
1716        # NOTE: not sure what correct behavior is, so forbidding format for now.
1717        "$md5$RPgLa6IJ$$$WTvAlUJ7MqH5xak2FMEwS/",
1718
1719        ]
1720
1721    platform_crypt_support = [
1722        ("solaris", True),
1723        ("freebsd|openbsd|netbsd|linux|darwin", False),
1724    ]
1725    def do_verify(self, secret, hash):
1726        # Override to fake error for "$..." hash string listed in known_correct_configs (above)
1727        # These have to be hash strings, in order to test bare salt issue.
1728        if isinstance(hash, str) and hash.endswith("$.................DUMMY"):
1729            raise ValueError("pretending '$...' stub hash is config string")
1730        return self.handler.verify(secret, hash)
1731
1732#=============================================================================
1733# unix disabled / fallback
1734#=============================================================================
1735class unix_disabled_test(HandlerCase):
1736    handler = hash.unix_disabled
1737#    accepts_all_hashes = True # TODO: turn this off.
1738
1739    known_correct_hashes = [
1740        # everything should hash to "!" (or "*" on BSD),
1741        # and nothing should verify against either string
1742        ("password", "!"),
1743        (UPASS_TABLE, "*"),
1744    ]
1745
1746    known_unidentified_hashes = [
1747        # should never identify anything crypt() could return...
1748        "$1$xxx",
1749        "abc",
1750        "./az",
1751        "{SHA}xxx",
1752    ]
1753
1754    def test_76_hash_border(self):
1755        # so empty strings pass
1756        self.accepts_all_hashes = True
1757        super(unix_disabled_test, self).test_76_hash_border()
1758
1759    def test_90_special(self):
1760        """test marker option & special behavior"""
1761        warnings.filterwarnings("ignore", "passing settings to .*.hash\(\) is deprecated")
1762        handler = self.handler
1763
1764        # preserve hash if provided
1765        self.assertEqual(handler.genhash("stub", "!asd"), "!asd")
1766
1767        # use marker if no hash
1768        self.assertEqual(handler.genhash("stub", ""), handler.default_marker)
1769        self.assertEqual(handler.hash("stub"), handler.default_marker)
1770        self.assertEqual(handler.using().default_marker, handler.default_marker)
1771
1772        # custom marker
1773        self.assertEqual(handler.genhash("stub", "", marker="*xxx"), "*xxx")
1774        self.assertEqual(handler.hash("stub", marker="*xxx"), "*xxx")
1775        self.assertEqual(handler.using(marker="*xxx").hash("stub"), "*xxx")
1776
1777        # reject invalid marker
1778        self.assertRaises(ValueError, handler.genhash, 'stub', "", marker='abc')
1779        self.assertRaises(ValueError, handler.hash, 'stub', marker='abc')
1780        self.assertRaises(ValueError, handler.using, marker='abc')
1781
1782class unix_fallback_test(HandlerCase):
1783    handler = hash.unix_fallback
1784    accepts_all_hashes = True
1785
1786    known_correct_hashes = [
1787        # *everything* should hash to "!", and nothing should verify
1788        ("password", "!"),
1789        (UPASS_TABLE, "!"),
1790    ]
1791
1792    # silence annoying deprecation warning
1793    def setUp(self):
1794        super(unix_fallback_test, self).setUp()
1795        warnings.filterwarnings("ignore", "'unix_fallback' is deprecated")
1796
1797    def test_90_wildcard(self):
1798        """test enable_wildcard flag"""
1799        h = self.handler
1800        self.assertTrue(h.verify('password','', enable_wildcard=True))
1801        self.assertFalse(h.verify('password',''))
1802        for c in "!*x":
1803            self.assertFalse(h.verify('password',c, enable_wildcard=True))
1804            self.assertFalse(h.verify('password',c))
1805
1806    def test_91_preserves_existing(self):
1807        """test preserves existing disabled hash"""
1808        handler = self.handler
1809
1810        # use marker if no hash
1811        self.assertEqual(handler.genhash("stub", ""), "!")
1812        self.assertEqual(handler.hash("stub"), "!")
1813
1814        # use hash if provided and valid
1815        self.assertEqual(handler.genhash("stub", "!asd"), "!asd")
1816
1817#=============================================================================
1818# eof
1819#=============================================================================
1820