diff options
| author | Eli Collins <elic@assurancetechnologies.com> | 2011-04-29 16:18:38 -0400 |
|---|---|---|
| committer | Eli Collins <elic@assurancetechnologies.com> | 2011-04-29 16:18:38 -0400 |
| commit | 0a911f70599de598d65147dc9b19ead51ff9ab38 (patch) | |
| tree | 5b846674cece38dea221271607c31f718fb8a7a6 | |
| parent | c8d8eb0d9b1c753d342307b070fb1ad09cc351a6 (diff) | |
| download | passlib-0a911f70599de598d65147dc9b19ead51ff9ab38.tar.gz | |
added ldap_pbkdf2_{digest} variants; UTs & docs; removed prefix from pdkdf2_sha1 for compat w/ existing hashes
| -rw-r--r-- | docs/lib/passlib.hash.ldap_pbkdf2_digest.rst | 38 | ||||
| -rw-r--r-- | docs/lib/passlib.hash.pbkdf2_digest.rst | 17 | ||||
| -rw-r--r-- | docs/lib/passlib.hash.rst | 1 | ||||
| -rw-r--r-- | passlib/default.cfg | 10 | ||||
| -rw-r--r-- | passlib/handlers/pbkdf2.py | 13 | ||||
| -rw-r--r-- | passlib/handlers/roundup.py | 5 | ||||
| -rw-r--r-- | passlib/registry.py | 7 | ||||
| -rw-r--r-- | passlib/tests/test_drivers.py | 40 |
8 files changed, 111 insertions, 20 deletions
diff --git a/docs/lib/passlib.hash.ldap_pbkdf2_digest.rst b/docs/lib/passlib.hash.ldap_pbkdf2_digest.rst new file mode 100644 index 0000000..d734960 --- /dev/null +++ b/docs/lib/passlib.hash.ldap_pbkdf2_digest.rst @@ -0,0 +1,38 @@ +================================================================= +:samp:`passlib.hash.ldap_pbkdf2_{digest}` - Generic PBKDF2 Hashes +================================================================= + +.. index:: pbkdf2 hash; generic ldap + +.. currentmodule:: passlib.hash + +PassLib provides three custom hash schemes based on the PBKDF2 [#pbkdf2]_ algorithm +which are compatible with the :ref:`ldap hash format <ldap-hashes>`: +:class:`!ldap_pbkdf2_sha1`, :class:`!ldap_pbkdf2_sha256`, :class:`!ldap_pbkdf2_sha512`. +They feature variable length salts, variable rounds. + +.. seealso:: + + These classes are simply wrappers around the :doc:`MCF-Compatible Simple PBKDF2 Hashes <passlib.hash.pbkdf2_digest>`. + +Interface +========= +.. class:: ldap_pbkdf2_sha1() + + this is the same as :class:`pbkdf2_sha1`, except that it + uses ``{PBKDF2}`` as it's identifying prefix instead of ``$pdkdf2$``. + +.. class:: ldap_pbkdf2_sha256() + + this is the same as :class:`pbkdf2_sha256`, except that it + uses ``{PBKDF2-SHA256}`` as it's identifying prefix instead of ``$pdkdf2-sha256$``. + +.. class:: ldap_pbkdf2_sha512() + + this is the same as :class:`pbkdf2_sha512`, except that it + uses ``{PBKDF2-SHA512}`` as it's identifying prefix instead of ``$pdkdf2-sha512$``. + +References +========== +.. [#pbkdf2] The specification for the PBKDF2 algorithm - `<http://tools.ietf.org/html/rfc2898#section-5.2>`_, + part of :rfc:`2898`. diff --git a/docs/lib/passlib.hash.pbkdf2_digest.rst b/docs/lib/passlib.hash.pbkdf2_digest.rst index 1014907..fac5ca9 100644 --- a/docs/lib/passlib.hash.pbkdf2_digest.rst +++ b/docs/lib/passlib.hash.pbkdf2_digest.rst @@ -1,14 +1,14 @@ =============================================================== -:samp:`passlib.hash.pbkdf2_{digest}` - Simple PBKDF2 Hashes +:samp:`passlib.hash.pbkdf2_{digest}` - Generic PBKDF2 Hashes =============================================================== -.. index:: pbkdf2; password hash +.. index:: pbkdf2 hash; generic mcf .. currentmodule:: passlib.hash PassLib provides three custom hash schemes based on the PBKDF2 [#pbkdf2]_ algorithm which are compatible with the :ref:`modular crypt format <modular-crypt-format>`: -:class:`pbkdf2_sha1`, :class:`pbkdf2_sha256`, :class:`pbkdf2_sha512`. +:class:`!pbkdf2_sha1`, :class:`!pbkdf2_sha256`, :class:`!pbkdf2_sha512`. They feature variable length salts, variable rounds. Security-wise, PBKDF2 is currently one of the leading key derivation functions, @@ -18,6 +18,10 @@ it is not vulnerable to any of the known weaknesses of SHA-1 [#hmac-sha1]_, and can be safely used. However, for those still concerned, SHA-256 and SHA-512 versions are offered as well. +.. seealso:: + + Alternate version of these hashes - :doc:`LDAP-Compatible Simple PBKDF2 Hashes <passlib.hash.ldap_pbkdf2_digest>` + Usage ===== These classes support both rounds and salts, @@ -42,9 +46,9 @@ Interface Format & Algorithm ================== -An example :class:`!pbkdf2_sha256` hash (of ``password``): +An example :class:`!pbkdf2_sha256` hash (of ``password``):: -``$pbkdf2-sha256$6400$.6UI/S.nXIk8jcbdHx3Fhg$98jZicV16ODfEsEZeYPGHU3kbrUrvUEXOPimVSQDD44``. + $pbkdf2-sha256$6400$.6UI/S.nXIk8jcbdHx3Fhg$98jZicV16ODfEsEZeYPGHU3kbrUrvUEXOPimVSQDD44 All of the pbkdf2 hashes defined by passlib follow the same format, :samp:`$pbkdf2-{digest}${rounds}${salt}${checksum}`. @@ -82,4 +86,5 @@ References .. [#pbkdf2] The specification for the PBKDF2 algorithm - `<http://tools.ietf.org/html/rfc2898#section-5.2>`_, part of :rfc:`2898`. -.. [#hmac-sha1] While SHA1 has fallen to collision attacks, HMAC-SHA1 is still considered secure - `<http://www.schneier.com/blog/archives/2005/02/sha1_broken.html>`_. +.. [#hmac-sha1] While SHA1 has fallen to collision attacks, HMAC-SHA1 as used by PBKDF2 + is still considered secure - `<http://www.schneier.com/blog/archives/2005/02/sha1_broken.html>`_. diff --git a/docs/lib/passlib.hash.rst b/docs/lib/passlib.hash.rst index 8a2e99c..47297cc 100644 --- a/docs/lib/passlib.hash.rst +++ b/docs/lib/passlib.hash.rst @@ -144,6 +144,7 @@ but follow the LDAP format: .. toctree:: :maxdepth: 1 + passlib.hash.ldap_pbkdf2_digest passlib.hash.atlassian_pbkdf2_sha1 .. diff --git a/passlib/default.cfg b/passlib/default.cfg index c68f518..b45e048 100644 --- a/passlib/default.cfg +++ b/passlib/default.cfg @@ -11,9 +11,17 @@ all.vary_rounds = 10% bsdi_crypt.default_rounds = 30000 -phpass.default_rounds = 10 bcrypt.default_rounds = 10 sha1_crypt.default_rounds = 30000 sun_md5_crypt.default_rounds = 30000 sha256_crypt.default_rounds = 30000 sha512_crypt.default_rounds = 30000 + +ldap_bsdi_crypt.default_rounds = 30000 +ldap_bcrypt.default_rounds = 10 +ldap_sha1_crypt.default_rounds = 30000 +ldap_sun_md5_crypt.default_rounds = 30000 +ldap_sha256_crypt.default_rounds = 30000 +ldap_sha512_crypt.default_rounds = 30000 + +phpass.default_rounds = 10 diff --git a/passlib/handlers/pbkdf2.py b/passlib/handlers/pbkdf2.py index 946efde..adbba76 100644 --- a/passlib/handlers/pbkdf2.py +++ b/passlib/handlers/pbkdf2.py @@ -88,10 +88,11 @@ class Pbkdf2DigestHandler(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.Gen secret = secret.encode("utf-8") return pbkdf2(secret, self.salt, self.rounds, self.checksum_size, self._prf) -def create_pbkdf2_hash(hash_name, digest_size): +def create_pbkdf2_hash(hash_name, digest_size, ident=None): "create new Pbkdf2DigestHandler subclass for a specific hash" name = 'pbkdf2_' + hash_name - ident = "$pbkdf2-%s$" % (hash_name,) + if ident is None: + ident = "$pbkdf2-%s$" % (hash_name,) prf = "hmac-%s" % (hash_name,) base = Pbkdf2DigestHandler return type(name, (base,), dict( @@ -100,7 +101,7 @@ def create_pbkdf2_hash(hash_name, digest_size): _prf = prf, checksum_size=digest_size, encoded_checksum_size=(digest_size*4+2)//3, - __doc__="""This class implements Passlib's PBKDF2-%(prf)s based hash, and follows the :ref:`password-hash-api`. + __doc__="""This class implements a generic ``PBKDF2-%(prf)s``-based password hash, and follows the :ref:`password-hash-api`. It supports a variable-length salt, and a variable number of rounds. @@ -124,10 +125,14 @@ def create_pbkdf2_hash(hash_name, digest_size): #--------------------------------------------------------- #derived handlers #--------------------------------------------------------- -pbkdf2_sha1 = create_pbkdf2_hash("sha1", 20) +pbkdf2_sha1 = create_pbkdf2_hash("sha1", 20, ident="$pbkdf2$") pbkdf2_sha256 = create_pbkdf2_hash("sha256", 32) pbkdf2_sha512 = create_pbkdf2_hash("sha512", 64) +ldap_pbkdf2_sha1 = uh.PrefixWrapper("ldap_pbkdf2_sha1", pbkdf2_sha1, "{PBKDF2}", "$pbkdf2$") +ldap_pbkdf2_sha256 = uh.PrefixWrapper("ldap_pbkdf2_sha256", pbkdf2_sha256, "{PBKDF2-SHA256}", "$pbkdf2-sha256$") +ldap_pbkdf2_sha512 = uh.PrefixWrapper("ldap_pbkdf2_sha512", pbkdf2_sha512, "{PBKDF2-SHA512}", "$pbkdf2-sha512$") + #========================================================= #dlitz's pbkdf2 hash #========================================================= diff --git a/passlib/handlers/roundup.py b/passlib/handlers/roundup.py index ebc2d5a..9992e5f 100644 --- a/passlib/handlers/roundup.py +++ b/passlib/handlers/roundup.py @@ -11,7 +11,6 @@ from passlib.utils import handlers as uh #local __all__ = [ "roundup_plaintext", - "roundup_pbkdf2_sha1", "ldap_hex_md5", "ldap_hex_sha1", ] @@ -21,10 +20,6 @@ __all__ = [ roundup_plaintext = uh.PrefixWrapper("roundup_plaintext", "plaintext", prefix="{plaintext}", lazy=True) -roundup_pbkdf2_sha1 = uh.PrefixWrapper("roundup_pbkdf2_sha1", "pbkdf2_sha1", - prefix="{PBKDF2}", - orig_prefix="$pbkdf2-sha1$", lazy=True) - #NOTE: these are here because they're currently only known to be used by roundup ldap_hex_md5 = uh.PrefixWrapper("ldap_hex_md5", "hex_md5", "{MD5}", lazy=True) ldap_hex_sha1 = uh.PrefixWrapper("ldap_hex_sha1", "hex_sha1", "{SHA}", lazy=True) diff --git a/passlib/registry.py b/passlib/registry.py index 942f94b..46e38a6 100644 --- a/passlib/registry.py +++ b/passlib/registry.py @@ -103,6 +103,11 @@ _handler_locations = { "ldap_sha1_crypt": ("passlib.handlers.ldap_digests","ldap_sha1_crypt"), "ldap_sha256_crypt":("passlib.handlers.ldap_digests","ldap_sha256_crypt"), "ldap_sha512_crypt":("passlib.handlers.ldap_digests","ldap_sha512_crypt"), + "ldap_pbkdf2_sha1": ("passlib.handlers.pbkdf2", "ldap_pbkdf2_sha1"), + "ldap_pbkdf2_sha256": + ("passlib.handlers.pbkdf2", "ldap_pbkdf2_sha256"), + "ldap_pbkdf2_sha512": + ("passlib.handlers.pbkdf2", "ldap_pbkdf2_sha512"), "md5_crypt": ("passlib.handlers.md5_crypt", "md5_crypt"), "mysql323": ("passlib.handlers.mysql", "mysql323"), "mysql41": ("passlib.handlers.mysql", "mysql41"), @@ -116,8 +121,6 @@ _handler_locations = { "plaintext": ("passlib.handlers.misc", "plaintext"), "postgres_md5": ("passlib.handlers.postgres", "postgres_md5"), "roundup_plaintext":("passlib.handlers.roundup", "roundup_plaintext"), - "roundup_pbkdf2_sha1": - ("passlib.handlers.roundup", "roundup_pbkd2_sha1"), "sha1_crypt": ("passlib.handlers.sha1_crypt", "sha1_crypt"), "sha256_crypt": ("passlib.handlers.sha2_crypt", "sha256_crypt"), "sha512_crypt": ("passlib.handlers.sha2_crypt", "sha512_crypt"), diff --git a/passlib/tests/test_drivers.py b/passlib/tests/test_drivers.py index 907981a..60c1b88 100644 --- a/passlib/tests/test_drivers.py +++ b/passlib/tests/test_drivers.py @@ -273,6 +273,42 @@ class LdapMd5CryptTest(HandlerCase): BuiltinLdapMd5CryptTest = create_backend_case(LdapMd5CryptTest, "builtin") #========================================================= +#ldap_pbkdf2_{digest} +#========================================================= +from passlib.handlers import pbkdf2 as pk2 + +#NOTE: since these are all wrappers for the pbkdf2_{digest} hasehs, +# they don't extensive separate testing. + +class LdapPbkdf2Test(TestCase): + + def test_wrappers(self): + "test ldap pbkdf2 wrappers" + + self.assertTrue( + pk2.ldap_pbkdf2_sha1.verify( + "password", + '{PBKDF2}1212$OB.dtnSEXZK8U5cgxU/GYQ$y5LKPOplRmok7CZp/aqVDVg8zGI', + ) + ) + + self.assertTrue( + pk2.ldap_pbkdf2_sha256.verify( + "password", + '{PBKDF2-SHA256}1212$4vjV83LKPjQzk31VI4E0Vw$hsYF68OiOUPdDZ1Fg' + '.fJPeq1h/gXXY7acBp9/6c.tmQ' + ) + ) + + self.assertTrue( + pk2.ldap_pbkdf2_sha512.verify( + "password", + '{PBKDF2-SHA512}1212$RHY0Fr3IDMSVO/RSZyb5ow$eNLfBK.eVozomMr.1gYa1' + '7k9B7KIK25NOEshvhrSX.esqY3s.FvWZViXz4KoLlQI.BzY/YTNJOiKc5gBYFYGww' + ) + ) + +#========================================================= #md5 crypt #========================================================= from passlib.handlers.md5_crypt import md5_crypt, raw_md5_crypt @@ -458,9 +494,9 @@ class AtlassianPbkdf2Sha1Test(HandlerCase): class Pbkdf2Sha1Test(HandlerCase): handler = pk2.pbkdf2_sha1 known_correct_hashes = ( - ("password", '$pbkdf2-sha1$1212$OB.dtnSEXZK8U5cgxU/GYQ$y5LKPOplRmok7CZp/aqVDVg8zGI'), + ("password", '$pbkdf2$1212$OB.dtnSEXZK8U5cgxU/GYQ$y5LKPOplRmok7CZp/aqVDVg8zGI'), (u'\u0399\u03c9\u03b1\u03bd\u03bd\u03b7\u03c2', - '$pbkdf2-sha1$1212$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc'), + '$pbkdf2$1212$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc'), ) class Pbkdf2Sha256Test(HandlerCase): |
