ó ö 5Xc@sÛdZddlZejeƒZddlmZmZmZm Z ddl m Z m Z ddl mZmZmZmZddlmZmZddljjZdgZdejejejejfd„ƒYZdS( s:passlib.handlers.scram - hash for SCRAM credential storageiÿÿÿÿN(tconsteqtsaslprept to_native_strt splitcomma(t ab64_decodet ab64_encode(t bascii_to_strt iteritemstutnative_string_types(t pbkdf2_hmactnorm_hash_nametscramcBseZdZdZd ZedƒZdZdZd Z d Z d"Z d Z dddgZ dddddgZd#Zed„ƒZedd„ƒZed„ƒZed„ƒZd„Zed#d#d„ƒZd#d„Zed„Zed„ƒZd„Zd#d„Zeed„ƒZRS($sZThis class provides a format for storing SCRAM passwords, and follows the :ref:`password-hash-api`. It supports a variable-length salt, and a variable number of rounds. The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: :type salt: bytes :param salt: Optional salt bytes. If specified, the length must be between 0-1024 bytes. If not specified, a 12 byte salt will be autogenerated (this is recommended). :type salt_size: int :param salt_size: Optional number of bytes to use when autogenerating new salts. Defaults to 12 bytes, but can be any value between 0 and 1024. :type rounds: int :param rounds: Optional number of rounds to use. Defaults to 100000, but must be within ``range(1,1<<32)``. :type algs: list of strings :param algs: Specify list of digest algorithms to use. By default each scram hash will contain digests for SHA-1, SHA-256, and SHA-512. This can be overridden by specify either be a list such as ``["sha-1", "sha-256"]``, or a comma-separated string such as ``"sha-1, sha-256"``. Names are case insensitive, and may use :mod:`!hashlib` or `IANA `_ hash names. :type relaxed: bool :param relaxed: By default, providing an invalid value for one of the other keywords will result in a :exc:`ValueError`. If ``relaxed=True``, and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` will be issued instead. Correctable errors include ``rounds`` that are too small or too large, and ``salt`` strings that are too long. .. versionadded:: 1.6 In addition to the standard :ref:`password-hash-api` methods, this class also provides the following methods for manipulating Passlib scram hashes in ways useful for pluging into a SCRAM protocol stack: .. automethod:: extract_digest_info .. automethod:: extract_digest_algs .. automethod:: derive_digest R tsaltt salt_sizetroundstalgss$scram$i ii †iii tlinearssha-1ssha-256ssha-512ssha-224ssha-384cCsSt|dƒ}|j|ƒ}|j}|s<tdƒ‚n|j|j||fS(sèreturn (salt, rounds, digest) for specific hash algorithm. :type hash: str :arg hash: :class:`!scram` hash stored for desired user :type alg: str :arg alg: Name of digest algorithm (e.g. ``"sha-1"``) requested by client. This value is run through :func:`~passlib.crypto.digest.norm_hash_name`, so it is case-insensitive, and can be the raw SCRAM mechanism name (e.g. ``"SCRAM-SHA-1"``), the IANA name, or the hashlib name. :raises KeyError: If the hash does not contain an entry for the requested digest algorithm. :returns: A tuple containing ``(salt, rounds, digest)``, where *digest* matches the raw bytes returned by SCRAM's :func:`Hi` function for the stored password, the provided *salt*, and the iteration count (*rounds*). *salt* and *digest* are both raw (unencoded) bytes. tianasscram hash contains no digests(R t from_stringtchecksumt ValueErrorR R(tclsthashtalgtselftchkmap((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pytextract_digest_info|s  RcCsF|j|ƒj}|dkr"|Sg|D]}t||ƒ^q)SdS(sêReturn names of all algorithms stored in a given hash. :type hash: str :arg hash: The :class:`!scram` hash to parse :type format: str :param format: This changes the naming convention used by the returned algorithm names. By default the names are IANA-compatible; possible values are ``"iana"`` or ``"hashlib"``. :returns: Returns a list of digest algorithms; e.g. ``["sha-1"]`` RN(RRR (RRtformatRR((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pytextract_digest_algs¢s cCs:t|tƒr!|jdƒ}nt|t|ƒ||ƒS(s;helper to create SaltedPassword digest for SCRAM. This performs the step in the SCRAM protocol described as:: SaltedPassword := Hi(Normalize(password), salt, i) :type password: unicode or utf-8 bytes :arg password: password to run through digest :type salt: bytes :arg salt: raw salt data :type rounds: int :arg rounds: number of iterations. :type alg: str :arg alg: name of digest to use (e.g. ``"sha-1"``). :returns: raw bytes of ``SaltedPassword`` sutf-8(t isinstancetbytestdecodeR R(RtpasswordR RR((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pyt derive_digest¼sc CsÄt|ddƒ}|jdƒs6tjj|ƒ‚n|djdƒ}t|ƒdkrptjj|ƒ‚n|\}}}t|ƒ}|t |ƒkr²tjj|ƒ‚nyt |j dƒƒ}Wn#t k rðtjj|ƒ‚nX|s tjj|ƒ‚n™d|kr™d}i} x~|jdƒD]^} | jdƒ\} } yt | j dƒƒ| | ss$scram$%d$%s$%s(RRR RtjoinRR(RR R6((Rs:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pyt to_string s   cKsR|dk r|}ntt|ƒj|}|dk rN|j|ƒ|_n|S(N(R2tsuperR tusingt _norm_algst default_algs(RR?Rtkwdstsubcls((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pyR=s    cKs°tt|ƒj||j}|dk rX|dk rFtdƒ‚n|j|ƒ}nK|dk r||j|jƒƒ}n'|jr—t |j ƒ}n t dƒ‚||_ dS(Ns+checksum & algs kwds are mutually exclusivesno algs list specified( R<R t__init__RR2t RuntimeErrorR>tkeyst use_defaultstlistR?R1R(RRR@t digest_map((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pyRB+s      cCsãt|tƒs*tjj|ddƒ‚nx—t|ƒD]‰\}}|t|dƒkrntd|fƒ‚nt|ƒdkr–td|fƒ‚nt|t ƒs7tjj|ddƒ‚q7q7Wd |krßtd ƒ‚n|S( NtdictRRs*malformed algorithm name in scram hash: %ri s0SCRAM limits algorithm names to 9 characters: %rs raw bytestdigestsssha-1s-sha-1 must be in algorithm list of scram hash( RRHR(R)tExpectedTypeErrorRR RR,R(RRtrelaxedRR8((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pyt_norm_checksum>s cCsxt|tƒrt|ƒ}ntd„|Dƒƒ}td„|DƒƒrYtdƒ‚nd|krttdƒ‚n|S(snormalize algs parametercss|]}t|dƒVqdS(RN(R (R9R((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pys Uscss!|]}t|ƒdkVqdS(i N(R,(R9R((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pys Vss-SCRAM limits alg names to max of 9 charactersssha-1s-sha-1 must be in algorithm list of scram hash(RR RtsortedtanyR(RR((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pyR>Ps cKs5t|jƒj|jƒstStt|ƒj|S(N(tsetRt issupersetR?tTrueR<R t_calc_needs_update(RR@((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pyRR`scs^|j‰|j‰|j‰|r4ˆˆˆˆ|ƒSt‡‡‡‡fd†|jDƒƒSdS(Nc3s*|] }|ˆˆˆˆ|ƒfVqdS(N((R9R(RRR tsecret(s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pys ws(RR R"RHR(RRSR((RRR RSs:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pyt_calc_checksumms   c Cs\tj|ƒ|j|ƒ}|j}|sJtd|j|jfƒ‚n|r t}}xŠt|ƒD]|\}} |j||ƒ} t | ƒt | ƒkrÅtd|t | ƒt | ƒfƒ‚nt | | ƒrÝt }qgt }qgW|r|rtdƒ‚qX|SnOx@|j D]5}||kr|j||ƒ} t | ||ƒSqWt dƒ‚dS(Ns.expected %s hash, got %s config string insteads+mis-sized %s digest in scram hash: %r != %rs4scram hash verified inconsistently, may be corruptedssha-1 digest not found!(R(tvalidate_secretRRRtnametFalseRRTR,RRQt _verify_algstAssertionError( RRSRtfullRRtcorrecttfailedRR8tother((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pytverify{s0   "    (ssaltRsroundssalgsIIÿÿÿÿN(t__name__t __module__t__doc__RVt setting_kwdsRtidenttdefault_salt_sizet max_salt_sizetdefault_roundst min_roundst max_roundst rounds_costR?RXR2Rt classmethodRRR"RR;R=RBRWRLR>RRRTR^(((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pyR s85   &!0    (Ratloggingt getLoggerR_tlogt passlib.utilsRRRRtpasslib.utils.binaryRRtpasslib.utils.compatRRRR tpasslib.crypto.digestR R tpasslib.utils.handlerstutilsthandlersR(t__all__t HasRoundst HasRawSalttHasRawChecksumtGenericHandlerR (((s:/usr/lib/python2.7/site-packages/passlib/handlers/scram.pyts ""