def test_90_bcrypt_padding(self): """test passlib correctly handles bcrypt padding bits""" self.require_TEST_MODE("full") # # prevents reccurrence of issue 25 (https://code.google.com/p/passlib/issues/detail?id=25) # were some unused bits were incorrectly set in bcrypt salt strings. # (fixed since 1.5.3) # bcrypt = self.handler corr_desc = ".*incorrectly set padding bits" # # test hash() / genconfig() don't generate invalid salts anymore # def check_padding(hash): assert hash.startswith(("$2a$", "$2b$")) and len(hash) >= 28, \ "unexpectedly malformed hash: %r" % (hash,) self.assertTrue( hash[28] in '.Oeu', "unused bits incorrectly set in hash: %r" % (hash, )) for i in irange(6): check_padding(bcrypt.genconfig()) for i in irange(3): check_padding(bcrypt.using(rounds=bcrypt.min_rounds).hash("bob")) # # test genconfig() corrects invalid salts & issues warning. # with self.assertWarningList(["salt too large", corr_desc]): hash = bcrypt.genconfig(salt="." * 21 + "A.", rounds=5, relaxed=True) self.assertEqual(hash, "$2b$05$" + "." * (22 + 31)) # # test public methods against good & bad hashes # samples = self.known_incorrect_padding for pwd, bad, good in samples: # make sure genhash() corrects bad configs, leaves good unchanged with self.assertWarningList([corr_desc]): self.assertEqual(bcrypt.genhash(pwd, bad), good) with self.assertWarningList([]): self.assertEqual(bcrypt.genhash(pwd, good), good) # make sure verify() works correctly with good & bad hashes with self.assertWarningList([corr_desc]): self.assertTrue(bcrypt.verify(pwd, bad)) with self.assertWarningList([]): self.assertTrue(bcrypt.verify(pwd, good)) # make sure normhash() corrects bad hashes, leaves good unchanged with self.assertWarningList([corr_desc]): self.assertEqual(bcrypt.normhash(bad), good) with self.assertWarningList([]): self.assertEqual(bcrypt.normhash(good), good) # make sure normhash() leaves non-bcrypt hashes alone self.assertEqual(bcrypt.normhash("$md5$abc"), "$md5$abc")
def test_90_bcrypt_padding(self): """test passlib correctly handles bcrypt padding bits""" self.require_TEST_MODE("full") # # prevents reccurrence of issue 25 (https://code.google.com/p/passlib/issues/detail?id=25) # were some unused bits were incorrectly set in bcrypt salt strings. # (fixed since 1.5.3) # bcrypt = self.handler corr_desc = ".*incorrectly set padding bits" # # test hash() / genconfig() don't generate invalid salts anymore # def check_padding(hash): assert hash.startswith(("$2a$", "$2b$")) and len(hash) >= 28, \ "unexpectedly malformed hash: %r" % (hash,) self.assertTrue(hash[28] in '.Oeu', "unused bits incorrectly set in hash: %r" % (hash,)) for i in irange(6): check_padding(bcrypt.genconfig()) for i in irange(3): check_padding(bcrypt.using(rounds=bcrypt.min_rounds).hash("bob")) # # test genconfig() corrects invalid salts & issues warning. # with self.assertWarningList(["salt too large", corr_desc]): hash = bcrypt.genconfig(salt="."*21 + "A.", rounds=5, relaxed=True) self.assertEqual(hash, "$2b$05$" + "." * (22 + 31)) # # test public methods against good & bad hashes # samples = self.known_incorrect_padding for pwd, bad, good in samples: # make sure genhash() corrects bad configs, leaves good unchanged with self.assertWarningList([corr_desc]): self.assertEqual(bcrypt.genhash(pwd, bad), good) with self.assertWarningList([]): self.assertEqual(bcrypt.genhash(pwd, good), good) # make sure verify() works correctly with good & bad hashes with self.assertWarningList([corr_desc]): self.assertTrue(bcrypt.verify(pwd, bad)) with self.assertWarningList([]): self.assertTrue(bcrypt.verify(pwd, good)) # make sure normhash() corrects bad hashes, leaves good unchanged with self.assertWarningList([corr_desc]): self.assertEqual(bcrypt.normhash(bad), good) with self.assertWarningList([]): self.assertEqual(bcrypt.normhash(good), good) # make sure normhash() leaves non-bcrypt hashes alone self.assertEqual(bcrypt.normhash("$md5$abc"), "$md5$abc")
def test_calc_digest_v2(self): """ test digest calc v2 matches bcrypt() """ from passlib.hash import bcrypt from passlib.crypto.digest import compile_hmac from passlib.utils.binary import b64encode # manually calc intermediary digest salt = "nyKYxTAvjmy6lMDYMl11Uu" secret = "test" temp_digest = compile_hmac("sha256", salt.encode("ascii"))( secret.encode("ascii")) temp_digest = b64encode(temp_digest).decode("ascii") self.assertEqual(temp_digest, "J5TlyIDm+IcSWmKiDJm+MeICndBkFVPn4kKdJW8f+xY=") # manually final hash from intermediary # XXX: genhash() could be useful here bcrypt_digest = bcrypt(ident="2b", salt=salt, rounds=12)._calc_checksum(temp_digest) self.assertEqual(bcrypt_digest, "M0wE0Ov/9LXoQFCe.jRHu3MSHPF54Ta") self.assertTrue( bcrypt.verify(temp_digest, "$2b$12$" + salt + bcrypt_digest)) # confirm handler outputs same thing. # XXX: genhash() could be useful here result = self.handler(ident="2b", salt=salt, rounds=12)._calc_checksum(secret) self.assertEqual(result, bcrypt_digest)
def validate_authentication(self, username, password, handler): """Validate authentication with hashed password""" msg = "Authentication failed." if not self.has_user(username): raise AuthenticationFailed(msg) if username != 'anonymous': if not bcrypt.verify(password, self.user_table[username]['pwd']): raise AuthenticationFailed(msg)
def verify_password(self, password): return bcrypt.verify(password, self.password)
def check_password_hash(stored, given): if stored is None or stored == "": return False return bcrypt.verify(given.encode("UTF-8"), stored)