diff options
| -rw-r--r-- | docs/install.rst | 18 | ||||
| -rw-r--r-- | docs/lib/passlib.hash.hex_digests.rst | 9 | ||||
| -rw-r--r-- | passlib/context.py | 24 | ||||
| -rw-r--r-- | passlib/registry.py | 2 | ||||
| -rw-r--r-- | passlib/utils/pbkdf2.py | 38 |
5 files changed, 52 insertions, 39 deletions
diff --git a/docs/install.rst b/docs/install.rst index fe2c048..28a9172 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -6,7 +6,7 @@ Supported Platforms =================== Passlib requires Python 2 (>= 2.5) or Python 3. It should work with the following Python implementations: - + * CPython 2 -- 2.5 or newer. * CPython 3 -- all versions. * PyPy -- 1.5 or newer. @@ -14,12 +14,12 @@ It should work with the following Python implementations: Passlib should work with all operating systems, as it contains builtin fallbacks -for almost all OS-dependant features. +for almost all OS-dependant features. Optional Libraries ================== * `py-bcrypt <http://www.mindrot.org/projects/py-bcrypt/>`_ or - `bcryptor <https://bitbucket.org/ares/bcryptor/overview>`_ + `bcryptor <https://bitbucket.org/ares/bcryptor/overview>`_ If either of these packages are installed, they will be used to provide support for the BCrypt hash algorithm. @@ -32,7 +32,7 @@ Optional Libraries If installed, M2Crypto will be used to accelerate some internal functions used by PBKDF2-based hashes, but it is not required even in that case. - + Installation Instructions ========================= To download and install using :command:`easy_install`:: @@ -42,16 +42,16 @@ To download and install using :command:`easy_install`:: To download and install using :command:`pip`:: pip install passlib - + To install from a source directory using :command:`setup.py`:: - python setup.py install + python setup.py install .. note:: - + Passlib's source ships as Python 2 code, and the setup script invokes the :command:`2to3` tool + a preprocessor - to translate the source to Python 3 code at install time. + to translate the source to Python 3 code at install time. Aside from this internal detail, installation under Python 3 should be identical to that of Python 2. @@ -76,6 +76,8 @@ Once PassLib and Nose have been installed, the tests may be run from the source PASSLIB_TESTS="all" nosetests -v passlib/tests --with-coverage \ --cover-package=passlib --cover-html --cover-html-dir build/coverage +(There will be a large proportion of skipped tests, this is normal). + Documentation ============= The latest copy of this documentation should always be available diff --git a/docs/lib/passlib.hash.hex_digests.rst b/docs/lib/passlib.hash.hex_digests.rst index 9bc3653..8b3100f 100644 --- a/docs/lib/passlib.hash.hex_digests.rst +++ b/docs/lib/passlib.hash.hex_digests.rst @@ -11,6 +11,15 @@ and should not be used in new applications. However, for the sake of backwards compatibility when converting existing applications, PassLib provides wrappers for few of the common hashes. +.. warning:: + + To reiterate the above: + Using a single round of any cryptographic hash + (especially without a salt) is so insecure + that it's barely better than plaintext. + Do not use these schemes in new applications. + + Usage ===== These classes all wrap the underlying hashlib implementations, diff --git a/passlib/context.py b/passlib/context.py index 77ea10c..5426042 100644 --- a/passlib/context.py +++ b/passlib/context.py @@ -59,7 +59,7 @@ def _parse_policy_key(key): def _parse_policy_value(cat, name, opt, value): "helper to parse policy values" - #FIXME: kinda primitive :| + #FIXME: kinda primitive to parse things this way :| if name == "context": if opt == "schemes" or opt == "deprecated": if isinstance(value, str): @@ -78,10 +78,10 @@ def parse_policy_items(source): "helper to parse CryptPolicy options" # py2k # if hasattr(source, "iteritems"): - source = source.iteritems() + source = source.iteritems() # py3k # #if hasattr(source, "items"): - # source = source.items() + # source = source.items() # end py3k # for key, value in source: cat, name, opt = _parse_policy_key(key) @@ -180,7 +180,7 @@ class CryptPolicy(object): """ #NOTE: we want config parser object to have native strings as keys. # so we parse as bytes under py2, and unicode under py3. - # + # # encoding issues are handled under py2 via to_bytes(), # which ensures everything is utf-8 internally. @@ -194,12 +194,12 @@ class CryptPolicy(object): with open(path, "rb") as stream: source = stream.read() source = source.decode(encoding).encode("utf-8") - return cls._from_stream(StringIO(source), section, path) + return cls._from_stream(StringIO(source), section, path) # Py3k # #with open(path, "r", encoding=encoding) as stream: # return cls._from_stream(stream, section, path) # end Py3k # - + @classmethod def from_string(cls, source, section="passlib", encoding="utf-8"): """create new policy from specified section of an ini-formatted string. @@ -214,7 +214,7 @@ class CryptPolicy(object): # so we parse as bytes under py2, and unicode under py3. # to handle encoding issues under py2, we use # "to_bytes()" to transcode to utf-8 as needed. - + # Py2k # source = to_bytes(source, "utf-8", source_encoding=encoding, errname="source") # Py3k # @@ -240,20 +240,20 @@ class CryptPolicy(object): raise #support for deprecated 1.4 behavior, will be removed in 1.6 if filename: - warn("from_path(): the file %r contains an unescaped '%%', this will be fatal in passlib 1.6" % (path,), stacklevel=3) + warn("from_path(): the file %r contains an unescaped '%%', this will be fatal in passlib 1.6" % (path,), stacklevel=3) else: warn("from_string(): the provided string contains an unescaped '%', this will be fatal in passlib 1.6", stacklevel=3) p = ConfigParser() stream.seek(pos) p.readfp(stream) items = p.items(section) - + # py3k # #items = p.items(section) # end py3k # - + return cls(**dict(items)) - + @classmethod def from_source(cls, source): """create new policy from input. @@ -674,7 +674,7 @@ class CryptPolicy(object): self._write_to_parser(p, section) p.write(stream) - def to_string(self, section="passlib", encoding=None): + def to_string(self, section="passlib", encoding=None): "render to INI string; inverse of from_string() constructor" buf = StringIO() self.to_file(buf, section) diff --git a/passlib/registry.py b/passlib/registry.py index 06b9657..f319840 100644 --- a/passlib/registry.py +++ b/passlib/registry.py @@ -159,7 +159,7 @@ def register_crypt_handler_path(name, path): called :samp:`{name}`, or the path may contain a colon, specifying the module and module attribute to use. for example, the following would cause ``get_handler("myhash")`` to look - for a class named ``myhash`` within the ``myapp.helpers`` module:: + for a class named ``myhash`` within the ``myapp.helpers`` module:: >>> from passlib.registry import registry_crypt_handler_path >>> registry_crypt_handler_path("myhash", "myapp.helpers") diff --git a/passlib/utils/pbkdf2.py b/passlib/utils/pbkdf2.py index aa5ea5b..29477c1 100644 --- a/passlib/utils/pbkdf2.py +++ b/passlib/utils/pbkdf2.py @@ -95,33 +95,33 @@ def _clear_prf_cache(): def get_prf(name): """lookup pseudo-random family (prf) by name. - + :arg name: this must be the name of a recognized prf. currently this only recognizes names with the format :samp:`hmac-{digest}`, where :samp:`{digest}` is the name of a hash function such as ``md5``, ``sha256``, etc. - + this can also be a callable with the signature ``prf(secret, message) -> digest``, in which case it will be returned unchanged. - + :raises ValueError: if the name is not known :raises TypeError: if the name is not a callable or string - + :returns: a tuple of :samp:`({func}, {digest_size})`. - + * :samp:`{func}` is a function implementing the specified prf, and has the signature ``func(secret, message) -> digest``. - + * :samp:`{digest_size}` is an integer indicating the number of bytes the function returns. - + usage example:: - + >>> from passlib.utils.pbkdf2 import get_prf >>> hmac_sha256, dsize = get_prf("hmac-sha256") >>> hmac_sha256 @@ -131,7 +131,7 @@ def get_prf(name): >>> digest = hmac_sha256('password', 'message') this function will attempt to return the fastest implementation - it can find; if M2Crypto is present, and supports the specified prf, + it can find; if M2Crypto is present, and supports the specified prf, :func:`M2Crypto.EVP.hmac` will be used behind the scenes. """ global _prf_cache @@ -167,14 +167,16 @@ def pbkdf1(secret, salt, rounds, keylen, hash="sha1"): * a callable with the prototype ``hash(message) -> raw digest`` * a string matching one of the hashes recognized by hashlib - + :returns: raw bytes of generated key - - This algorithm is deprecated, new code should use PBKDF2. - Among other reasons, ``keylen`` cannot be larger - than the digest size of the specified hash. - + + .. note:: + + This algorithm is deprecated, new code should use PBKDF2. + Among other reasons, ``keylen`` cannot be larger + than the digest size of the specified hash. + """ #prepare secret & salt if not isinstance(secret, bytes): @@ -213,7 +215,7 @@ def pbkdf1(secret, salt, rounds, keylen, hash="sha1"): block = hf(block).digest() r += 1 return block[:keylen] - + #================================================================================= #pbkdf2 #================================================================================= @@ -232,7 +234,7 @@ def pbkdf2(secret, salt, rounds, keylen, prf="hmac-sha1"): this can be any string or callable accepted by :func:`get_prf`. this defaults to ``hmac-sha1`` (the only prf explicitly listed in the PBKDF2 specification) - + :returns: raw bytes of generated key """ @@ -253,7 +255,7 @@ def pbkdf2(secret, salt, rounds, keylen, prf="hmac-sha1"): #NOTE: doing check here, because M2crypto won't take longs (which this is, under 32bit) if keylen > MAX_HMAC_SHA1_KEYLEN: raise ValueError("key length too long") - + #NOTE: M2crypto reliably segfaults for me if given keylengths # larger than 40 (crashes at 41 on one system, 61 on another). # so just avoiding it for longer calls. |
