online
  #   ˆÁÄ„„ãŸa–ß=¿J*e¶¥8 ¸Ðn4Ê˜´oÃ ?÷     """passlib.handlers.des_crypt - traditional unix (DES) crypt and variants"""
#=============================================================================
# imports
#=============================================================================
# core
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
# site
# pkg
from passlib.utils import safe_crypt, test_crypt, to_unicode
from passlib.utils.binary import h64, h64big
from passlib.utils.compat import byte_elem_value, u, uascii_to_str, unicode, suppress_cause
from passlib.crypto.des import des_encrypt_int_block
import passlib.utils.handlers as uh
# local
__all__ = [
    "des_crypt",
    "bsdi_crypt",
    "bigcrypt",
    "crypt16",
]

#=============================================================================
# pure-python backend for des_crypt family
#=============================================================================
_BNULL = b'\x00'

def _crypt_secret_to_key(secret):
    """convert 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.
    """
    # NOTE: this would set the parity bits correctly,
    #       but des_encrypt_int_block() would just ignore them...
    ##return sum(expand_7bit(byte_elem_value(c) & 0x7f) << (56-i*8)
    ##           for i, c in enumerate(secret[:8]))
    return sum((byte_elem_value(c) & 0x7f) << (57-i*8)
               for i, c in enumerate(secret[:8]))

def _raw_des_crypt(secret, salt):
    """pure-python backed for des_crypt"""
    assert len(salt) == 2

    # NOTE: some OSes will accept non-HASH64 characters in the salt,
    #       but what value they assign these characters varies wildy,
    #       so just rejecting them outright.
    #       the same goes for single-character salts...
    #       some OSes duplicate the char, some insert a '.' char,
    #       and openbsd does (something) which creates an invalid hash.
    salt_value = h64.decode_int12(salt)

    # gotta do something - no official policy since this predates unicode
    if isinstance(secret, unicode):
        secret = secret.encode("utf-8")
    assert isinstance(secret, bytes)

    # forbidding NULL char because underlying crypt() rejects them too.
    if _BNULL in secret:
        raise uh.exc.NullPasswordError(des_crypt)

    # convert first 8 bytes of secret string into an integer
    key_value = _crypt_secret_to_key(secret)

    # run data through des using input of 0
    result = des_encrypt_int_block(key_value, 0, salt_value, 25)

    # run h64 encode on result
    return h64big.encode_int64(result)

def _bsdi_secret_to_key(secret):
    """convert secret to DES key used by bsdi_crypt"""
    key_value = _crypt_secret_to_key(secret)
    idx = 8
    end = len(secret)
    while idx < end:
        next = idx + 8
        tmp_value = _crypt_secret_to_key(secret[idx:next])
        key_value = des_encrypt_int_block(key_value, key_value) ^ tmp_value
        idx = next
    return key_value

def _raw_bsdi_crypt(secret, rounds, salt):
    """pure-python backend for bsdi_crypt"""

    # decode salt
    salt_value = h64.decode_int24(salt)

    # gotta do something - no official policy since this predates unicode
    if isinstance(secret, unicode):
        secret = secret.encode("utf-8")
    assert isinstance(secret, bytes)

    # forbidding NULL char because underlying crypt() rejects them too.
    if _BNULL in secret:
        raise uh.exc.NullPasswordError(bsdi_crypt)

    # convert secret string into an integer
    key_value = _bsdi_secret_to_key(secret)

    # run data through des using input of 0
    result = des_encrypt_int_block(key_value, 0, salt_value, rounds)

    # run h64 encode on result
    return h64big.encode_int64(result)

#=============================================================================
# handlers
#=============================================================================
class des_crypt(uh.Tr