diff options
| -rw-r--r-- | docs/contents.rst | 2 | ||||
| -rw-r--r-- | docs/copyright.rst | 6 | ||||
| -rw-r--r-- | docs/index.rst | 2 | ||||
| -rw-r--r-- | docs/install.rst | 2 | ||||
| -rw-r--r-- | docs/lib/passlib.hash.rst | 24 | ||||
| -rw-r--r-- | docs/lib/passlib.hash/algorithms.rst | 4 | ||||
| -rw-r--r-- | docs/lib/passlib.hash/contexts.rst | 4 | ||||
| -rw-r--r-- | docs/lib/passlib.hash/implementation.rst | 4 | ||||
| -rw-r--r-- | docs/lib/passlib.hash/quickstart.rst | 4 | ||||
| -rw-r--r-- | docs/lib/passlib.hash/utils.rst | 4 | ||||
| -rw-r--r--[-rwxr-xr-x] | passlib/__init__.py | 150 | ||||
| -rw-r--r-- | passlib/_slow_bcrypt.py (renamed from passlib/hash/_slow_bcrypt.py) | 2 | ||||
| -rw-r--r-- | passlib/_slow_unix_crypt.py (renamed from passlib/hash/_slow_unix_crypt.py) | 0 | ||||
| -rw-r--r-- | passlib/base.py (renamed from passlib/hash/base.py) | 16 | ||||
| -rw-r--r-- | passlib/bcrypt.py (renamed from passlib/hash/bcrypt.py) | 7 | ||||
| -rw-r--r-- | passlib/gen.py | 2 | ||||
| -rw-r--r-- | passlib/hash/__init__.py | 150 | ||||
| -rw-r--r-- | passlib/md5_crypt.py (renamed from passlib/hash/md5_crypt.py) | 4 | ||||
| -rw-r--r-- | passlib/mysql.py (renamed from passlib/hash/mysql.py) | 8 | ||||
| -rw-r--r-- | passlib/pbkdf2.py (renamed from passlib/hash/pbkdf2.py) | 0 | ||||
| -rw-r--r-- | passlib/postgres.py (renamed from passlib/hash/postgres.py) | 4 | ||||
| -rw-r--r-- | passlib/sha_crypt.py (renamed from passlib/hash/sha_crypt.py) | 12 | ||||
| -rw-r--r-- | passlib/tests/test_base.py (renamed from passlib/tests/test_hash_base.py) | 2 | ||||
| -rw-r--r-- | passlib/tests/test_base_context.py (renamed from passlib/tests/test_crypt_context.py) | 39 | ||||
| -rwxr-xr-x | passlib/tests/test_bcrypt.py (renamed from passlib/tests/test_hash_bcrypt.py) | 6 | ||||
| -rw-r--r-- | passlib/tests/test_frontend.py (renamed from passlib/tests/test_hash_frontend.py) | 48 | ||||
| -rw-r--r-- | passlib/tests/test_md5_crypt.py (renamed from passlib/tests/test_hash_md5_crypt.py) | 5 | ||||
| -rw-r--r-- | passlib/tests/test_mysql.py (renamed from passlib/tests/test_hash_mysql.py) | 5 | ||||
| -rw-r--r-- | passlib/tests/test_pbkdf2.py (renamed from passlib/tests/test_hash_pbkdf2.py) | 6 | ||||
| -rw-r--r-- | passlib/tests/test_postgres.py (renamed from passlib/tests/test_hash_postgres.py) | 5 | ||||
| -rw-r--r-- | passlib/tests/test_sha_crypt.py (renamed from passlib/tests/test_hash_sha_crypt.py) | 7 | ||||
| -rw-r--r-- | passlib/tests/test_unix_crypt.py (renamed from passlib/tests/test_hash_unix_crypt.py) | 8 | ||||
| -rw-r--r-- | passlib/unix_crypt.py (renamed from passlib/hash/unix_crypt.py) | 4 | ||||
| -rw-r--r-- | passlib/util.py | 6 |
34 files changed, 276 insertions, 276 deletions
diff --git a/docs/contents.rst b/docs/contents.rst index 44f46b3..dd4ceb4 100644 --- a/docs/contents.rst +++ b/docs/contents.rst @@ -9,7 +9,7 @@ Table Of Contents overview lib/passlib - lib/passlib.hash + lib/passlib lib/passlib.gen lib/passlib.util diff --git a/docs/copyright.rst b/docs/copyright.rst index ee19414..fc2c6ac 100644 --- a/docs/copyright.rst +++ b/docs/copyright.rst @@ -53,7 +53,7 @@ implementation of OpenBSD's BCrypt algorithm, written by Damien Miller, and released under a BSD license. :mod:`passlib._bcrypt` is a python translation of this code, -which is used as a fallback backend for :class:`passlib.hash.BCrypt` +which is used as a fallback backend for :class:`passlib.BCrypt` when the external python library `py-bcrypt <http://www.mindrot.org/projects/py-bcrypt/>`_ is not installed. @@ -75,7 +75,7 @@ This is the license and copyright for jBCrypt:: MD5-Crypt --------- -The class :class:`passlib.hash.Md5Crypt` is a pure-python +The class :class:`passlib.Md5Crypt` is a pure-python implementation of the md5-crypt password hashing algorithm. It's derived from the FreeBSD md5-crypt implementation `<http://www.freebsd.org/cgi/cvsweb.cgi/~checkout~/src/lib/libcrypt/crypt.c?rev=1.2>`_, which was released under the following license:: @@ -93,7 +93,7 @@ Originally written by Aki Yoshida, and modified by others, it was released under a BSD-like license. :mod:`passlib._unix_crypt` is a python translation of this code, -which is used as a fallback backend for :class:`passlib.hash.UnixCrypt` +which is used as a fallback backend for :class:`passlib.UnixCrypt` for platforms where stdlib's :mod:`crypt` is not available. This is the license and copyright for UnixCrypt.java:: diff --git a/docs/index.rst b/docs/index.rst index 8e501f1..821ee65 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -14,7 +14,7 @@ A quick sample of some of the more frequently used modules: * :mod:`bps.host` -- desktop and host resources * :mod:`bps.logs` -- enhancements to Python's logging system * :mod:`bps.text` -- text parsing and formatting - * :mod:`passlib.hash` -- password hashing algorithms + * :mod:`passlib` -- password hashing algorithms ... see the :doc:`library overview <overview>` for a complete list. diff --git a/docs/install.rst b/docs/install.rst index 8204e1f..1b29858 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -19,7 +19,7 @@ The following libraries will be used if present, but they are not required: * If installed, `py-bcrypt <http://www.mindrot.org/projects/py-bcrypt/>`_ will be used instead of PassLib's slower pure-python bcrypt implementation. - (see :class:`passlib.hash.BCrypt`). + (see :class:`passlib.BCrypt`). Installing ========== diff --git a/docs/lib/passlib.hash.rst b/docs/lib/passlib.hash.rst index 0f2bfb0..621ed0d 100644 --- a/docs/lib/passlib.hash.rst +++ b/docs/lib/passlib.hash.rst @@ -1,8 +1,8 @@ ============================================= -:mod:`passlib.hash` - Password Hashing +:mod:`passlib` - Password Hashing ============================================= -.. module:: passlib.hash +.. module:: passlib :synopsis: password hashing (unix-crypt, md5-crypt, etc) Overview @@ -28,17 +28,17 @@ Sections ======== The documentation for the pwhash module is broken into the following sections: -* :doc:`Quick Start <passlib.hash/quickstart>` -- frontend funcs for quickly creating / validating hashes -* :doc:`Crypt Contexts <passlib.hash/contexts>` -- for using just the algorithms your application needs -* :doc:`Crypt Algorithms <passlib.hash/algorithms>` -- details of the algorithms BPS implements -* :doc:`Implementing a Custom Crypt Algorithm <passlib.hash/implementation>` -- Roll your own -* :doc:`Helper Functions <passlib.hash/utils>` +* :doc:`Quick Start <passlib/quickstart>` -- frontend funcs for quickly creating / validating hashes +* :doc:`Crypt Contexts <passlib/contexts>` -- for using just the algorithms your application needs +* :doc:`Crypt Algorithms <passlib/algorithms>` -- details of the algorithms BPS implements +* :doc:`Implementing a Custom Crypt Algorithm <passlib/implementation>` -- Roll your own +* :doc:`Helper Functions <passlib/utils>` .. toctree:: :hidden: - passlib.hash/quickstart - passlib.hash/contexts - passlib.hash/algorithms - passlib.hash/implementation - passlib.hash/utils + passlib/quickstart + passlib/contexts + passlib/algorithms + passlib/implementation + passlib/utils diff --git a/docs/lib/passlib.hash/algorithms.rst b/docs/lib/passlib.hash/algorithms.rst index 730743f..acb28f5 100644 --- a/docs/lib/passlib.hash/algorithms.rst +++ b/docs/lib/passlib.hash/algorithms.rst @@ -1,8 +1,8 @@ ============================================= -:mod:`passlib.hash` - Crypt Algorithms +:mod:`passlib` - Crypt Algorithms ============================================= -.. currentmodule:: passlib.hash +.. currentmodule:: passlib All of the crypt algorithms must inherit from :class:`CryptAlgorithm`, which defines a common interface all algorithms must support. diff --git a/docs/lib/passlib.hash/contexts.rst b/docs/lib/passlib.hash/contexts.rst index 3718df3..aa463f9 100644 --- a/docs/lib/passlib.hash/contexts.rst +++ b/docs/lib/passlib.hash/contexts.rst @@ -1,8 +1,8 @@ ============================================= -:mod:`passlib.hash` - Crypt Contexts +:mod:`passlib` - Crypt Contexts ============================================= -.. currentmodule:: passlib.hash +.. currentmodule:: passlib For more complex deployment scenarios than the frontend functions described in :doc:`Quick Start <quickstart>`, diff --git a/docs/lib/passlib.hash/implementation.rst b/docs/lib/passlib.hash/implementation.rst index 7f603c9..4ea6e24 100644 --- a/docs/lib/passlib.hash/implementation.rst +++ b/docs/lib/passlib.hash/implementation.rst @@ -1,8 +1,8 @@ =================================================================== -:mod:`passlib.hash` - Implementing a Custom Crypt Algorithm +:mod:`passlib` - Implementing a Custom Crypt Algorithm =================================================================== -.. currentmodule:: passlib.hash +.. currentmodule:: passlib New password algorithms can be implemented by subclassing :class:`CryptAlgorithm`, diff --git a/docs/lib/passlib.hash/quickstart.rst b/docs/lib/passlib.hash/quickstart.rst index 94bc40d..c6128f8 100644 --- a/docs/lib/passlib.hash/quickstart.rst +++ b/docs/lib/passlib.hash/quickstart.rst @@ -1,8 +1,8 @@ ======================================== -:mod:`passlib.hash` - Quick Start +:mod:`passlib` - Quick Start ======================================== -.. currentmodule:: passlib.hash +.. currentmodule:: passlib Usage Example ============= diff --git a/docs/lib/passlib.hash/utils.rst b/docs/lib/passlib.hash/utils.rst index 345e80b..4da7d54 100644 --- a/docs/lib/passlib.hash/utils.rst +++ b/docs/lib/passlib.hash/utils.rst @@ -1,8 +1,8 @@ ============================================= -:mod:`passlib.hash` - Helper Functions +:mod:`passlib` - Helper Functions ============================================= -.. currentmodule:: passlib.hash +.. currentmodule:: passlib A couple of utility functions are available, mainly useful when writing custom password hash algorithms. diff --git a/passlib/__init__.py b/passlib/__init__.py index 8e577de..2d8974f 100755..100644 --- a/passlib/__init__.py +++ b/passlib/__init__.py @@ -1,2 +1,152 @@ """passlib - suite of password hashing & generation routinges""" + __version__ = "1.1" + +from passlib.base import CryptContext +import passlib.unix_crypt +import passlib.md5_crypt +import passlib.bcrypt +import passlib.sha_crypt + +#========================================================= +#build up the standard context objects +#========================================================= + +#default context for quick use.. recognizes common algorithms, uses SHA-512 as default +default_context = CryptContext(["unix-crypt", "md5-crypt", "bcrypt", "sha256-crypt", "sha512-crypt"]) + +def identify(hash, name=True): + """Identify algorithm which generated a password hash. + + :arg hash: + The hash string to identify. + :param name: + If ``True``, this function will return a name identifying the hash algorithm (the default). + If ``False``, it will return the handler object associated with that algorithm. + + The following algorithms are currently recognized: + + =================== ================================================ + Name Description + ------------------- ------------------------------------------------ + ``"unix-crypt"`` the historical unix-crypt algorithm + + ``"md5-crypt"`` the md5-crypt algorithm, usually identified + by the prefix ``$1$`` in unix shadow files. + + ``"bcrypt"`` the openbsd blowfish-crypt algorithm, + usually identified by the prefixes ``$2$`` or ``$2a$`` + in unix shadow files. + + ``"sha256-crypt"`` the 256-bit version of the sha-crypt algorithm, + usually identified by the prefix ``$5$`` + in unix shadow files. + + ``"sha512-crypt"`` the 512-bit version of the sha-crypt algorithm, + usually identified by the prefix ``$6$`` + in unix shadow files. + =================== ================================================ + + :returns: + The name of the hash, or ``None`` if the hash could not be identified. + (The return may be altered by the *resolve* keyword). + + .. note:: + This is a convience wrapper for ``pwhash.default_context.identify(hash)``. + """ + return default_context.identify(hash, name=name) + +def encrypt(secret, hash=None, alg=None, **kwds): + """Encrypt secret using a password hash algorithm. + + :type secret: str + :arg secret: + String containing the secret to encrypt + + :type hash: str|None + :arg hash: + Optional previously existing hash string which + will be used to provide default value for the salt, rounds, + or other algorithm-specific options. + If not specified, algorithm-chosen defaults will be used. + + :type alg: str|None + :param alg: + Optionally specify the name of the algorithm to use. + If no algorithm is specified, an attempt is made + to guess from the hash string. If no hash string + is specified, sha512-crypt will be used. + See :func:`identify` for a list of algorithm names. + + All other keywords are passed on to the specific password algorithm + being used to encrypt the secret. + + :type keep_salt: bool + :param keep_salt: + This option is accepted by all of the builtin algorithms. + + By default, a new salt value generated each time + a secret is encrypted. However, if this keyword + is set to ``True``, and a previous hash string is provided, + the salt from that string will be used instead. + + .. note:: + This is generally only useful when verifying an existing hash + (see :func:`verify`). Other than that, this option should be + avoided, as re-using a salt will needlessly decrease security. + + :type rounds: int + :param rounds: + For the sha256-crypt and sha512-crypt algorithms, + this option lets you specify the number of rounds + of encryption to use. For the bcrypt algorithm, + this option lets you specify the log-base-2 of + the number of rounds of encryption to use. + + For all three of these algorithms, you can either + specify a positive integer, or one of the strings + "fast", "medium", "slow" to choose a preset number + of rounds corresponding to an appropriate level + of encryption. + + :returns: + The secret as encoded by the specified algorithm and options. + """ + return default_context.encrypt(secret, hash=hash, alg=alg, **kwds) + +def verify(secret, hash, alg=None): + """verify a secret against an existing hash. + + This checks if a secret matches against the one stored + inside the specified hash. By default this uses :func:`encrypt` + to re-crypt the secret, and compares it to the provided hash; + though some algorithms may implement this in a more efficient manner. + + :type secret: str + :arg secret: + A string containing the secret to check. + + :type hash: str + :param hash: + A string containing the hash to check against. + + :type alg: str|None + :param alg: + Optionally specify the name of the algorithm to use. + If no algorithm is specified, an attempt is made + to guess from the hash string. If it can't be + identified, a ValueError will be raised. + See :func:`identify` for a list of algorithm names. + + :returns: + ``True`` if the secret matches, otherwise ``False``. + """ + return default_context.verify(secret, hash, alg=alg) + +#some general os-context helpers (these may not match your os policy exactly, but are generally useful) +linux_context = CryptContext([ "unix-crypt", "md5-crypt", "sha256-crypt", "sha512-crypt" ]) +bsd_context = CryptContext([ "unix-crypt", "md5-crypt", "bcrypt" ]) + +#========================================================= +#eof +#========================================================= diff --git a/passlib/hash/_slow_bcrypt.py b/passlib/_slow_bcrypt.py index 2606b2e..147ae2e 100644 --- a/passlib/hash/_slow_bcrypt.py +++ b/passlib/_slow_bcrypt.py @@ -1,4 +1,4 @@ -"""passlib.hash._slow_bcrypt - fallback pure-python bcrypt implementation +"""passlib._slow_bcrypt - fallback pure-python bcrypt implementation History ========== diff --git a/passlib/hash/_slow_unix_crypt.py b/passlib/_slow_unix_crypt.py index f2d738f..f2d738f 100644 --- a/passlib/hash/_slow_unix_crypt.py +++ b/passlib/_slow_unix_crypt.py diff --git a/passlib/hash/base.py b/passlib/base.py index fca174d..46af8ad 100644 --- a/passlib/hash/base.py +++ b/passlib/base.py @@ -1,4 +1,4 @@ -"""passlib.hash - implementation of various password hashing functions""" +"""passlib - implementation of various password hashing functions""" #========================================================= #imports #========================================================= @@ -235,7 +235,7 @@ class CryptAlgorithm(object): Usage Example:: - >>> from passlib.hash.md5_crypt import Md5Crypt + >>> from passlib.md5_crypt import Md5Crypt >>> #encrypt a secret, creating a new hash >>> hash = Md5Crypt.encrypt("it's a secret") >>> hash @@ -367,7 +367,7 @@ class CryptContext(object): 'bcrypt' >>> #or just return the CryptAlgorithm instance directly >>> myctx.identify(hash1, resolve=True) - <passlib.hash.BCrypt object, name="bcrypt"> + <passlib.BCrypt object, name="bcrypt"> >>> #you can get a list of algs... >>> myctx.keys() @@ -376,7 +376,7 @@ class CryptContext(object): >>> #and get the CryptAlgorithm object by name >>> bc = myctx['bcrypt'] >>> bc - <passlib.hash.BCrypt object, name="bcrypt"> + <passlib.BCrypt object, name="bcrypt"> """ def __init__(self, handlers): @@ -384,7 +384,7 @@ class CryptContext(object): def _norm_handler(self, handler): if isinstance(handler, str): - handler = get_crypto_algorithm(handler) + handler = get_crypt_algorithm(handler) if not is_crypt_alg(handler): raise TypeError, "handler must be CryptAlgorithm class or name: %r" % (handler,) return handler @@ -412,7 +412,7 @@ class CryptContext(object): if name in handler.aliases: return handler else: - return self._args[-1] + return self._handlers[-1] if required: raise KeyError, "no crypt algorithm by that name in context: %r" % (name,) return None @@ -442,7 +442,7 @@ class CryptContext(object): # also so if handler 0 is a legacy "plaintext" handler or some such, # it doesn't match *everything* that's passed into this function. for handler in reversed(self._handlers): - if handlers.identify(hash): + if handler.identify(hash): if name: return handler.name else: @@ -501,7 +501,7 @@ class CryptContext(object): handler = self.lookup(alg, required=True) else: handler = self.identify(hash, required=True) - return crypt.verify(secret, hash, **kwds) + return handler.verify(secret, hash, **kwds) def is_crypt_context(obj): "check if obj following CryptContext protocol" diff --git a/passlib/hash/bcrypt.py b/passlib/bcrypt.py index 6fa07ee..79604ae 100644 --- a/passlib/hash/bcrypt.py +++ b/passlib/bcrypt.py @@ -1,4 +1,4 @@ -"""passlib.hash.bcrypt""" +"""passlib.bcrypt""" #========================================================= #imports #========================================================= @@ -9,7 +9,7 @@ import logging; log = logging.getLogger(__name__) #site #libs from passlib.util import HashInfo, h64_gensalt -from passlib.hash.base import CryptAlgorithm, register_crypt_algorithm +from passlib.base import CryptAlgorithm, register_crypt_algorithm #pkg #local __all__ = [ @@ -26,7 +26,7 @@ try: backend = "pybcrypt" except ImportError: #fall back to our much slower pure-python implementation - import passlib.hash._slow_bcrypt as bcrypt + import passlib._slow_bcrypt as bcrypt backend = "builtin" #========================================================= @@ -118,7 +118,6 @@ class BCrypt(CryptAlgorithm): if not salt: salt = h64_gensalt(22) enc_salt = "$2a$%d$%s" % (rounds, salt) - print repr([secret, enc_salt]) return bcrypt.hashpw(secret, enc_salt) @classmethod diff --git a/passlib/gen.py b/passlib/gen.py index fdf0693..bbb27a1 100644 --- a/passlib/gen.py +++ b/passlib/gen.py @@ -1,4 +1,4 @@ -"""passlib.hash - password hashing tools""" +"""passlib - password hashing tools""" #========================================================= #imports #========================================================= diff --git a/passlib/hash/__init__.py b/passlib/hash/__init__.py deleted file mode 100644 index aa547cc..0000000 --- a/passlib/hash/__init__.py +++ /dev/null @@ -1,150 +0,0 @@ -from passlib.hash.base import CryptContext -import passlib.hash.unix_crypt -import passlib.hash.md5_crypt -import passlib.hash.bcrypt -import passlib.hash.sha_crypt - -#========================================================= -#build up the standard context objects -#========================================================= - -#default context for quick use.. recognizes common algorithms, uses SHA-512 as default -default_context = CryptContext(["unix-crypt", "md5-crypt", "bcrypt", "sha256-crypt", "sha512-crypt"]) - -def identify(hash, name=name): - """Identify algorithm which generated a password hash. - - :arg hash: - The hash string to identify. - :param resolve: - If ``True``, this function will return a :class:`CryptAlgorithm` - instance which can handle the hash. - If ``False`` (the default), then only the name of the hash algorithm - will be returned. - - The following algorithms are currently recognized: - - =================== ================================================ - Name Description - ------------------- ------------------------------------------------ - ``"unix-crypt"`` the historical unix-crypt algorithm - - ``"md5-crypt"`` the md5-crypt algorithm, usually identified - by the prefix ``$1$`` in unix shadow files. - - ``"bcrypt"`` the openbsd blowfish-crypt algorithm, - usually identified by the prefixes ``$2$`` or ``$2a$`` - in unix shadow files. - - ``"sha256-crypt"`` the 256-bit version of the sha-crypt algorithm, - usually identified by the prefix ``$5$`` - in unix shadow files. - - ``"sha512-crypt"`` the 512-bit version of the sha-crypt algorithm, - usually identified by the prefix ``$6$`` - in unix shadow files. - =================== ================================================ - - :returns: - The name of the hash, or ``None`` if the hash could not be identified. - (The return may be altered by the *resolve* keyword). - - .. note:: - This is a convience wrapper for ``pwhash.default_context.identify(hash)``. - """ - return default_context.identify(hash, name=name) - -def encrypt(secret, hash=None, alg=None, **kwds): - """Encrypt secret using a password hash algorithm. - - :type secret: str - :arg secret: - String containing the secret to encrypt - - :type hash: str|None - :arg hash: - Optional previously existing hash string which - will be used to provide default value for the salt, rounds, - or other algorithm-specific options. - If not specified, algorithm-chosen defaults will be used. - - :type alg: str|None - :param alg: - Optionally specify the name of the algorithm to use. - If no algorithm is specified, an attempt is made - to guess from the hash string. If no hash string - is specified, sha512-crypt will be used. - See :func:`identify` for a list of algorithm names. - - All other keywords are passed on to the specific password algorithm - being used to encrypt the secret. - - :type keep_salt: bool - :param keep_salt: - This option is accepted by all of the builtin algorithms. - - By default, a new salt value generated each time - a secret is encrypted. However, if this keyword - is set to ``True``, and a previous hash string is provided, - the salt from that string will be used instead. - - .. note:: - This is generally only useful when verifying an existing hash - (see :func:`verify`). Other than that, this option should be - avoided, as re-using a salt will needlessly decrease security. - - :type rounds: int - :param rounds: - For the sha256-crypt and sha512-crypt algorithms, - this option lets you specify the number of rounds - of encryption to use. For the bcrypt algorithm, - this option lets you specify the log-base-2 of - the number of rounds of encryption to use. - - For all three of these algorithms, you can either - specify a positive integer, or one of the strings - "fast", "medium", "slow" to choose a preset number - of rounds corresponding to an appropriate level - of encryption. - - :returns: - The secret as encoded by the specified algorithm and options. - """ - return default_context.encrypt(secret, hash=hash, alg=alg, **kwds) - -def verify(secret, hash, alg=None): - """verify a secret against an existing hash. - - This checks if a secret matches against the one stored - inside the specified hash. By default this uses :func:`encrypt` - to re-crypt the secret, and compares it to the provided hash; - though some algorithms may implement this in a more efficient manner. - - :type secret: str - :arg secret: - A string containing the secret to check. - - :type hash: str - :param hash: - A string containing the hash to check against. - - :type alg: str|None - :param alg: - Optionally specify the name of the algorithm to use. - If no algorithm is specified, an attempt is made - to guess from the hash string. If it can't be - identified, a ValueError will be raised. - See :func:`identify` for a list of algorithm names. - - :returns: - ``True`` if the secret matches, otherwise ``False``. - """ - return default_context.verify(secret, hash, alg=alg) - -#some general os-context helpers (these may not match your os policy exactly, but are generally useful) -linux_context = CryptContext([ "unix-crypt", "md5-crypt", "sha256-crypt", "sha512-crypt" ]) -bsd_context = CryptContext([ "unix-crypt", "md5-crypt", "bcrypt" ]) - -#========================================================= -#eof -#========================================================= diff --git a/passlib/hash/md5_crypt.py b/passlib/md5_crypt.py index b48f5b4..4335542 100644 --- a/passlib/hash/md5_crypt.py +++ b/passlib/md5_crypt.py @@ -1,4 +1,4 @@ -"""passlib.hash - implementation of various password hashing functions""" +"""passlib - implementation of various password hashing functions""" #========================================================= #imports #========================================================= @@ -14,7 +14,7 @@ import os #libs from passlib.util import classproperty, abstractmethod, is_seq, srandom, \ HashInfo, h64_gensalt, h64_encode_3_offsets, h64_encode_1_offset -from passlib.hash.base import CryptAlgorithm, register_crypt_algorithm +from passlib.base import CryptAlgorithm, register_crypt_algorithm #pkg #local __all__ = [ diff --git a/passlib/hash/mysql.py b/passlib/mysql.py index aeef333..a00e454 100644 --- a/passlib/hash/mysql.py +++ b/passlib/mysql.py @@ -1,4 +1,4 @@ -"""passlib.hash - implementation of various password hashing functions""" +"""passlib - implementation of various password hashing functions""" #========================================================= #imports #========================================================= @@ -13,7 +13,7 @@ import os #site #libs from passlib.util import classproperty, abstractmethod, is_seq, srandom -from passlib.hash.base import CryptAlgorithm, CryptContext, register_crypt_algorithm +from passlib.base import CryptAlgorithm, CryptContext, register_crypt_algorithm #pkg #local __all__ = [ @@ -36,7 +36,7 @@ class Mysql10Crypt(CryptAlgorithm): and should only be used to verify existing password hashes. """ - name = "mysql-1.0-crypt" + name = "mysql-10-crypt" hash_bytes = 32 _pat = re.compile(r"^[0-9a-f]{16}$", re.I) @@ -78,7 +78,7 @@ class Mysql41Crypt(CryptAlgorithm): Description taken from http://dev.mysql.com/doc/refman/6.0/en/password-hashing.html """ - name = "mysql-4.1-crypt" + name = "mysql-41-crypt" hash_bytes = 80 _pat = re.compile(r"^\*[0-9A-F]{40}$", re.I) diff --git a/passlib/hash/pbkdf2.py b/passlib/pbkdf2.py index 016023b..016023b 100644 --- a/passlib/hash/pbkdf2.py +++ b/passlib/pbkdf2.py diff --git a/passlib/hash/postgres.py b/passlib/postgres.py index 3054b99..e526e75 100644 --- a/passlib/hash/postgres.py +++ b/passlib/postgres.py @@ -1,4 +1,4 @@ -"""passlib.hash - implementation of various password hashing functions""" +"""passlib - implementation of various password hashing functions""" #========================================================= #imports #========================================================= @@ -13,7 +13,7 @@ import os #site #libs from passlib.util import classproperty, abstractmethod, is_seq, srandom -from passlib.hash.base import CryptAlgorithm, CryptContext, register_crypt_algorithm +from passlib.base import CryptAlgorithm, CryptContext, register_crypt_algorithm #pkg #local __all__ = [ diff --git a/passlib/hash/sha_crypt.py b/passlib/sha_crypt.py index 5c17e30..4263683 100644 --- a/passlib/hash/sha_crypt.py +++ b/passlib/sha_crypt.py @@ -1,4 +1,4 @@ -"""passlib.hash.sha_crypt - implements SHA-256-Crypt & SHA-512-Crypt +"""passlib.sha_crypt - implements SHA-256-Crypt & SHA-512-Crypt Implementation written based on specification at `<http://www.akkadia.org/drepper/SHA-crypt.txt>`_. It should be byte-compatible with unix shadow hashes beginning with ``$5$`` and ``$6%``. @@ -21,9 +21,9 @@ import time import os #site #libs -from passlib.hash.base import CryptAlgorithm, register_crypt_algorithm +from passlib.base import CryptAlgorithm, register_crypt_algorithm from passlib.util import classproperty, abstractmethod, is_seq, srandom, \ - HashInfo, h64_gensalt, h64_encode_3_offsets, h64_encode_2_offsets + HashInfo, h64_gensalt, h64_encode_3_offsets, h64_encode_2_offsets, h64_encode_1_offset #pkg #local __all__ = [ @@ -241,7 +241,7 @@ class Sha256Crypt(_ShaCrypt): #========================================================= #algorithm info #========================================================= - name='sha-256-crypt' + name='sha256-crypt' hash_bytes = 32 #========================================================= @@ -297,7 +297,7 @@ class Sha512Crypt(_ShaCrypt): Usage Example:: - >>> from passlib.hash import Sha512Crypt + >>> from passlib import Sha512Crypt >>> crypt = Sha512Crypt() >>> #to encrypt a new secret with this algorithm >>> hash = crypt.encrypt("forget me not") @@ -314,7 +314,7 @@ class Sha512Crypt(_ShaCrypt): #========================================================= #algorithm info #========================================================= - name='sha-512-crypt' + name='sha512-crypt' hash_bytes = 64 #========================================================= diff --git a/passlib/tests/test_hash_base.py b/passlib/tests/test_base.py index aa50898..70e50ea 100644 --- a/passlib/tests/test_hash_base.py +++ b/passlib/tests/test_base.py @@ -9,7 +9,7 @@ import warnings from logging import getLogger #site #pkg -from passlib.hash.base import CryptAlgorithm +from passlib.base import CryptAlgorithm from passlib.tests.utils import TestCase, enable_suite from passlib.util import h64_gensalt #module diff --git a/passlib/tests/test_crypt_context.py b/passlib/tests/test_base_context.py index 174b4ea..7526efd 100644 --- a/passlib/tests/test_crypt_context.py +++ b/passlib/tests/test_base_context.py @@ -9,21 +9,18 @@ import warnings from logging import getLogger #site #pkg -from passlib import hash as pwhash +from passlib.base import CryptContext from passlib.tests.utils import TestCase, enable_suite -from passlib.hash.unix_crypt import UnixCrypt -from passlib.hash.sha_crypt import Sha512Crypt -from passlib.hash.md5_crypt import Md5Crypt -from passlib.tests.test_hash_base import UnsaltedAlg, SaltedAlg, SampleAlg +from passlib.unix_crypt import UnixCrypt +from passlib.sha_crypt import Sha512Crypt +from passlib.md5_crypt import Md5Crypt +from passlib.tests.test_base import UnsaltedAlg, SaltedAlg, SampleAlg #module log = getLogger(__name__) #========================================================= #CryptContext #========================================================= - -CryptContext = pwhash.CryptContext - class CryptContextTest(TestCase): "test CryptContext object's behavior" @@ -36,10 +33,10 @@ class CryptContextTest(TestCase): cc = CryptContext([UnsaltedAlg, SaltedAlg, SampleAlg]) #parse - a, b, c = cc - self.assertIsInstance(a, UnsaltedAlg) - self.assertIsInstance(b, SaltedAlg) - self.assertIsInstance(c, SampleAlg) + a, b, c = cc._handlers + self.assertIs(a, UnsaltedAlg) + self.assertIs(b, SaltedAlg) + self.assertIs(c, SampleAlg) def test_01_constructor(self): "test CryptContext constructor using instances" @@ -50,7 +47,7 @@ class CryptContextTest(TestCase): cc = CryptContext([a,b,c]) #verify elements - self.assertEquals(list(cc), [a, b, c]) + self.assertEquals(list(cc._handlers), [a, b, c]) #TODO: test constructor using names @@ -356,23 +353,23 @@ class CryptContextTest(TestCase): def test_50_lookup(self): "test CryptContext.lookup()" cc = CryptContext([UnsaltedAlg, SaltedAlg, SampleAlg]) - a, b, c = cc + a, b, c = cc._handlers self.assertEquals(cc.lookup('unsalted'), a) self.assertEquals(cc.lookup('salted'), b) self.assertEquals(cc.lookup('sample'), c) self.assertEquals(cc.lookup('md5-crypt'), None) - self.assertEquals(cc.lookup(['unsalted']), a) - self.assertEquals(cc.lookup(['md5-crypt']), None) - self.assertEquals(cc.lookup(['unsalted', 'salted', 'md5-crypt']), b) + ##self.assertEquals(cc.lookup(['unsalted']), a) + ##self.assertEquals(cc.lookup(['md5-crypt']), None) + ##self.assertEquals(cc.lookup(['unsalted', 'salted', 'md5-crypt']), b) #TODO: lookup required=True def test_51_identify(self): "test CryptContext.identify" cc = CryptContext([UnsaltedAlg, SaltedAlg, SampleAlg]) - a, b, c = cc + a, b, c = cc._handlers for crypt in (a, b, c): h = crypt.encrypt("test") @@ -388,7 +385,7 @@ class CryptContextTest(TestCase): def test_52_encrypt_and_verify(self): "test CryptContext.encrypt & verify" cc = CryptContext([UnsaltedAlg, SaltedAlg, SampleAlg]) - a, b, c = cc + a, b, c = cc._handlers #check encrypt/id/verify pass for all algs for crypt in (a, b, c): @@ -408,7 +405,7 @@ class CryptContextTest(TestCase): def test_53_encrypt_salting(self): "test CryptContext.encrypt salting options" cc = CryptContext([UnsaltedAlg, SaltedAlg, SampleAlg]) - a, b, c = cc + a, b, c = cc._handlers self.assert_(c.has_salt) h = cc.encrypt("test") @@ -426,7 +423,7 @@ class CryptContextTest(TestCase): "test CryptContext.verify allows hash=None" cc = CryptContext([UnsaltedAlg, SaltedAlg, SampleAlg]) self.assertEquals(cc.verify('xxx', None), False) - for crypt in cc: + for crypt in cc._handlers: self.assertEquals(cc.verify('xxx', None, alg=crypt.name), False) #XXX: haven't decided if this should be part of protocol diff --git a/passlib/tests/test_hash_bcrypt.py b/passlib/tests/test_bcrypt.py index 5862fb7..8f62846 100755 --- a/passlib/tests/test_hash_bcrypt.py +++ b/passlib/tests/test_bcrypt.py @@ -26,9 +26,9 @@ except ImportError: pybcrypt = None #pkg from passlib.tests.utils import TestCase, enable_suite -from passlib.hash import _slow_bcrypt as slow_bcrypt -from passlib.tests.test_hash_base import _CryptTestCase as CryptTestCase -import passlib.hash.bcrypt as mod +from passlib import _slow_bcrypt as slow_bcrypt +from passlib.tests.test_base import _CryptTestCase as CryptTestCase +import passlib.bcrypt as mod #========================================================= #test slow_bcrypt backend diff --git a/passlib/tests/test_hash_frontend.py b/passlib/tests/test_frontend.py index 3887c7b..60e6095 100644 --- a/passlib/tests/test_hash_frontend.py +++ b/passlib/tests/test_frontend.py @@ -9,7 +9,7 @@ import warnings from logging import getLogger #site #pkg -from passlib import hash as pwhash +import passlib as mod from passlib.tests.utils import TestCase #module log = getLogger(__name__) @@ -17,12 +17,21 @@ log = getLogger(__name__) #========================================================= #pull crypt tests #========================================================= -#this test suite uses info stored in the specific hash algs' test suites, -#so we have to import them here. -from passlib.tests.test_hash_sha_crypt import Sha256CryptTest, Sha512CryptTest -from passlib.tests.test_hash_unix_crypt import UnixCryptTest -from passlib.tests.test_hash_bcrypt import BCryptTest -from passlib.tests.test_hash_md5_crypt import Md5CryptTest +def get_crypt_cases(): + + #this test suite uses info stored in the specific hash algs' test suites, + #so we have to import them here. + from passlib.tests.test_sha_crypt import Sha256CryptTest, Sha512CryptTest + from passlib.tests.test_unix_crypt import UnixCryptTest + from passlib.tests.test_bcrypt import BCryptTest + from passlib.tests.test_md5_crypt import Md5CryptTest + + crypt_cases = [ UnixCryptTest, Md5CryptTest, Sha256CryptTest] + if BCryptTest: + crypt_cases.append(BCryptTest) + crypt_cases.extend([ Sha512CryptTest ]) + + return crypt_cases #========================================================= #quick access functions @@ -30,14 +39,11 @@ from passlib.tests.test_hash_md5_crypt import Md5CryptTest class QuickAccessTest(TestCase): "test quick access functions" - crypt_cases = [ UnixCryptTest, Md5CryptTest, Sha256CryptTest] - if BCryptTest: - crypt_cases.append(BCryptTest) - crypt_cases.extend([ Sha512CryptTest ]) + crypt_cases = get_crypt_cases() def test_00_identify(self): "test pwhash.identify()" - identify = pwhash.identify + identify = mod.identify for cc in self.crypt_cases: name = cc.alg.name for _, hash in cc.positive_knowns: @@ -51,7 +57,7 @@ class QuickAccessTest(TestCase): def test_01_verify(self): "test pwhash.verify()" - verify = pwhash.verify + verify = mod.verify for cc in self.crypt_cases: name = cc.alg.name for secret, hash in cc.positive_knowns[:3]: @@ -66,9 +72,9 @@ class QuickAccessTest(TestCase): def test_02_encrypt(self): "test pwhash.encrypt()" - identify = pwhash.identify - verify = pwhash.verify - encrypt = pwhash.encrypt + identify = mod.identify + verify = mod.verify + encrypt = mod.encrypt for cc in self.crypt_cases: alg = cc.alg.name s = 'test' @@ -81,14 +87,14 @@ class QuickAccessTest(TestCase): def test_04_default_context(self): "test pwhash.default_context contents" - dc = pwhash.default_context + dc = mod.default_context for case in self.crypt_cases: - self.assert_(case.alg.name in dc) + self.assert_(dc.lookup(case.alg.name) is case.alg) - last = 'sha-512-crypt' - self.assertEqual(dc.keys()[-1], last) + last = 'sha512-crypt' + self.assertEqual(dc.lookup().name, last) h = dc.encrypt("test") - self.assertEqual(dc.identify(h), last) + self.assertEqual(dc.identify(h).name, last) self.assertEqual(dc.verify('test', h, alg=last), True) #========================================================= diff --git a/passlib/tests/test_hash_md5_crypt.py b/passlib/tests/test_md5_crypt.py index 01a6c85..3197f7e 100644 --- a/passlib/tests/test_hash_md5_crypt.py +++ b/passlib/tests/test_md5_crypt.py @@ -9,10 +9,9 @@ import warnings from logging import getLogger #site #pkg -from passlib import hash as pwhash from passlib.tests.utils import TestCase, enable_suite -from passlib.tests.test_hash_base import _CryptTestCase as CryptTestCase -import passlib.hash.md5_crypt as mod +from passlib.tests.test_base import _CryptTestCase as CryptTestCase +import passlib.md5_crypt as mod #module log = getLogger(__name__) diff --git a/passlib/tests/test_hash_mysql.py b/passlib/tests/test_mysql.py index c3ce9ef..2842b36 100644 --- a/passlib/tests/test_hash_mysql.py +++ b/passlib/tests/test_mysql.py @@ -9,10 +9,9 @@ import warnings from logging import getLogger #site #pkg -from passlib import hash as pwhash from passlib.tests.utils import TestCase, enable_suite -from passlib.tests.test_hash_base import _CryptTestCase as CryptTestCase -import passlib.hash.mysql as mod +from passlib.tests.test_base import _CryptTestCase as CryptTestCase +import passlib.mysql as mod #module log = getLogger(__name__) diff --git a/passlib/tests/test_hash_pbkdf2.py b/passlib/tests/test_pbkdf2.py index e1807d4..92f2f7c 100644 --- a/passlib/tests/test_hash_pbkdf2.py +++ b/passlib/tests/test_pbkdf2.py @@ -1,4 +1,4 @@ -"""tests for passlib.hash.pbkdf2""" +"""tests for passlib.pbkdf2""" #========================================================= #imports #========================================================= @@ -11,8 +11,8 @@ from logging import getLogger #site #pkg from passlib.tests.utils import TestCase, enable_suite -import passlib.hash.pbkdf2 as mod -from passlib.tests.test_hash_base import _CryptTestCase as CryptTestCase +import passlib.pbkdf2 as mod +from passlib.tests.test_base import _CryptTestCase as CryptTestCase #module log = getLogger(__name__) diff --git a/passlib/tests/test_hash_postgres.py b/passlib/tests/test_postgres.py index d3290c9..dab23a5 100644 --- a/passlib/tests/test_hash_postgres.py +++ b/passlib/tests/test_postgres.py @@ -9,10 +9,9 @@ import warnings from logging import getLogger #site #pkg -from passlib import hash as pwhash from passlib.tests.utils import TestCase, enable_suite -from passlib.tests.test_hash_base import _CryptTestCase as CryptTestCase -import passlib.hash.postgres as mod +from passlib.tests.test_base import _CryptTestCase as CryptTestCase +import passlib.postgres as mod #module log = getLogger(__name__) diff --git a/passlib/tests/test_hash_sha_crypt.py b/passlib/tests/test_sha_crypt.py index 8a0eb54..68cc635 100644 --- a/passlib/tests/test_hash_sha_crypt.py +++ b/passlib/tests/test_sha_crypt.py @@ -9,10 +9,9 @@ import warnings from logging import getLogger #site #pkg -from passlib import hash as pwhash from passlib.tests.utils import TestCase, enable_suite -from passlib.tests.test_hash_base import _CryptTestCase as CryptTestCase -import passlib.hash.sha_crypt as mod +from passlib.tests.test_base import _CryptTestCase as CryptTestCase +import passlib.sha_crypt as mod #module log = getLogger(__name__) @@ -58,6 +57,8 @@ class Sha512BackendTest(TestCase): "hLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX." ), ] def test512(self): + "verify sha512 passes specification test vectors" + crypt = mod.Sha512Crypt for hash, secret, result in self.cases512: diff --git a/passlib/tests/test_hash_unix_crypt.py b/passlib/tests/test_unix_crypt.py index 868aa1f..5ffab35 100644 --- a/passlib/tests/test_hash_unix_crypt.py +++ b/passlib/tests/test_unix_crypt.py @@ -10,9 +10,9 @@ from logging import getLogger #site #pkg from passlib.tests.utils import TestCase, enable_suite -from passlib.hash._slow_unix_crypt import crypt as builtin_crypt -import passlib.hash.unix_crypt as mod -from passlib.tests.test_hash_base import _CryptTestCase as CryptTestCase +from passlib._slow_unix_crypt import crypt as builtin_crypt +import passlib.unix_crypt as mod +from passlib.tests.test_base import _CryptTestCase as CryptTestCase #module log = getLogger(__name__) @@ -95,7 +95,7 @@ class UnixCryptBackendTest(TestCase): self.assertRaises(ValueError, crypt, "fooey","") #NOTE: stdlib crypt's behavior is rather bizarre in this case - # (see wrapper in passlib.hash.unix_crypt). + # (see wrapper in passlib.unix_crypt). # passlib wraps stdlib crypt so it raises ValueError self.assertRaises(ValueError, crypt, "fooey","f") diff --git a/passlib/hash/unix_crypt.py b/passlib/unix_crypt.py index 062d766..c2d8c51 100644 --- a/passlib/hash/unix_crypt.py +++ b/passlib/unix_crypt.py @@ -1,4 +1,4 @@ -"""passlib.hash - implementation of various password hashing functions""" +"""passlib - implementation of various password hashing functions""" #========================================================= #imports #========================================================= @@ -12,7 +12,7 @@ import time import os #site #pkg -from passlib.hash.base import CryptAlgorithm, register_crypt_algorithm +from passlib.base import CryptAlgorithm, register_crypt_algorithm from passlib.util import classproperty, abstractmethod, is_seq, srandom, h64_gensalt, h64_validate #local __all__ = [ diff --git a/passlib/util.py b/passlib/util.py index ee0ebf0..469bef3 100644 --- a/passlib/util.py +++ b/passlib/util.py @@ -231,7 +231,7 @@ def h64_validate(value): "helper to validate salt strings" return all(c in H64_CHARS for c in value) -def h64_encode_3_offsets(cls, buffer, o1, o2, o3): +def h64_encode_3_offsets(buffer, o1, o2, o3): "do hash64 encode of three bytes at specified offsets in buffer; returns 4 chars" #how 4 char output corresponds to 3 byte input: # @@ -252,7 +252,7 @@ def h64_encode_3_offsets(cls, buffer, o1, o2, o3): H64_CHARS[((v3&0x03)<<4) + (v2>>4)] + \ H64_CHARS[v3>>2] -def h64_encode_2_offsets(cls, buffer, o1, o2): +def h64_encode_2_offsets(buffer, o1, o2): "do hash64 encode of two bytes at specified offsets in buffer; 2 missing msg set null; returns 3 chars" v1 = ord(buffer[o1]) v2 = ord(buffer[o2]) @@ -260,7 +260,7 @@ def h64_encode_2_offsets(cls, buffer, o1, o2): H64_CHARS[((v2&0x0F)<<2) + (v1>>6)] + \ H64_CHARS[(v2>>4)] -def h64_encode_1_offset(cls, buffer, o1): +def h64_encode_1_offset(buffer, o1): "do hash64 encode of single byte at specified offset in buffer; 4 missing msb set null; returns 2 chars" v1 = ord(buffer[o1]) return H64_CHARS[v1&0x3F] + H64_CHARS[v1>>6] |
