blob: 5dc83b4ecbfa008d78d41ef2d51bd1784ba2d111 [file] [log] [blame]
Serhiy Storchakaeab3ff72017-10-24 19:36:17 +03001import sys
Christian Heimesdd15f6c2008-03-16 00:07:10 +00002import unittest
R. David Murraya21e4ca2009-03-31 23:16:50 +00003
Roger E. Massefab8ab81996-12-20 22:36:52 +00004
shireenrao243a73d2019-08-13 17:27:34 -04005try:
6 import crypt
7 IMPORT_ERROR = None
8except ImportError as ex:
Steve Dowered367812020-01-09 09:00:29 -08009 if sys.platform != 'win32':
10 raise unittest.SkipTest(str(ex))
shireenrao243a73d2019-08-13 17:27:34 -040011 crypt = None
12 IMPORT_ERROR = str(ex)
13
14
Steve Dowered367812020-01-09 09:00:29 -080015@unittest.skipUnless(sys.platform == 'win32', 'This should only run on windows')
16@unittest.skipIf(crypt, 'import succeeded')
shireenrao243a73d2019-08-13 17:27:34 -040017class TestWhyCryptDidNotImport(unittest.TestCase):
shireenrao243a73d2019-08-13 17:27:34 -040018
19 def test_import_failure_message(self):
20 self.assertIn('not supported', IMPORT_ERROR)
21
22
Steve Dowered367812020-01-09 09:00:29 -080023@unittest.skipUnless(crypt, 'crypt module is required')
Christian Heimesdd15f6c2008-03-16 00:07:10 +000024class CryptTestCase(unittest.TestCase):
25
26 def test_crypt(self):
Serhiy Storchakaeab3ff72017-10-24 19:36:17 +030027 cr = crypt.crypt('mypassword')
28 cr2 = crypt.crypt('mypassword', cr)
29 self.assertEqual(cr2, cr)
30 cr = crypt.crypt('mypassword', 'ab')
31 if cr is not None:
32 cr2 = crypt.crypt('mypassword', cr)
33 self.assertEqual(cr2, cr)
Christian Heimesdd15f6c2008-03-16 00:07:10 +000034
Sean Reifscheidere2dfefb2011-02-22 10:55:44 +000035 def test_salt(self):
Brett Cannondaa57992011-02-22 21:48:06 +000036 self.assertEqual(len(crypt._saltchars), 64)
37 for method in crypt.methods:
Sean Reifscheidere2dfefb2011-02-22 10:55:44 +000038 salt = crypt.mksalt(method)
Serhiy Storchakaeab3ff72017-10-24 19:36:17 +030039 self.assertIn(len(salt) - method.salt_chars, {0, 1, 3, 4, 6, 7})
40 if method.ident:
41 self.assertIn(method.ident, salt[:len(salt)-method.salt_chars])
Sean Reifscheidere2dfefb2011-02-22 10:55:44 +000042
43 def test_saltedcrypt(self):
Brett Cannondaa57992011-02-22 21:48:06 +000044 for method in crypt.methods:
Serhiy Storchakaeab3ff72017-10-24 19:36:17 +030045 cr = crypt.crypt('assword', method)
46 self.assertEqual(len(cr), method.total_size)
47 cr2 = crypt.crypt('assword', cr)
48 self.assertEqual(cr2, cr)
49 cr = crypt.crypt('assword', crypt.mksalt(method))
50 self.assertEqual(len(cr), method.total_size)
Sean Reifscheidere2dfefb2011-02-22 10:55:44 +000051
52 def test_methods(self):
Brett Cannondaa57992011-02-22 21:48:06 +000053 self.assertTrue(len(crypt.methods) >= 1)
Serhiy Storchakaeab3ff72017-10-24 19:36:17 +030054 if sys.platform.startswith('openbsd'):
55 self.assertEqual(crypt.methods, [crypt.METHOD_BLOWFISH])
56 else:
57 self.assertEqual(crypt.methods[-1], crypt.METHOD_CRYPT)
58
shireenrao243a73d2019-08-13 17:27:34 -040059 @unittest.skipUnless(
60 crypt
61 and (
62 crypt.METHOD_SHA256 in crypt.methods or crypt.METHOD_SHA512 in crypt.methods
63 ),
64 'requires support of SHA-2',
65 )
Serhiy Storchakacede8c92017-11-16 13:22:51 +020066 def test_sha2_rounds(self):
67 for method in (crypt.METHOD_SHA256, crypt.METHOD_SHA512):
68 for rounds in 1000, 10_000, 100_000:
69 salt = crypt.mksalt(method, rounds=rounds)
70 self.assertIn('$rounds=%d$' % rounds, salt)
71 self.assertEqual(len(salt) - method.salt_chars,
72 11 + len(str(rounds)))
73 cr = crypt.crypt('mypassword', salt)
74 self.assertTrue(cr)
75 cr2 = crypt.crypt('mypassword', cr)
76 self.assertEqual(cr2, cr)
77
shireenrao243a73d2019-08-13 17:27:34 -040078 @unittest.skipUnless(
79 crypt and crypt.METHOD_BLOWFISH in crypt.methods, 'requires support of Blowfish'
80 )
Serhiy Storchakacede8c92017-11-16 13:22:51 +020081 def test_blowfish_rounds(self):
Serhiy Storchakaeab3ff72017-10-24 19:36:17 +030082 for log_rounds in range(4, 11):
Serhiy Storchakacede8c92017-11-16 13:22:51 +020083 salt = crypt.mksalt(crypt.METHOD_BLOWFISH, rounds=1 << log_rounds)
Serhiy Storchakaeab3ff72017-10-24 19:36:17 +030084 self.assertIn('$%02d$' % log_rounds, salt)
85 self.assertIn(len(salt) - crypt.METHOD_BLOWFISH.salt_chars, {6, 7})
86 cr = crypt.crypt('mypassword', salt)
87 self.assertTrue(cr)
88 cr2 = crypt.crypt('mypassword', cr)
89 self.assertEqual(cr2, cr)
90
Serhiy Storchakacede8c92017-11-16 13:22:51 +020091 def test_invalid_rounds(self):
92 for method in (crypt.METHOD_SHA256, crypt.METHOD_SHA512,
93 crypt.METHOD_BLOWFISH):
94 with self.assertRaises(TypeError):
95 crypt.mksalt(method, rounds='4096')
96 with self.assertRaises(TypeError):
97 crypt.mksalt(method, rounds=4096.0)
98 for rounds in (0, 1, -1, 1<<999):
99 with self.assertRaises(ValueError):
100 crypt.mksalt(method, rounds=rounds)
101 with self.assertRaises(ValueError):
102 crypt.mksalt(crypt.METHOD_BLOWFISH, rounds=1000)
103 for method in (crypt.METHOD_CRYPT, crypt.METHOD_MD5):
104 with self.assertRaisesRegex(ValueError, 'support'):
105 crypt.mksalt(method, rounds=4096)
Serhiy Storchakaeab3ff72017-10-24 19:36:17 +0300106
Sean Reifscheidere2dfefb2011-02-22 10:55:44 +0000107
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000108if __name__ == "__main__":
Ezio Melotti90bbbd12013-01-11 05:18:45 +0200109 unittest.main()