summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2011-04-29 16:18:38 -0400
committerEli Collins <elic@assurancetechnologies.com>2011-04-29 16:18:38 -0400
commit0a911f70599de598d65147dc9b19ead51ff9ab38 (patch)
tree5b846674cece38dea221271607c31f718fb8a7a6
parentc8d8eb0d9b1c753d342307b070fb1ad09cc351a6 (diff)
downloadpasslib-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.rst38
-rw-r--r--docs/lib/passlib.hash.pbkdf2_digest.rst17
-rw-r--r--docs/lib/passlib.hash.rst1
-rw-r--r--passlib/default.cfg10
-rw-r--r--passlib/handlers/pbkdf2.py13
-rw-r--r--passlib/handlers/roundup.py5
-rw-r--r--passlib/registry.py7
-rw-r--r--passlib/tests/test_drivers.py40
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):