5Xc@sdZddlZejeZddlmZmZmZm Z ddl m Z m Z ddl mZmZmZmZddlmZmZddljjZdgZdejejejejfdYZdS( s:passlib.handlers.scram - hash for SCRAM credential storageiN(tconsteqtsaslprept to_native_strt splitcomma(t ab64_decodet ab64_encode(t bascii_to_strt iteritemstutnative_string_types(t pbkdf2_hmactnorm_hash_nametscramcBseZdZdZd ZedZdZdZd Z d Z d"Z d Z dddgZ dddddgZd#ZedZeddZedZedZdZed#d#dZd#dZedZedZdZd#dZeedZRS($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 iiiii tlinearssha-1ssha-256ssha-512ssha-224ssha-384cCsSt|d}|j|}|j}|s<tdn|j|j||fS(sreturn (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(sReturn 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_algss cCs:t|tr!|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_digestsc Cst|dd}|jds6tjj|n|djd}t|dkrptjj|n|\}}}t|}|t |krtjj|nyt |j d}Wn#t k rtjj|nX|s tjj|nd|krd}i} x~|jdD]^} | 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    cKstt|j||j}|dk rX|dk rFtdn|j|}nK|dk r||j|j}n'|jrt |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      cCst|ts*tjj|ddnxt|D]\}}|t|dkrntd|fnt|dkrtd|fnt|t s7tjj|ddq7q7Wd |krtd 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|trt|}ntd|D}td|DrYtdnd|krttdn|S(snormalize algs parametercss|]}t|dVqdS(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|jj|jstStt|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|Stfd|jDSdS(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|jfn|r t}}xt|D]|\}} |j||} t | t | krtd|t | t | fnt | | rt }qgt }qgW|r|rtdqX|SnOx@|j D]5}||kr|j||} t | ||SqWt ddS(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   "    (ssaltRsroundssalgsIIN(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 ""