def test_crypt(self): """test crypt.crypt() wrappers""" from lib.passlib.utils import has_crypt, safe_crypt, test_crypt # test everything is disabled if not has_crypt: self.assertEqual(safe_crypt("test", "aa"), None) self.assertFalse(test_crypt("test", "aaqPiZY5xR5l.")) raise self.skipTest("crypt.crypt() not available") # XXX: this assumes *every* crypt() implementation supports des_crypt. # if this fails for some platform, this test will need modifying. # test return type self.assertIsInstance(safe_crypt(u("test"), u("aa")), unicode) # test ascii password h1 = u('aaqPiZY5xR5l.') self.assertEqual(safe_crypt(u('test'), u('aa')), h1) self.assertEqual(safe_crypt(b('test'), b('aa')), h1) # test utf-8 / unicode password h2 = u('aahWwbrUsKZk.') self.assertEqual(safe_crypt(u('test\u1234'), 'aa'), h2) self.assertEqual(safe_crypt(b('test\xe1\x88\xb4'), 'aa'), h2) # test latin-1 password hash = safe_crypt(b('test\xff'), 'aa') if PY3: # py3 supports utf-8 bytes only. self.assertEqual(hash, None) else: # but py2 is fine. self.assertEqual(hash, u('aaOx.5nbTU/.M')) # test rejects null chars in password self.assertRaises(ValueError, safe_crypt, '\x00', 'aa') # check test_crypt() h1x = h1[:-1] + 'x' self.assertTrue(test_crypt("test", h1)) self.assertFalse(test_crypt("test", h1x)) # check crypt returning variant error indicators # some platforms return None on errors, others empty string, # The BSDs in some cases return ":" import lib.passlib.utils as mod orig = mod._crypt try: fake = None mod._crypt = lambda secret, hash: fake for fake in [None, "", ":", ":0", "*0"]: self.assertEqual(safe_crypt("test", "aa"), None) self.assertFalse(test_crypt("test", h1)) fake = 'xxx' self.assertEqual(safe_crypt("test", "aa"), "xxx") finally: mod._crypt = orig
def _calc_checksum_os_crypt(self, secret): config = self.to_string(config=True) hash = safe_crypt(secret, config) if hash: assert hash.startswith(config) and len(hash) == len(config) + 29 return hash[-28:] else: return self._calc_checksum_builtin(secret)
def _calc_checksum_os_crypt(self, secret): config = self.ident + self.salt hash = safe_crypt(secret, config) if hash: assert hash.startswith(config) and len(hash) == len(config) + 23 return hash[-22:] else: return self._calc_checksum_builtin(secret)
def _calc_checksum_os_crypt(self, secret): config = self.to_string() hash = safe_crypt(secret, config) if hash: assert hash.startswith(config[:9]) and len(hash) == 20 return hash[-11:] else: return self._calc_checksum_builtin(secret)
def _calc_checksum_os_crypt(self, secret): # NOTE: safe_crypt encodes unicode secret -> utf8 # no official policy since des-crypt predates unicode hash = safe_crypt(secret, self.salt) if hash: assert hash.startswith(self.salt) and len(hash) == 13 return hash[2:] else: return self._calc_checksum_builtin(secret)
def _calc_checksum_os_crypt(self, secret): config = self.ident + self.salt hash = safe_crypt(secret, config) if hash: assert hash.startswith(config) and len(hash) == len(config) + 23 return hash[-22:] else: # py3's crypt.crypt() can't handle non-utf8 bytes. # fallback to builtin alg, which is always available. return self._calc_checksum_builtin(secret)
def _calc_checksum_os_crypt(self, secret): hash = safe_crypt(secret, self.to_string()) if hash: # NOTE: avoiding full parsing routine via from_string().checksum, # and just extracting the bit we need. cs = self.checksum_size assert hash.startswith(self.ident) and hash[-cs - 1] == _UDOLLAR return hash[-cs:] else: return self._calc_checksum_builtin(secret)
def _calc_checksum_os_crypt(self, secret): config = self.to_string() hash = safe_crypt(secret, config) if hash: assert hash.startswith(config[:9]) and len(hash) == 20 return hash[-11:] else: # py3's crypt.crypt() can't handle non-utf8 bytes. # fallback to builtin alg, which is always available. return self._calc_checksum_builtin(secret)
def _calc_checksum_os_crypt(self, secret): hash = safe_crypt(secret, self.to_string()) if hash: # NOTE: avoiding full parsing routine via from_string().checksum, # and just extracting the bit we need. cs = self.checksum_size assert hash.startswith(self.ident) and hash[-cs-1] == _UDOLLAR return hash[-cs:] else: return self._calc_checksum_builtin(secret)
def _calc_checksum_os_crypt(self, secret): # NOTE: we let safe_crypt() encode unicode secret -> utf8; # no official policy since des-crypt predates unicode hash = safe_crypt(secret, self.salt) if hash: assert hash.startswith(self.salt) and len(hash) == 13 return hash[2:] else: # py3's crypt.crypt() can't handle non-utf8 bytes. # fallback to builtin alg, which is always available. return self._calc_checksum_builtin(secret)
def _calc_checksum_os_crypt(self, secret): hash = safe_crypt(secret, self.to_string()) if hash: # NOTE: avoiding full parsing routine via from_string().checksum, # and just extracting the bit we need. cs = self.checksum_size assert hash.startswith(self.ident) and hash[-cs - 1] == _UDOLLAR return hash[-cs:] else: # py3's crypt.crypt() can't handle non-utf8 bytes. # fallback to builtin alg, which is always available. return self._calc_checksum_builtin(secret)
def _calc_checksum_os_crypt(self, secret, config): hash = safe_crypt(secret, config) if hash: assert hash.startswith(config) and len(hash) == len(config)+31 return hash[-31:] else: # NOTE: Have to raise this error because python3's crypt.crypt() only accepts unicode. # This means it can't handle any passwords that aren't either unicode # or utf-8 encoded bytes. However, hashing a password with an alternate # encoding should be a pretty rare edge case; if user needs it, they can just # install bcrypt backend. # XXX: is this the right error type to raise? # maybe have safe_crypt() not swallow UnicodeDecodeError, and have handlers # like sha256_crypt trap it if they have alternate method of handling them? raise uh.exc.MissingBackendError( "non-utf8 encoded passwords can't be handled by crypt.crypt() under python3, " "recommend running `pip install bcrypt`.", )