diff options
| author | Eli Collins <elic@assurancetechnologies.com> | 2012-01-09 23:17:30 -0500 |
|---|---|---|
| committer | Eli Collins <elic@assurancetechnologies.com> | 2012-01-09 23:17:30 -0500 |
| commit | 1c449d2ddea632f3b7770f6d0c08f8435ea0cd18 (patch) | |
| tree | f2d57863635c81c7267340eaf35c684ce6154420 /docs | |
| parent | 29e6db01cb272996a3e6f88cdbd8662f7024d605 (diff) | |
| download | passlib-1c449d2ddea632f3b7770f6d0c08f8435ea0cd18.tar.gz | |
lots of work on scram hash
handler
-------
* added 'scram' to default registry list
* handler 'algs' keyword now parsed & validated correctly
* digest names normalized -> IANA spec
* saslprep() integrated into code
* added config string format
related
-------
* added documentation (still needs cleaning up though)
* added majority of UTs, still need to add a few edge cases
other
-----
* redid context->handler deprecation link - code now looks for
handler._deprecated_detector(settings) to generate a callable,
should be more efficient, and allow errors to be throw at bind-time
instead of call-time.
* pbkdf2() function now treats keylen = -1 as request for
keylen = PRF digest size.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/lib/passlib.hash.rst | 1 | ||||
| -rw-r--r-- | docs/lib/passlib.hash.scram.rst | 136 |
2 files changed, 137 insertions, 0 deletions
diff --git a/docs/lib/passlib.hash.rst b/docs/lib/passlib.hash.rst index 7c58cfe..fc108ab 100644 --- a/docs/lib/passlib.hash.rst +++ b/docs/lib/passlib.hash.rst @@ -94,6 +94,7 @@ they can be used compatibly along side other modular crypt format hashes. passlib.hash.pbkdf2_digest passlib.hash.cta_pbkdf2_sha1 passlib.hash.dlitz_pbkdf2_sha1 + passlib.hash.scram Special note should be made of the fallback helper, which is not an actual hash scheme, but provides "disabled account" diff --git a/docs/lib/passlib.hash.scram.rst b/docs/lib/passlib.hash.scram.rst new file mode 100644 index 0000000..0a22c93 --- /dev/null +++ b/docs/lib/passlib.hash.scram.rst @@ -0,0 +1,136 @@ +=================================================================== +:class:`passlib.hash.scram` - SCRAM Hash +=================================================================== + +.. currentmodule:: passlib.hash + +SCRAM is a password-based challenge response protocol defined by :rfc:`5802`. +While Passlib does not provide an implementation of SCRAM, applications +which use SCRAM on the server side frequently need a way to store +user passwords in a secure format that can be used to authenticate users over +SCRAM. + +To accomplish this, Passlib provides the following +:ref:`modular-crypt-format`-compatible password hash scheme which uses the +``"$scram$"`` identifier. This format encodes a salt, rounds settings, and one +or more :func:`~passlib.utils.pbkdf2.pbkdf2` digests, one digest for each +of the hash algorithms the server wishes to support over SCRAM. + +Since this format is PBKDF2-based, it has equivalent security to +Passlib's other :doc:`pbkdf2 hashes <passlib.hash.pbkdf2_digest>`, +and can be used to authenticate users using either the SCRAM-specific class +methods documentated below, or the normal :ref:`password-hash-api`. + +.. note:: + + If you aren't working with the SCRAM protocol, you probably + don't need to use this hash format. + +Usage +===== +This class can be used like any other Passlib hash, as follows:: + + >>> from passlib.hash import scram + + >>> #generate new salt, encrypt password against default list of algorithms + >>> h = scram.encrypt("password") + >>> h + '$scram$40000$xxxxxx$sha-1=..............................,\ + sha-256=........................................,\ + sha-512=.........................................' + + >>> #same, but with explict number of rounds + >>> scram.encrypt("password", rounds=10000) + '$scram$40000$xxxxxx$sha-1=..............................,\ + sha-256=........................................,\ + sha-512=.........................................' + + >>> #check if hash is recognized + >>> scram.identify(h) + True + >>> #check if some other hash is recognized + >>> scram.identify('$1$3azHgidD$SrJPt7B.9rekpmwJwtON31') + False + + >>> #verify correct password + >>> scram.verify("password", h) + True + >>> scram.verify("secret", h) #verify incorrect password + False + +Additionally, this class provides a number of useful methods +for SCRAM-specific actions:: + + >>> from passlib.hash import scram + >>> # generate new salt, encrypt password against default list of algorithms + >>> h = scram.encrypt("password") + >>> h + '$scram$40000$xxxxxx$sha-1=..............................,\ + sha-256=........................................,\ + sha-512=.........................................' + + >>> # generate new salt, encrypt password against specific list of algorithms + >>> # and choose explicit number of rounds + >>> h = scram.encrypt("password", rounds=1000, algs="sha-1,sha-256,md5") + >>> h + '$scram$40000$xxxxxx$sha-1=..............................,\ + sha-256=........................................,\ + md5=.........................................' + + >>> # given a scram hash, retrieve the information SCRAM needs + >>> # to authenticate using a specific mechanism - + >>> # returns salt, rounds, digest + >>> scram.extact_digest_info("sha-1") + (b"xxxxxx", 400000, b".................") + + >>> # given a scram hash, return list of digest algs present + >>> scram.extract_digest_algs(h) + ["sha-1","sha-256","md5"] + + >>> # and a standalone helper that can calculated the SaltedPassword + >>> # portion of the SCRAM protocol. + >>> scram.derive_digest("password", b'xxxxx', 40000, 'sha-1') + b'..............................' + +Interface +========= +.. autoclass:: scram(algs=None, salt=None, rounds=None, strict=False) + +Format & Algorithm +================== +An example scram hash (of the string ``password``) is: + + ``$6$rounds=40000$JvTuqzqw9bQ8iBl6$SxklIkW4gz00LvuOsKRCfNEllLciOqY/FSAwODHon45YTJEozmy.QAWiyVpuiq7XMTUMWbIWWEuQytdHkigcN/``. + +An scram hash string has the format :samp:`$scram${rounds}${salt}${alg}={digest}{,...}`, where: + +* ``$scram$`` is the prefix used to identify Passlib scram hashes, + following the :ref:`modular-crypt-format` + +* :samp:`{rounds}` is the decimal number of rounds to use (40000 in the example). + +* :samp:`{salt}` is a base64 encoded salt string (``JvTuqzqw9bQ8iBl6`` in the example). + +* :samp:`{alg}` is a lowercase IANA hash function name, which should + match the digest in the SCRAM mechanism name. + +* :samp:`{digest}` is a base64 digest for the specific algorithm. + +* There will be one or more `{alg}={digest}` pairs, separated by a comma; + per the SCRAM specification, the algorithm ``sha-1`` should always be present. + +There is also an alternate format :samp:`$scram${rounds}${salt}${alg}{,...}` +which is used to represent a configuration string that doesn't contain +any digests. + +The algorithm used to calculate each digest is +``pbkdf2(salsprep(password).encode("utf-8"), salt, rounds, -1, alg)``, +as laid out in the SCRAM specification. All digests +verify against the same password, or the hash should be considered malformed. + +.. note:: + + This format is similar in spirit to the LDAP storage format for SCRAM hashes, + defined in :rfc:`5803`, except that it encodes everything into a single + string, and does not have any storage requirements (outside of the ability + to store 1024+ character ascii strings). |
