summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2012-05-01 12:42:43 -0400
committerEli Collins <elic@assurancetechnologies.com>2012-05-01 12:42:43 -0400
commit7d4769b401b4fea8e21062e6e85503f20989aabd (patch)
tree23efda80cf128f79e475bc38054ce3c45ae219a8
parent3fa87b2933ba2f596297297f97b8fc3e335ba581 (diff)
downloadpasslib-7d4769b401b4fea8e21062e6e85503f20989aabd.tar.gz
loads of documentation updates
-rw-r--r--.hgignore1
-rw-r--r--CHANGES74
-rw-r--r--docs/conf.py2
-rw-r--r--docs/index.rst15
-rw-r--r--docs/install.rst26
-rw-r--r--docs/lib/passlib.context-tutorial.rst40
-rw-r--r--docs/lib/passlib.hash.bcrypt.rst2
-rw-r--r--docs/lib/passlib.hash.bsdi_crypt.rst2
-rw-r--r--docs/lib/passlib.hash.cisco_pix.rst2
-rw-r--r--docs/lib/passlib.hash.cisco_type7.rst35
-rw-r--r--docs/lib/passlib.hash.des_crypt.rst2
-rw-r--r--docs/lib/passlib.hash.django_std.rst4
-rw-r--r--docs/lib/passlib.hash.fshp.rst2
-rw-r--r--docs/lib/passlib.hash.hex_digests.rst2
-rw-r--r--docs/lib/passlib.hash.lmhash.rst2
-rw-r--r--docs/lib/passlib.hash.nthash.rst2
-rw-r--r--docs/lib/passlib.hash.oracle10.rst2
-rw-r--r--docs/lib/passlib.hash.oracle11.rst2
-rw-r--r--docs/lib/passlib.hash.postgres_md5.rst2
-rw-r--r--docs/lib/passlib.hash.scram.rst4
-rw-r--r--docs/lib/passlib.utils.rst47
-rw-r--r--docs/modular_crypt_format.rst24
-rw-r--r--passlib/apache.py66
-rw-r--r--passlib/handlers/cisco.py2
-rw-r--r--passlib/handlers/oracle.py2
-rw-r--r--passlib/handlers/postgres.py2
-rw-r--r--passlib/utils/__init__.py80
-rw-r--r--passlib/utils/pbkdf2.py21
28 files changed, 282 insertions, 185 deletions
diff --git a/.hgignore b/.hgignore
index 157710f..fc95742 100644
--- a/.hgignore
+++ b/.hgignore
@@ -8,3 +8,4 @@ glob:*$py.class
glob:MANIFEST
glob:.tox
glob:app.yaml
+glob:.noseids
diff --git a/CHANGES b/CHANGES
index 4e05706..e0e94ba 100644
--- a/CHANGES
+++ b/CHANGES
@@ -15,23 +15,35 @@ Overview
Welcome to Passlib 1.6.
The main goal of this release was to clean up the codebase, reducing
- the amount of internally-redundant code, and simplify the publically
- exposed interface. This release also brings with it
- a number of other improvements, including: 10 or so new hash algorithms,
- additional security precautions for the existing ones, numerous
- execution-time improvements, and reorganized documentation.
-
- .. note::
-
- In order to simplify the publically exposed interface, a number
- of the more cumbersome and less-used aspects (particularly the
- semi-internal :class:`!CryptPolicy` class) have been deprecated.
- This should not affect 99% of the code using Passlib.
-
- Just the same, *all deprecated interfaces are still supported, and will continue
- to be supported for at least one more major release*.
- To help with migration, all deprecated functions will issue an informative :exc:`DeprecationWarning`
- when they are invoked, detailing their suggested replacement.
+ the amount of internally-redundant code, and to simplify the publically
+ exposed interface. It also brings with it a number of other improvements:
+ 10 or so new hash algorithms, additional security precautions
+ for the existing algorithms, a number of speed improvements,
+ and reorganized documentation.
+
+Deprecated APIs
+...............
+ In order to improve the publically exposed interface,
+ some of the more cumbersome and less-used functions in Passlib
+ have been deprecated / renamed. This should not affect 99% of applications.
+ That said, all the deprecated interfaces are still present, and will continue
+ to be supported for at least one more major release.
+ To help with migration, all deprecated functions should issue an informative
+ :exc:`DeprecationWarning` when they are invoked, detailing their suggested replacement.
+ The following interfaces have changed:
+
+ * The semi-internal :class:`!CryptPolicy` class has been deprecated
+ in it's entirety. All functionality has been rolled into the
+ parent :class:`!CryptContext` class (see :ref:`below <crypt-policy-deprecated>` for more).
+
+ * The interface of the :mod:`passlib.apache` classes has been improved:
+ some confusing methods and options have been renamed, some new
+ constructors and other functions have been added.
+
+ * The (undocumented) :mod:`!passlib.win32` module has been deprecated,
+ all of it's functionality is now offered through the
+ :doc:`lmhash <lib/passlib.hash.lmhash>` and :doc:`nthash <lib/passlib.hash.nthash>`
+ algorithms.
New Hashes
----------
@@ -76,8 +88,7 @@ Existing Hashes
This limit should be larger than any reasonable password size,
and prevents various things including DOS abuses, and exploitation
of OSes with a buggy :func:`!crypt` implementation.
- See :exc:`!PasswordSizeError` for how to change
- this limit.
+ See :exc:`~passlib.exc.PasswordSizeError` for how to change this limit.
.. _consteq-issue:
@@ -127,6 +138,8 @@ Existing Hashes
This most likely only affects internal Passlib code.
+.. _crypt-policy-deprecated:
+
CryptContext
------------
@@ -143,7 +156,7 @@ CryptContext
* All new (and hopefully clearer) :ref:`tutorial <context-tutorial>`
and :ref:`reference <context-reference>` documentation.
- * The :class:`CryptPolicy` class and the :attr:`!CryptContext.policy` attribute have been deprecated.
+ * The :class:`CryptPolicy` class and the :attr:`!CryptContext.policy` attribute have been deprecated.
This was a semi-internal class, which most applications
were not involved with at all, but to be conservative about
@@ -152,14 +165,14 @@ CryptContext
All of the functionality of this class has been rolled into
:class:`!CryptContext` itself, so there's one less class to remember.
- Most of the methods exposed by :class:`!CryptPolicy` are now
- :class:`!CryptContext` methods.
+ Many of the methods provided by :class:`!CryptPolicy` are now
+ :class:`!CryptContext` methods, most with the same name and call syntax.
Information on migrating existing code can be found in
the deprecation warnings issued by the class itself,
and in the :class:`CryptPolicy` documentation.
- * Two new class constructors have been added: :meth:`CryptContext.from_path`
- and :meth:`CryptContext.from_string`, for loading CryptContext objects
+ * Two new class constructors have been added (:meth:`CryptContext.from_path`
+ and :meth:`CryptContext.from_string`) to aid in loading CryptContext objects
directly from a configuration file.
* The :ref:`deprecated <context-deprecated-option>` keyword
@@ -194,6 +207,10 @@ Other Modules
override Django's password hashing framework with a custom Passlib
policy (an undocumented beta version of this was present in the 1.5 release).
+ * **new**: The :func:`passlib.utils.saslprep` function may be useful
+ for applications which need to normalize the unicode representation
+ of passwords before they are hashed.
+
Bugfixes
--------
@@ -220,6 +237,8 @@ Internal Changes
even features the addition of some simplistic fuzz testing.
It will take a bit longer to run though. While not perfect,
statement coverage is at about 95%.
+ Additionally, the hash test suite has been enhanced with many more
+ test vectors across the board, including 8-bit test vectors.
* The internal framework used to construct the hash classes (:mod:`passlib.utils.handlers`)
was rewritten drastically. The new version provides stricter input checking,
@@ -409,8 +428,8 @@ Documentation
* Added quickstart guide to documentation.
* Various minor improvements.
-Internals
----------
+Internal Changes
+----------------
* Added more handler utility functions to reduce code duplication.
* Expanded kdf helpers in :mod:`passlib.utils.pbkdf2`.
@@ -421,9 +440,6 @@ Internals
:exc:`~passlib.exc.MissingBackendError`
if no backends are available.
-Other
------
-
* Builtin tests now use :mod:`!unittest2` if available.
* Setup script no longer requires distribute or setuptools.
* added (undocumented, experimental) Django app
diff --git a/docs/conf.py b/docs/conf.py
index d28206c..4151274 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -138,7 +138,7 @@ issue_tracker_url = "gc:passlib"
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'cloud'
+html_theme = 'redcloud'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
diff --git a/docs/index.rst b/docs/index.rst
index 433c251..5396e6b 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -27,8 +27,8 @@ using the :doc:`SHA256-Crypt </lib/passlib.hash.sha256_crypt>` algorithm::
>>> sha256_crypt.verify("joshua", hash)
False
-Contents
-========
+Content Summary
+===============
.. rst-class:: floater
@@ -85,13 +85,12 @@ Application Helpers
:mod:`passlib.ext.django`
Django plugin which monkeypatches support for (almost) any hash in Passlib.
-Support Modules
----------------
- :mod:`passlib.exc`
-
- custom warnings and exceptions used by Passlib
-
..
+ Support Modules
+ ---------------
+ :mod:`passlib.exc`
+
+ custom warnings and exceptions used by Passlib
:mod:`passlib.registry`
:mod:`passlib.utils`
diff --git a/docs/install.rst b/docs/install.rst
index 5007686..1fdfa31 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -54,34 +54,30 @@ To install from a source directory using :command:`setup.py`::
Testing
=======
-Passlib contains a comprehensive set of unittests providing nearly complete coverage.
+Passlib contains a comprehensive set of unittests (about 38% of the total code),
+which provide nearly complete coverage, and verification of the hash
+algorithms using multiple external sources (if detected at runtime).
All unit tests are contained within the :mod:`passlib.tests` subpackage,
and are designed to be run using the
`Nose <http://somethingaboutorange.com/mrl/projects/nose>`_ unit testing library.
-Once Passlib and Nose have been installed, the tests may be run from the source directory::
+Once Passlib and Nose have been installed, the main suite of tests may be run from the source directory::
- # to run the full passlib test suite...
- PASSLIB_TEST_MODE="full" nosetests -v --tests passlib/tests
+ nosetests --tests passlib/tests
-Tests may also be run via ``setup.py test`` or the included ``tox.ini`` file.
+To run the full test suite, which includes internal cross-checks and mock-testing
+of features not provided natively by the host OS::
-.. note::
+ PASSLIB_TEST_MODE="full" nosetests --tests passlib/tests
- Due to the critical nature of password hashing, Passlib's unittest framework
- is rather extensive, covering the behavior of all the classes, 8-bit
- test vectors for all supported hashes, and some primitive fuzz testing;
- it occupies ~38% of the Passlib codebase. Because of this, the full test
- suite make take some time to run. Setting ``PASSLIB_TEST_MODE`` to
- ``"quick"`` or ``"default"`` will speed things up.
+Tests may also be run via ``setup.py test`` or the included ``tox.ini`` file.
.. rst-class:: html-toggle
-Documentation
-=============
+Building the Documentation
+==========================
The latest copy of this documentation should always be available
online at `<http://packages.python.org/passlib>`_.
-
If you wish to generate your own copy of the documentation,
you will need to:
diff --git a/docs/lib/passlib.context-tutorial.rst b/docs/lib/passlib.context-tutorial.rst
index 338cbe8..953bc51 100644
--- a/docs/lib/passlib.context-tutorial.rst
+++ b/docs/lib/passlib.context-tutorial.rst
@@ -12,7 +12,7 @@
Overview
========
-The central class in the :mod:`passlib.context` module is the :class:`!CryptContext` class.
+The :mod:`passlib.context` module contains one main class: :class:`!passlib.context.CryptContext`.
This class is designed to take care of many of the more frequent
coding patterns which occur in applications that need to handle multiple
password hashes at once:
@@ -51,38 +51,41 @@ Tutorial / Walkthrough
Basic Usage
-----------
At it's base, the :class:`!CryptContext` class is just a list of
-:class:`!PasswordHash` objects, imported by name
+:class:`~passlib.ifc.PasswordHash` objects, imported by name
from the :mod:`passlib.hash` module. The following snippet creates
-a new context object which supports three hash algorithms --
-:doc:`sha256_crypt <passlib.hash.sha256_crypt>`,
+a new context object which supports three hash algorithms
+(:doc:`sha256_crypt <passlib.hash.sha256_crypt>`,
:doc:`md5_crypt <passlib.hash.md5_crypt>`, and
-:doc:`des_crypt <passlib.hash.des_crypt>`::
+:doc:`des_crypt <passlib.hash.des_crypt>`)::
>>> from passlib.context import CryptContext
>>> myctx = CryptContext(schemes=["sha256_crypt", "md5_crypt", "des_crypt"])
This new object exposes a very similar set of methods to the :class:`!PasswordHash`
-interface. Hashing and verifying passwords is equally straightforward::
+interface, and hashing and verifying passwords is equally as straightforward::
- >>> # loads first algorithm in the list (sha256_crypt),
+ >>> # this loads first algorithm in the schemes list (sha256_crypt),
>>> # generates a new salt, and hashes the password:
>>> hash1 = myctx.encrypt("joshua")
>>> hash1
'$5$rounds=80000$HFEGd1wnFknpibRl$VZqjyYcTenv7CtOf986hxuE0pRaGXnuLXyfb7m9xL69'
+ >>> # when verifying a password, the algorithm is identified automatically:
+ >>> myctx.verify("gtnw", hash1)
+ False
+ >>> myctx.verify("joshua", hash1)
+ True
+
>>> # alternately, you can explicitly pick one of the configured algorithms,
>>> # through this is rarely needed in practice:
- >>> hash2 = myctx.encrypt("letmein", scheme="md5_crypt")
+ >>> hash2 = myctx.encrypt("dogsnamehere", scheme="md5_crypt")
>>> hash2
'$1$e2nig/AC$stejMS1ek6W0/UogYKFao/'
- >>> # when verifying a password, the algorithm is identified automatically:
- >>> myctx.verify("socks", hash1)
+ >>> myctx.verify("letmein", hash2)
False
- >>> myctx.verify("joshua", hash1)
+ >>> myctx.verify("dogsnamehere", hash2)
True
- >>> myctx.verify("joshua", hash2)
- False
If not told otherwise, the context object will use the first algorithm listed
in ``schemes`` when encrypting new hashes. This default can be changed by
@@ -97,6 +100,10 @@ using the ``default`` keyword::
>>> myctx.identify(hash)
'des_crypt'
+This concludes the basics of how to use a CryptContext object.
+The rest of the sections detail the various features it offers,
+which probably provide a better argument for *why* you'd want to use it.
+
.. seealso::
* the :meth:`CryptContext.encrypt`, :meth:`~CryptContext.verify`, and :meth:`~CryptContext.identify` methods.
@@ -506,8 +513,11 @@ the following code in the correct function::
In the above code, the 'category' kwd can be omitted entirely, *OR*
set to a string matching a user category specified in the policy file.
In the latter case, any category-specific policy settings will be enforced.
- For this example, assume it's ``None`` for most users, and ``"admin"`` for special users.
- this namespace is entirely application chosen, it just has to match the policy file.
+
+ For the purposes of this example (and the sample config file listed above),
+ it's assumed this value will be ``None`` for most users, and ``"admin"`` for special users.
+ This namespace is entirely up to the application, it just has to match the
+ category names used in the config file.
See :ref:`user-categories` for more details.
diff --git a/docs/lib/passlib.hash.bcrypt.rst b/docs/lib/passlib.hash.bcrypt.rst
index f917dae..686665c 100644
--- a/docs/lib/passlib.hash.bcrypt.rst
+++ b/docs/lib/passlib.hash.bcrypt.rst
@@ -34,7 +34,7 @@ for new applications. This class can be used directly as follows::
:ref:`py-bcrypt or bcryptor <optional-libraries>`
if this algorithm is going to be used.
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
=========
diff --git a/docs/lib/passlib.hash.bsdi_crypt.rst b/docs/lib/passlib.hash.bsdi_crypt.rst
index c8e4b9b..3492dcc 100644
--- a/docs/lib/passlib.hash.bsdi_crypt.rst
+++ b/docs/lib/passlib.hash.bsdi_crypt.rst
@@ -31,7 +31,7 @@ It class can be used directly as follows::
>>> bsdi_crypt.verify("secret", hash)
False
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
=========
diff --git a/docs/lib/passlib.hash.cisco_pix.rst b/docs/lib/passlib.hash.cisco_pix.rst
index cb15639..a6327a7 100644
--- a/docs/lib/passlib.hash.cisco_pix.rst
+++ b/docs/lib/passlib.hash.cisco_pix.rst
@@ -42,7 +42,7 @@ PIX firewalls. This class can be used directly as follows::
>>> pix.verify("password", hash2)
True
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
=========
diff --git a/docs/lib/passlib.hash.cisco_type7.rst b/docs/lib/passlib.hash.cisco_type7.rst
index 1fdb9d3..e1efc80 100644
--- a/docs/lib/passlib.hash.cisco_type7.rst
+++ b/docs/lib/passlib.hash.cisco_type7.rst
@@ -14,7 +14,7 @@
.. currentmodule:: passlib.hash
This class implements the "Type 7" password encoding used Cisco IOS.
-This is not actually a true hash, but a reversible XOR Cipher encoding of the plaintext
+This is not actually a true hash, but a reversible XOR Cipher encoding the plaintext
password. Type 7 strings are (and were designed to be) plaintext equivalent;
the goal was to protect from "over the shoulder" eavesdropping, and
little else. They can be trivially decoded.
@@ -38,7 +38,7 @@ This class can be used directly as follows::
>>> cisco_type7.decode(h)
"password"
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
.. note::
@@ -61,13 +61,16 @@ An example encoding (of ``"password"``) is ``044B0A151C36435C0D``.
This has a salt/offset of 4 (``04`` in the example),
and encodes password via ``4B0A151C36435C0D``.
-The algorithm is a straightforward XOR Cipher (though note the description below
-may not be entirely correct, see `Deviations`_ for details):
+.. note::
+ The following description may not be entirely correct with
+ respect to the official algorithm, see the `Deviations`_ section for details.
+
+The algorithm is a straightforward XOR Cipher:
1. The algorithm relies on the following ``ascii``-encoded 53-byte
- secret key::
+ constant::
- dsfd;kfoA,.iyewrkldJKDHSUBsgvca69834ncxv9873254k;fg87
+ "dsfd;kfoA,.iyewrkldJKDHSUBsgvca69834ncxv9873254k;fg87"
2. A integer salt should be generated from the range
0 .. 15. The first two characters of the encoded string are the
@@ -77,11 +80,11 @@ may not be entirely correct, see `Deviations`_ for details):
For each byte in the password (starting with the 0th byte),
the :samp:`{i}`'th byte of the password is encoded as follows:
- * let ``j=(i + salt) % keylen``
- * XOR the :samp:`{i}`'th byte of the password with the :samp:`{j}`'th byte
- of the secret key.
- * encode the resulting byte as uppercase hexidecimal,
- and append to the encoded string.
+ a. let ``j=(i + salt) % 53``
+ b. XOR the :samp:`{i}`'th byte of the password with the :samp:`{j}`'th byte
+ of the magic constant.
+ c. encode the resulting byte as uppercase hexidecimal,
+ and append to the encoded string.
Deviations
==========
@@ -98,13 +101,13 @@ It may be updated as more information becomes available.
different encoding is desired by an application, the password should be
encoded before handing it to Passlib.
-* Magic Key:
+* Magic Constant:
- Some implementations contain a truncated 26-byte key instead of the
- 53-byte key listed above. However, it is likely those implementations have an
- incomplete copy of the key, as they exhibit other issues as well after
+ Other implementations contain a truncated 26-byte constant instead of the
+ 53-byte constant listed above. However, it is likely those implementations
+ were merely incomplete, as they exhibit other issues as well after
the 26th byte is reached (throwing an error, truncating the password,
- outputing garbage), instead of wrapping around to the beginning of the key.
+ outputing garbage), and only worked for shorter passwords.
* Salt Range:
diff --git a/docs/lib/passlib.hash.des_crypt.rst b/docs/lib/passlib.hash.des_crypt.rst
index 17113b3..f0ed330 100644
--- a/docs/lib/passlib.hash.des_crypt.rst
+++ b/docs/lib/passlib.hash.des_crypt.rst
@@ -26,7 +26,7 @@ It can used directly as follows::
>>> des_crypt.verify("letmein", hash)
False
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
=========
diff --git a/docs/lib/passlib.hash.django_std.rst b/docs/lib/passlib.hash.django_std.rst
index a908f00..1b76383 100644
--- a/docs/lib/passlib.hash.django_std.rst
+++ b/docs/lib/passlib.hash.django_std.rst
@@ -52,7 +52,7 @@ These classes can be used directly as follows::
>>> handler.verify("eville", h)
False
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
---------
@@ -130,7 +130,7 @@ These classes can be used directly as follows::
>>> handler.verify("eville", h)
False
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
---------
diff --git a/docs/lib/passlib.hash.fshp.rst b/docs/lib/passlib.hash.fshp.rst
index 60e490d..7328ca4 100644
--- a/docs/lib/passlib.hash.fshp.rst
+++ b/docs/lib/passlib.hash.fshp.rst
@@ -39,7 +39,7 @@ It can be used directly as follows::
>>> fshp.verify("secret", hash)
False
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
=========
diff --git a/docs/lib/passlib.hash.hex_digests.rst b/docs/lib/passlib.hash.hex_digests.rst
index e1a7aa0..d9d9cb0 100644
--- a/docs/lib/passlib.hash.hex_digests.rst
+++ b/docs/lib/passlib.hash.hex_digests.rst
@@ -32,7 +32,7 @@ and can be used directly as follows::
>>> hex_sha1.verify("secret", h) #verify incorrect password
False
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
=========
diff --git a/docs/lib/passlib.hash.lmhash.rst b/docs/lib/passlib.hash.lmhash.rst
index fdd3234..eb3123b 100644
--- a/docs/lib/passlib.hash.lmhash.rst
+++ b/docs/lib/passlib.hash.lmhash.rst
@@ -36,7 +36,7 @@ This class can be used directly as follows::
>>> lmhash.verify("secret", h)
False
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
=========
diff --git a/docs/lib/passlib.hash.nthash.rst b/docs/lib/passlib.hash.nthash.rst
index ebee71a..da58f9c 100644
--- a/docs/lib/passlib.hash.nthash.rst
+++ b/docs/lib/passlib.hash.nthash.rst
@@ -33,7 +33,7 @@ This class can be used directly as follows::
>>> nthash.verify("secret", h)
False
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
=========
diff --git a/docs/lib/passlib.hash.oracle10.rst b/docs/lib/passlib.hash.oracle10.rst
index 7fd6ccb..540f086 100644
--- a/docs/lib/passlib.hash.oracle10.rst
+++ b/docs/lib/passlib.hash.oracle10.rst
@@ -31,7 +31,7 @@ a username for all encrypt/verify operations)::
>>> oracle10.verify("letmein", hash, user="username")
False
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
.. warning::
diff --git a/docs/lib/passlib.hash.oracle11.rst b/docs/lib/passlib.hash.oracle11.rst
index 84282d2..8eb8d80 100644
--- a/docs/lib/passlib.hash.oracle11.rst
+++ b/docs/lib/passlib.hash.oracle11.rst
@@ -21,7 +21,7 @@ This class can be can be used directly as follows::
>>> oracle11.verify("secret", hash)
False
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
.. warning::
diff --git a/docs/lib/passlib.hash.postgres_md5.rst b/docs/lib/passlib.hash.postgres_md5.rst
index 2d038ef..b9e6200 100644
--- a/docs/lib/passlib.hash.postgres_md5.rst
+++ b/docs/lib/passlib.hash.postgres_md5.rst
@@ -35,7 +35,7 @@ That aside, this class can be used directly as follows::
>>> postgres_md5.verify("password", hash, user="username")
False
-.. seealso:: :ref:`password hash usage <password-hash-examples>` for more examples
+.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
=========
diff --git a/docs/lib/passlib.hash.scram.rst b/docs/lib/passlib.hash.scram.rst
index 177ed3b..e9c0205 100644
--- a/docs/lib/passlib.hash.scram.rst
+++ b/docs/lib/passlib.hash.scram.rst
@@ -55,8 +55,8 @@ This class can be used like any other Passlib hash, as follows::
>>> scram.verify("secret", hash)
False
-See :ref:`password hash usage <password-hash-examples>` for more examples
-for more examples of how to use the common hash interface.
+See the generic :ref:`PasswordHash usage examples <password-hash-examples>`
+for more details on how to use the common hash interface.
Additionally, this class provides a number of useful methods for SCRAM-specific actions:
* You can override the default list of digests, and/or the number of iterations::
diff --git a/docs/lib/passlib.utils.rst b/docs/lib/passlib.utils.rst
index 02bf19c..9ecafda 100644
--- a/docs/lib/passlib.utils.rst
+++ b/docs/lib/passlib.utils.rst
@@ -19,36 +19,36 @@ They may also be useful when implementing custom handlers for existing legacy fo
Constants
=========
-.. data:: sys_bits
+..
+ .. data:: sys_bits
- Native bit size of host architecture (either 32 or 64 bit).
- used for various purposes internally.
+ Native bit size of host architecture (either 32 or 64 bit).
+ used for various purposes internally.
.. data:: unix_crypt_schemes
- List of the names of all the handlers in :mod:`passlib.hash`
- which are supported by the native :func:`crypt()` function
- of at least one OS.
+ List of the names of all the hashes in :mod:`passlib.hash`
+ which are natively supported by :func:`crypt` on at least one operating
+ system.
For all hashes in this list, the expression
- ``get_crypt_handler(name).has_backend("os_crypt")``
- will return ``True`` iff there is native OS support for that hash.
-
+ :samp:`passlib.hash.{alg}.has_backend("os_crypt")`
+ will return ``True`` if the host OS natively supports the hash.
This list is used by :data:`~passlib.hosts.host_context`
and :data:`~passlib.apps.ldap_context` to determine
which hashes are supported by the host.
- See :ref:`mcf-identifiers` for a table of which OSes
- are known to support which hashes.
+ .. seealso:: :ref:`mcf-identifiers` for a table of which OSes are known to support which hashes.
..
PYPY
JYTHON
rounds_cost_values
-Decorators
-==========
-.. autofunction:: classproperty
+..
+ Decorators
+ ==========
+ .. autofunction:: classproperty
Unicode Helpers
===============
@@ -77,7 +77,7 @@ Base64 Encoding
Base64Engine Class
------------------
Passlib has to deal with a number of different Base64 encodings,
-with varying endianness, as well as wildly different value <-> character
+with varying endianness, as well as wildly different character <-> value
mappings. This is all encapsulated in the :class:`Base64Engine` class,
which provides common encoding actions for an arbitrary base64-style encoding
scheme. There are also a couple of predefined instances which are commonly
@@ -99,8 +99,8 @@ Common Character Maps
This encoding system appears to have originated with
:class:`~passlib.hash.des_crypt`, but is used by
:class:`~passlib.hash.md5_crypt`, :class:`~passlib.hash.sha256_crypt`,
- and others. Within Passlib, this encoding is referred as ``hash64`` encoding
- to distinguish it from normal base64 and other encodings.
+ and others. Within Passlib, this encoding is referred as the "hash64" encoding,
+ to distinguish it from normal base64 and others.
.. data:: BCRYPT_CHARS
@@ -128,18 +128,17 @@ Predefined Instances
the :class:`Base64Engine` class;
the interface remains mostly unchanged.
-Other
------
-.. autofunction:: ab64_encode
-.. autofunction:: ab64_decode
-
..
+ Other
+ -----
+ .. autofunction:: ab64_encode
+ .. autofunction:: ab64_decode
+
.. data:: AB64_CHARS
Variant of standard Base64 character map used by some
custom Passlib hashes (see :func:`ab64_encode`).
-
..
Host OS
=======
@@ -150,7 +149,7 @@ Randomness
==========
.. data:: rng
- The random number generator used by passlib to generate
+ The random number generator used by Passlib to generate
salt strings and other things which don't require a
cryptographically strong source of randomness.
diff --git a/docs/modular_crypt_format.rst b/docs/modular_crypt_format.rst
index d80bae4..22a285a 100644
--- a/docs/modular_crypt_format.rst
+++ b/docs/modular_crypt_format.rst
@@ -123,23 +123,22 @@ Identifiers & Platform Support
==============================
The following table lists of all the major MCF hashes supported by Passlib,
-and indicates which operating systems [#gae]_ offer native support.
+and indicates which operating systems offer native support for them [#gae]_.
-.. todo:: include MacOS X in this list
-
-==================================== ==================== =========== =========== =========== =========== =======
-Scheme Prefix Linux FreeBSD NetBSD OpenBSD Solaris
-==================================== ==================== =========== =========== =========== =========== =======
-:class:`~passlib.hash.des_crypt` n/a y y y y y
-:class:`~passlib.hash.bsdi_crypt` ``_`` y y y
+==================================== ==================== =========== =========== =========== =========== ======= =======
+Scheme Prefix Linux FreeBSD NetBSD OpenBSD Solaris MacOSX
+==================================== ==================== =========== =========== =========== =========== ======= =======
+:class:`~passlib.hash.des_crypt` none y y y y y y
+:class:`~passlib.hash.bsdi_crypt` ``_`` y y y y
:class:`~passlib.hash.md5_crypt` ``$1$`` y y y y y
-:class:`~passlib.hash.sun_md5_crypt` ``$md5$``, ``$md5,`` y
-:class:`~passlib.hash.bcrypt` ``$2$``, ``$2a$`` y y y y
+:class:`~passlib.hash.sun_md5_crypt` ``$md5$``, ``$md5,`` y
+:class:`~passlib.hash.bcrypt` ``$2$``, ``$2a$``,
+ ``$2x$``, ``$2y$`` y y y y
:class:`~passlib.hash.bsd_nthash` ``$3$`` y
:class:`~passlib.hash.sha256_crypt` ``$5$`` y y
:class:`~passlib.hash.sha512_crypt` ``$6$`` y y
:class:`~passlib.hash.sha1_crypt` ``$sha1$`` y
-==================================== ==================== =========== =========== =========== =========== =======
+==================================== ==================== =========== =========== =========== =========== ======= =======
The following table lists the other MCF hashes supported by Passlib,
most of which are only used by applications:
@@ -163,6 +162,7 @@ Scheme Prefix Primary Use (if
appears to provide hash support matching that of a typical Linux system.
.. [#cta] :class:`!cta_pbkdf2_sha1` and :class:`!dlitz_pbkdf2_sha1` both use
- the same identifier. They can be distinguished
+ the same identifier. While there are other internal differences,
+ they can be quickly distinguished
by the fact that cta hashes will always end in ``=``, while dlitz
hashes contain no ``=`` at all.
diff --git a/passlib/apache.py b/passlib/apache.py
index 58e0a84..ce4dbb9 100644
--- a/passlib/apache.py
+++ b/passlib/apache.py
@@ -415,7 +415,7 @@ class HtpasswdFile(_CommonFile):
a new htpasswd file, applications can set ``new=True`` so that
the existing file (if any) will not be loaded.
- .. versionchanged:: 1.6
+ .. versionadded:: 1.6
This feature was previously enabled by setting ``autoload=False``.
That alias has been deprecated, and will be removed in Passlib 1.8
@@ -444,7 +444,7 @@ class HtpasswdFile(_CommonFile):
Must be one of ``"apr_md5_crypt"``, ``"des_crypt"``, ``"ldap_sha1"``,
``"plaintext"``. It defaults to ``"apr_md5_crypt"``.
- .. versionchanged:: 1.6
+ .. versionadded:: 1.6
This keyword was previously named ``default``. That alias
has been deprecated, and will be removed in Passlib 1.8.
@@ -464,6 +464,23 @@ class HtpasswdFile(_CommonFile):
will probably not be usuable by another application,
and particularly not by Apache.
+ :param autoload:
+ Set to ``False`` to prevent the constructor from automatically
+ loaded the file from disk.
+
+ .. deprecated:: 1.6
+ This has been replaced by the *new* keyword.
+ Instead of setting ``autoload=False``, you should use
+ ``new=True``. Support for this keyword will be removed
+ in Passlib 1.8.
+
+ :param default:
+ Change the default algorithm used to encrypt new passwords.
+
+ .. deprecated:: 1.6
+ This has been renamed to *default_scheme* for clarity.
+ Support for this alias will be removed in Passlib 1.8.
+
Loading & Saving
================
.. automethod:: load
@@ -487,6 +504,19 @@ class HtpasswdFile(_CommonFile):
======================
.. automethod:: from_string
+ Attributes
+ ==========
+ .. attribute:: path
+
+ Path to local file that will be used as the default
+ for all :meth:`load` and :meth:`save` operations.
+ May be written to, initialized by the *path* constructor keyword.
+
+ .. attribute:: autosave
+
+ Writeable flag indicating whether changes will be automatically
+ written to *path*.
+
Errors
======
:raises ValueError:
@@ -697,7 +727,7 @@ class HtdigestFile(_CommonFile):
a new htpasswd file, applications can set ``new=True`` so that
the existing file (if any) will not be loaded.
- .. versionchanged:: 1.6
+ .. versionadded:: 1.6
This feature was previously enabled by setting ``autoload=False``.
That alias has been deprecated, and will be removed in Passlib 1.8
@@ -720,6 +750,16 @@ class HtdigestFile(_CommonFile):
This is also exposed as a readonly instance attribute.
+ :param autoload:
+ Set to ``False`` to prevent the constructor from automatically
+ loaded the file from disk.
+
+ .. deprecated:: 1.6
+ This has been replaced by the *new* keyword.
+ Instead of setting ``autoload=False``, you should use
+ ``new=True``. Support for this keyword will be removed
+ in Passlib 1.8.
+
Loading & Saving
================
.. automethod:: load
@@ -745,6 +785,26 @@ class HtdigestFile(_CommonFile):
======================
.. automethod:: from_string
+ Attributes
+ ==========
+ .. attribute:: default_realm
+
+ The default realm that will be used if one is not provided
+ to methods that require it. By default this is ``None``,
+ in which case an explicit realm must be provided for every
+ method call. Can be written to.
+
+ .. attribute:: path
+
+ Path to local file that will be used as the default
+ for all :meth:`load` and :meth:`save` operations.
+ May be written to, initialized by the *path* constructor keyword.
+
+ .. attribute:: autosave
+
+ Writeable flag indicating whether changes will be automatically
+ written to *path*.
+
Errors
======
:raises ValueError:
diff --git a/passlib/handlers/cisco.py b/passlib/handlers/cisco.py
index 956a060..3bc90a7 100644
--- a/passlib/handlers/cisco.py
+++ b/passlib/handlers/cisco.py
@@ -26,7 +26,7 @@ __all__ = [
class cisco_pix(uh.HasUserContext, uh.StaticHandler):
"""This class implements the password hash used by Cisco PIX firewalls,
and follows the :ref:`password-hash-api`.
- It has a single round, and relies on the username
+ It does a single round of hashing, and relies on the username
as the salt.
The :meth:`~passlib.ifc.PasswordHash.encrypt`, :meth:`~passlib.ifc.PasswordHash.genhash`, and :meth:`~passlib.ifc.PasswordHash.verify` methods
diff --git a/passlib/handlers/oracle.py b/passlib/handlers/oracle.py
index 7c028be..08850f0 100644
--- a/passlib/handlers/oracle.py
+++ b/passlib/handlers/oracle.py
@@ -54,7 +54,7 @@ ORACLE10_MAGIC = b("\x01\x23\x45\x67\x89\xAB\xCD\xEF")
class oracle10(uh.HasUserContext, uh.StaticHandler):
"""This class implements the password hash used by Oracle up to version 10g, and follows the :ref:`password-hash-api`.
- It has no salt and a single fixed round.
+ It does a single round of hashing, and relies on the username as the salt.
The :meth:`~passlib.ifc.PasswordHash.encrypt`, :meth:`~passlib.ifc.PasswordHash.genhash`, and :meth:`~passlib.ifc.PasswordHash.verify` methods all require the
following additional contextual keywords:
diff --git a/passlib/handlers/postgres.py b/passlib/handlers/postgres.py
index bb555ec..1324d83 100644
--- a/passlib/handlers/postgres.py
+++ b/passlib/handlers/postgres.py
@@ -24,7 +24,7 @@ __all__ = [
class postgres_md5(uh.HasUserContext, uh.StaticHandler):
"""This class implements the Postgres MD5 Password hash, and follows the :ref:`password-hash-api`.
- It has no salt and a single fixed round.
+ It does a single round of hashing, and relies on the username as the salt.
The :meth:`~passlib.ifc.PasswordHash.encrypt`, :meth:`~passlib.ifc.PasswordHash.genhash`, and :meth:`~passlib.ifc.PasswordHash.verify` methods all require the
following additional contextual keywords:
diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py
index a40b744..3e503a2 100644
--- a/passlib/utils/__init__.py
+++ b/passlib/utils/__init__.py
@@ -244,7 +244,7 @@ class memoized_property(object):
#=============================================================================
def consteq(left, right):
- """check two strings/bytes for equality, taking constant time relative
+ """Check two strings/bytes for equality, taking constant time relative
to the size of the righthand input.
The purpose of this function is to aid in preventing timing attacks
@@ -316,7 +316,7 @@ def splitcomma(source, sep=","):
return [ elem.strip() for elem in source.split(sep) ]
def saslprep(source, param="value"):
- """normalizes unicode string using SASLPrep stringprep profile.
+ """Normalizes unicode string using SASLPrep stringprep profile.
The SASLPrep profile is defined in :rfc:`4013`.
It provides a uniform scheme for normalizing unicode usernames
@@ -443,18 +443,16 @@ if stringprep is None: # pragma: no cover -- runtime detection
# bytes helpers
#=============================================================================
def render_bytes(source, *args):
- """helper for using formatting operator with bytes.
-
- this function is motivated by the fact that
- :class:`bytes` instances do not support % or {} formatting under python 3.
- this function is an attempt to provide a replacement
- that will work uniformly under python 2 & 3.
+ """Peform ``%`` formating using bytes in a uniform manner across Python 2/3.
+ This function is motivated by the fact that
+ :class:`bytes` instances do not support ``%`` or ``{}`` formatting under Python 3.
+ This function is an attempt to provide a replacement:
it converts everything to unicode (decode bytes instances as latin-1),
performs the required formatting, then encodes the result to latin-1.
- calling ``render_bytes(source, *args)`` should function roughly the same as
- ``source % args`` under python 2.
+ Calling ``render_bytes(source, *args)`` should function roughly the same as
+ ``source % args`` under Python 2.
"""
if isinstance(source, bytes):
source = source.decode("latin-1")
@@ -481,10 +479,10 @@ else:
return unhexlify(('%%0%dx' % (count<<1)) % value)
add_doc(bytes_to_int, "decode byte string as single big-endian integer")
-add_doc(int_to_bytes, "encode intger as single big-endian byte string")
+add_doc(int_to_bytes, "encode integer as single big-endian byte string")
def xor_bytes(left, right):
- "perform bitwise-xor of two byte strings"
+ "Perform bitwise-xor of two byte strings (must be same size)"
return int_to_bytes(bytes_to_int(left) ^ bytes_to_int(right), len(left))
def repeat_string(source, size):
@@ -520,7 +518,7 @@ def is_ascii_codec(codec):
return _ASCII_TEST_UNICODE.encode(codec) == _ASCII_TEST_BYTES
def is_same_codec(left, right):
- "check if two codec names are aliases for same codec"
+ "Check if two codec names are aliases for same codec"
if left == right:
return True
if not (left and right):
@@ -530,12 +528,12 @@ def is_same_codec(left, right):
_B80 = b('\x80')[0]
_U80 = u('\x80')
def is_ascii_safe(source):
- "check if source (bytes or unicode) contains only 7-bit ascii"
+ "Check if string (bytes or unicode) contains only 7-bit ascii"
r = _B80 if isinstance(source, bytes) else _U80
return all(c < r for c in source)
def to_bytes(source, encoding="utf-8", param="value", source_encoding=None):
- """helper to normalize input to bytes.
+ """Helper to normalize input to bytes.
:arg source:
Source bytes/unicode to process.
@@ -571,13 +569,13 @@ def to_bytes(source, encoding="utf-8", param="value", source_encoding=None):
else:
raise ExpectedStringError(source, param)
-def to_unicode(source, source_encoding="utf-8", param="value"):
- """helper to normalize input to unicode.
+def to_unicode(source, encoding="utf-8", param="value"):
+ """Helper to normalize input to unicode.
:arg source:
source bytes/unicode to process.
- :arg source_encoding:
+ :arg encoding:
encoding to use when decoding bytes instances.
:param param:
@@ -587,13 +585,13 @@ def to_unicode(source, source_encoding="utf-8", param="value"):
:returns:
* returns unicode strings unchanged.
- * returns bytes strings decoded using *source_encoding*
+ * returns bytes strings decoded using *encoding*
"""
- assert source_encoding
+ assert encoding
if isinstance(source, unicode):
return source
elif isinstance(source, bytes):
- return source.decode(source_encoding)
+ return source.decode(encoding)
else:
raise ExpectedStringError(source, param)
@@ -615,10 +613,10 @@ else:
raise ExpectedStringError(source, param)
add_doc(to_native_str,
- """take in unicode or bytes, return native string.
+ """Take in unicode or bytes, return native string.
- python 2: encodes unicode using specified encoding, leaves bytes alone.
- python 3: leaves unicode alone, decodes bytes using specified encoding.
+ Python 2: encodes unicode using specified encoding, leaves bytes alone.
+ Python 3: leaves unicode alone, decodes bytes using specified encoding.
:raises TypeError: if source is not unicode or bytes.
@@ -645,28 +643,42 @@ def to_hash_str(source, encoding="ascii"): # pragma: no cover -- deprecated & un
#=================================================================================
class Base64Engine(object):
- """provides routines for encoding/decoding base64 data using
+ """Provides routines for encoding/decoding base64 data using
arbitrary character mappings, selectable endianness, etc.
:arg charmap:
A string of 64 unique characters,
- which will be used to encode successive 6-bit chunks.
- A character's position within the string will correspond
+ which will be used to encode successive 6-bit chunks of data.
+ A character's position within the string should correspond
to it's 6-bit value.
:param big:
Whether the encoding should be big-endian (default False).
+ .. note::
+ This class does not currently handle base64's padding characters
+ in any way what so ever.
+
Raw Bytes <-> Encoded Bytes
===========================
+ The following methods convert between raw bytes,
+ and strings encoded using the engine's specific base64 variant:
+
.. automethod:: encode_bytes
.. automethod:: decode_bytes
.. automethod:: encode_transposed_bytes
.. automethod:: decode_transposed_bytes
- .. automethod:: check_repair_unused
+
+ ..
+ .. automethod:: check_repair_unused
+ .. automethod:: repair_unused
Integers <-> Encoded Bytes
==========================
+ The following methods allow encoding and decoding
+ unsigned integers to and from the engine's specific base64 variant.
+ Endianess is determined by the engine's ``big`` constructor keyword.
+
.. automethod:: encode_int6
.. automethod:: decode_int6
@@ -757,7 +769,7 @@ class Base64Engine(object):
# encoding byte strings
#=============================================================
def encode_bytes(self, source):
- """encode bytes to engine's specific base64 variant.
+ """encode bytes to base64 string.
:arg source: byte string to encode.
:returns: byte string containing encoded data.
@@ -860,7 +872,7 @@ class Base64Engine(object):
#=============================================================
def decode_bytes(self, source):
- """decode bytes from engine's specific base64 variant.
+ """decode bytes from base64 string.
:arg source: byte string to decode.
:returns: byte string containing decoded data.
@@ -1060,7 +1072,7 @@ class Base64Engine(object):
# integer decoding helpers - mainly used by des_crypt family
#=============================================================
def _decode_int(self, source, bits):
- """decode hash64 string -> integer
+ """decode base64 string -> integer
:arg source: base64 string to decode.
:arg bits: number of bits in resulting integer.
@@ -1114,7 +1126,7 @@ class Base64Engine(object):
raise ValueError("invalid character")
def decode_int12(self, source):
- "decodes 2 char string -> 12-bit integer (little-endian order)"
+ "decodes 2 char string -> 12-bit integer"
if not isinstance(source, bytes):
raise TypeError("source must be bytes, not %s" % (type(source),))
if len(source) != 2:
@@ -1129,7 +1141,7 @@ class Base64Engine(object):
raise ValueError("invalid character")
def decode_int24(self, source):
- "decodes 4 char string -> 24-bit integer (little-endian order)"
+ "decodes 4 char string -> 24-bit integer"
if not isinstance(source, bytes):
raise TypeError("source must be bytes, not %s" % (type(source),))
if len(source) != 4:
@@ -1349,7 +1361,7 @@ else:
return None
return result
-add_doc(safe_crypt, """wrapper around stdlib's crypt.
+add_doc(safe_crypt, """Wrapper around stdlib's crypt.
This is a wrapper around stdlib's :func:`!crypt.crypt`, which attempts
to provide uniform behavior across Python 2 and 3.
diff --git a/passlib/utils/pbkdf2.py b/passlib/utils/pbkdf2.py
index b2d3b23..916b295 100644
--- a/passlib/utils/pbkdf2.py
+++ b/passlib/utils/pbkdf2.py
@@ -59,18 +59,18 @@ _nhn_hash_names = [
_nhn_cache = {}
def norm_hash_name(name, format="hashlib"):
- """normalize hash function name
+ """Normalize hash function name
:arg name:
- un-normalized hash function name.
+ Original hash function name.
- this name can be a Python :mod:`~hashlib` digest name,
- a SCRAM mechanism name, IANA assigned hash name, etc;
- case is ignored, underscores converted to hyphens.
+ This name can be a Python :mod:`~hashlib` digest name,
+ a SCRAM mechanism name, IANA assigned hash name, etc.
+ Case is ignored, and underscores are converted to hyphens.
:param format:
- naming convention to normalize hash names to.
- possible values are:
+ Naming convention to normalize to.
+ Possible values are:
* ``"hashlib"`` (the default) - normalizes name to be compatible
with Python's :mod:`!hashlib`.
@@ -80,7 +80,7 @@ def norm_hash_name(name, format="hashlib"):
and then uses a heuristic to give a "best guess".
:returns:
- hash name, returned as native string.
+ Hash name, returned as native :class:`!str`.
"""
# check cache
try:
@@ -303,6 +303,7 @@ def pbkdf1(secret, salt, rounds, keylen=None, hash="sha1"):
# NOTE: if hash unknown, new() will throw ValueError, which we'd just
# reraise anyways; so instead of checking, we just let it get
# thrown during first use, below
+ # TODO: use builtin md4 class if hashlib doesn't have it.
def hash_const(msg):
return hashlib.new(hash, msg)
@@ -343,11 +344,11 @@ def pbkdf2(secret, salt, rounds, keylen=None, prf="hmac-sha1"):
:param rounds: number of rounds to use to generate key
:arg keylen:
number of bytes to generate.
- if set to `None``, will use digest size of selected prf.
+ if set to ``None``, will use digest size of selected prf.
:param prf:
psuedo-random family to use for key strengthening.
this can be any string or callable accepted by :func:`get_prf`.
- this defaults to ``hmac-sha1`` (the only prf explicitly listed in
+ this defaults to ``"hmac-sha1"`` (the only prf explicitly listed in
the PBKDF2 specification)
:returns: