1import sys 2import unittest 3from test.support import check_sanitizer, warnings_helper 4 5 6try: 7 if check_sanitizer(address=True, memory=True): 8 raise unittest.SkipTest("The crypt module SEGFAULTs on ASAN/MSAN builds") 9 crypt = warnings_helper.import_deprecated("crypt") 10 IMPORT_ERROR = None 11except ImportError as ex: 12 if sys.platform != 'win32': 13 raise unittest.SkipTest(str(ex)) 14 crypt = None 15 IMPORT_ERROR = str(ex) 16 17 18@unittest.skipUnless(sys.platform == 'win32', 'This should only run on windows') 19@unittest.skipIf(crypt, 'import succeeded') 20class TestWhyCryptDidNotImport(unittest.TestCase): 21 22 def test_import_failure_message(self): 23 self.assertIn('not supported', IMPORT_ERROR) 24 25 26@unittest.skipUnless(crypt, 'crypt module is required') 27class CryptTestCase(unittest.TestCase): 28 29 def test_crypt(self): 30 cr = crypt.crypt('mypassword') 31 cr2 = crypt.crypt('mypassword', cr) 32 self.assertEqual(cr2, cr) 33 cr = crypt.crypt('mypassword', 'ab') 34 if cr is not None: 35 cr2 = crypt.crypt('mypassword', cr) 36 self.assertEqual(cr2, cr) 37 38 def test_salt(self): 39 self.assertEqual(len(crypt._saltchars), 64) 40 for method in crypt.methods: 41 salt = crypt.mksalt(method) 42 self.assertIn(len(salt) - method.salt_chars, {0, 1, 3, 4, 6, 7}) 43 if method.ident: 44 self.assertIn(method.ident, salt[:len(salt)-method.salt_chars]) 45 46 def test_saltedcrypt(self): 47 for method in crypt.methods: 48 cr = crypt.crypt('assword', method) 49 self.assertEqual(len(cr), method.total_size) 50 cr2 = crypt.crypt('assword', cr) 51 self.assertEqual(cr2, cr) 52 cr = crypt.crypt('assword', crypt.mksalt(method)) 53 self.assertEqual(len(cr), method.total_size) 54 55 def test_methods(self): 56 self.assertTrue(len(crypt.methods) >= 1) 57 if sys.platform.startswith('openbsd'): 58 self.assertEqual(crypt.methods, [crypt.METHOD_BLOWFISH]) 59 else: 60 self.assertEqual(crypt.methods[-1], crypt.METHOD_CRYPT) 61 62 @unittest.skipUnless( 63 crypt 64 and ( 65 crypt.METHOD_SHA256 in crypt.methods or crypt.METHOD_SHA512 in crypt.methods 66 ), 67 'requires support of SHA-2', 68 ) 69 def test_sha2_rounds(self): 70 for method in (crypt.METHOD_SHA256, crypt.METHOD_SHA512): 71 for rounds in 1000, 10_000, 100_000: 72 salt = crypt.mksalt(method, rounds=rounds) 73 self.assertIn('$rounds=%d$' % rounds, salt) 74 self.assertEqual(len(salt) - method.salt_chars, 75 11 + len(str(rounds))) 76 cr = crypt.crypt('mypassword', salt) 77 self.assertTrue(cr) 78 cr2 = crypt.crypt('mypassword', cr) 79 self.assertEqual(cr2, cr) 80 81 @unittest.skipUnless( 82 crypt and crypt.METHOD_BLOWFISH in crypt.methods, 'requires support of Blowfish' 83 ) 84 def test_blowfish_rounds(self): 85 for log_rounds in range(4, 11): 86 salt = crypt.mksalt(crypt.METHOD_BLOWFISH, rounds=1 << log_rounds) 87 self.assertIn('$%02d$' % log_rounds, salt) 88 self.assertIn(len(salt) - crypt.METHOD_BLOWFISH.salt_chars, {6, 7}) 89 cr = crypt.crypt('mypassword', salt) 90 self.assertTrue(cr) 91 cr2 = crypt.crypt('mypassword', cr) 92 self.assertEqual(cr2, cr) 93 94 def test_invalid_rounds(self): 95 for method in (crypt.METHOD_SHA256, crypt.METHOD_SHA512, 96 crypt.METHOD_BLOWFISH): 97 with self.assertRaises(TypeError): 98 crypt.mksalt(method, rounds='4096') 99 with self.assertRaises(TypeError): 100 crypt.mksalt(method, rounds=4096.0) 101 for rounds in (0, 1, -1, 1<<999): 102 with self.assertRaises(ValueError): 103 crypt.mksalt(method, rounds=rounds) 104 with self.assertRaises(ValueError): 105 crypt.mksalt(crypt.METHOD_BLOWFISH, rounds=1000) 106 for method in (crypt.METHOD_CRYPT, crypt.METHOD_MD5): 107 with self.assertRaisesRegex(ValueError, 'support'): 108 crypt.mksalt(method, rounds=4096) 109 110 111if __name__ == "__main__": 112 unittest.main() 113