U
    La_W                     @   s(  d Z ddlZddlZeeZddlmZ ddlm	Z	m
Z
mZ ddlmZmZ ddlmZmZmZmZmZ ddlmZ ddlm  mZ dd	d
dgZdZdd Zdd Zdd Zdd Z G dd dej!ej"ej#ej$Z%G dd	 d	ej"ej&ej#ej$Z'G dd
 d
ej#ej$Z(G dd dej!ej#ej$Z)dS )zFpasslib.handlers.des_crypt - traditional unix (DES) crypt and variants    N)warn)
safe_crypt
test_crypt
to_unicode)h64h64big)byte_elem_valueuuascii_to_strunicodesuppress_cause)des_encrypt_int_block	des_crypt
bsdi_cryptbigcryptcrypt16    c                 C   s   t dd t| dd D S )zconvert secret to 64-bit DES key.

    this only uses the first 8 bytes of the secret,
    and discards the high 8th bit of each byte at that.
    a null parity bit is inserted after every 7th bit of the output.
    c                 s   s*   | ]"\}}t |d @ d|d  > V  qdS )   9      N)r   ).0ic r   >/tmp/pip-unpacked-wheel-8v2dfbvt/passlib/handlers/des_crypt.py	<genexpr>(   s   z'_crypt_secret_to_key.<locals>.<genexpr>Nr   )sum	enumerate)secretr   r   r   _crypt_secret_to_key   s    r   c                 C   sp   t |dkstt|}t| tr.| d} t| ts<tt| krPt	j
tt| }t|d|d}t|S )z pure-python backed for des_crypt   utf-8r      )lenAssertionErrorr   decode_int12
isinstancer   encodebytes_BNULLuhexcNullPasswordErrorr   r   r   r   encode_int64)r   salt
salt_value	key_valueresultr   r   r   _raw_des_crypt+   s    


r2   c                 C   sL   t | }d}t| }||k rH|d }t | || }t|||A }|}q|S )z,convert secret to DES key used by bsdi_cryptr   )r   r#   r   )r   r0   idxendnext	tmp_valuer   r   r   _bsdi_secret_to_keyI   s    r7   c                 C   s`   t |}t| tr| d} t| ts,tt| kr@tj	
tt| }t|d||}t|S )z"pure-python backend for bsdi_cryptr!   r   )r   decode_int24r&   r   r'   r(   r$   r)   r*   r+   r,   r   r7   r   r   r-   )r   roundsr.   r/   r0   r1   r   r   r   _raw_bsdi_cryptU   s    


r:   c                   @   s   e Zd ZdZd ZdZejZdZ	d Z
ZejZdZeedejejB Zedd Zd	d
 Zdd ZdZedd Zdd Zedd Zdd ZdS )r   a  This class implements the des-crypt password hash, and follows the :ref:`password-hash-api`.

    It supports a fixed-length salt.

    The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords:

    :type salt: str
    :param salt:
        Optional salt string.
        If not specified, one will be autogenerated (this is recommended).
        If specified, it must be 2 characters, drawn from the regexp range ``[./0-9A-Za-z]``.

    :param bool truncate_error:
        By default, des_crypt will silently truncate passwords larger than 8 bytes.
        Setting ``truncate_error=True`` will cause :meth:`~passlib.ifc.PasswordHash.hash`
        to raise a :exc:`~passlib.exc.PasswordTruncateError` instead.

        .. versionadded:: 1.7

    :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
        ``salt`` strings that are too long.

        .. versionadded:: 1.6
    r.   Ztruncate_error   r    r   zU
        ^
        (?P<salt>[./a-z0-9]{2})
        (?P<chk>[./a-z0-9]{11})?
        $c                 C   s6   t |dd}|d d |dd   }}| ||p0d dS )Nasciihashr    r.   checksum)r   )clsr>   r.   chkr   r   r   from_string   s    zdes_crypt.from_stringc                 C   s   t d| j| jf }t|S Nz%s%sr	   r.   r@   r
   selfr>   r   r   r   	to_string   s    zdes_crypt.to_stringc                 C   s   | j r| | | |S )N)use_defaults_check_truncate_policyZ_calc_checksum_backendrG   r   r   r   r   _calc_checksum   s    
zdes_crypt._calc_checksumZos_cryptbuiltinc                 C   s"   t ddr| | j dS dS d S )NtestZabgOeLfPimXQoTFr   _set_calc_checksum_backend_calc_checksum_os_cryptrA   r   r   r   _load_backend_os_crypt   s    
z des_crypt._load_backend_os_cryptc                 C   sT   t || j}|d kr| |S || jr6t|dkrHtj| | j||dd  S )N   r    )r   r.   _calc_checksum_builtin
startswithr#   r*   r+   CryptBackendError)rG   r   r>   r   r   r   rR      s    
z!des_crypt._calc_checksum_os_cryptc                 C   s   |  | j dS NTrQ   rV   rS   r   r   r   _load_backend_builtin   s    zdes_crypt._load_backend_builtinc                 C   s   t || jddS Nr=   )r2   r.   r'   decoderK   r   r   r   rV      s    z des_crypt._calc_checksum_builtinN)__name__
__module____qualname____doc__namesetting_kwdsr*   HASH64_CHARSchecksum_charschecksum_sizemin_salt_sizemax_salt_size
salt_charstruncate_sizerecompiler	   XI_hash_regexclassmethodrC   rH   rL   backendsrT   rR   r[   rV   r   r   r   r   r   p   s,   $





c                       s   e Zd ZdZd ZdZdZejZ	d Z
ZejZdZdZdZdZeed	ejejB Zed
d Zdd ZdZe fddZe fddZ fddZdZedd Zdd Z edd Z!dd Z"  Z#S )r   a
  This class implements the BSDi-Crypt password hash, and follows the :ref:`password-hash-api`.

    It supports a fixed-length salt, and a variable number of rounds.

    The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords:

    :type salt: str
    :param salt:
        Optional salt string.
        If not specified, one will be autogenerated (this is recommended).
        If specified, it must be 4 characters, drawn from the regexp range ``[./0-9A-Za-z]``.

    :type rounds: int
    :param rounds:
        Optional number of rounds to use.
        Defaults to 5001, must be between 1 and 16777215, inclusive.

    :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

    .. versionchanged:: 1.6
        :meth:`hash` will now issue a warning if an even number of rounds is used
        (see :ref:`bsdi-crypt-security-issues` regarding weak DES keys).
    )r.   r9   r<      i     i Zlinearz
        ^
        _
        (?P<rounds>[./a-z0-9]{4})
        (?P<salt>[./a-z0-9]{4})
        (?P<chk>[./a-z0-9]{11})?
        $c                 C   sV   t |dd}| j|}|s(tj| |ddd\}}}| t|	d||dS )Nr=   r>   r9   r.   rB   )r9   r.   r@   )
r   ro   matchr*   r+   InvalidHashErrorgroupr   r8   r'   )rA   r>   mr9   r.   rB   r   r   r   rC   4  s    zbsdi_crypt.from_stringc                 C   s,   t dt| jd| j| jf }t|S )Nz_%s%s%sr=   )r	   r   Zencode_int24r9   r]   r.   r@   r
   rF   r   r   r   rH   A  s
     zbsdi_crypt.to_stringTc                    s.   t t| jf |}|jd@ s*tdtjj |S )Nrs   zHbsdi_crypt rounds should be odd, as even rounds may reveal weak DES keys)superr   usingdefault_roundsr   r*   r+   ZPasslibSecurityWarning)rA   kwdssubcls	__class__r   r   ry   N  s    
zbsdi_crypt.usingc                    s   t t|  }|dB S )Nrs   )rx   r   _generate_rounds)rA   r9   r}   r   r   r   W  s    zbsdi_crypt._generate_roundsc                    s    | j d@ sdS tt| jf |S )Nrs   T)r9   rx   r   _calc_needs_update)rG   r{   r}   r   r   r   e  s    
zbsdi_crypt._calc_needs_updaterM   c                 C   s"   t ddr| | j dS dS d S )NrO   z_/...lLDAxARksGCHin.TFrP   rS   r   r   r   rT   t  s    
z!bsdi_crypt._load_backend_os_cryptc                 C   s^   |   }t||}|d kr$| |S ||d d rBt|dkrRtj| |||dd  S )N	      )rH   r   rV   rW   r#   r*   r+   rX   )rG   r   configr>   r   r   r   rR   |  s    

z"bsdi_crypt._calc_checksum_os_cryptc                 C   s   |  | j dS rY   rZ   rS   r   r   r   r[     s    z bsdi_crypt._load_backend_builtinc                 C   s   t || j| jddS r\   )r:   r9   r.   r'   r]   rK   r   r   r   rV     s    z!bsdi_crypt._calc_checksum_builtin)$r^   r_   r`   ra   rb   rc   rf   r*   rd   re   rg   rh   ri   rz   Z
min_roundsZ
max_roundsZrounds_costrk   rl   r	   rm   rn   ro   rp   rC   rH   Z_avoid_even_roundsry   r   r   rq   rT   rR   r[   rV   __classcell__r   r   r}   r   r      s<   #





c                       sr   e Zd ZdZd ZdZejZd Z	Z
ejZeedejejB Zedd Zdd Zd fd
d	Zdd Z  ZS )r   ag  This class implements the BigCrypt password hash, and follows the :ref:`password-hash-api`.

    It supports a fixed-length salt.

    The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords:

    :type salt: str
    :param salt:
        Optional salt string.
        If not specified, one will be autogenerated (this is recommended).
        If specified, it must be 22 characters, drawn from the regexp range ``[./0-9A-Za-z]``.

    :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
        ``salt`` strings that are too long.

        .. versionadded:: 1.6
    )r.   r    zX
        ^
        (?P<salt>[./a-z0-9]{2})
        (?P<chk>([./a-z0-9]{11})+)?
        $c                 C   sD   t |dd}| j|}|s(tj| |dd\}}| ||dS Nr=   r>   r.   rB   r?   r   ro   rt   r*   r+   ru   rv   rA   r>   rw   r.   rB   r   r   r   rC     s    zbigcrypt.from_stringc                 C   s   t d| j| jf }t|S rD   rE   rF   r   r   r   rH     s    zbigcrypt.to_stringFc                    s0   t t| j||d}t|d r,tj| |S )N)relaxedr<   )rx   r   _norm_checksumr#   r*   r+   ru   )rG   r@   r   r}   r   r   r     s    zbigcrypt._norm_checksumc                 C   sp   t |tr|d}t|| jd}d}t|}||k rf|d }|t||| |dd 7 }|}q2|dS )Nr!   r=   r   r   i)r&   r   r'   r2   r.   r#   r]   )rG   r   rB   r3   r4   r5   r   r   r   rL     s    

zbigcrypt._calc_checksum)F)r^   r_   r`   ra   rb   rc   r*   rd   re   rg   rh   ri   rk   rl   r	   rm   rn   ro   rp   rC   rH   r   rL   r   r   r   r}   r   r     s   


	c                   @   sh   e Zd ZdZd ZdZdZejZ	d Z
ZejZdZeedejejB Zedd Zd	d
 Zdd ZdS )r   a  This class implements the crypt16 password hash, and follows the :ref:`password-hash-api`.

    It supports a fixed-length salt.

    The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords:

    :type salt: str
    :param salt:
        Optional salt string.
        If not specified, one will be autogenerated (this is recommended).
        If specified, it must be 2 characters, drawn from the regexp range ``[./0-9A-Za-z]``.

    :param bool truncate_error:
        By default, crypt16 will silently truncate passwords larger than 16 bytes.
        Setting ``truncate_error=True`` will cause :meth:`~passlib.ifc.PasswordHash.hash`
        to raise a :exc:`~passlib.exc.PasswordTruncateError` instead.

        .. versionadded:: 1.7

    :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
        ``salt`` strings that are too long.

        .. versionadded:: 1.6
    r;      r       zU
        ^
        (?P<salt>[./a-z0-9]{2})
        (?P<chk>[./a-z0-9]{22})?
        $c                 C   sD   t |dd}| j|}|s(tj| |dd\}}| ||dS r   r   r   r   r   r   rC   +  s    zcrypt16.from_stringc                 C   s   t d| j| jf }t|S rD   rE   rF   r   r   r   rH   4  s    zcrypt16.to_stringc                 C   s   t |tr|d}| jr$| | zt| jd}W n  tk
rZ   t	tdY nX t
|}t|d|d}t
|dd }t|d|d}t|t| }|dS )	Nr!   r=   zinvalid chars in saltr   r   r   r      )r&   r   r'   rI   rJ   r   r%   r.   
ValueErrorr   r   r   r   r-   r]   )rG   r   r/   key1Zresult1key2Zresult2rB   r   r   r   rL   ;  s    


zcrypt16._calc_checksumN)r^   r_   r`   ra   rb   rc   rf   r*   rd   re   rg   rh   ri   rj   rk   rl   r	   rm   rn   ro   rp   rC   rH   rL   r   r   r   r   r     s   $


)*ra   rk   logging	getLoggerr^   logwarningsr   Zpasslib.utilsr   r   r   Zpasslib.utils.binaryr   r   Zpasslib.utils.compatr   r	   r
   r   r   Zpasslib.crypto.desr   Zpasslib.utils.handlersutilshandlersr*   __all__r)   r   r2   r7   r:   ZTruncateMixinZHasManyBackendsZHasSaltZGenericHandlerr   Z	HasRoundsr   r   r   r   r   r   r   <module>   s2    

  $S